@one-payments/adapters-web
v1.0.6
Published
Web platform adapters for One Payments SDK
Readme
@one-payments/adapters-web
Web platform adapters for One Payments SDK. Provides browser-based implementations for HTTP, Storage, Crypto, and Timer operations.
Features
- 🌐 Browser APIs - Built on native Web APIs (Fetch, LocalStorage, Web Crypto, setTimeout)
- 🔒 Secure - Uses Web Crypto API for HMAC generation
- 💾 Persistent Storage - LocalStorage for session management
- ⚡ Lightweight - No external dependencies
- 🎯 TypeScript - Full type safety
- 🧩 Framework Agnostic - Works with React, Vue, Angular, and vanilla JS
Installation
npm install @one-payments/adapters-web
# or
yarn add @one-payments/adapters-web
# or
pnpm add @one-payments/adapters-webUsage
Basic Usage
import { createWebAdapters } from '@one-payments/adapters-web';
// Create adapters instance
const adapters = createWebAdapters();
// Use with any One Payments component
// React example:
<OnePayment
config={config}
adapters={adapters}
amount={5000}
currency="USD"
orderId="order-123"
/>React
import { createWebAdapters } from '@one-payments/adapters-web';
import { OnePayment } from '@one-payments/react';
function CheckoutPage() {
const adapters = createWebAdapters();
return (
<OnePayment
config={config}
adapters={adapters}
{...paymentProps}
/>
);
}Vue 3
<script setup lang="ts">
import { createWebAdapters } from '@one-payments/adapters-web';
import { OnePayment } from '@one-payments/vue';
const adapters = createWebAdapters();
</script>
<template>
<OnePayment
:config="config"
:adapters="adapters"
v-bind="paymentProps"
/>
</template>Angular
import { Component } from '@angular/core';
import { createWebAdapters } from '@one-payments/adapters-web';
import { OnePaymentComponent } from '@one-payments/angular';
@Component({
selector: 'app-checkout',
standalone: true,
imports: [OnePaymentComponent],
template: `
<one-payment
[config]="config"
[adapters]="adapters"
/>
`
})
export class CheckoutComponent {
adapters = createWebAdapters();
}Vanilla JavaScript
<!DOCTYPE html>
<html>
<head>
<script type="module" src="https://unpkg.com/@one-payments/web-components"></script>
</head>
<body>
<one-payment id="payment"></one-payment>
<script type="module">
import { createWebAdapters } from 'https://unpkg.com/@one-payments/adapters-web';
const adapters = createWebAdapters();
const paymentElement = document.getElementById('payment');
paymentElement.adapters = adapters;
paymentElement.config = { /*...*/ };
</script>
</body>
</html>Server-Side Rendering (SSR)
Important: This package uses browser-only APIs and cannot be used during server-side rendering. Initialize adapters on the client-side only.
Next.js Integration
For Next.js (and other SSR frameworks), dynamically import and initialize adapters in useEffect:
'use client';
import { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
import type { Adapters } from '@one-payments/core';
// Dynamic import of payment component
const OnePayment = dynamic(
() => import('@one-payments/react').then((mod) => mod.OnePayment),
{ ssr: false }
);
export default function CheckoutPage() {
const [adapters, setAdapters] = useState<Adapters | null>(null);
// Initialize adapters on client-side only
useEffect(() => {
import('@one-payments/adapters-web').then(({ createWebAdapters }) => {
setAdapters(createWebAdapters());
});
}, []);
if (!adapters) {
return <div>Loading payment system...</div>;
}
return (
<OnePayment
config={config}
adapters={adapters}
{...props}
/>
);
}Why this is needed:
- Web APIs like
window,localStorage,crypto.subtledon't exist in Node.js - SSR renders on the server first, causing "ReferenceError: window is not defined"
- Dynamic import with
ssr: falseensures code only runs in the browser
See the Next.js Integration Guide for complete instructions.
Nuxt 3
<script setup>
import { ref, onMounted } from 'vue';
const adapters = ref(null);
onMounted(async () => {
const { createWebAdapters } = await import('@one-payments/adapters-web');
adapters.value = createWebAdapters();
});
</script>
<template>
<ClientOnly>
<OnePayment v-if="adapters" :adapters="adapters" />
</ClientOnly>
</template>Adapter Implementations
HTTP Adapter
Uses the native fetch API for HTTP requests:
interface HttpAdapter {
fetch(url: string, options?: RequestInit): Promise<Response>;
}
// Implementation
const httpAdapter = {
fetch: (url, options) => window.fetch(url, options)
};Storage Adapter
Uses localStorage for persistent client-side storage:
interface StorageAdapter {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
}
// Implementation
const storageAdapter = {
getItem: (key) => Promise.resolve(localStorage.getItem(key)),
setItem: (key, value) => Promise.resolve(localStorage.setItem(key, value)),
removeItem: (key) => Promise.resolve(localStorage.removeItem(key))
};Storage Keys Used:
one-payments-session-*- Payment session dataone-payments-config-*- Cached configuration
Crypto Adapter
Uses Web Crypto API for secure cryptographic operations:
interface CryptoAdapter {
generateHMAC(message: string, secret: string): Promise<string>;
randomUUID(): string;
}
// Implementation uses crypto.subtle for HMAC-SHA256
const cryptoAdapter = {
generateHMAC: async (message, secret) => {
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const messageData = encoder.encode(message);
const key = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', key, messageData);
return Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
},
randomUUID: () => crypto.randomUUID()
};Timer Adapter
Uses native JavaScript timer functions:
interface TimerAdapter {
setTimeout(callback: () => void, delay: number): number;
clearTimeout(id: number): void;
}
// Implementation
const timerAdapter = {
setTimeout: (callback, delay) => window.setTimeout(callback, delay),
clearTimeout: (id) => window.clearTimeout(id)
};Browser Support
Required Browser Features
- Fetch API - All modern browsers (IE11 needs polyfill)
- LocalStorage - All browsers supporting Web Storage API
- Web Crypto API - Chrome 37+, Firefox 34+, Safari 11+, Edge 12+
- crypto.randomUUID() - Chrome 92+, Firefox 95+, Safari 15.4+
Polyfills
For older browsers, you may need polyfills:
<!-- Fetch polyfill for IE11 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/fetch.umd.js"></script>
<!-- crypto.randomUUID polyfill -->
<script>
if (!crypto.randomUUID) {
crypto.randomUUID = function() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
};
}
</script>Browser Compatibility
| Browser | Minimum Version | Notes | |---------|----------------|-------| | Chrome | 92+ | Full support | | Firefox | 95+ | Full support | | Safari | 15.4+ | Full support | | Edge | 92+ | Full support | | Mobile Safari | iOS 15.4+ | Full support | | Chrome Mobile | 92+ | Full support |
Security Considerations
HMAC Generation
- Uses Web Crypto API's
crypto.subtlefor secure HMAC-SHA256 - Secret keys never leave the browser
- HMAC signatures used for API request authentication
Storage Security
- Uses
localStoragewhich is origin-isolated - Data is accessible only to your domain
- No sensitive card data is stored (PCI compliance)
- Session tokens expire after use
Content Security Policy (CSP)
If your site uses CSP, ensure these directives:
Content-Security-Policy:
script-src 'self' 'unsafe-eval';
connect-src 'self' https://*.one.ooo;
frame-src https://*.one.ooo;Comparison with Other Adapters
vs. @one-payments/adapters-crypto-js
| Feature | adapters-web | adapters-crypto-js | |---------|--------------|-------------------| | Environment | Modern browsers | Legacy browsers, WebView | | Crypto | Web Crypto API | CryptoJS library | | Bundle Size | ~2KB | ~50KB | | Performance | Native (faster) | JavaScript (slower) | | Use Case | Standard web apps | React Native WebView, IE11 |
Use @one-payments/adapters-crypto-js when:
- Supporting IE11 or older browsers
- Using React Native WebView (no Web Crypto API)
- Server-side rendering with crypto operations
Use @one-payments/adapters-web when:
- Building modern web applications
- Supporting Chrome, Firefox, Safari, Edge (latest versions)
- Performance is a priority
vs. @one-payments/adapters-native
| Feature | adapters-web | adapters-native | |---------|--------------|-----------------| | Platform | Web browsers | React Native | | Storage | localStorage | AsyncStorage | | HTTP | fetch | React Native fetch | | Use Case | Web apps | Native mobile apps |
Troubleshooting
Error: "window is not defined"
Cause: Trying to import adapters during SSR
Solution: Initialize in useEffect (React) or onMounted (Vue):
// ❌ Don't do this
const adapters = createWebAdapters();
// ✅ Do this
const [adapters, setAdapters] = useState(null);
useEffect(() => {
import('@one-payments/adapters-web').then(({ createWebAdapters }) => {
setAdapters(createWebAdapters());
});
}, []);Error: "crypto.subtle is undefined"
Cause: Page not served over HTTPS (Web Crypto requires secure context)
Solution:
- Use HTTPS in production
- For localhost, modern browsers allow HTTP
- For testing, use
chrome://flags/#unsafely-treat-insecure-origin-as-secure
Error: "localStorage is not defined"
Cause: Browser privacy mode or storage disabled
Solution: Check if storage is available:
try {
const adapters = createWebAdapters();
} catch (error) {
console.error('Storage not available:', error);
// Show message to user to disable privacy mode
}Testing
Mock adapters in tests:
// test-utils.ts
export const mockAdapters = {
http: {
fetch: jest.fn()
},
storage: {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn()
},
crypto: {
generateHMAC: jest.fn().mockResolvedValue('mock-hmac'),
randomUUID: jest.fn().mockReturnValue('mock-uuid')
},
timer: {
setTimeout: jest.fn(),
clearTimeout: jest.fn()
}
};
// Your test
it('should process payment', () => {
render(<OnePayment adapters={mockAdapters} {...props} />);
// ...
});Related Packages
- @one-payments/core - Core types and interfaces
- @one-payments/react - React wrapper
- @one-payments/vue - Vue wrapper
- @one-payments/angular - Angular wrapper
- @one-payments/adapters-crypto-js - CryptoJS-based adapter
- @one-payments/adapters-native - React Native adapter
Requirements
- Modern browser with ES2020 support
- HTTPS (for Web Crypto API)
- LocalStorage enabled
Bundle Size
- Minified: ~2KB
- Gzipped: ~1KB
License
MIT
