@akedly/shield
v1.0.1
Published
Client-side PoW solver and Turnstile helper for Akedly Shield V1.2
Maintainers
Readme
@akedly/shield
Client-side Proof-of-Work solver and Turnstile helper for Akedly Shield V1.2.
Installation
npm install @akedly/shieldOr via CDN:
<script src="https://unpkg.com/@akedly/shield/dist/akedly-shield.min.js"></script>Quick Start
import { solvePow } from '@akedly/shield';
// 1. Get challenge from your server
const res = await fetch('/api/v1.2/transactions/challenge?APIKey=...&pipelineID=...');
const { data } = await res.json();
// 2. Solve PoW
const { nonce } = await solvePow(data.challenge, data.difficulty);
// 3. Send OTP with solution
await fetch('/api/v1.2/transactions/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
APIKey: '...',
pipelineID: '...',
verificationAddress: { phoneNumber: '+201234567890' },
powSolution: { challengeToken: data.challengeToken, nonce }
})
});API Reference
solvePow(challenge, difficulty, options?)
Convenience function that creates a solver, finds the nonce, and cleans up.
challenge— 64-char hex string from the serverdifficulty— integer (number of leading hex zeros required)options.onProgress(hashesChecked)— progress callbackoptions.useWorker—true,false, or'auto'(default:'auto')- Returns
Promise<{ nonce: number }>
new AkedlyShield(options?)
Reusable solver instance.
options.useWorker—true,false, or'auto'(default:'auto')
.solve(challenge, difficulty, options?)
Same as solvePow but reuses the instance.
.terminate()
Kills the active Web Worker and releases the Blob URL.
getTurnstileToken(siteKey, options?)
Browser-only. Creates a hidden Turnstile widget, resolves with the token, and cleans up.
siteKey— Cloudflare Turnstile site keyoptions.theme—'light','dark', or'auto'options.size—'normal'or'compact'- Returns
Promise<string>
renderTurnstile(siteKey, container, options?)
Renders a Turnstile widget into a DOM element.
container— DOM element to render into- Returns
Promise<string>(token)
Platform Support
| Platform | PoW Solver | Turnstile |
|----------|-----------|-----------|
| Browser (Worker) | Web Worker (off-thread) | getTurnstileToken() |
| Browser (no Worker) | Batched main-thread | getTurnstileToken() |
| React Native | Batched main-thread | Use bridge page |
| Node.js | Sync with native crypto | N/A |
Web Worker Behavior
When useWorker is 'auto' (default), the library:
- Checks if
Worker,Blob, andURL.createObjectURLare available - If yes, bundles the solver code into a Blob URL Worker (no separate file needed)
- If no (e.g., React Native), falls back to batched main-thread solving with
setTimeout(fn, 0)between batches to keep the UI responsive
Algorithm
hash = SHA256(challenge + ":" + String(nonce)) // hex digest
valid = hash.startsWith("0".repeat(difficulty)) // leading hex zerosThe solver increments nonce from 0 until a valid hash is found.
Full Integration Example
import { solvePow, getTurnstileToken } from '@akedly/shield';
async function sendOTP(phoneNumber, apiKey, pipelineID) {
// Step 1: Get challenge
const challengeRes = await fetch(
`https://api.akedly.io/api/v1.2/transactions/challenge?APIKey=${apiKey}&pipelineID=${pipelineID}`
);
const { data } = await challengeRes.json();
// Step 2: Solve PoW (if required)
let powSolution;
if (data.challengeRequired) {
const { nonce } = await solvePow(data.challenge, data.difficulty, {
onProgress: (checked) => console.log(`${checked} hashes checked...`)
});
powSolution = { challengeToken: data.challengeToken, nonce };
}
// Step 3: Get Turnstile token (if required)
let turnstileToken;
if (data.turnstile?.required) {
turnstileToken = await getTurnstileToken(data.turnstile.siteKey);
}
// Step 4: Send OTP
const sendRes = await fetch('https://api.akedly.io/api/v1.2/transactions/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
APIKey: apiKey,
pipelineID,
verificationAddress: { phoneNumber },
powSolution,
turnstileToken
})
});
return sendRes.json();
}Related Packages
- Dart/Flutter:
akedly_shield - Swift (iOS):
AkedlyShield - Kotlin (Android):
com.akedly.shield
