@bwalletx/connect 0.4.1 → 0.5.3
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/CHANGELOG.md +20 -0
- package/README.md +6 -2
- package/assets/protocol/401.jpg +0 -0
- package/assets/protocol/401.mp4 +0 -0
- package/assets/protocol/402.jpg +0 -0
- package/assets/protocol/402.mp4 +0 -0
- package/assets/protocol/403.jpg +0 -0
- package/assets/protocol/403.mp4 +0 -0
- package/dist/access-Dp0eKIOc.d.cts +118 -0
- package/dist/access-Dp0eKIOc.d.ts +118 -0
- package/dist/bwalletx-connect.global.js +20 -17
- package/dist/bwalletx-connect.global.js.map +1 -1
- package/dist/{chunk-NNMUSWPG.js → chunk-IUDD7YTQ.js} +200 -10
- package/dist/chunk-IUDD7YTQ.js.map +1 -0
- package/dist/chunk-MWD4BCO5.js +182 -0
- package/dist/chunk-MWD4BCO5.js.map +1 -0
- package/dist/{chunk-FUQ46RJV.js → chunk-PI42H3XY.js} +65 -10
- package/dist/chunk-PI42H3XY.js.map +1 -0
- package/dist/{chunk-7NAKOJGZ.js → chunk-QRXFL66W.js} +220 -10
- package/dist/chunk-QRXFL66W.js.map +1 -0
- package/dist/element.cjs +290 -14
- package/dist/element.cjs.map +1 -1
- package/dist/element.js +2 -1
- package/dist/element.js.map +1 -1
- package/dist/index.cjs +437 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -1
- package/dist/index.d.ts +71 -1
- package/dist/index.js +36 -4
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +377 -9
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +52 -2
- package/dist/next.d.ts +52 -2
- package/dist/next.js +92 -1
- package/dist/next.js.map +1 -1
- package/dist/react.cjs +561 -226
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -0
- package/dist/react.d.ts +5 -0
- package/dist/react.js +12 -3
- package/dist/react.js.map +1 -1
- package/dist/server.cjs +406 -9
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +111 -1
- package/dist/server.d.ts +111 -1
- package/dist/server.js +47 -1
- package/package.json +12 -11
- package/dist/chunk-7NAKOJGZ.js.map +0 -1
- package/dist/chunk-FUQ46RJV.js.map +0 -1
- package/dist/chunk-NNMUSWPG.js.map +0 -1
package/dist/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/next.ts"],"sourcesContent":["/**\n * Next.js App Router adapter. Route handlers use standard Request/Response, so they also work in\n * any Fetch-API server (Hono, Remix, Bun, Workers).\n *\n * // lib/bwalletx.ts\n * export const auth = createBwalletXAuth({ origin: process.env.APP_ORIGIN!, store: pgStore({ query }) });\n * // app/api/bwalletx/challenge/route.ts → export const POST = auth.challenge;\n * // app/api/bwalletx/verify/route.ts → export const POST = auth.verify;\n * // app/api/bwalletx/logout/route.ts → export const POST = auth.logout;\n * // app/api/bwalletx/session/route.ts → export const GET = auth.session;\n * // server component: const s = await auth.getSession();\n */\nimport { IdentityLinkConflictError } from './link.js';\nimport { createChallenge, originAllowed, verifySignIn, type NonceStore } from './server.js';\nimport { assertSecret, readCookie, serializeCookie, signSession, verifySession, type SessionPayload } from './session.js';\n\nexport type { SessionPayload } from './session.js';\n\nexport interface VerifiedExtra {\n /** Your user id (e.g. from signInOrLink). Stored in the session as `uid`. */\n uid?: string;\n handle?: string;\n paymail?: string;\n [claim: string]: unknown;\n}\n\nexport interface BwalletXAuthOptions {\n /** YOUR origin from config, e.g. \"https://example.com\". Never from the request. */\n origin: string;\n /** A shared nonce store: redisStore or pgStore. memoryStore only in development. */\n store: NonceStore;\n /** HMAC secret, 32+ chars. Default: process.env[secretEnv]. There is no fallback; requests throw without it. */\n secret?: string;\n /** Env var holding the secret. Default 'BWALLETX_SESSION_SECRET'. */\n secretEnv?: string;\n /** Cookie name. Default 'bwx_session'. */\n cookieName?: string;\n /** Session lifetime in seconds. Default 7 days. */\n maxAge?: number;\n /** Default: true when origin is https. */\n secureCookie?: boolean;\n sameSite?: 'Lax' | 'Strict' | 'None';\n cookieDomain?: string;\n /**\n * Runs after the signature is verified, before the cookie is set: link to your user, look up a\n * handle. Throw IdentityLinkConflictError to answer 409; return false to refuse (403).\n */\n onVerified?: (identityKey: string, req: Request) => Promise<VerifiedExtra | void | false> | VerifiedExtra | void | false;\n}\n\nexport interface BwalletXAuth {\n challenge(req: Request): Promise<Response>;\n verify(req: Request): Promise<Response>;\n logout(req: Request): Promise<Response>;\n session(req: Request): Promise<Response>;\n /** The session, or null. With no argument it reads cookies() from next/headers. */\n getSession(source?: Request | Headers | string | null): Promise<SessionPayload | null>;\n /** Make a cookie for an identity you verified yourself (e.g. after account linking elsewhere). */\n sessionCookie(claims: Omit<SessionPayload, 'iat' | 'exp'>): Promise<string>;\n clearCookie(): string;\n}\n\nconst json = (body: unknown, status = 200, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json', 'cache-control': 'no-store', ...headers } });\n\nasync function body(req: Request): Promise<Record<string, unknown> | null> {\n try {\n const b = await req.json();\n return b && typeof b === 'object' ? (b as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\nexport function createBwalletXAuth(o: BwalletXAuthOptions): BwalletXAuth {\n if (!o.store) throw new Error('createBwalletXAuth needs a nonce store (redisStore, pgStore; memoryStore for dev)');\n const cookieName = o.cookieName ?? 'bwx_session';\n const maxAge = o.maxAge ?? 7 * 24 * 3600;\n const secure = o.secureCookie ?? o.origin.startsWith('https:');\n const secret = () => {\n const s = o.secret ?? (typeof process !== 'undefined' ? process.env?.[o.secretEnv ?? 'BWALLETX_SESSION_SECRET'] : undefined);\n assertSecret(s);\n return s;\n };\n const cookie = (v: string, age: number) => serializeCookie(v, { name: cookieName, maxAge: age, secure, sameSite: o.sameSite, domain: o.cookieDomain });\n const badOrigin = (req: Request) => !originAllowed(req.headers.get('origin'), o.origin);\n\n const fromSource = async (source?: Request | Headers | string | null): Promise<string | null> => {\n if (typeof source === 'string') return readCookie(source, cookieName);\n if (source instanceof Headers) return readCookie(source.get('cookie'), cookieName);\n if (source && typeof (source as Request).headers?.get === 'function') return readCookie((source as Request).headers.get('cookie'), cookieName);\n // Server components / route handlers: Next's cookies(). Imported lazily so the package does not require Next.\n const { cookies } = (await import('next/headers')) as { cookies: () => unknown };\n const jar = (await cookies()) as { get(n: string): { value: string } | undefined };\n return jar.get(cookieName)?.value ?? null;\n };\n\n const auth: BwalletXAuth = {\n async challenge(req) {\n secret();\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n const b = await body(req);\n try {\n return json(await createChallenge({ origin: o.origin, identityKey: b?.identityKey, store: o.store }));\n } catch (e) {\n return json({ error: (e as Error).message }, 400);\n }\n },\n async verify(req) {\n const key = secret();\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n const b = await body(req);\n const identityKey = await verifySignIn({ origin: o.origin, identityKey: b?.identityKey, nonce: b?.nonce, signature: b?.signature, store: o.store });\n if (!identityKey) return json({ error: 'sign-in failed' }, 401);\n let extra: VerifiedExtra = {};\n try {\n const r = await o.onVerified?.(identityKey, req);\n if (r === false) return json({ error: 'not allowed' }, 403);\n if (r) extra = r;\n } catch (e) {\n if (e instanceof IdentityLinkConflictError) return json({ error: e.message, code: e.code }, 409);\n throw e;\n }\n const token = await signSession({ ...extra, sub: identityKey }, { secret: key, maxAge });\n return json({ identityKey, uid: extra.uid, handle: extra.handle, paymail: extra.paymail }, 200, { 'set-cookie': cookie(token, maxAge) });\n },\n async logout(req) {\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n return json({ ok: true }, 200, { 'set-cookie': cookie('', 0) });\n },\n async session(req) {\n const s = await auth.getSession(req);\n return s ? json({ identityKey: s.sub, uid: s.uid, handle: s.handle, paymail: s.paymail, exp: s.exp }) : json({ identityKey: null }, 200);\n },\n async getSession(source) {\n const key = secret();\n return verifySession(await fromSource(source), { secret: key });\n },\n async sessionCookie(claims) {\n return cookie(await signSession(claims, { secret: secret(), maxAge }), maxAge);\n },\n clearCookie: () => cookie('', 0),\n };\n return auth;\n}\n\nexport { IdentityLinkConflictError, linkIdentity, signInOrLink } from './link.js';\nexport { memoryStore, redisStore, pgStore, pgNonceTableSql } from './server.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8DA,IAAM,OAAO,CAACA,OAAe,SAAS,KAAK,UAAkC,CAAC,MAC5E,IAAI,SAAS,KAAK,UAAUA,KAAI,GAAG,EAAE,QAAQ,SAAS,EAAE,gBAAgB,oBAAoB,iBAAiB,YAAY,GAAG,QAAQ,EAAE,CAAC;AAEzI,eAAe,KAAK,KAAuD;AACzE,MAAI;AACF,UAAM,IAAI,MAAM,IAAI,KAAK;AACzB,WAAO,KAAK,OAAO,MAAM,WAAY,IAAgC;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,GAAsC;AACvE,MAAI,CAAC,EAAE,MAAO,OAAM,IAAI,MAAM,mFAAmF;AACjH,QAAM,aAAa,EAAE,cAAc;AACnC,QAAM,SAAS,EAAE,UAAU,IAAI,KAAK;AACpC,QAAM,SAAS,EAAE,gBAAgB,EAAE,OAAO,WAAW,QAAQ;AAC7D,QAAM,SAAS,MAAM;AACnB,UAAM,IAAI,EAAE,WAAW,OAAO,YAAY,cAAc,QAAQ,MAAM,EAAE,aAAa,yBAAyB,IAAI;AAClH,iBAAa,CAAC;AACd,WAAO;AAAA,EACT;AACA,QAAM,SAAS,CAAC,GAAW,QAAgB,gBAAgB,GAAG,EAAE,MAAM,YAAY,QAAQ,KAAK,QAAQ,UAAU,EAAE,UAAU,QAAQ,EAAE,aAAa,CAAC;AACrJ,QAAM,YAAY,CAAC,QAAiB,CAAC,cAAc,IAAI,QAAQ,IAAI,QAAQ,GAAG,EAAE,MAAM;AAEtF,QAAM,aAAa,OAAO,WAAuE;AAC/F,QAAI,OAAO,WAAW,SAAU,QAAO,WAAW,QAAQ,UAAU;AACpE,QAAI,kBAAkB,QAAS,QAAO,WAAW,OAAO,IAAI,QAAQ,GAAG,UAAU;AACjF,QAAI,UAAU,OAAQ,OAAmB,SAAS,QAAQ,WAAY,QAAO,WAAY,OAAmB,QAAQ,IAAI,QAAQ,GAAG,UAAU;AAE7I,UAAM,EAAE,QAAQ,IAAK,MAAM,OAAO,cAAc;AAChD,UAAM,MAAO,MAAM,QAAQ;AAC3B,WAAO,IAAI,IAAI,UAAU,GAAG,SAAS;AAAA,EACvC;AAEA,QAAM,OAAqB;AAAA,IACzB,MAAM,UAAU,KAAK;AACnB,aAAO;AACP,UAAI,UAAU,GAAG,EAAG,QAAO,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;AACpE,YAAM,IAAI,MAAM,KAAK,GAAG;AACxB,UAAI;AACF,eAAO,KAAK,MAAM,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,aAAa,GAAG,aAAa,OAAO,EAAE,MAAM,CAAC,CAAC;AAAA,MACtG,SAAS,GAAG;AACV,eAAO,KAAK,EAAE,OAAQ,EAAY,QAAQ,GAAG,GAAG;AAAA,MAClD;AAAA,IACF;AAAA,IACA,MAAM,OAAO,KAAK;AAChB,YAAM,MAAM,OAAO;AACnB,UAAI,UAAU,GAAG,EAAG,QAAO,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;AACpE,YAAM,IAAI,MAAM,KAAK,GAAG;AACxB,YAAM,cAAc,MAAM,aAAa,EAAE,QAAQ,EAAE,QAAQ,aAAa,GAAG,aAAa,OAAO,GAAG,OAAO,WAAW,GAAG,WAAW,OAAO,EAAE,MAAM,CAAC;AAClJ,UAAI,CAAC,YAAa,QAAO,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG;AAC9D,UAAI,QAAuB,CAAC;AAC5B,UAAI;AACF,cAAM,IAAI,MAAM,EAAE,aAAa,aAAa,GAAG;AAC/C,YAAI,MAAM,MAAO,QAAO,KAAK,EAAE,OAAO,cAAc,GAAG,GAAG;AAC1D,YAAI,EAAG,SAAQ;AAAA,MACjB,SAAS,GAAG;AACV,YAAI,aAAa,0BAA2B,QAAO,KAAK,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,GAAG,GAAG;AAC/F,cAAM;AAAA,MACR;AACA,YAAM,QAAQ,MAAM,YAAY,EAAE,GAAG,OAAO,KAAK,YAAY,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC;AACvF,aAAO,KAAK,EAAE,aAAa,KAAK,MAAM,KAAK,QAAQ,MAAM,QAAQ,SAAS,MAAM,QAAQ,GAAG,KAAK,EAAE,cAAc,OAAO,OAAO,MAAM,EAAE,CAAC;AAAA,IACzI;AAAA,IACA,MAAM,OAAO,KAAK;AAChB,UAAI,UAAU,GAAG,EAAG,QAAO,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;AACpE,aAAO,KAAK,EAAE,IAAI,KAAK,GAAG,KAAK,EAAE,cAAc,OAAO,IAAI,CAAC,EAAE,CAAC;AAAA,IAChE;AAAA,IACA,MAAM,QAAQ,KAAK;AACjB,YAAM,IAAI,MAAM,KAAK,WAAW,GAAG;AACnC,aAAO,IAAI,KAAK,EAAE,aAAa,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,QAAQ,SAAS,EAAE,SAAS,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,aAAa,KAAK,GAAG,GAAG;AAAA,IACzI;AAAA,IACA,MAAM,WAAW,QAAQ;AACvB,YAAM,MAAM,OAAO;AACnB,aAAO,cAAc,MAAM,WAAW,MAAM,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE;AAAA,IACA,MAAM,cAAc,QAAQ;AAC1B,aAAO,OAAO,MAAM,YAAY,QAAQ,EAAE,QAAQ,OAAO,GAAG,OAAO,CAAC,GAAG,MAAM;AAAA,IAC/E;AAAA,IACA,aAAa,MAAM,OAAO,IAAI,CAAC;AAAA,EACjC;AACA,SAAO;AACT;","names":["body"]}
|
|
1
|
+
{"version":3,"sources":["../src/next.ts"],"sourcesContent":["/**\n * Next.js App Router adapter. Route handlers use standard Request/Response, so they also work in\n * any Fetch-API server (Hono, Remix, Bun, Workers).\n *\n * // lib/bwalletx.ts\n * export const auth = createBwalletXAuth({ origin: process.env.APP_ORIGIN!, store: pgStore({ query }) });\n * // app/api/bwalletx/challenge/route.ts → export const POST = auth.challenge;\n * // app/api/bwalletx/verify/route.ts → export const POST = auth.verify;\n * // app/api/bwalletx/logout/route.ts → export const POST = auth.logout;\n * // app/api/bwalletx/session/route.ts → export const GET = auth.session;\n * // server component: const s = await auth.getSession();\n */\nimport { IdentityLinkConflictError } from './link.js';\nimport { createChallenge, originAllowed, verifySignIn, type NonceStore } from './server.js';\nimport { assertSecret, readCookie, serializeCookie, signSession, verifySession, type SessionPayload } from './session.js';\n\nexport type { SessionPayload } from './session.js';\n\nexport interface VerifiedExtra {\n /** Your user id (e.g. from signInOrLink). Stored in the session as `uid`. */\n uid?: string;\n handle?: string;\n paymail?: string;\n [claim: string]: unknown;\n}\n\nexport interface BwalletXAuthOptions {\n /** YOUR origin from config, e.g. \"https://example.com\". Never from the request. */\n origin: string;\n /** A shared nonce store: redisStore or pgStore. memoryStore only in development. */\n store: NonceStore;\n /** HMAC secret, 32+ chars. Default: process.env[secretEnv]. There is no fallback; requests throw without it. */\n secret?: string;\n /** Env var holding the secret. Default 'BWALLETX_SESSION_SECRET'. */\n secretEnv?: string;\n /** Cookie name. Default 'bwx_session'. */\n cookieName?: string;\n /** Session lifetime in seconds. Default 7 days. */\n maxAge?: number;\n /** Default: true when origin is https. */\n secureCookie?: boolean;\n sameSite?: 'Lax' | 'Strict' | 'None';\n cookieDomain?: string;\n /**\n * Runs after the signature is verified, before the cookie is set: link to your user, look up a\n * handle. Throw IdentityLinkConflictError to answer 409; return false to refuse (403).\n */\n onVerified?: (identityKey: string, req: Request) => Promise<VerifiedExtra | void | false> | VerifiedExtra | void | false;\n}\n\nexport interface BwalletXAuth {\n challenge(req: Request): Promise<Response>;\n verify(req: Request): Promise<Response>;\n logout(req: Request): Promise<Response>;\n session(req: Request): Promise<Response>;\n /** The session, or null. With no argument it reads cookies() from next/headers. */\n getSession(source?: Request | Headers | string | null): Promise<SessionPayload | null>;\n /** Make a cookie for an identity you verified yourself (e.g. after account linking elsewhere). */\n sessionCookie(claims: Omit<SessionPayload, 'iat' | 'exp'>): Promise<string>;\n clearCookie(): string;\n}\n\nconst json = (body: unknown, status = 200, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json', 'cache-control': 'no-store', ...headers } });\n\nasync function body(req: Request): Promise<Record<string, unknown> | null> {\n try {\n const b = await req.json();\n return b && typeof b === 'object' ? (b as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\nexport function createBwalletXAuth(o: BwalletXAuthOptions): BwalletXAuth {\n if (!o.store) throw new Error('createBwalletXAuth needs a nonce store (redisStore, pgStore; memoryStore for dev)');\n const cookieName = o.cookieName ?? 'bwx_session';\n const maxAge = o.maxAge ?? 7 * 24 * 3600;\n const secure = o.secureCookie ?? o.origin.startsWith('https:');\n const secret = () => {\n const s = o.secret ?? (typeof process !== 'undefined' ? process.env?.[o.secretEnv ?? 'BWALLETX_SESSION_SECRET'] : undefined);\n assertSecret(s);\n return s;\n };\n const cookie = (v: string, age: number) => serializeCookie(v, { name: cookieName, maxAge: age, secure, sameSite: o.sameSite, domain: o.cookieDomain });\n const badOrigin = (req: Request) => !originAllowed(req.headers.get('origin'), o.origin);\n\n const fromSource = async (source?: Request | Headers | string | null): Promise<string | null> => {\n if (typeof source === 'string') return readCookie(source, cookieName);\n if (source instanceof Headers) return readCookie(source.get('cookie'), cookieName);\n if (source && typeof (source as Request).headers?.get === 'function') return readCookie((source as Request).headers.get('cookie'), cookieName);\n // Server components / route handlers: Next's cookies(). Imported lazily so the package does not require Next.\n const { cookies } = (await import('next/headers')) as { cookies: () => unknown };\n const jar = (await cookies()) as { get(n: string): { value: string } | undefined };\n return jar.get(cookieName)?.value ?? null;\n };\n\n const auth: BwalletXAuth = {\n async challenge(req) {\n secret();\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n const b = await body(req);\n try {\n return json(await createChallenge({ origin: o.origin, identityKey: b?.identityKey, store: o.store }));\n } catch (e) {\n return json({ error: (e as Error).message }, 400);\n }\n },\n async verify(req) {\n const key = secret();\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n const b = await body(req);\n const identityKey = await verifySignIn({ origin: o.origin, identityKey: b?.identityKey, nonce: b?.nonce, signature: b?.signature, store: o.store });\n if (!identityKey) return json({ error: 'sign-in failed' }, 401);\n let extra: VerifiedExtra = {};\n try {\n const r = await o.onVerified?.(identityKey, req);\n if (r === false) return json({ error: 'not allowed' }, 403);\n if (r) extra = r;\n } catch (e) {\n if (e instanceof IdentityLinkConflictError) return json({ error: e.message, code: e.code }, 409);\n throw e;\n }\n const token = await signSession({ ...extra, sub: identityKey }, { secret: key, maxAge });\n return json({ identityKey, uid: extra.uid, handle: extra.handle, paymail: extra.paymail }, 200, { 'set-cookie': cookie(token, maxAge) });\n },\n async logout(req) {\n if (badOrigin(req)) return json({ error: 'origin not allowed' }, 403);\n return json({ ok: true }, 200, { 'set-cookie': cookie('', 0) });\n },\n async session(req) {\n const s = await auth.getSession(req);\n return s ? json({ identityKey: s.sub, uid: s.uid, handle: s.handle, paymail: s.paymail, exp: s.exp }) : json({ identityKey: null }, 200);\n },\n async getSession(source) {\n const key = secret();\n return verifySession(await fromSource(source), { secret: key });\n },\n async sessionCookie(claims) {\n return cookie(await signSession(claims, { secret: secret(), maxAge }), maxAge);\n },\n clearCookie: () => cookie('', 0),\n };\n return auth;\n}\n\nexport { IdentityLinkConflictError, linkIdentity, signInOrLink } from './link.js';\nexport { memoryStore, redisStore, pgStore, pgNonceTableSql } from './server.js';\n\n// ── $401/$403 access gate ──────────────────────────────────────────────────────────────────\n\nimport { ACCESS_ERROR_STATUS, AccessError, accessErrorMessage, canonicalJson, normaliseRequirement, type AccessRequirement } from './access.js';\nimport { checkTokenHolding, createAccessChallenge, verifyAccess, type AccessResolver } from './access-server.js';\n\nexport interface BwalletXAccessOptions {\n origin: string;\n store: NonceStore;\n /** The gate. From YOUR config, never the request. */\n require: AccessRequirement;\n resolver: AccessResolver;\n secret?: string;\n secretEnv?: string;\n /** Default 'bwx_access'. Use a different name per gate. */\n cookieName?: string;\n /** Cookie lifetime in seconds. Default 1 day. */\n maxAge?: number;\n /** Re-check token holdings at most this often per process (seconds). Default 300. */\n recheckEvery?: number;\n secureCookie?: boolean;\n sameSite?: 'Lax' | 'Strict' | 'None';\n cookieDomain?: string;\n}\n\nexport type AccessState =\n | { ok: true; identityKey: string; addresses: string[]; checkedAt: number }\n | { ok: false; error: AccessError['code'] | 'no_session'; message: string; have?: string | number; need?: string | number };\n\nexport interface BwalletXAccess {\n challenge(req: Request): Promise<Response>;\n verify(req: Request): Promise<Response>;\n logout(req: Request): Promise<Response>;\n /** GET: the current AccessState as JSON (re-checks holdings when stale). */\n status(req: Request): Promise<Response>;\n /** The access state for a request / cookies(). Re-checks holdings every `recheckEvery` seconds. */\n getAccess(source?: Request | Headers | string | null): Promise<AccessState>;\n readonly require: AccessRequirement;\n}\n\nconst errJson = (e: AccessError) => json(e.toJSON(), ACCESS_ERROR_STATUS[e.code]);\n\n/**\n * A token- or identity-gated area. Routes:\n * app/api/access/challenge/route.ts → export const POST = gate.challenge;\n * app/api/access/verify/route.ts → export const POST = gate.verify;\n * app/api/access/status/route.ts → export const GET = gate.status;\n * page: const a = await gate.getAccess(); if (!a.ok) show the \"get the token\" path.\n */\nexport function createBwalletXAccess(o: BwalletXAccessOptions): BwalletXAccess {\n if (!o.store) throw new Error('createBwalletXAccess needs a nonce store');\n const require = normaliseRequirement(o.require);\n const reqHash = canonicalJson(require);\n const cookieName = o.cookieName ?? 'bwx_access';\n const maxAge = o.maxAge ?? 24 * 3600;\n const recheckMs = (o.recheckEvery ?? 300) * 1000;\n const secure = o.secureCookie ?? o.origin.startsWith('https:');\n const secret = () => {\n const s = o.secret ?? (typeof process !== 'undefined' ? process.env?.[o.secretEnv ?? 'BWALLETX_SESSION_SECRET'] : undefined);\n assertSecret(s);\n return s;\n };\n const cookie = (v: string, age: number) => serializeCookie(v, { name: cookieName, maxAge: age, secure, sameSite: o.sameSite, domain: o.cookieDomain });\n const badOrigin = (req: Request) => !originAllowed(req.headers.get('origin'), o.origin);\n /** sub+addresses → last good check time. Per process; a sale ends access within recheckEvery. */\n const checked = new Map<string, number>();\n\n const readToken = async (source?: Request | Headers | string | null): Promise<string | null> => {\n if (typeof source === 'string') return readCookie(source, cookieName);\n if (source instanceof Headers) return readCookie(source.get('cookie'), cookieName);\n if (source && typeof (source as Request).headers?.get === 'function') return readCookie((source as Request).headers.get('cookie'), cookieName);\n const { cookies } = (await import('next/headers')) as { cookies: () => unknown };\n const jar = (await cookies()) as { get(n: string): { value: string } | undefined };\n return jar.get(cookieName)?.value ?? null;\n };\n\n const gate: BwalletXAccess = {\n require,\n async challenge(req) {\n secret();\n if (badOrigin(req)) return json({ error: 'bad_request', message: 'origin not allowed' }, 403);\n const b = await body(req);\n try {\n return json(await createAccessChallenge({ origin: o.origin, require, store: o.store, identityKey: b?.identityKey }));\n } catch (e) {\n return errJson(e instanceof AccessError ? e : new AccessError('bad_request', (e as Error).message));\n }\n },\n async verify(req) {\n const key = secret();\n if (badOrigin(req)) return json({ error: 'bad_request', message: 'origin not allowed' }, 403);\n const b = await body(req);\n try {\n const g = await verifyAccess({ origin: o.origin, response: b, store: o.store, resolver: o.resolver, require });\n const token = await signSession({ sub: g.identityKey, acc: reqHash, ad: g.addresses }, { secret: key, maxAge });\n checked.set(`${g.identityKey}|${g.addresses.join(',')}`, Date.now());\n return json({ ok: true, identityKey: g.identityKey, have: g.have }, 200, { 'set-cookie': cookie(token, maxAge) });\n } catch (e) {\n if (e instanceof AccessError) return errJson(e);\n throw e;\n }\n },\n async logout(req) {\n if (badOrigin(req)) return json({ error: 'bad_request', message: 'origin not allowed' }, 403);\n return json({ ok: true }, 200, { 'set-cookie': cookie('', 0) });\n },\n async status(req) {\n const a = await gate.getAccess(req);\n return json(a, 200);\n },\n async getAccess(source) {\n const s = await verifySession(await readToken(source), { secret: secret() });\n if (!s || s.acc !== reqHash) return { ok: false, error: 'no_session', message: 'Not signed in to this gate.' };\n const addresses = Array.isArray(s.ad) ? (s.ad as unknown[]).filter((x): x is string => typeof x === 'string') : [];\n const k = `${s.sub}|${addresses.join(',')}`;\n const last = checked.get(k) ?? 0;\n if (require.token && Date.now() - last >= recheckMs) {\n try {\n await checkTokenHolding(require, addresses, o.resolver);\n checked.set(k, Date.now());\n } catch (e) {\n checked.delete(k);\n const ae = e instanceof AccessError ? e : new AccessError('indexer_unavailable', (e as Error).message);\n return { ok: false, error: ae.code, message: ae.message === ae.code ? accessErrorMessage(ae.code, ae) : ae.message, have: ae.have, need: ae.need };\n }\n }\n return { ok: true, identityKey: s.sub, addresses, checkedAt: checked.get(k) ?? last };\n },\n };\n return gate;\n}\n"],"mappings":"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","names":["body","require"]}
|