@bwalletx/connect 0.3.0 → 0.5.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +145 -4
  3. package/assets/protocol/401.jpg +0 -0
  4. package/assets/protocol/401.mp4 +0 -0
  5. package/assets/protocol/402.jpg +0 -0
  6. package/assets/protocol/402.mp4 +0 -0
  7. package/assets/protocol/403.jpg +0 -0
  8. package/assets/protocol/403.mp4 +0 -0
  9. package/dist/access-Z6xQwKVF.d.cts +118 -0
  10. package/dist/access-Z6xQwKVF.d.ts +118 -0
  11. package/dist/bwalletx-connect.global.js +41 -3
  12. package/dist/bwalletx-connect.global.js.map +1 -1
  13. package/dist/{chunk-NNMUSWPG.js → chunk-CVLXFNAG.js} +123 -1
  14. package/dist/chunk-CVLXFNAG.js.map +1 -0
  15. package/dist/chunk-GF6GUDZL.js +404 -0
  16. package/dist/chunk-GF6GUDZL.js.map +1 -0
  17. package/dist/chunk-MWD4BCO5.js +182 -0
  18. package/dist/chunk-MWD4BCO5.js.map +1 -0
  19. package/dist/chunk-QRXFL66W.js +652 -0
  20. package/dist/chunk-QRXFL66W.js.map +1 -0
  21. package/dist/element.cjs +209 -0
  22. package/dist/element.cjs.map +1 -1
  23. package/dist/element.js +2 -1
  24. package/dist/element.js.map +1 -1
  25. package/dist/index.cjs +706 -5
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +66 -62
  28. package/dist/index.d.ts +66 -62
  29. package/dist/index.js +63 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/next.cjs +783 -0
  32. package/dist/next.cjs.map +1 -0
  33. package/dist/next.d.cts +98 -0
  34. package/dist/next.d.ts +98 -0
  35. package/dist/next.js +198 -0
  36. package/dist/next.js.map +1 -0
  37. package/dist/react.cjs +795 -36
  38. package/dist/react.cjs.map +1 -1
  39. package/dist/react.d.cts +74 -28
  40. package/dist/react.d.ts +74 -28
  41. package/dist/react.js +177 -4
  42. package/dist/react.js.map +1 -1
  43. package/dist/server.cjs +742 -10
  44. package/dist/server.cjs.map +1 -1
  45. package/dist/server.d.cts +314 -2
  46. package/dist/server.d.ts +314 -2
  47. package/dist/server.js +82 -107
  48. package/dist/server.js.map +1 -1
  49. package/dist/wallets-VOKIKBbO.d.cts +250 -0
  50. package/dist/wallets-VOKIKBbO.d.ts +250 -0
  51. package/package.json +32 -6
  52. package/dist/chunk-NNMUSWPG.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access.ts"],"sourcesContent":["/**\n * $401 / $402 / $403 access protocol, version 1. Shared by sites (client + server) and wallets.\n * The full spec is docs/ACCESS-PROTOCOL.md. Pure: no I/O, @bsv/sdk types only.\n *\n * 401 identity \"prove who you are (at identity level N, or KYC'd)\"\n * 402 payment \"pay for this\" (the challenge format is reserved; payment itself uses pay())\n * 403 access \"prove you hold N of token X (or N basis points of its supply)\"\n */\nimport type { WalletProtocol } from '@bsv/sdk';\n\nexport const ACCESS_VERSION = 1 as const;\n/** Security level 2, a protocol name used for nothing else. Wallets recognise it and show the kind's video. */\nexport const ACCESS_PROTOCOL: WalletProtocol = [2, 'bwalletx access'];\n/** How long a challenge is valid. */\nexport const ACCESS_CHALLENGE_LIFETIME_S = 120;\n/** At most this many holding proofs are read from one response. */\nexport const MAX_HOLDING_PROOFS = 50;\n\nexport type AccessKind = '401' | '402' | '403';\n\nexport interface TokenRequirement {\n /** 'bsv21:<txid>_<vout>' */\n id: string;\n /** Minimum raw (unscaled, integer string) amount. */\n min?: string;\n /** Minimum in basis points of total supply (1 = 0.01%, 10000 = 100%). */\n minBps?: number;\n}\n\nexport interface AccessRequirement {\n token?: TokenRequirement;\n /** $401 identity level (bit-sign strands): 1 Basic, 2 Verified, 3 Strong, 4 Sovereign (Veriff). */\n identityLevel?: number;\n /** A live KYC credential is required. */\n kyc?: boolean;\n}\n\n/** What the wallet signs, as canonical JSON. Times are seconds since the epoch. */\nexport interface AccessChallenge {\n v: 1;\n kind: AccessKind;\n origin: string;\n nonce: string;\n iat: number;\n exp: number;\n /** The identity key the site expects. A different wallet account is `wrong_account`. */\n sub?: string;\n require: AccessRequirement;\n}\n\n/** A key that locks some of the required token, proving control by signing the same challenge bytes. */\nexport interface HoldingProof {\n /** Compressed public key hex of the key locking the outputs. */\n pubkey: string;\n /** DER signature by that key over SHA-256(challenge bytes), as BRC-100 createSignature returns. */\n signature: number[];\n /** Optional hint: outpoints ('txid_vout') this key holds. Servers must not trust it. */\n outpoints?: string[];\n}\n\n/** What the wallet (via requestAccess) posts back to the site. */\nexport interface AccessResponse {\n v: 1;\n /** The challenge string exactly as issued. */\n challenge: string;\n identityKey: string;\n /** DER signature: createSignature({ protocolID: ACCESS_PROTOCOL, keyID: nonce, counterparty: 'anyone', data: challenge bytes }). */\n signature: number[];\n holdings?: HoldingProof[];\n}\n\nexport type AccessErrorCode =\n | 'not_installed'\n | 'user_rejected'\n | 'wrong_account'\n | 'insufficient_tokens'\n | 'identity_level_too_low'\n | 'kyc_required'\n | 'indexer_unavailable'\n | 'expired'\n | 'replay'\n | 'invalid_signature'\n | 'bad_request';\n\n/** The HTTP status a site should answer each code with. */\nexport const ACCESS_ERROR_STATUS: Record<AccessErrorCode, number> = {\n not_installed: 424,\n user_rejected: 403,\n wrong_account: 409,\n insufficient_tokens: 403,\n identity_level_too_low: 403,\n kyc_required: 403,\n indexer_unavailable: 503,\n expired: 401,\n replay: 401,\n invalid_signature: 401,\n bad_request: 400,\n};\n\nexport interface AccessErrorBody {\n error: AccessErrorCode;\n message: string;\n /** insufficient_tokens: raw amounts; identity_level_too_low: levels. */\n have?: string | number;\n need?: string | number;\n}\n\nexport class AccessError extends Error {\n readonly code: AccessErrorCode;\n readonly have?: string | number;\n readonly need?: string | number;\n constructor(code: AccessErrorCode, message?: string, extra: { have?: string | number; need?: string | number } = {}) {\n super(message ?? code);\n this.name = 'AccessError';\n this.code = code;\n this.have = extra.have;\n this.need = extra.need;\n }\n toJSON(): AccessErrorBody {\n const b: AccessErrorBody = { error: this.code, message: this.message };\n if (this.have !== undefined) b.have = this.have;\n if (this.need !== undefined) b.need = this.need;\n return b;\n }\n}\n\n/** One video + poster + colour per kind, so wallets and sites show the same thing. Paths are inside the package. */\nexport const PROTOCOL_MEDIA: Record<AccessKind, { name: string; color: string; video: string; poster: string }> = {\n '401': { name: 'Identity', color: '#22c55e', video: 'assets/protocol/401.mp4', poster: 'assets/protocol/401.jpg' },\n '402': { name: 'Payment', color: '#3b82f6', video: 'assets/protocol/402.mp4', poster: 'assets/protocol/402.jpg' },\n '403': { name: 'Access', color: '#ef4444', video: 'assets/protocol/403.mp4', poster: 'assets/protocol/403.jpg' },\n};\n\n/** Media URLs on a CDN (unpkg) for a given package version. */\nexport function protocolMediaUrl(kind: AccessKind, which: 'video' | 'poster', version = 'latest'): string {\n return `https://unpkg.com/@bwalletx/connect@${version}/${PROTOCOL_MEDIA[kind][which]}`;\n}\n\n/**\n * Canonical JSON: object keys sorted by code unit, no whitespace, undefined members dropped.\n * Only strings, finite numbers, booleans, null, arrays and plain objects are allowed.\n */\nexport function canonicalJson(v: unknown): string {\n if (v === null) return 'null';\n if (typeof v === 'string' || typeof v === 'boolean') return JSON.stringify(v);\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) throw new Error('canonicalJson: non-finite number');\n return JSON.stringify(v);\n }\n if (Array.isArray(v)) return `[${v.map((x) => canonicalJson(x)).join(',')}]`;\n if (typeof v === 'object') {\n const o = v as Record<string, unknown>;\n const keys = Object.keys(o).filter((k) => o[k] !== undefined).sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(o[k])}`).join(',')}}`;\n }\n throw new Error(`canonicalJson: unsupported ${typeof v}`);\n}\n\n/** The bytes every signature in the protocol covers: UTF-8 of the challenge string. */\nexport function challengeBytes(challenge: string): number[] {\n return Array.from(new TextEncoder().encode(challenge));\n}\n\nconst TOKEN_ID = /^bsv21:[0-9a-f]{64}_\\d{1,6}$/;\nconst RAW = /^[1-9]\\d{0,38}$/;\n\n/** Throws AccessError('bad_request') if the requirement is malformed. Returns a normalised copy. */\nexport function normaliseRequirement(r: unknown): AccessRequirement {\n if (!r || typeof r !== 'object') throw new AccessError('bad_request', 'require must be an object');\n const req = r as Record<string, unknown>;\n const out: AccessRequirement = {};\n if (req.token !== undefined) {\n const t = req.token as Record<string, unknown>;\n if (!t || typeof t !== 'object' || typeof t.id !== 'string') throw new AccessError('bad_request', 'require.token.id is required');\n const id = t.id.trim().toLowerCase();\n if (!TOKEN_ID.test(id)) throw new AccessError('bad_request', \"require.token.id must be 'bsv21:<txid>_<vout>'\");\n const hasMin = t.min !== undefined;\n const hasBps = t.minBps !== undefined;\n if (hasMin === hasBps) throw new AccessError('bad_request', 'require.token needs exactly one of min or minBps');\n out.token = { id };\n if (hasMin) {\n if (typeof t.min !== 'string' || !RAW.test(t.min)) throw new AccessError('bad_request', 'require.token.min must be a positive integer string (raw units)');\n out.token.min = t.min;\n } else {\n if (!Number.isInteger(t.minBps) || (t.minBps as number) < 1 || (t.minBps as number) > 10000) {\n throw new AccessError('bad_request', 'require.token.minBps must be an integer 1..10000');\n }\n out.token.minBps = t.minBps as number;\n }\n }\n if (req.identityLevel !== undefined) {\n if (!Number.isInteger(req.identityLevel) || (req.identityLevel as number) < 1 || (req.identityLevel as number) > 10) {\n throw new AccessError('bad_request', 'require.identityLevel must be an integer 1..10');\n }\n out.identityLevel = req.identityLevel as number;\n }\n if (req.kyc !== undefined) {\n if (typeof req.kyc !== 'boolean') throw new AccessError('bad_request', 'require.kyc must be a boolean');\n if (req.kyc) out.kyc = true;\n }\n if (!out.token && !out.identityLevel && !out.kyc) throw new AccessError('bad_request', 'require is empty');\n return out;\n}\n\n/** The kind a requirement implies: any token → 403; otherwise 401. */\nexport function kindFor(r: AccessRequirement): AccessKind {\n return r.token ? '403' : '401';\n}\n\n/** Parse and validate a challenge string. Throws AccessError('bad_request'). Does not check expiry. */\nexport function parseAccessChallenge(s: unknown): AccessChallenge {\n if (typeof s !== 'string' || s.length > 4096) throw new AccessError('bad_request', 'challenge must be a string');\n let c: AccessChallenge;\n try {\n c = JSON.parse(s) as AccessChallenge;\n } catch {\n throw new AccessError('bad_request', 'challenge is not JSON');\n }\n if (!c || typeof c !== 'object' || c.v !== 1) throw new AccessError('bad_request', 'unsupported challenge version');\n if (c.kind !== '401' && c.kind !== '402' && c.kind !== '403') throw new AccessError('bad_request', 'bad kind');\n if (typeof c.origin !== 'string' || typeof c.nonce !== 'string' || !/^[A-Za-z0-9_-]{16,64}$/.test(c.nonce)) {\n throw new AccessError('bad_request', 'bad origin or nonce');\n }\n if (!Number.isInteger(c.iat) || !Number.isInteger(c.exp) || c.exp <= c.iat) throw new AccessError('bad_request', 'bad iat/exp');\n if (c.sub !== undefined && (typeof c.sub !== 'string' || !/^0[23][0-9a-f]{64}$/.test(c.sub))) throw new AccessError('bad_request', 'bad sub');\n c.require = normaliseRequirement(c.require);\n if (canonicalJson(c) !== s) throw new AccessError('bad_request', 'challenge is not canonical');\n return c;\n}\n\n/** Raw amount needed for a token requirement, given total supply (needed only for minBps). Rounds up. */\nexport function tokenNeedRaw(t: TokenRequirement, supplyRaw?: string): string {\n if (t.min) return t.min;\n if (supplyRaw === undefined || !/^\\d+$/.test(supplyRaw)) throw new AccessError('indexer_unavailable', 'token supply unknown');\n const n = BigInt(supplyRaw) * BigInt(t.minBps!);\n const need = (n + 9999n) / 10000n;\n return (need < 1n ? 1n : need).toString();\n}\n\n/** Compare unscaled integer strings. Fails closed on malformed input. */\nexport function atLeastRaw(have: string, need: string): boolean {\n try {\n return BigInt(have) >= BigInt(need);\n } catch {\n return false;\n }\n}\n\n/** A user-readable line for an error code. */\nexport function accessErrorMessage(code: AccessErrorCode, e: { have?: string | number; need?: string | number } = {}): string {\n switch (code) {\n case 'not_installed': return 'No bWalletX (or other BRC-100 wallet) was found.';\n case 'user_rejected': return 'The request was declined in the wallet.';\n case 'wrong_account': return 'The wallet is signed in to a different account than this site expects.';\n case 'insufficient_tokens': return `Not enough tokens: holding ${e.have ?? 0}, need ${e.need ?? '?'}.`;\n case 'identity_level_too_low': return `Identity level ${e.have ?? 0} is below the required level ${e.need ?? '?'}.`;\n case 'kyc_required': return 'A verified identity (KYC) is required.';\n case 'indexer_unavailable': return 'Holdings could not be checked right now. Try again shortly.';\n case 'expired': return 'The request expired. Try again.';\n case 'replay': return 'That request was already used. Try again.';\n case 'invalid_signature': return 'The wallet signature did not verify.';\n case 'bad_request': return 'The request was malformed.';\n }\n}\n"],"mappings":"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","names":[]}