domainkit 0.20.1 → 0.22.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 +41 -0
- package/dist/CallbackRecovery.mjs +48 -0
- package/dist/CallbackRecovery.mjs.map +1 -0
- package/dist/Cloudflare.mjs +19 -10
- package/dist/Cloudflare.mjs.map +1 -1
- package/dist/Connect.mjs +39 -11
- package/dist/Connect.mjs.map +1 -1
- package/dist/Provider.mjs.map +1 -1
- package/dist/Server.mjs +139 -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 +2 -1
- package/dist/entry/server.mjs +1 -2
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- 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/CallbackRecovery.d.ts +12 -0
- package/dist/types/Connect.d.ts +150 -0
- package/dist/types/Provider.d.ts +9 -0
- package/dist/types/Server.d.ts +48 -0
- package/dist/types/entry/client.d.ts +1 -0
- package/dist/types/index.d.ts +1 -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 +14 -10
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
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";
|
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { DnsRecord_exports } from "./DnsRecord.mjs";
|
|
|
3
3
|
import { Plan_exports } from "./Plan.mjs";
|
|
4
4
|
import { Reason_exports } from "./Reason.mjs";
|
|
5
5
|
import { Approval_exports } from "./Approval.mjs";
|
|
6
|
+
import { CallbackRecovery_exports } from "./CallbackRecovery.mjs";
|
|
6
7
|
import { Custody_exports } from "./Custody.mjs";
|
|
7
8
|
import { Principal_exports } from "./Principal.mjs";
|
|
8
9
|
import { Provider_exports } from "./Provider.mjs";
|
|
@@ -26,7 +27,7 @@ import { version } from "./package.mjs";
|
|
|
26
27
|
* Lifecycle services: Connect, Provision, Cleanup, Verify.
|
|
27
28
|
* Host seams: Storage, Custody, Principal.
|
|
28
29
|
* Providers: Provider, Providers, Cloudflare, Vercel.
|
|
29
|
-
* Values: DomainName, DnsRecord, Plan, Approval, Receipt.
|
|
30
|
+
* Values: DomainName, DnsRecord, Plan, Approval, Receipt, CallbackRecovery.
|
|
30
31
|
* Everything else: Reason, Resolver, DomainKit (the composed layer and `DomainKit.Error`).
|
|
31
32
|
*
|
|
32
33
|
* Subpath: domainkit/testing.
|
|
@@ -34,6 +35,6 @@ import { version } from "./package.mjs";
|
|
|
34
35
|
/** The current package version from the package manifest. */
|
|
35
36
|
const VERSION = version;
|
|
36
37
|
//#endregion
|
|
37
|
-
export { Approval_exports as Approval, Cleanup_exports as Cleanup, Cloudflare_exports as Cloudflare, Connect_exports as Connect, Custody_exports as Custody, DnsRecord_exports as DnsRecord, DomainKit_exports as DomainKit, DomainName_exports as DomainName, Plan_exports as Plan, Principal_exports as Principal, Provider_exports as Provider, Providers_exports as Providers, Provision_exports as Provision, Reason_exports as Reason, Receipt_exports as Receipt, Resolver_exports as Resolver, Storage_exports as Storage, VERSION, Vercel_exports as Vercel, Verify_exports as Verify };
|
|
38
|
+
export { Approval_exports as Approval, CallbackRecovery_exports as CallbackRecovery, Cleanup_exports as Cleanup, Cloudflare_exports as Cloudflare, Connect_exports as Connect, Custody_exports as Custody, DnsRecord_exports as DnsRecord, DomainKit_exports as DomainKit, DomainName_exports as DomainName, Plan_exports as Plan, Principal_exports as Principal, Provider_exports as Provider, Providers_exports as Providers, Provision_exports as Provision, Reason_exports as Reason, Receipt_exports as Receipt, Resolver_exports as Resolver, Storage_exports as Storage, VERSION, Vercel_exports as Vercel, Verify_exports as Verify };
|
|
38
39
|
|
|
39
40
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["packageJson.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * domainkit — the Effect-native root. One module per concept: services expose `Service` (the tag)\n * and `Interface` (its shape), value modules expose `Model` (the schema).\n *\n * Lifecycle services: Connect, Provision, Cleanup, Verify.\n * Host seams: Storage, Custody, Principal.\n * Providers: Provider, Providers, Cloudflare, Vercel.\n * Values: DomainName, DnsRecord, Plan, Approval, Receipt.\n * Everything else: Reason, Resolver, DomainKit (the composed layer and `DomainKit.Error`).\n *\n * Subpath: domainkit/testing.\n */\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\n/** The current package version from the package manifest. */\nexport const VERSION = packageJson.version;\n\nexport * as Approval from \"./Approval.ts\";\nexport * as Cleanup from \"./Cleanup.ts\";\nexport * as Cloudflare from \"./Cloudflare.ts\";\nexport * as Connect from \"./Connect.ts\";\nexport * as Custody from \"./Custody.ts\";\nexport * as DnsRecord from \"./DnsRecord.ts\";\nexport * as DomainKit from \"./DomainKit.ts\";\nexport * as DomainName from \"./DomainName.ts\";\nexport * as Plan from \"./Plan.ts\";\nexport * as Principal from \"./Principal.ts\";\nexport * as Provider from \"./Provider.ts\";\nexport * as Providers from \"./Providers.ts\";\nexport * as Provision from \"./Provision.ts\";\nexport * as Reason from \"./Reason.ts\";\nexport * as Receipt from \"./Receipt.ts\";\nexport * as Resolver from \"./Resolver.ts\";\nexport * as Storage from \"./Storage.ts\";\nexport * as Vercel from \"./Vercel.ts\";\nexport * as Verify from \"./Verify.ts\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["packageJson.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * domainkit — the Effect-native root. One module per concept: services expose `Service` (the tag)\n * and `Interface` (its shape), value modules expose `Model` (the schema).\n *\n * Lifecycle services: Connect, Provision, Cleanup, Verify.\n * Host seams: Storage, Custody, Principal.\n * Providers: Provider, Providers, Cloudflare, Vercel.\n * Values: DomainName, DnsRecord, Plan, Approval, Receipt, CallbackRecovery.\n * Everything else: Reason, Resolver, DomainKit (the composed layer and `DomainKit.Error`).\n *\n * Subpath: domainkit/testing.\n */\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\n/** The current package version from the package manifest. */\nexport const VERSION = packageJson.version;\n\nexport * as Approval from \"./Approval.ts\";\nexport * as CallbackRecovery from \"./CallbackRecovery.ts\";\nexport * as Cleanup from \"./Cleanup.ts\";\nexport * as Cloudflare from \"./Cloudflare.ts\";\nexport * as Connect from \"./Connect.ts\";\nexport * as Custody from \"./Custody.ts\";\nexport * as DnsRecord from \"./DnsRecord.ts\";\nexport * as DomainKit from \"./DomainKit.ts\";\nexport * as DomainName from \"./DomainName.ts\";\nexport * as Plan from \"./Plan.ts\";\nexport * as Principal from \"./Principal.ts\";\nexport * as Provider from \"./Provider.ts\";\nexport * as Providers from \"./Providers.ts\";\nexport * as Provision from \"./Provision.ts\";\nexport * as Reason from \"./Reason.ts\";\nexport * as Receipt from \"./Receipt.ts\";\nexport * as Resolver from \"./Resolver.ts\";\nexport * as Storage from \"./Storage.ts\";\nexport * as Vercel from \"./Vercel.ts\";\nexport * as Verify from \"./Verify.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,MAAa,UAAUA"}
|
|
@@ -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":"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"}
|
|
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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Browser-safe recovery hints for returning from an authenticated provider callback. */
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
export declare const Model: Schema.Struct<{
|
|
4
|
+
readonly kind: Schema.Literals<readonly ["cancelled", "restart", "inspect"]>;
|
|
5
|
+
readonly provider: Schema.String;
|
|
6
|
+
readonly connectionId: Schema.optionalKey<Schema.String>;
|
|
7
|
+
}>;
|
|
8
|
+
export type Model = typeof Model.Type;
|
|
9
|
+
/** Reads a complete recovery hint; ignores missing, duplicate, or invalid metadata. */
|
|
10
|
+
export declare const read: (url: URL) => Model | null;
|
|
11
|
+
/** Clones the URL and replaces or clears all recovery hints, preserving other parameters and hash. */
|
|
12
|
+
export declare const write: (url: URL, outcome: Model | null) => URL;
|
package/dist/types/Connect.d.ts
CHANGED
|
@@ -233,6 +233,127 @@ 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
|
+
readonly connectionId?: string;
|
|
246
|
+
};
|
|
247
|
+
Failed: {
|
|
248
|
+
readonly error: Errors.DomainKitError;
|
|
249
|
+
readonly recovery: "restart" | "inspect";
|
|
250
|
+
readonly connectionId?: string;
|
|
251
|
+
};
|
|
252
|
+
}>;
|
|
253
|
+
export declare const Completion: {
|
|
254
|
+
readonly $is: <Tag extends "Cancelled" | "Connected" | "Failed">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
255
|
+
readonly _tag: "Cancelled";
|
|
256
|
+
readonly error: Errors.DomainKitError;
|
|
257
|
+
readonly connectionId?: string;
|
|
258
|
+
}, {
|
|
259
|
+
readonly _tag: Tag;
|
|
260
|
+
}> | Extract<{
|
|
261
|
+
readonly _tag: "Connected";
|
|
262
|
+
readonly started: Exclude<Started, {
|
|
263
|
+
readonly _tag: "Redirect";
|
|
264
|
+
}>;
|
|
265
|
+
}, {
|
|
266
|
+
readonly _tag: Tag;
|
|
267
|
+
}> | Extract<{
|
|
268
|
+
readonly _tag: "Failed";
|
|
269
|
+
readonly error: Errors.DomainKitError;
|
|
270
|
+
readonly recovery: "restart" | "inspect";
|
|
271
|
+
readonly connectionId?: string;
|
|
272
|
+
}, {
|
|
273
|
+
readonly _tag: Tag;
|
|
274
|
+
}>;
|
|
275
|
+
readonly $match: {
|
|
276
|
+
<Cases extends { readonly [Tag in "Cancelled" | "Connected" | "Failed"]: (args: Extract<{
|
|
277
|
+
readonly _tag: "Cancelled";
|
|
278
|
+
readonly error: Errors.DomainKitError;
|
|
279
|
+
readonly connectionId?: string;
|
|
280
|
+
} | {
|
|
281
|
+
readonly _tag: "Connected";
|
|
282
|
+
readonly started: Exclude<Started, {
|
|
283
|
+
readonly _tag: "Redirect";
|
|
284
|
+
}>;
|
|
285
|
+
} | {
|
|
286
|
+
readonly _tag: "Failed";
|
|
287
|
+
readonly error: Errors.DomainKitError;
|
|
288
|
+
readonly recovery: "restart" | "inspect";
|
|
289
|
+
readonly connectionId?: string;
|
|
290
|
+
}, {
|
|
291
|
+
readonly _tag: Tag;
|
|
292
|
+
}>) => any; }>(cases: Cases): (value: {
|
|
293
|
+
readonly _tag: "Cancelled";
|
|
294
|
+
readonly error: Errors.DomainKitError;
|
|
295
|
+
readonly connectionId?: string;
|
|
296
|
+
} | {
|
|
297
|
+
readonly _tag: "Connected";
|
|
298
|
+
readonly started: Exclude<Started, {
|
|
299
|
+
readonly _tag: "Redirect";
|
|
300
|
+
}>;
|
|
301
|
+
} | {
|
|
302
|
+
readonly _tag: "Failed";
|
|
303
|
+
readonly error: Errors.DomainKitError;
|
|
304
|
+
readonly recovery: "restart" | "inspect";
|
|
305
|
+
readonly connectionId?: string;
|
|
306
|
+
}) => import("effect/Unify").Unify<ReturnType<Cases["Cancelled" | "Connected" | "Failed"]>>;
|
|
307
|
+
<Cases extends { readonly [Tag in "Cancelled" | "Connected" | "Failed"]: (args: Extract<{
|
|
308
|
+
readonly _tag: "Cancelled";
|
|
309
|
+
readonly error: Errors.DomainKitError;
|
|
310
|
+
readonly connectionId?: string;
|
|
311
|
+
} | {
|
|
312
|
+
readonly _tag: "Connected";
|
|
313
|
+
readonly started: Exclude<Started, {
|
|
314
|
+
readonly _tag: "Redirect";
|
|
315
|
+
}>;
|
|
316
|
+
} | {
|
|
317
|
+
readonly _tag: "Failed";
|
|
318
|
+
readonly error: Errors.DomainKitError;
|
|
319
|
+
readonly recovery: "restart" | "inspect";
|
|
320
|
+
readonly connectionId?: string;
|
|
321
|
+
}, {
|
|
322
|
+
readonly _tag: Tag;
|
|
323
|
+
}>) => any; }>(value: {
|
|
324
|
+
readonly _tag: "Cancelled";
|
|
325
|
+
readonly error: Errors.DomainKitError;
|
|
326
|
+
readonly connectionId?: string;
|
|
327
|
+
} | {
|
|
328
|
+
readonly _tag: "Connected";
|
|
329
|
+
readonly started: Exclude<Started, {
|
|
330
|
+
readonly _tag: "Redirect";
|
|
331
|
+
}>;
|
|
332
|
+
} | {
|
|
333
|
+
readonly _tag: "Failed";
|
|
334
|
+
readonly error: Errors.DomainKitError;
|
|
335
|
+
readonly recovery: "restart" | "inspect";
|
|
336
|
+
readonly connectionId?: string;
|
|
337
|
+
}, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["Cancelled" | "Connected" | "Failed"]>>;
|
|
338
|
+
};
|
|
339
|
+
readonly Cancelled: Data.TaggedEnum.ConstructorFrom<{
|
|
340
|
+
readonly _tag: "Cancelled";
|
|
341
|
+
readonly error: Errors.DomainKitError;
|
|
342
|
+
readonly connectionId?: string;
|
|
343
|
+
}, "_tag">;
|
|
344
|
+
readonly Connected: Data.TaggedEnum.ConstructorFrom<{
|
|
345
|
+
readonly _tag: "Connected";
|
|
346
|
+
readonly started: Exclude<Started, {
|
|
347
|
+
readonly _tag: "Redirect";
|
|
348
|
+
}>;
|
|
349
|
+
}, "_tag">;
|
|
350
|
+
readonly Failed: Data.TaggedEnum.ConstructorFrom<{
|
|
351
|
+
readonly _tag: "Failed";
|
|
352
|
+
readonly error: Errors.DomainKitError;
|
|
353
|
+
readonly recovery: "restart" | "inspect";
|
|
354
|
+
readonly connectionId?: string;
|
|
355
|
+
}, "_tag">;
|
|
356
|
+
};
|
|
236
357
|
/** `attach` either attached the domain or needs the caller to pick a zone. */
|
|
237
358
|
export type Selection = Data.TaggedEnum<{
|
|
238
359
|
SelectionRequired: {
|
|
@@ -477,6 +598,16 @@ export interface Interface {
|
|
|
477
598
|
readonly continuationId: string;
|
|
478
599
|
readonly callbackUrl: string;
|
|
479
600
|
}) => Fx<Started>;
|
|
601
|
+
/**
|
|
602
|
+
* Classify only after live owner/actor verification inside the completion lock. Optional
|
|
603
|
+
* `provider` binds the flow to a mounted route. Invalid flows fail without an outcome.
|
|
604
|
+
* Cancellation and failure leave the continuation retryable; persistence is not atomic.
|
|
605
|
+
*/
|
|
606
|
+
readonly completeOutcome: (input: {
|
|
607
|
+
readonly continuationId: string;
|
|
608
|
+
readonly callbackUrl: string;
|
|
609
|
+
readonly provider?: string;
|
|
610
|
+
}) => Fx<Completion>;
|
|
480
611
|
readonly attach: (input: {
|
|
481
612
|
readonly connectionId: string;
|
|
482
613
|
readonly domain: string;
|
|
@@ -586,6 +717,25 @@ export declare const complete: (input: {
|
|
|
586
717
|
readonly connection: Storage.Connection;
|
|
587
718
|
readonly candidates: ReadonlyArray<Provider.Target>;
|
|
588
719
|
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
720
|
+
export declare const completeOutcome: (input: {
|
|
721
|
+
readonly continuationId: string;
|
|
722
|
+
readonly callbackUrl: string;
|
|
723
|
+
readonly provider?: string;
|
|
724
|
+
}) => Effect.Effect<{
|
|
725
|
+
readonly _tag: "Cancelled";
|
|
726
|
+
readonly error: Errors.DomainKitError;
|
|
727
|
+
readonly connectionId?: string;
|
|
728
|
+
} | {
|
|
729
|
+
readonly _tag: "Connected";
|
|
730
|
+
readonly started: Exclude<Started, {
|
|
731
|
+
readonly _tag: "Redirect";
|
|
732
|
+
}>;
|
|
733
|
+
} | {
|
|
734
|
+
readonly _tag: "Failed";
|
|
735
|
+
readonly error: Errors.DomainKitError;
|
|
736
|
+
readonly recovery: "restart" | "inspect";
|
|
737
|
+
readonly connectionId?: string;
|
|
738
|
+
}, Errors.DomainKitError, Principal.Service | Service>;
|
|
589
739
|
export declare const attach: (input: {
|
|
590
740
|
readonly connectionId: string;
|
|
591
741
|
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,25 @@ 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 connectionId: Schema.optionalKey<Schema.String>;
|
|
11407
|
+
readonly returnTo: Schema.String;
|
|
11408
|
+
}>, Schema.Struct<{
|
|
11409
|
+
readonly _tag: Schema.Literal<"Failed">;
|
|
11410
|
+
readonly provider: Schema.String;
|
|
11411
|
+
readonly connectionId: Schema.optionalKey<Schema.String>;
|
|
11412
|
+
readonly returnTo: Schema.String;
|
|
11413
|
+
readonly recovery: Schema.Literals<readonly ["restart", "inspect"]>;
|
|
11414
|
+
}>]>;
|
|
11415
|
+
export type CallbackOutcome = typeof CallbackOutcome.Type;
|
|
11396
11416
|
export interface Options {
|
|
11397
11417
|
/**
|
|
11398
11418
|
* Where the callback route is reachable from the provider, without the `/callback/:provider`
|
|
@@ -11401,7 +11421,35 @@ export interface Options {
|
|
|
11401
11421
|
readonly callbackBaseUrl?: string;
|
|
11402
11422
|
/** Where interactive flows return when the callback carries no `returnTo`. */
|
|
11403
11423
|
readonly defaultReturnTo?: string;
|
|
11424
|
+
/**
|
|
11425
|
+
* Select a same-origin destination, or return undefined to use the saved/default returnTo.
|
|
11426
|
+
* Default recovery redirects include CallbackRecovery hints; Connected clears those hints. Invoked
|
|
11427
|
+
* only for a verified live flow; no request, state, code, secrets, or storage rows reach this
|
|
11428
|
+
* policy. Close over acquired host services; its Effect requires no environment.
|
|
11429
|
+
* A policy failure after Connected cannot undo persistence: inspect before restarting.
|
|
11430
|
+
*/
|
|
11431
|
+
readonly callback?: (outcome: CallbackOutcome) => Effect.Effect<string | undefined, Errors.DomainKitError>;
|
|
11404
11432
|
}
|
|
11433
|
+
/** Offline registration requirements, not proof of provider console or grant readiness. */
|
|
11434
|
+
export declare const RegistrationSettings: Schema.Union<readonly [Schema.Struct<{
|
|
11435
|
+
readonly _tag: Schema.Literal<"OAuth">;
|
|
11436
|
+
readonly provider: Schema.String;
|
|
11437
|
+
readonly callbackUrl: Schema.String;
|
|
11438
|
+
readonly clientAuth: Schema.Literals<readonly ["none", "client_secret_basic", "client_secret_post"]>;
|
|
11439
|
+
readonly pkce: Schema.Literal<"S256">;
|
|
11440
|
+
readonly scopes: Schema.$Array<Schema.String>;
|
|
11441
|
+
}>, Schema.Struct<{
|
|
11442
|
+
readonly _tag: Schema.Literal<"Integration">;
|
|
11443
|
+
readonly provider: Schema.String;
|
|
11444
|
+
readonly callbackUrl: Schema.String;
|
|
11445
|
+
readonly clientAuth: Schema.Literal<"client_secret_post">;
|
|
11446
|
+
}>]>;
|
|
11447
|
+
export type RegistrationSettings = typeof RegistrationSettings.Type;
|
|
11448
|
+
/** Derive only public setup values; no credentials, identity, storage, or network are needed. */
|
|
11449
|
+
export declare const registrationSettings: (input: {
|
|
11450
|
+
readonly providers: ReadonlyArray<Provider.Definition>;
|
|
11451
|
+
readonly callbackBaseUrl: string;
|
|
11452
|
+
}) => Effect.Effect<ReadonlyArray<RegistrationSettings>, Errors.DomainKitError>;
|
|
11405
11453
|
/** Everything the handlers need: the lifecycle services, Storage, and the host's `Identity`. */
|
|
11406
11454
|
export type Services = Provision.Service | Cleanup.Service | Connect.Service | Verify.Service | Providers.Service | Storage.Service | Identity;
|
|
11407
11455
|
/**
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** The current package version from the package manifest. */
|
|
2
2
|
export declare const VERSION: string;
|
|
3
3
|
export * as Approval from "./Approval.ts";
|
|
4
|
+
export * as CallbackRecovery from "./CallbackRecovery.ts";
|
|
4
5
|
export * as Cleanup from "./Cleanup.ts";
|
|
5
6
|
export * as Cloudflare from "./Cloudflare.ts";
|
|
6
7
|
export * as Connect from "./Connect.ts";
|
|
@@ -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;
|