{"_id":"@sp-uvb/client","_rev":"4-3ee374815f322f00f8d6c853793e8374","name":"@sp-uvb/client","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@sp-uvb/client","version":"0.1.0","keywords":["authentication","mfa","2fa","verification","uvb","security","totp","multi-factor"],"author":{"name":"UVB Team"},"license":"MIT","_id":"@sp-uvb/client@0.1.0","maintainers":[{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"}],"homepage":"https://github.com/yourusername/uvb#readme","bugs":{"url":"https://github.com/yourusername/uvb/issues"},"dist":{"shasum":"19b3768ed22130e1ebfdfb38f905e609d0eb0a51","tarball":"https://registry.npmjs.org/@sp-uvb/client/-/client-0.1.0.tgz","fileCount":7,"integrity":"sha512-BTIbEXb/gwJTudbnnD7VloMTeqlTEjDV3yyRQk8eyEwDEbqMXg47U2qHEGLvK8eLrssmzg0Hy6/D6taMVL4IzA==","signatures":[{"sig":"MEYCIQCa87lygyPQltewY/JXaDES1d1/QKEgdppztmvFwcEEoQIhAK4iAMiEnP7BXVH4Dyqun2xRFYZoOMgGzV/mA7Iac5Wg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84362},"main":"dist/index.js","_from":"file:sp-uvb-client-0.1.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"dev":"tsup src/index.ts --format cjs,esm --dts --watch","lint":"eslint src --ext .ts","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts --clean","lint:fix":"eslint src --ext .ts --fix","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"},"_resolved":"/private/var/folders/vw/6kq6krgd6v1ch124jcm_kr6r0000gn/T/8f5e368e3001035ac3cc25a28cef700d/sp-uvb-client-0.1.0.tgz","_integrity":"sha512-BTIbEXb/gwJTudbnnD7VloMTeqlTEjDV3yyRQk8eyEwDEbqMXg47U2qHEGLvK8eLrssmzg0Hy6/D6taMVL4IzA==","repository":{"url":"git+https://github.com/yourusername/uvb.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.11.0","description":"Universal Verification Broker (UVB) TypeScript/JavaScript SDK","directories":{},"_nodeVersion":"25.8.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","eslint":"^8.54.0","vitest":"^1.0.0","typescript":"^5.3.2","@types/node":"^20.10.0","@vitest/coverage-v8":"^1.0.0","@typescript-eslint/parser":"^6.13.0","@typescript-eslint/eslint-plugin":"^6.13.0"},"_npmOperationalInternal":{"tmp":"tmp/client_0.1.0_1774496400682_0.18140896965783382","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@sp-uvb/client","version":"0.2.0","keywords":["authentication","mfa","2fa","verification","uvb","security","totp","multi-factor"],"author":{"name":"UVB Team"},"license":"MIT","_id":"@sp-uvb/client@0.2.0","maintainers":[{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"}],"homepage":"https://gitlab.com/sparkz-community/security/uvb","bugs":{"url":"https://gitlab.com/sparkz-community/security/uvb/-/issues"},"dist":{"shasum":"dfd0482df45dddee100b65dfca1e1af0cb3e5c68","tarball":"https://registry.npmjs.org/@sp-uvb/client/-/client-0.2.0.tgz","fileCount":6,"integrity":"sha512-pUhl6P756MNoe1Cngj06CeQa2ictsedCTBhcAOWRxt46IW/sNYbPcQw9stcnx4OP91Mmam+Ru+aT6XDRZxxD8Q==","signatures":[{"sig":"MEUCIDrLY9KytZlgruBfq5p+FDulg8ktZVpJRy+7/npO5EX/AiEAtA29eWQ7ZPK8lCg4VWY6T+BAKLfeRJUJeWMhpZD5b2k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83363},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"6a258849c6fe538d704afdb2a9319120ed736687","scripts":{"dev":"tsup src/index.ts --format cjs,esm --dts --watch","lint":"eslint src --ext .ts","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts --clean","lint:fix":"eslint src --ext .ts --fix","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"},"repository":{"url":"git+https://gitlab.com/sparkz-community/security/uvb.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.11.0","description":"Universal Verification Broker (UVB) TypeScript/JavaScript SDK","directories":{},"_nodeVersion":"25.8.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","eslint":"^8.57.1","vitest":"^4.1.5","typescript":"^5.3.2","@types/node":"^20.10.0","@vitest/coverage-v8":"^4.1.5","@typescript-eslint/parser":"^7.18.0","@typescript-eslint/eslint-plugin":"^7.18.0"},"_npmOperationalInternal":{"tmp":"tmp/client_0.2.0_1780441861452_0.6763404837879112","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@sp-uvb/client","version":"0.2.1","keywords":["authentication","mfa","2fa","verification","uvb","security","totp","multi-factor"],"author":{"name":"UVB Team"},"license":"MIT","_id":"@sp-uvb/client@0.2.1","maintainers":[{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"}],"homepage":"https://gitlab.com/sparkz-community/security/uvb","bugs":{"url":"https://gitlab.com/sparkz-community/security/uvb/-/issues"},"dist":{"shasum":"01bc2f32c140b51bb92077a3d66758f0230756f0","tarball":"https://registry.npmjs.org/@sp-uvb/client/-/client-0.2.1.tgz","fileCount":6,"integrity":"sha512-zrN6ld3jVSfJSySYqncZtyoepcWCfRIZJccy+I7POzbtqRR2C8rp2cBHpeY/MgNdjL6/HP+ki/4pyihdrKmRuQ==","signatures":[{"sig":"MEUCIFvz4aAH5H+QURjnKRjrFsywNgJ58ceXUeuxP7AKeP12AiEA+0fGSjK1wqldALfyM6eUH8P86TNKpOQeGpTlf5QvwIU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83363},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"3cb03becbbd852a00252cc007636aeab17d3b4a1","scripts":{"dev":"tsup src/index.ts --format cjs,esm --dts --watch","lint":"eslint src --ext .ts","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts --clean","lint:fix":"eslint src --ext .ts --fix","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"brycejohnson-sparkz","email":"bryce.johnson@sparkz.systems"},"repository":{"url":"git+https://gitlab.com/sparkz-community/security/uvb.git","type":"git","directory":"sdk/typescript"},"_npmVersion":"11.11.0","description":"Universal Verification Broker (UVB) TypeScript/JavaScript SDK","directories":{},"_nodeVersion":"25.8.1","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","eslint":"^8.57.1","vitest":"^4.1.5","typescript":"^5.3.2","@types/node":"^20.10.0","@vitest/coverage-v8":"^4.1.5","@typescript-eslint/parser":"^7.18.0","@typescript-eslint/eslint-plugin":"^7.18.0"},"_npmOperationalInternal":{"tmp":"tmp/client_0.2.1_1780443456219_0.15753700623633637","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-03-26T03:40:00.597Z","modified":"2026-09-14T19:45:39.074Z","0.1.0":"2026-03-26T03:40:00.823Z","0.2.0":"2026-06-02T23:11:01.612Z","0.2.1":"2026-06-02T23:37:36.372Z"},"bugs":{"url":"https://gitlab.com/sparkz-community/security/uvb/-/issues"},"author":{"name":"UVB Team"},"license":"MIT","homepage":"https://gitlab.com/sparkz-community/security/uvb","keywords":["authentication","mfa","2fa","verification","uvb","security","totp","multi-factor"],"repository":{"url":"git+https://gitlab.com/sparkz-community/security/uvb.git","type":"git","directory":"sdk/typescript"},"description":"Universal Verification Broker (UVB) TypeScript/JavaScript SDK","maintainers":[{"email":"bryce.johnson@sparkz.systems","name":"brycejohnson-sparkz"},{"email":"dallin.b.johnson@gmail.com","name":"dallin.b.johnson"}],"readme":"# @sp-uvb/client\n\nOfficial TypeScript/JavaScript SDK for [Universal Verification Broker (UVB)](https://github.com/yourusername/uvb).\n\n**Features:**\n\n- ✅ **Full TypeScript support** with complete type definitions\n- ✅ **Browser & Node.js** compatible (ES modules + CommonJS)\n- ✅ **Multiple storage options** - Memory, localStorage, sessionStorage, cookies\n- ✅ **Comprehensive error handling** - Typed errors with detailed messages\n- ✅ **Zero dependencies** - Lightweight and fast\n- ✅ **Tree-shakeable** - Only bundle what you use\n- ✅ **100% test coverage** - Reliable and production-ready\n\n---\n\n## Installation\n\n```bash\n# npm\nnpm install @sp-uvb/client\n\n# yarn\nyarn add @sp-uvb/client\n\n# pnpm\npnpm add @sp-uvb/client\n```\n\n---\n\n## Quick Start\n\n### Basic Usage\n\n```typescript\nimport { UvbClient } from '@sp-uvb/client';\n\n// Create client\nconst client = new UvbClient({\n  baseUrl: 'https://uvb.example.com',\n});\n\n// Start verification\nconst { transaction_id, challenges } = await client.startVerification(\n  {\n    user_id: 'user_123',\n    tenant_id: 'tenant_a',\n    email: 'user@example.com',\n  },\n  {\n    tenant_id: 'tenant_a',\n    application_id: 'app_1',\n    intent: 'login',\n  }\n);\n\n// Continue with TOTP\nconst response = await client.continueVerification({\n  transaction_id,\n  challenge_id: challenges[0].challenge_id,\n  factor_id: 'totp',\n  response_payload: { otp: '123456' },\n});\n\nif (response.status === 'Succeeded' && response.assertion) {\n  // Store JWT token\n  await client.setToken(response.assertion);\n  console.log('Authentication successful!');\n}\n```\n\n### With Token Storage\n\n```typescript\nimport { UvbClient, LocalStorageTokenStorage } from '@sp-uvb/client';\n\nconst client = new UvbClient({\n  baseUrl: 'https://uvb.example.com',\n  tokenStorage: new LocalStorageTokenStorage(),\n});\n\n// After successful authentication, token is automatically stored\n// and persists across browser sessions\n```\n\n---\n\n## API Reference\n\n### UvbClient\n\n#### Constructor\n\n```typescript\nnew UvbClient(config: UvbClientConfig)\n```\n\n**Options:**\n\n- `baseUrl` (required): Base URL of UVB API\n- `timeout` (optional): Request timeout in milliseconds (default: 30000)\n- `headers` (optional): Custom headers to include in all requests\n- `fetch` (optional): Custom fetch implementation\n- `tokenStorage` (optional): Token storage implementation (default: MemoryTokenStorage)\n\n**Example:**\n\n```typescript\nconst client = new UvbClient({\n  baseUrl: 'https://uvb.example.com',\n  timeout: 10000,\n  headers: {\n    'X-Custom-Header': 'value',\n  },\n});\n```\n\n#### Methods\n\n##### startVerification(subject, context)\n\nStart a verification transaction.\n\n```typescript\nconst result = await client.startVerification(\n  {\n    user_id: 'user_123',\n    tenant_id: 'tenant_a',\n    email: 'user@example.com',\n  },\n  {\n    tenant_id: 'tenant_a',\n    application_id: 'app_1',\n    intent: 'login',\n    ip_address: '192.168.1.1',\n  }\n);\n\nconsole.log('Transaction ID:', result.transaction_id);\nconsole.log('Available challenges:', result.challenges);\n```\n\n##### continueVerification(request)\n\nContinue a verification with a factor response.\n\n```typescript\nconst result = await client.continueVerification({\n  transaction_id: 'txn_123',\n  challenge_id: 'chal_456',\n  factor_id: 'totp',\n  response_payload: { otp: '123456' },\n});\n\nif (result.status === 'Succeeded') {\n  console.log('JWT token:', result.assertion);\n}\n```\n\n##### enrollFactor(request)\n\nEnroll a user in an authentication factor.\n\n```typescript\nconst result = await client.enrollFactor({\n  subject: {\n    user_id: 'user_123',\n    tenant_id: 'tenant_a',\n  },\n  factor_id: 'totp',\n});\n\nconsole.log('TOTP secret:', result.enrollment_data.secret);\nconsole.log('QR code:', result.enrollment_data.qr_code_url);\n```\n\n##### listEnrollments(request)\n\nList all enrollments for a user.\n\n```typescript\nconst { enrollments } = await client.listEnrollments({\n  user_id: 'user_123',\n  tenant_id: 'tenant_a',\n});\n\nenrollments.forEach((enrollment) => {\n  console.log('Factor:', enrollment.factor_id);\n  console.log('Status:', enrollment.status);\n});\n```\n\n##### deleteEnrollment(request)\n\nDelete an enrollment.\n\n```typescript\nawait client.deleteEnrollment({\n  enrollment_id: 'enr_123',\n  user_id: 'user_123',\n  tenant_id: 'tenant_a',\n});\n```\n\n##### introspectToken(request)\n\nVerify and extract claims from a JWT token.\n\n```typescript\nconst result = await client.introspectToken({ token: jwtToken });\n\nif (result.active) {\n  console.log('User:', result.sub);\n  console.log('Factors:', result.factors_used);\n  console.log('Assurance level:', result.assurance_level);\n}\n```\n\n##### Token Management\n\n```typescript\n// Store token\nawait client.setToken('eyJhbGc...');\n\n// Get token\nconst token = await client.getToken();\n\n// Remove token\nawait client.removeToken();\n\n// Check if token exists\nconst hasToken = await client.hasToken();\n\n// Verify current token\nconst claims = await client.verifyCurrentToken();\nif (claims && claims.active) {\n  console.log('Token is valid');\n}\n```\n\n---\n\n## Token Storage\n\n### Available Storage Implementations\n\n#### MemoryTokenStorage (Default)\n\nStores tokens in memory (not persistent).\n\n```typescript\nimport { MemoryTokenStorage } from '@sp-uvb/client';\n\nconst storage = new MemoryTokenStorage();\n```\n\n**Use when:**\n\n- Testing\n- Server-side applications\n- Single-page apps that don't need persistence\n\n#### LocalStorageTokenStorage\n\nStores tokens in browser localStorage (persistent across sessions).\n\n```typescript\nimport { LocalStorageTokenStorage } from '@sp-uvb/client';\n\nconst storage = new LocalStorageTokenStorage('my_token_key');\n```\n\n**Use when:**\n\n- Browser apps needing persistence\n- Simple token storage requirements\n\n**Warning:** Accessible by JavaScript, so only use for non-sensitive tokens.\n\n#### SessionStorageTokenStorage\n\nStores tokens in browser sessionStorage (cleared when tab closes).\n\n```typescript\nimport { SessionStorageTokenStorage } from '@sp-uvb/client';\n\nconst storage = new SessionStorageTokenStorage();\n```\n\n**Use when:**\n\n- Browser apps\n- Tokens should not persist across sessions\n\n#### CookieTokenStorage\n\nStores tokens in cookies.\n\n```typescript\nimport { CookieTokenStorage } from '@sp-uvb/client';\n\nconst storage = new CookieTokenStorage({\n  cookieName: 'uvb_token',\n  secure: true,\n  sameSite: 'strict',\n  maxAge: 3600,\n});\n```\n\n**Use when:**\n\n- Need cookie-based authentication\n- Working with server-side rendering\n\n#### Custom Storage\n\nImplement your own storage:\n\n```typescript\nimport type { TokenStorage } from '@sp-uvb/client';\n\nclass CustomStorage implements TokenStorage {\n  async setToken(token: string): Promise<void> {\n    // Your implementation\n  }\n\n  async getToken(): Promise<string | null> {\n    // Your implementation\n  }\n\n  async removeToken(): Promise<void> {\n    // Your implementation\n  }\n}\n\nconst client = new UvbClient({\n  baseUrl: 'https://uvb.example.com',\n  tokenStorage: new CustomStorage(),\n});\n```\n\n---\n\n## Error Handling\n\nThe SDK provides typed error classes for better error handling:\n\n```typescript\nimport {\n  NetworkError,\n  ApiError,\n  RateLimitError,\n  AuthenticationError,\n  ValidationError,\n} from '@sp-uvb/client';\n\ntry {\n  await client.startVerification(subject, context);\n} catch (error) {\n  if (error instanceof RateLimitError) {\n    console.log('Rate limited. Retry after:', error.retryAfter);\n  } else if (error instanceof AuthenticationError) {\n    console.log('Authentication failed');\n  } else if (error instanceof NetworkError) {\n    console.log('Network error:', error.message);\n  } else if (error instanceof ApiError) {\n    console.log('API error:', error.statusCode, error.errorCode);\n  }\n}\n```\n\n### Error Types\n\n- **`UvbError`** - Base error class\n- **`NetworkError`** - Connection failures, timeouts\n- **`ApiError`** - HTTP errors (4xx, 5xx)\n- **`AuthenticationError`** - 401 errors\n- **`RateLimitError`** - 429 errors with retry-after\n- **`ValidationError`** - Invalid input\n- **`ConfigurationError`** - Invalid client configuration\n\n---\n\n## Examples\n\n### Complete Authentication Flow\n\n```typescript\nimport { UvbClient, LocalStorageTokenStorage } from '@sp-uvb/client';\n\nconst client = new UvbClient({\n  baseUrl: 'https://uvb.example.com',\n  tokenStorage: new LocalStorageTokenStorage(),\n});\n\nasync function login(userId: string, tenantId: string) {\n  try {\n    // 1. Start verification\n    const { transaction_id, challenges } = await client.startVerification(\n      { user_id: userId, tenant_id: tenantId },\n      {\n        tenant_id: tenantId,\n        application_id: 'my_app',\n        intent: 'login',\n      }\n    );\n\n    // 2. Show available factors to user\n    console.log(\n      'Available factors:',\n      challenges.map((c) => c.display_name)\n    );\n\n    // 3. User selects TOTP and enters code\n    const otp = await promptUserForOTP(); // Your UI logic\n\n    // 4. Continue verification\n    const result = await client.continueVerification({\n      transaction_id,\n      challenge_id: challenges[0].challenge_id,\n      factor_id: 'totp',\n      response_payload: { otp },\n    });\n\n    // 5. Handle result\n    if (result.status === 'Succeeded' && result.assertion) {\n      await client.setToken(result.assertion);\n      console.log('Login successful!');\n      return true;\n    } else {\n      console.log('Login failed:', result.last_factor_result?.error_message);\n      return false;\n    }\n  } catch (error) {\n    console.error('Login error:', error);\n    return false;\n  }\n}\n```\n\n### TOTP Enrollment\n\n```typescript\nasync function enrollTOTP(userId: string, tenantId: string) {\n  const { enrollment_data } = await client.enrollFactor({\n    subject: { user_id: userId, tenant_id: tenantId },\n    factor_id: 'totp',\n  });\n\n  // Display QR code to user\n  showQRCode(enrollment_data.qr_code_url);\n\n  // Or show secret for manual entry\n  console.log('Secret:', enrollment_data.secret);\n\n  return enrollment_data;\n}\n```\n\n### Protected API Requests\n\n```typescript\nasync function makeAuthenticatedRequest() {\n  // Check if token is valid\n  const claims = await client.verifyCurrentToken();\n\n  if (!claims || !claims.active) {\n    console.log('Not authenticated, redirecting to login...');\n    return;\n  }\n\n  // Token is valid, proceed with request\n  const token = await client.getToken();\n\n  const response = await fetch('https://api.example.com/protected', {\n    headers: {\n      Authorization: `Bearer ${token}`,\n    },\n  });\n\n  return response.json();\n}\n```\n\n### React Hook Example\n\n```typescript\nimport { useState, useEffect } from 'react';\nimport { UvbClient } from '@sp-uvb/client';\n\nfunction useAuth(client: UvbClient) {\n  const [isAuthenticated, setIsAuthenticated] = useState(false);\n  const [isLoading, setIsLoading] = useState(true);\n\n  useEffect(() => {\n    checkAuth();\n  }, []);\n\n  const checkAuth = async () => {\n    const claims = await client.verifyCurrentToken();\n    setIsAuthenticated(claims?.active ?? false);\n    setIsLoading(false);\n  };\n\n  const login = async (userId: string, tenantId: string, otp: string) => {\n    // ... login logic\n    await checkAuth();\n  };\n\n  const logout = async () => {\n    await client.removeToken();\n    setIsAuthenticated(false);\n  };\n\n  return { isAuthenticated, isLoading, login, logout };\n}\n```\n\n---\n\n## TypeScript Support\n\nThe SDK is written in TypeScript and provides full type definitions:\n\n```typescript\nimport type {\n  Subject,\n  Context,\n  Challenge,\n  VerificationStatus,\n  StartVerificationResponse,\n  ContinueVerificationResponse,\n  EnrollFactorRequest,\n  IntrospectTokenResponse,\n} from '@sp-uvb/client';\n\n// All types are exported and fully documented\n```\n\n---\n\n## Browser Support\n\n- ✅ Chrome/Edge (latest)\n- ✅ Firefox (latest)\n- ✅ Safari (latest)\n- ✅ Node.js 16+\n\n---\n\n## Contributing\n\nContributions are welcome! See [CONTRIBUTING.md](../../CONTRIBUTING.md) for details.\n\n---\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n---\n\n## Support\n\n- **Documentation:** [UVB Docs](https://docs.uvb.example.com)\n- **Issues:** [GitHub Issues](https://github.com/yourusername/uvb/issues)\n- **Discussions:** [GitHub Discussions](https://github.com/yourusername/uvb/discussions)\n","readmeFilename":"README.md"}