@shelchin/paywall
v0.0.1
Published
Flexible paywall system for membership and usage quota management with blockchain verification
Maintainers
Readme
@shelchin/paywall
A flexible paywall system for managing membership and usage quotas with blockchain verification.
Features
- Membership verification via smart contract
- Usage quota tracking with daily limits
- IndexedDB caching with anti-tampering protection
- Signature-based security - wallet signature as personalized salt
- Browser fingerprint - prevents cross-device cache copying
- Safe verification - RPC failures don't delete valid cache
- Configurable - contract address, ABI, cache keys, timing all customizable
Installation
bun add @shelchin/paywall
# or
npm install @shelchin/paywallPeer Dependencies
svelte^5.0.0viem^2.0.0
Quick Start
1. Initialize the paywall
import { initPaywall } from '@shelchin/paywall';
import MyPremiumABI from './contracts/MyPremium.json';
initPaywall({
contract: {
address: '0x...', // Your membership contract
abi: MyPremiumABI.abi,
functionName: 'getSubscriptionInfo' // Optional, defaults to 'getSubscriptionInfo'
},
cache: {
membershipKeyPrefix: 'myapp-membership', // Optional
usageKeyPrefix: 'myapp-usage', // Optional
checksumSalt: 'myapp-v1' // Optional
},
selfHostedMode: import.meta.env.VITE_SELF_HOSTED === 'true' // Optional
});2. Create a paywall rule
import { createMembershipOnlyRule } from '@shelchin/paywall';
export const myFeaturePaywall = createMembershipOnlyRule('my-feature', {
daily: 100, // Free tier: 100 items per day
countBy: 'items'
});3. Use in components
<script>
import { usePaywall } from '@shelchin/paywall';
import { myFeaturePaywall } from './paywall';
const paywall = usePaywall({ rule: myFeaturePaywall });
async function handleAction() {
const result = await paywall.check(items.length);
if (!result.allowed) {
showUpgradeModal();
return;
}
if (!result.freeUse) {
showPaymentConfirm(result);
return;
}
await doAction();
await paywall.recordUsage(items.length);
}
</script>Configuration
Contract Configuration
interface ContractConfig {
address: Address; // Contract address
abi: Abi; // Contract ABI
functionName?: string; // Default: 'getSubscriptionInfo'
}The contract function should return [isPremium: boolean, expiryTime: uint256, remainingTime: uint256].
Cache Configuration
interface CacheConfig {
membershipKeyPrefix?: string; // Default: 'paywall-membership'
usageKeyPrefix?: string; // Default: 'paywall-usage'
checksumSalt?: string; // Default: 'paywall-v1'
}Timing Configuration
interface TimingConfig {
verifyIntervalMs?: number; // Default: 180000 (3 min)
initialVerifyDelayMs?: number; // Default: 5000
maxRetryAttempts?: number; // Default: 3
retryBaseDelayMs?: number; // Default: 1000
retryMaxDelayMs?: number; // Default: 10000
}Rule Types
Membership Only
createMembershipOnlyRule('feature-id', freeQuota?, options?)Pay Per Use
createPayPerUseRule('feature-id', perUseFee, options?)Hybrid (Free + Pay)
createHybridRule('feature-id', {
freeQuota: { daily: 10, countBy: 'items' },
perUseFee: 0.003,
feeInContract: true
});Free (No Restrictions)
createFreeRule('feature-id');API Reference
Stores
createMembershipStore()- Creates membership state storeuseMembershipStore()- Gets membership store from contextcreateUsageQuotaStore()- Creates usage tracking storeuseUsageQuotaStore()- Gets usage store from context
Composables
usePaywall({ rule })- Main paywall checkerverifyMembership(address, chainId, rpcUrl)- Verify cached membershipterminateVerifier()- Cleanup worker
Security Utilities
requestSignature(walletClient, address)- Request signature for securitygenerateSecureChecksum(...)- Generate tamper-proof checksumverifySecureChecksum(...)- Verify checksum
Self-Hosted Mode
Set selfHostedMode: true to bypass all paywall checks:
initPaywall({
contract: { ... },
selfHostedMode: import.meta.env.VITE_SELF_HOSTED === 'true'
});Then build with:
VITE_SELF_HOSTED=true bun run buildLicense
MIT
