@ministryofmany/client 0.1.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/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ This project is dual-licensed under either of:
2
+
3
+ - Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
4
+ - MIT license (https://opensource.org/licenses/MIT)
5
+
6
+ at your option.
7
+
8
+ Unless you explicitly state otherwise, any contribution intentionally
9
+ submitted for inclusion in this project by you shall be dual licensed as
10
+ above, without any additional terms or conditions.
package/README.md ADDED
@@ -0,0 +1,282 @@
1
+ # @ministryofmany/client
2
+
3
+ OIDC relying-party SDK for **Minister** — an OpenID Connect identity provider
4
+ that lets users authenticate _and_ disclose W3C verifiable-credential "badges"
5
+ (email-domain, age-over-N, residency, connected accounts, and more).
6
+
7
+ Use this in your app to:
8
+
9
+ - Run the authorization-code flow with PKCE (S256) against Minister.
10
+ - Verify the returned `id_token` (signature, issuer, audience, nonce).
11
+ - Extract and **signature-verify** the disclosed badges against Minister's
12
+ public keys, with holder-binding enforced.
13
+
14
+ Three ways to integrate: run the full flow yourself (`createMinisterClient`), verify tokens/badges on a backend (`createMinisterVerifier`), or plug into Auth.js (`@ministryofmany/client/auth-js`).
15
+
16
+ ESM-only. Runs on Node 20+, Deno, and edge runtimes (Vercel Edge, Cloudflare
17
+ Workers) — it uses the Web Crypto API and `fetch`, not `node:crypto`.
18
+
19
+ ## Install
20
+
21
+ ```sh
22
+ pnpm add @ministryofmany/client
23
+ ```
24
+
25
+ `jose` and `zod` are runtime dependencies and are installed automatically.
26
+
27
+ ## Quick start
28
+
29
+ Create one client and reuse it. `issuer` is Minister's origin.
30
+
31
+ ```ts
32
+ import { createMinisterClient } from "@ministryofmany/client";
33
+
34
+ export const minister = createMinisterClient({
35
+ issuer: "https://ministry.id",
36
+ clientId: process.env.MINISTER_CLIENT_ID!,
37
+ clientSecret: process.env.MINISTER_CLIENT_SECRET, // omit for public/PKCE-only clients
38
+ redirectUri: "https://yourapp.example/auth/minister/callback",
39
+ });
40
+ ```
41
+
42
+ ### 1. Start — build the authorization URL and persist flow state
43
+
44
+ ```ts
45
+ import type { OidcFlowState } from "@ministryofmany/client";
46
+
47
+ export async function startLogin() {
48
+ const { verifier, challenge } = await minister.generatePkce();
49
+ const state = minister.randomToken();
50
+ const nonce = minister.randomToken();
51
+
52
+ // Ask for the badges your app needs. `openid` is required; the SDK does
53
+ // not add it for you. `badgeScope("age-over-21")` === "badge:age-over-21".
54
+ const url = await minister.getAuthorizationUrl({
55
+ scopes: [
56
+ "openid",
57
+ "profile",
58
+ minister.badgeScope("age-over-21"),
59
+ minister.badgeScope("email-domain"),
60
+ ],
61
+ state,
62
+ nonce,
63
+ codeChallenge: challenge,
64
+ });
65
+
66
+ // YOU own persistence. Store this keyed by `state`; the SDK stores nothing.
67
+ const flow: OidcFlowState = {
68
+ state,
69
+ nonce,
70
+ codeVerifier: verifier,
71
+ expiresAt: Date.now() + 10 * 60_000, // 10 minutes
72
+ };
73
+ await saveFlow(state, flow); // your storage: signed cookie, KV, DB row, ...
74
+
75
+ return url; // redirect the user here (302)
76
+ }
77
+ ```
78
+
79
+ > **You own the flow state, and you must consume it atomically by `state`.**
80
+ > On callback, look the record up by the returned `state`, **delete it in the
81
+ > same operation** (delete-on-read), and reject if it is missing or expired.
82
+ > This makes each `state`/`nonce` usable at most once, which is what defends
83
+ > the flow against CSRF and replay. The SDK deliberately stores nothing.
84
+
85
+ ### 2. Callback — exchange the code for verified claims + badges
86
+
87
+ ```ts
88
+ export async function handleCallback(req: Request) {
89
+ const url = new URL(req.url);
90
+ const code = url.searchParams.get("code");
91
+ const state = url.searchParams.get("state");
92
+ if (!code || !state) throw new Error("missing code/state");
93
+
94
+ // Atomic consume: fetch AND delete by state in one step.
95
+ const flow = await takeFlow(state);
96
+ if (!flow || flow.expiresAt < Date.now()) {
97
+ throw new Error("unknown or expired login flow");
98
+ }
99
+
100
+ const { claims, badges, rejected } = await minister.exchangeCode({
101
+ code,
102
+ codeVerifier: flow.codeVerifier,
103
+ expectedNonce: flow.nonce,
104
+ });
105
+
106
+ // `claims.sub` is a pairwise pseudonymous id — stable for this user at
107
+ // YOUR client, and different from what other RPs see.
108
+ // `badges` are already signature-verified and holder-bound.
109
+ const isAdult = badges.some((b) => b.type === "age-over-21");
110
+
111
+ // `rejected` holds any disclosed badges that failed verification (bad
112
+ // signature, expired, wrong issuer, ...). Login still succeeds; log/alert
113
+ // on these if a partner may be misconfigured.
114
+
115
+ await upsertUser({
116
+ ministerSub: claims.sub,
117
+ name: claims.name,
118
+ avatar: claims.picture,
119
+ isAdult,
120
+ });
121
+
122
+ // ... set your own session ...
123
+ }
124
+ ```
125
+
126
+ `exchangeCode` throws `MinisterTokenError` if the token exchange fails or the
127
+ `id_token` signature / issuer / audience / nonce / expiry checks fail — map
128
+ that to a `401`. A disclosed badge that fails verification is **not** fatal:
129
+ it is dropped from `badges` and surfaced in `rejected`, and login proceeds.
130
+
131
+ ### Verifying a badge received out of band
132
+
133
+ Badges can also reach you outside the OIDC flow (e.g. a Minister share link).
134
+ Verify any Minister VC JWT against Minister's public keys:
135
+
136
+ ```ts
137
+ import { VcVerificationError } from "@ministryofmany/client";
138
+
139
+ try {
140
+ const badge = await minister.verifyMinisterBadge(vcJwt);
141
+ // badge.type -> the badge slug, e.g. "email-domain"
142
+ // badge.claims -> schema-validated claims, e.g. { domain: "example.com" }
143
+ // badge.subject -> the holder's stable Minister DID (== credentialSubject.id);
144
+ // NOT the id_token `sub` (that is a per-RP pairwise value)
145
+ // badge.raw -> the original JWT, for storage/forwarding
146
+ } catch (err) {
147
+ if (err instanceof VcVerificationError) {
148
+ // invalid signature, wrong issuer, bad envelope, or holder-binding mismatch
149
+ }
150
+ throw err;
151
+ }
152
+ ```
153
+
154
+ Optionally validate the claim shape against the known badge vocabulary:
155
+
156
+ ```ts
157
+ import { getBadgeClaimSchema } from "@ministryofmany/client";
158
+
159
+ const schema = getBadgeClaimSchema("email-domain");
160
+ const parsed = schema?.safeParse(badge.claims);
161
+ ```
162
+
163
+ ## Verify on your backend (without running the flow)
164
+
165
+ If your app uses an OIDC library (or another service runs the flow) and you
166
+ just need to verify a Minister `id_token` and its badges, use the verifier —
167
+ no flow state, no redirect handling:
168
+
169
+ ```ts
170
+ import { createMinisterVerifier } from "@ministryofmany/client";
171
+
172
+ const minister = createMinisterVerifier({
173
+ issuer: "https://ministry.id",
174
+ clientId: "your-client-id", // enables the id_token `aud` check (recommended)
175
+ });
176
+
177
+ const claims = await minister.verifyIdToken(idToken); // throws MinisterTokenError on a bad token
178
+ // claims: { sub, name?, picture?, raw }
179
+
180
+ const { badges, rejected } = await minister.verifyBadges(idToken);
181
+ // badges: [{ type: "age-over-21", claims: { threshold: 21 }, subject, raw }, ...]
182
+ // rejected: [{ raw, error }] (badges that failed verification; never throws per-badge)
183
+ ```
184
+
185
+ `verifyBadges` accepts either a raw `id_token` string (it verifies the wrapper
186
+ first) or an already-verified payload object (it trusts the wrapper and only
187
+ verifies the badge VCs). The verifier caches Minister's JWKS after the first
188
+ fetch. Pass `jwks` to inject a key in tests.
189
+
190
+ ## With Auth.js (next-auth)
191
+
192
+ `@ministryofmany/client/auth-js` gives you a provider config and a badge helper you
193
+ hand to Auth.js through its documented extension points. We do **not** modify,
194
+ fork, or pin Auth.js — `@auth/core` is a types-only optional peer.
195
+
196
+ ```ts
197
+ import NextAuth from "next-auth";
198
+ import { ministerProvider, ministerBadgesFromProfile } from "@ministryofmany/client/auth-js";
199
+ import { badgeScopes } from "@ministryofmany/client/badges";
200
+
201
+ export const { handlers, auth } = NextAuth({
202
+ providers: [
203
+ ministerProvider({
204
+ clientId: process.env.MINISTER_CLIENT_ID!,
205
+ clientSecret: process.env.MINISTER_CLIENT_SECRET, // omit for public clients
206
+ issuer: process.env.MINISTER_ISSUER!,
207
+ scopes: ["openid", "profile", ...badgeScopes(["age-over-18"])],
208
+ }),
209
+ ],
210
+ callbacks: {
211
+ async jwt({ token, profile }) {
212
+ if (profile) {
213
+ const { badges } = await ministerBadgesFromProfile(profile, {
214
+ issuer: process.env.MINISTER_ISSUER!,
215
+ });
216
+ token.ministerBadges = badges;
217
+ }
218
+ return token;
219
+ },
220
+ },
221
+ });
222
+ ```
223
+
224
+ `ministerProvider` returns a standard OIDC provider config; Auth.js verifies the
225
+ `id_token`, and `ministerBadgesFromProfile` verifies the nested badge VCs inside
226
+ your own callback.
227
+
228
+ ### Subpath imports
229
+
230
+ - `@ministryofmany/client` — the main entry: flow client, verifier, errors, types, and the badge vocabulary.
231
+ - `@ministryofmany/client/badges` — the badge vocabulary alone (slugs, scopes, Zod claim schemas, `badgeScope`/`badgeScopes`/`badgeTypeOf`). Dependency-light; no jose pulled in. Useful for building scope lists or parsing claims in a UI.
232
+ - `@ministryofmany/client/auth-js` — the Auth.js helpers only (`ministerProvider`, `ministerBadgesFromProfile`).
233
+
234
+ ## What "verified" means here
235
+
236
+ - **id_token:** EdDSA signature against Minister's JWKS, plus `iss` ==
237
+ configured issuer, `aud` == your `clientId`, and `nonce` == the value you
238
+ persisted at start, with `exp`/`iat` present and `exp` not in the past.
239
+ - **Each badge:** EdDSA signature against Minister's public keys, `iss` ==
240
+ `did:web:<minister-host>`, JWT `typ` == `vc+jwt`, a present and unexpired
241
+ `exp`, a well-formed `vc` envelope, and `credentialSubject.id` == the VC's
242
+ own `sub` (holder binding). A badge whose signature, issuer, type, expiry,
243
+ structure, or subject binding is wrong is rejected (dropped into `rejected`,
244
+ never thrown from `verifyBadges`).
245
+
246
+ > **Issuer-domain coupling (all badges rejected?).** The expected badge issuer
247
+ > is derived as `did:web:<host-of-your-configured-issuer>`. Minister signs badge
248
+ > VCs with `did:web:<MINISTER_ISSUER_DOMAIN>`. If the Minister deployment's
249
+ > `MINISTER_ISSUER_DOMAIN` host does not equal the OIDC issuer host, **every
250
+ > badge fails verification** and lands in `rejected` with an issuer mismatch
251
+ > (login and `id_token` verification are unaffected). If you see all badges
252
+ > rejected, check that Minister's `MINISTER_ISSUER_DOMAIN` host matches its
253
+ > OIDC issuer host.
254
+
255
+ ## API
256
+
257
+ | Export | Purpose |
258
+ | --- | --- |
259
+ | `createMinisterClient(config)` | Build a flow client bound to one Minister + RP. |
260
+ | `client.getAuthorizationUrl(args)` | Discover the authorize endpoint and build the redirect URL. |
261
+ | `client.exchangeCode(args)` | Token exchange + verify id_token + verify badges. Returns `{ claims, badges, rejected }`. |
262
+ | `client.verifyMinisterBadge(vcJwt, opts?)` | Verify a single VC badge; `type` is a slug string (e.g. `"email-domain"`). |
263
+ | `client.generatePkce()` | PKCE S256 `{ verifier, challenge }`. |
264
+ | `client.randomToken(bytes?)` | URL-safe random `state` / `nonce`. |
265
+ | `client.badgeScope(slug)` | `"badge:<slug>"` helper. |
266
+ | `createMinisterVerifier(config)` | Configure-once verifier: `verifyIdToken`, `verifyBadges`, `verifyBadge`. |
267
+ | `verifyMinisterIdToken`, `verifyMinisterBadges`, `verifyMinisterBadge` | The standalone verification functions. |
268
+ | `badgeScope`, `badgeScopes`, `badgeTypeOf`, `knownBadgeTypes`, `getBadgeClaimSchema` | Badge vocabulary helpers. |
269
+ | `MinisterTokenError` | Thrown when an `id_token` itself fails verification. |
270
+ | `OidcFlowState`, `MinisterClaims`, `VerifiedBadge`, `BadgesResult`, `RejectedBadge`, ... | Public types. |
271
+ | `VcVerificationError`, `OidcError`, `MinisterTokenError` | Error classes. |
272
+
273
+ ### Testing without the network
274
+
275
+ `exchangeCode` and `verifyMinisterBadge` accept injectable key sources so your
276
+ tests never hit Minister: pass `idTokenKey` / `badgeKey` (to `exchangeCode`) or
277
+ `{ key }` (to `verifyMinisterBadge`) — a `KeyLike`, a `Uint8Array`, or a `jose`
278
+ key-resolver function. The default is a remote JWKS fetched from Minister.
279
+
280
+ ## License
281
+
282
+ MIT OR Apache-2.0
@@ -0,0 +1,18 @@
1
+ import { OIDCConfig } from '@auth/core/providers';
2
+ import { JWTPayload } from 'jose';
3
+ import { K as KeyInput, B as BadgesResult } from './types-BHY-mOJf.js';
4
+
5
+ interface MinisterProviderOptions {
6
+ clientId: string;
7
+ clientSecret?: string;
8
+ issuer: string;
9
+ scopes?: string[];
10
+ }
11
+ declare function ministerProvider(options: MinisterProviderOptions): OIDCConfig<Record<string, unknown>>;
12
+ interface MinisterBadgesFromProfileOptions {
13
+ issuer: string;
14
+ key?: KeyInput;
15
+ }
16
+ declare function ministerBadgesFromProfile(profile: JWTPayload | Record<string, unknown>, options: MinisterBadgesFromProfileOptions): Promise<BadgesResult>;
17
+
18
+ export { type MinisterBadgesFromProfileOptions, type MinisterProviderOptions, ministerBadgesFromProfile, ministerProvider };
@@ -0,0 +1,27 @@
1
+ import {
2
+ verifyMinisterBadges
3
+ } from "./chunk-CSD6YO64.js";
4
+ import "./chunk-U2JFQKFV.js";
5
+
6
+ // src/auth-js.ts
7
+ function ministerProvider(options) {
8
+ const scopes = options.scopes ?? ["openid", "profile"];
9
+ return {
10
+ id: "minister",
11
+ name: "Minister",
12
+ type: "oidc",
13
+ issuer: options.issuer,
14
+ clientId: options.clientId,
15
+ clientSecret: options.clientSecret,
16
+ authorization: { params: { scope: scopes.join(" ") } },
17
+ checks: ["pkce", "state", "nonce"]
18
+ };
19
+ }
20
+ function ministerBadgesFromProfile(profile, options) {
21
+ return verifyMinisterBadges(profile, { issuer: options.issuer, key: options.key });
22
+ }
23
+ export {
24
+ ministerBadgesFromProfile,
25
+ ministerProvider
26
+ };
27
+ //# sourceMappingURL=auth-js.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth-js.ts"],"sourcesContent":["// @minister/client/auth-js — non-invasive helpers for Auth.js (next-auth).\n// We do NOT modify Auth.js; these are values/functions you hand to it via\n// its documented extension points. `@auth/core` is a types-only optional\n// peer used solely for the OIDCConfig return type.\nimport type { OIDCConfig } from \"@auth/core/providers\";\nimport type { JWTPayload } from \"jose\";\nimport { verifyMinisterBadges } from \"./verify-badges\";\nimport type { KeyInput, BadgesResult } from \"./types\";\n\nexport interface MinisterProviderOptions {\n clientId: string;\n clientSecret?: string;\n issuer: string;\n // Defaults to [\"openid\", \"profile\"]. Add badge:<type> scopes to request badges.\n scopes?: string[];\n}\n\n// Build the Auth.js OIDC provider config object. Drop it into\n// NextAuth({ providers: [ministerProvider({...})] }). Auth.js owns the\n// flow, session, and cookies; this is only its provider configuration.\nexport function ministerProvider(options: MinisterProviderOptions): OIDCConfig<Record<string, unknown>> {\n const scopes = options.scopes ?? [\"openid\", \"profile\"];\n return {\n id: \"minister\",\n name: \"Minister\",\n type: \"oidc\",\n issuer: options.issuer,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n authorization: { params: { scope: scopes.join(\" \") } },\n checks: [\"pkce\", \"state\", \"nonce\"],\n };\n}\n\nexport interface MinisterBadgesFromProfileOptions {\n issuer: string;\n key?: KeyInput;\n}\n\n// Verify the minister_badges in an Auth.js `profile` (already-verified\n// id_token payload). Call inside your own jwt/profile callback.\nexport function ministerBadgesFromProfile(\n profile: JWTPayload | Record<string, unknown>,\n options: MinisterBadgesFromProfileOptions,\n): Promise<BadgesResult> {\n return verifyMinisterBadges(profile as JWTPayload, { issuer: options.issuer, key: options.key });\n}\n"],"mappings":";;;;;;AAoBO,SAAS,iBAAiB,SAAuE;AACtG,QAAM,SAAS,QAAQ,UAAU,CAAC,UAAU,SAAS;AACrD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,QAAQ;AAAA,IAChB,UAAU,QAAQ;AAAA,IAClB,cAAc,QAAQ;AAAA,IACtB,eAAe,EAAE,QAAQ,EAAE,OAAO,OAAO,KAAK,GAAG,EAAE,EAAE;AAAA,IACrD,QAAQ,CAAC,QAAQ,SAAS,OAAO;AAAA,EACnC;AACF;AASO,SAAS,0BACd,SACA,SACuB;AACvB,SAAO,qBAAqB,SAAuB,EAAE,QAAQ,QAAQ,QAAQ,KAAK,QAAQ,IAAI,CAAC;AACjG;","names":[]}
@@ -0,0 +1,116 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const EmailDomainClaims: z.ZodObject<{
4
+ domain: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ domain: string;
7
+ }, {
8
+ domain: string;
9
+ }>;
10
+ type EmailDomainClaims = z.infer<typeof EmailDomainClaims>;
11
+ declare const EmailExactClaims: z.ZodObject<{
12
+ email: z.ZodString;
13
+ }, "strip", z.ZodTypeAny, {
14
+ email: string;
15
+ }, {
16
+ email: string;
17
+ }>;
18
+ type EmailExactClaims = z.infer<typeof EmailExactClaims>;
19
+ declare const OAUTH_PROVIDERS: readonly ["github", "google", "discord"];
20
+ declare const OAuthAccountClaims: z.ZodObject<{
21
+ provider: z.ZodEnum<["github", "google", "discord"]>;
22
+ accountId: z.ZodString;
23
+ handle: z.ZodOptional<z.ZodString>;
24
+ }, "strip", z.ZodTypeAny, {
25
+ provider: "github" | "google" | "discord";
26
+ accountId: string;
27
+ handle?: string | undefined;
28
+ }, {
29
+ provider: "github" | "google" | "discord";
30
+ accountId: string;
31
+ handle?: string | undefined;
32
+ }>;
33
+ type OAuthAccountClaims = z.infer<typeof OAuthAccountClaims>;
34
+ declare const AGE_THRESHOLDS: readonly [16, 18, 21, 25, 30, 35, 40, 45, 55, 65];
35
+ type AgeThreshold = (typeof AGE_THRESHOLDS)[number];
36
+ declare const AgeOverClaimsFor: (threshold: AgeThreshold) => z.ZodObject<{
37
+ threshold: z.ZodLiteral<16 | 18 | 21 | 25 | 30 | 35 | 40 | 45 | 55 | 65>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ threshold: 16 | 18 | 21 | 25 | 30 | 35 | 40 | 45 | 55 | 65;
40
+ }, {
41
+ threshold: 16 | 18 | 21 | 25 | 30 | 35 | 40 | 45 | 55 | 65;
42
+ }>;
43
+ declare const ResidencyCountryClaims: z.ZodObject<{
44
+ country: z.ZodString;
45
+ }, "strip", z.ZodTypeAny, {
46
+ country: string;
47
+ }, {
48
+ country: string;
49
+ }>;
50
+ type ResidencyCountryClaims = z.infer<typeof ResidencyCountryClaims>;
51
+ declare const ResidencyStateClaims: z.ZodObject<{
52
+ country: z.ZodString;
53
+ state: z.ZodString;
54
+ }, "strip", z.ZodTypeAny, {
55
+ state: string;
56
+ country: string;
57
+ }, {
58
+ state: string;
59
+ country: string;
60
+ }>;
61
+ type ResidencyStateClaims = z.infer<typeof ResidencyStateClaims>;
62
+ declare const ResidencyCityClaims: z.ZodObject<{
63
+ country: z.ZodString;
64
+ state: z.ZodString;
65
+ city: z.ZodString;
66
+ }, "strip", z.ZodTypeAny, {
67
+ state: string;
68
+ country: string;
69
+ city: string;
70
+ }, {
71
+ state: string;
72
+ country: string;
73
+ city: string;
74
+ }>;
75
+ type ResidencyCityClaims = z.infer<typeof ResidencyCityClaims>;
76
+ declare const InviteCodeClaims: z.ZodObject<{
77
+ label: z.ZodString;
78
+ }, "strip", z.ZodTypeAny, {
79
+ label: string;
80
+ }, {
81
+ label: string;
82
+ }>;
83
+ type InviteCodeClaims = z.infer<typeof InviteCodeClaims>;
84
+ declare const TlsnAttestationClaims: z.ZodObject<{
85
+ domain: z.ZodString;
86
+ claim: z.ZodString;
87
+ }, "strict", z.ZodTypeAny, {
88
+ domain: string;
89
+ claim: string;
90
+ }, {
91
+ domain: string;
92
+ claim: string;
93
+ }>;
94
+ type TlsnAttestationClaims = z.infer<typeof TlsnAttestationClaims>;
95
+
96
+ interface BadgeTypeDef {
97
+ slug: string;
98
+ credentialType: string;
99
+ scope: string;
100
+ claims: z.ZodType<unknown>;
101
+ }
102
+ declare function defineBadgeType(input: {
103
+ slug: string;
104
+ credentialType: string;
105
+ claims: z.ZodType<unknown>;
106
+ }): BadgeTypeDef;
107
+ declare const BADGE_TYPES: Record<string, BadgeTypeDef>;
108
+ declare function slugForCredentialType(credentialType: string): string | undefined;
109
+
110
+ declare function badgeScope(slug: string): string;
111
+ declare function badgeScopes(slugs: string[]): string[];
112
+ declare function badgeTypeOf(vcType: string[]): string | undefined;
113
+ declare function getBadgeClaimSchema(slug: string): z.ZodType<unknown> | undefined;
114
+ declare function knownBadgeTypes(): string[];
115
+
116
+ export { AGE_THRESHOLDS, AgeOverClaimsFor, type AgeThreshold, BADGE_TYPES, type BadgeTypeDef, EmailDomainClaims, EmailExactClaims, InviteCodeClaims, OAUTH_PROVIDERS, OAuthAccountClaims, ResidencyCityClaims, ResidencyCountryClaims, ResidencyStateClaims, TlsnAttestationClaims, badgeScope, badgeScopes, badgeTypeOf, defineBadgeType, getBadgeClaimSchema, knownBadgeTypes, slugForCredentialType };
@@ -0,0 +1,44 @@
1
+ import "../chunk-R4XGCZVA.js";
2
+ import {
3
+ AGE_THRESHOLDS,
4
+ AgeOverClaimsFor,
5
+ BADGE_TYPES,
6
+ EmailDomainClaims,
7
+ EmailExactClaims,
8
+ InviteCodeClaims,
9
+ OAUTH_PROVIDERS,
10
+ OAuthAccountClaims,
11
+ ResidencyCityClaims,
12
+ ResidencyCountryClaims,
13
+ ResidencyStateClaims,
14
+ TlsnAttestationClaims,
15
+ badgeScope,
16
+ badgeScopes,
17
+ badgeTypeOf,
18
+ defineBadgeType,
19
+ getBadgeClaimSchema,
20
+ knownBadgeTypes,
21
+ slugForCredentialType
22
+ } from "../chunk-U2JFQKFV.js";
23
+ export {
24
+ AGE_THRESHOLDS,
25
+ AgeOverClaimsFor,
26
+ BADGE_TYPES,
27
+ EmailDomainClaims,
28
+ EmailExactClaims,
29
+ InviteCodeClaims,
30
+ OAUTH_PROVIDERS,
31
+ OAuthAccountClaims,
32
+ ResidencyCityClaims,
33
+ ResidencyCountryClaims,
34
+ ResidencyStateClaims,
35
+ TlsnAttestationClaims,
36
+ badgeScope,
37
+ badgeScopes,
38
+ badgeTypeOf,
39
+ defineBadgeType,
40
+ getBadgeClaimSchema,
41
+ knownBadgeTypes,
42
+ slugForCredentialType
43
+ };
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}