@liveauth-labs/sdk 0.1.1 → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +178 -49
- package/dist/index.cjs +165 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -6
- package/dist/index.d.ts +72 -6
- package/dist/index.js +159 -48
- package/dist/index.js.map +1 -1
- package/dist/pow.worker.cjs +48 -3
- package/dist/pow.worker.cjs.map +1 -1
- package/dist/pow.worker.d.cts +15 -1
- package/dist/pow.worker.d.ts +15 -1
- package/dist/pow.worker.js +33 -3
- package/dist/pow.worker.js.map +1 -1
- package/package.json +16 -4
package/LICENSE
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LiveAuth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,48 +1,42 @@
|
|
|
1
|
-
# LiveAuth
|
|
1
|
+
# LiveAuth JS SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Human verification through economics, not heuristics.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/@liveauth-labs/sdk)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## What is LiveAuth?
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
cryptographic proof. If that fails or is skipped, it falls back to a small
|
|
9
|
-
Bitcoin Lightning payment.
|
|
10
|
+
LiveAuth verifies humans economically instead of heuristically.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
No fingerprinting.
|
|
13
|
-
No behavioral profiling.
|
|
12
|
+
Instead of CAPTCHAs or tracking, LiveAuth asks the browser to perform a short cryptographic proof. If that fails or is skipped, it falls back to a small Bitcoin Lightning payment.
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
- No cookies
|
|
15
|
+
- No fingerprinting
|
|
16
|
+
- No behavioral profiling
|
|
16
17
|
|
|
17
|
-
##
|
|
18
|
+
## How It Works
|
|
18
19
|
|
|
19
|
-
When a user
|
|
20
|
+
When a user triggers verification:
|
|
20
21
|
|
|
21
22
|
1. **Browser attempts Proof-of-Work (PoW)**
|
|
22
|
-
|
|
23
|
-
– Bots pay CPU / battery cost
|
|
23
|
+
Takes ~200–800ms for a real device. Bots pay CPU/battery cost.
|
|
24
24
|
|
|
25
25
|
2. **If PoW fails → Lightning fallback**
|
|
26
|
-
|
|
27
|
-
– Real economic cost to bots
|
|
26
|
+
Small payment (e.g. 21 sats). Real economic cost to bots.
|
|
28
27
|
|
|
29
28
|
3. **LiveAuth returns a short-lived JWT**
|
|
30
|
-
|
|
31
|
-
– No user identity required
|
|
29
|
+
Verifiable on your backend. No user identity required.
|
|
32
30
|
|
|
33
31
|
Most humans never see the Lightning step.
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
## Installation (JavaScript)
|
|
33
|
+
## Installation
|
|
38
34
|
|
|
39
35
|
```bash
|
|
40
36
|
npm install @liveauth-labs/sdk
|
|
41
37
|
```
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## Basic Usage
|
|
39
|
+
## Quick Start
|
|
46
40
|
|
|
47
41
|
```ts
|
|
48
42
|
import { LiveAuth } from '@liveauth-labs/sdk';
|
|
@@ -52,52 +46,187 @@ const liveauth = new LiveAuth({
|
|
|
52
46
|
});
|
|
53
47
|
|
|
54
48
|
const result = await liveauth.verify();
|
|
49
|
+
|
|
50
|
+
if (result.method === 'pow') {
|
|
51
|
+
// PoW succeeded - send token to your backend
|
|
52
|
+
console.log('Verified via PoW:', result.token);
|
|
53
|
+
} else {
|
|
54
|
+
// Lightning fallback - show invoice to user
|
|
55
|
+
console.log('Pay invoice:', result.lightning.invoice);
|
|
56
|
+
|
|
57
|
+
// Poll for payment confirmation
|
|
58
|
+
const token = await liveauth.pollLightning(result.lightning.sessionId);
|
|
59
|
+
console.log('Verified via Lightning:', token);
|
|
60
|
+
}
|
|
55
61
|
```
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
## API Reference
|
|
64
|
+
|
|
65
|
+
### `new LiveAuth(config)`
|
|
66
|
+
|
|
67
|
+
| Option | Type | Required | Description |
|
|
68
|
+
|--------|------|----------|-------------|
|
|
69
|
+
| `publicKey` | `string` | ✓ | Your LiveAuth public key |
|
|
70
|
+
| `baseUrl` | `string` | | API base URL (default: `https://api.liveauth.app`) |
|
|
71
|
+
|
|
72
|
+
### `verify(options?)`
|
|
73
|
+
|
|
74
|
+
Attempts verification, starting with PoW and falling back to Lightning if needed.
|
|
58
75
|
|
|
59
|
-
|
|
76
|
+
| Option | Type | Default | Description |
|
|
77
|
+
|--------|------|---------|-------------|
|
|
78
|
+
| `forceLightning` | `boolean` | `false` | Skip PoW, go straight to Lightning |
|
|
79
|
+
| `onProgress` | `function` | | Callback: `(hashesPerSec, iterations) => void` |
|
|
80
|
+
| `powTimeoutMs` | `number` | `30000` | Max time for PoW before fallback |
|
|
81
|
+
| `maxPowIterations` | `number` | `50000000` | Max iterations before fallback |
|
|
82
|
+
|
|
83
|
+
**Returns:** `Promise<LiveAuthResult>`
|
|
60
84
|
|
|
61
85
|
```ts
|
|
86
|
+
// PoW success
|
|
62
87
|
{
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
method: 'pow',
|
|
89
|
+
token: 'eyJhbGciOi...',
|
|
65
90
|
solveMs: 412,
|
|
66
91
|
difficultyBits: 18
|
|
67
92
|
}
|
|
93
|
+
|
|
94
|
+
// Lightning fallback
|
|
95
|
+
{
|
|
96
|
+
method: 'lightning',
|
|
97
|
+
lightning: {
|
|
98
|
+
sessionId: 'sess_xxx',
|
|
99
|
+
invoice: 'lnbc...',
|
|
100
|
+
amountSats: 21,
|
|
101
|
+
expiresAtUnix: 1234567890,
|
|
102
|
+
mode: 'LIVE'
|
|
103
|
+
},
|
|
104
|
+
diagnostics: {
|
|
105
|
+
reason: 'pow_unsupported'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
68
108
|
```
|
|
69
109
|
|
|
70
|
-
|
|
110
|
+
### `pollLightning(sessionId, options?)`
|
|
71
111
|
|
|
72
|
-
|
|
112
|
+
Polls for Lightning payment confirmation.
|
|
73
113
|
|
|
74
|
-
|
|
114
|
+
| Option | Type | Default | Description |
|
|
115
|
+
|--------|------|---------|-------------|
|
|
116
|
+
| `timeoutMs` | `number` | `300000` | Max wait time (5 min) |
|
|
117
|
+
| `intervalMs` | `number` | `2000` | Poll interval |
|
|
118
|
+
| `signal` | `AbortSignal` | | Cancellation signal |
|
|
75
119
|
|
|
76
|
-
The token
|
|
120
|
+
**Returns:** `Promise<string>` - The verification token
|
|
77
121
|
|
|
78
|
-
|
|
79
|
-
- projectPublicKey
|
|
80
|
-
- authType (pow or lightning)
|
|
81
|
-
- short expiration (default: 10 minutes)
|
|
122
|
+
## Error Handling
|
|
82
123
|
|
|
83
|
-
|
|
124
|
+
```ts
|
|
125
|
+
import {
|
|
126
|
+
LiveAuth,
|
|
127
|
+
LiveAuthTimeoutError,
|
|
128
|
+
LiveAuthCancelledError,
|
|
129
|
+
LiveAuthNetworkError,
|
|
130
|
+
LiveAuthPowTimeoutError
|
|
131
|
+
} from '@liveauth-labs/sdk';
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const result = await liveauth.verify();
|
|
135
|
+
} catch (err) {
|
|
136
|
+
if (err instanceof LiveAuthNetworkError) {
|
|
137
|
+
console.error('Network issue:', err.message);
|
|
138
|
+
} else if (err instanceof LiveAuthPowTimeoutError) {
|
|
139
|
+
console.error('PoW took too long');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
84
143
|
|
|
85
|
-
##
|
|
144
|
+
## Progress Feedback
|
|
86
145
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
146
|
+
Show users what's happening during PoW:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const result = await liveauth.verify({
|
|
150
|
+
onProgress: (hashesPerSec, iterations) => {
|
|
151
|
+
console.log(`${(iterations / 1000).toFixed(0)}k hashes @ ${hashesPerSec}/sec`);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
```
|
|
93
155
|
|
|
94
|
-
|
|
156
|
+
## Backend Verification
|
|
157
|
+
|
|
158
|
+
Send the JWT to your backend and verify it using your LiveAuth secret key.
|
|
159
|
+
|
|
160
|
+
### Example (Node.js)
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import jwt from 'jsonwebtoken';
|
|
164
|
+
|
|
165
|
+
app.post('/api/verify-liveauth', (req, res) => {
|
|
166
|
+
const { token } = req.body;
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
// Verify JWT signature with your LiveAuth secret key
|
|
170
|
+
const decoded = jwt.verify(token, process.env.LIVEAUTH_SECRET_KEY);
|
|
171
|
+
|
|
172
|
+
// Check expiration (JWT library handles this, but you can also check manually)
|
|
173
|
+
if (decoded.exp && decoded.exp < Date.now() / 1000) {
|
|
174
|
+
return res.status(401).json({ error: 'Token expired' });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Extract claims
|
|
178
|
+
const { projectId, projectPublicKey, authType, sub } = decoded;
|
|
179
|
+
|
|
180
|
+
// Verify it matches your project
|
|
181
|
+
if (projectPublicKey !== process.env.LIVEAUTH_PUBLIC_KEY) {
|
|
182
|
+
return res.status(401).json({ error: 'Invalid project' });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Success - user is verified
|
|
186
|
+
res.json({
|
|
187
|
+
verified: true,
|
|
188
|
+
authType, // 'pow' or 'lightning'
|
|
189
|
+
userId: sub
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
} catch (err) {
|
|
193
|
+
res.status(401).json({ error: 'Invalid token' });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Token Claims
|
|
199
|
+
|
|
200
|
+
The JWT contains:
|
|
201
|
+
- `sub` - Unique user identifier (format: `pow:{projectId}:{challengeHex}` or `lightning:{invoiceId}`)
|
|
202
|
+
- `projectId` - Your project's UUID
|
|
203
|
+
- `projectPublicKey` - Your public API key
|
|
204
|
+
- `authType` - Verification method: `pow` or `lightning`
|
|
205
|
+
- `exp` - Expiration timestamp (default: 10 minutes from issuance)
|
|
206
|
+
- `iat` - Issued at timestamp
|
|
207
|
+
|
|
208
|
+
**Security Notes:**
|
|
209
|
+
- Always verify the JWT signature using your secret key
|
|
210
|
+
- Check the `projectPublicKey` claim matches your expected key
|
|
211
|
+
- Respect the `exp` (expiration) claim
|
|
212
|
+
- The `sub` claim is ephemeral - don't use it as a permanent user ID unless you're tracking sessions
|
|
95
213
|
|
|
96
214
|
## Debug Mode
|
|
97
215
|
|
|
98
216
|
Add `?liveauth_debug=1` to your URL to see:
|
|
217
|
+
- Verification method used
|
|
218
|
+
- PoW difficulty and solve time
|
|
219
|
+
- Lightning fallback triggers
|
|
220
|
+
|
|
221
|
+
## Why LiveAuth?
|
|
222
|
+
|
|
223
|
+
| Traditional CAPTCHA | LiveAuth |
|
|
224
|
+
|--------------------|----------|
|
|
225
|
+
| Tracks behavior | No tracking |
|
|
226
|
+
| ML heuristics | Cryptography |
|
|
227
|
+
| CAPTCHA farms | Real economic cost |
|
|
228
|
+
| Bad UX | Invisible to most humans |
|
|
229
|
+
|
|
230
|
+
## License
|
|
99
231
|
|
|
100
|
-
|
|
101
|
-
- PoW difficulty
|
|
102
|
-
- Solve time
|
|
103
|
-
- Lightning fallback (demo mode)
|
|
232
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -20,26 +20,51 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
-
LiveAuth: () => LiveAuth
|
|
23
|
+
LiveAuth: () => LiveAuth,
|
|
24
|
+
LiveAuthCancelledError: () => LiveAuthCancelledError,
|
|
25
|
+
LiveAuthNetworkError: () => LiveAuthNetworkError,
|
|
26
|
+
LiveAuthPowTimeoutError: () => LiveAuthPowTimeoutError,
|
|
27
|
+
LiveAuthPowUnsupportedError: () => LiveAuthPowUnsupportedError,
|
|
28
|
+
LiveAuthTimeoutError: () => LiveAuthTimeoutError
|
|
24
29
|
});
|
|
25
30
|
module.exports = __toCommonJS(src_exports);
|
|
26
31
|
|
|
27
32
|
// src/errors.ts
|
|
28
33
|
var LiveAuthTimeoutError = class extends Error {
|
|
29
|
-
constructor(message = "
|
|
34
|
+
constructor(message = "LiveAuth verification timed out") {
|
|
30
35
|
super(message);
|
|
31
36
|
this.name = "LiveAuthTimeoutError";
|
|
32
37
|
}
|
|
33
38
|
};
|
|
34
39
|
var LiveAuthCancelledError = class extends Error {
|
|
35
|
-
constructor(message = "
|
|
40
|
+
constructor(message = "LiveAuth verification cancelled") {
|
|
36
41
|
super(message);
|
|
37
42
|
this.name = "LiveAuthCancelledError";
|
|
38
43
|
}
|
|
39
44
|
};
|
|
45
|
+
var LiveAuthNetworkError = class extends Error {
|
|
46
|
+
constructor(message = "LiveAuth network request failed", cause) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.cause = cause;
|
|
49
|
+
this.name = "LiveAuthNetworkError";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var LiveAuthPowUnsupportedError = class extends Error {
|
|
53
|
+
constructor(message = "Proof-of-Work is not supported in this environment") {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = "LiveAuthPowUnsupportedError";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var LiveAuthPowTimeoutError = class extends Error {
|
|
59
|
+
constructor(message = "Proof-of-Work timed out") {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = "LiveAuthPowTimeoutError";
|
|
62
|
+
}
|
|
63
|
+
};
|
|
40
64
|
|
|
41
65
|
// src/index.ts
|
|
42
66
|
var import_meta = {};
|
|
67
|
+
var SDK_VERSION = "0.2.0";
|
|
43
68
|
var LiveAuth = class {
|
|
44
69
|
constructor(config) {
|
|
45
70
|
this.config = config;
|
|
@@ -49,85 +74,149 @@ var LiveAuth = class {
|
|
|
49
74
|
this.baseUrl = config.baseUrl ?? "https://api.liveauth.app";
|
|
50
75
|
this.headers = {
|
|
51
76
|
"Content-Type": "application/json",
|
|
52
|
-
"X-LW-Public": config.publicKey
|
|
77
|
+
"X-LW-Public": config.publicKey,
|
|
78
|
+
"X-LW-SDK-Version": SDK_VERSION
|
|
53
79
|
};
|
|
54
80
|
}
|
|
55
81
|
/* ======================================================
|
|
56
82
|
* PUBLIC ENTRYPOINT
|
|
57
83
|
* ====================================================== */
|
|
58
|
-
async verify() {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
sig: challenge.sig
|
|
68
|
-
});
|
|
69
|
-
if (verifyRes.verified && verifyRes.token) {
|
|
84
|
+
async verify(options = {}) {
|
|
85
|
+
const {
|
|
86
|
+
forceLightning = false,
|
|
87
|
+
onProgress,
|
|
88
|
+
powTimeoutMs = 3e4,
|
|
89
|
+
maxPowIterations = 5e7
|
|
90
|
+
} = options;
|
|
91
|
+
if (forceLightning) {
|
|
92
|
+
const lightning = await this.startLightning();
|
|
70
93
|
return {
|
|
71
|
-
method: "
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
difficultyBits: challenge.difficultyBits
|
|
94
|
+
method: "lightning",
|
|
95
|
+
lightning,
|
|
96
|
+
diagnostics: { reason: "forced_lightning" }
|
|
75
97
|
};
|
|
76
98
|
}
|
|
77
|
-
if (
|
|
99
|
+
if (!this.canUsePow()) {
|
|
78
100
|
const lightning = await this.startLightning();
|
|
79
101
|
return {
|
|
80
102
|
method: "lightning",
|
|
81
|
-
lightning
|
|
103
|
+
lightning,
|
|
104
|
+
diagnostics: { reason: "pow_unsupported" }
|
|
82
105
|
};
|
|
83
106
|
}
|
|
84
|
-
|
|
107
|
+
const startedAt = performance.now();
|
|
108
|
+
try {
|
|
109
|
+
const challenge = await this.getPowChallenge();
|
|
110
|
+
const solution = await this.solvePow(challenge, {
|
|
111
|
+
onProgress,
|
|
112
|
+
timeoutMs: powTimeoutMs,
|
|
113
|
+
maxIterations: maxPowIterations
|
|
114
|
+
});
|
|
115
|
+
const verifyRes = await this.verifyPow({
|
|
116
|
+
challengeHex: challenge.challengeHex,
|
|
117
|
+
nonce: solution.nonce,
|
|
118
|
+
hashHex: solution.hashHex,
|
|
119
|
+
expiresAtUnix: challenge.expiresAtUnix,
|
|
120
|
+
difficultyBits: challenge.difficultyBits,
|
|
121
|
+
sig: challenge.sig
|
|
122
|
+
});
|
|
123
|
+
if (verifyRes.verified && verifyRes.token) {
|
|
124
|
+
return {
|
|
125
|
+
method: "pow",
|
|
126
|
+
token: verifyRes.token,
|
|
127
|
+
solveMs: Math.round(performance.now() - startedAt),
|
|
128
|
+
difficultyBits: challenge.difficultyBits
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (verifyRes.fallback === "lightning") {
|
|
132
|
+
const lightning = await this.startLightning();
|
|
133
|
+
return {
|
|
134
|
+
method: "lightning",
|
|
135
|
+
lightning,
|
|
136
|
+
diagnostics: { reason: "pow_server_fallback" }
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
throw new Error("LiveAuth: verification failed");
|
|
140
|
+
} catch (err) {
|
|
141
|
+
if (err instanceof LiveAuthPowTimeoutError || err instanceof LiveAuthPowUnsupportedError) {
|
|
142
|
+
const lightning = await this.startLightning();
|
|
143
|
+
return {
|
|
144
|
+
method: "lightning",
|
|
145
|
+
lightning,
|
|
146
|
+
diagnostics: {
|
|
147
|
+
reason: "pow_failed",
|
|
148
|
+
detail: err.message
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
85
154
|
}
|
|
86
155
|
/* ======================================================
|
|
87
156
|
* POW FLOW
|
|
88
157
|
* ====================================================== */
|
|
89
158
|
async getPowChallenge() {
|
|
90
|
-
const res = await
|
|
159
|
+
const res = await this.fetchWithRetry(`${this.baseUrl}/api/public/pow/challenge`, {
|
|
91
160
|
headers: this.headers
|
|
92
161
|
});
|
|
93
|
-
if (!res.ok) throw new
|
|
162
|
+
if (!res.ok) throw new LiveAuthNetworkError("PoW challenge failed");
|
|
94
163
|
return res.json();
|
|
95
164
|
}
|
|
96
165
|
async verifyPow(req) {
|
|
97
|
-
const res = await
|
|
166
|
+
const res = await this.fetchWithRetry(`${this.baseUrl}/api/public/pow/verify`, {
|
|
98
167
|
method: "POST",
|
|
99
168
|
headers: this.headers,
|
|
100
169
|
body: JSON.stringify(req)
|
|
101
170
|
});
|
|
102
|
-
if (!res.ok) throw new
|
|
171
|
+
if (!res.ok) throw new LiveAuthNetworkError("PoW verify failed");
|
|
103
172
|
return res.json();
|
|
104
173
|
}
|
|
105
174
|
/* ======================================================
|
|
106
175
|
* POW SOLVER (WORKER)
|
|
107
176
|
* ====================================================== */
|
|
108
|
-
solvePow(challenge) {
|
|
177
|
+
solvePow(challenge, options = {}) {
|
|
178
|
+
const { onProgress, timeoutMs = 3e4, maxIterations = 5e7 } = options;
|
|
109
179
|
if (!this.canUsePow()) {
|
|
110
|
-
return Promise.reject(
|
|
111
|
-
new Error("LiveAuth: PoW not supported in this environment")
|
|
112
|
-
);
|
|
180
|
+
return Promise.reject(new LiveAuthPowUnsupportedError());
|
|
113
181
|
}
|
|
114
182
|
return new Promise((resolve, reject) => {
|
|
115
183
|
const worker = new Worker(
|
|
116
184
|
new URL("./pow.worker.js", import_meta.url),
|
|
117
185
|
{ type: "module" }
|
|
118
186
|
);
|
|
119
|
-
|
|
187
|
+
const timeoutId = setTimeout(() => {
|
|
120
188
|
worker.terminate();
|
|
121
|
-
|
|
189
|
+
reject(new LiveAuthPowTimeoutError(`PoW timed out after ${timeoutMs}ms`));
|
|
190
|
+
}, timeoutMs);
|
|
191
|
+
worker.onmessage = (e) => {
|
|
192
|
+
const data = e.data;
|
|
193
|
+
if (data.type === "progress") {
|
|
194
|
+
onProgress?.(data.hashesPerSec ?? 0, data.iterations ?? 0);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (data.type === "timeout") {
|
|
198
|
+
clearTimeout(timeoutId);
|
|
199
|
+
worker.terminate();
|
|
200
|
+
reject(new LiveAuthPowTimeoutError(`PoW hit max iterations (${maxIterations})`));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (data.type === "solution" && data.nonce !== void 0 && data.hashHex) {
|
|
204
|
+
clearTimeout(timeoutId);
|
|
205
|
+
worker.terminate();
|
|
206
|
+
resolve({ nonce: data.nonce, hashHex: data.hashHex });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
122
209
|
};
|
|
123
210
|
worker.onerror = (e) => {
|
|
211
|
+
clearTimeout(timeoutId);
|
|
124
212
|
worker.terminate();
|
|
125
|
-
reject(e);
|
|
213
|
+
reject(new LiveAuthPowUnsupportedError(`Worker error: ${e.message}`));
|
|
126
214
|
};
|
|
127
215
|
worker.postMessage({
|
|
128
216
|
projectPublicKey: challenge.projectPublicKey,
|
|
129
217
|
challengeHex: challenge.challengeHex,
|
|
130
|
-
targetHex: challenge.targetHex
|
|
218
|
+
targetHex: challenge.targetHex,
|
|
219
|
+
maxIterations
|
|
131
220
|
});
|
|
132
221
|
});
|
|
133
222
|
}
|
|
@@ -135,26 +224,16 @@ var LiveAuth = class {
|
|
|
135
224
|
* LIGHTNING FALLBACK
|
|
136
225
|
* ====================================================== */
|
|
137
226
|
async startLightning() {
|
|
138
|
-
const res = await
|
|
227
|
+
const res = await this.fetchWithRetry(`${this.baseUrl}/api/public/auth/start`, {
|
|
139
228
|
method: "POST",
|
|
140
229
|
headers: this.headers,
|
|
141
230
|
body: JSON.stringify({ userHint: "browser" })
|
|
142
231
|
});
|
|
143
232
|
if (!res.ok) {
|
|
144
|
-
throw new
|
|
233
|
+
throw new LiveAuthNetworkError("Lightning auth start failed");
|
|
145
234
|
}
|
|
146
235
|
return res.json();
|
|
147
236
|
}
|
|
148
|
-
canUsePow() {
|
|
149
|
-
try {
|
|
150
|
-
if (typeof window === "undefined") return false;
|
|
151
|
-
if (typeof Worker === "undefined") return false;
|
|
152
|
-
if (typeof URL === "undefined") return false;
|
|
153
|
-
return true;
|
|
154
|
-
} catch {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
237
|
async pollLightning(sessionId, options) {
|
|
159
238
|
const timeoutMs = options?.timeoutMs ?? 5 * 6e4;
|
|
160
239
|
const intervalMs = options?.intervalMs ?? 2e3;
|
|
@@ -187,7 +266,7 @@ var LiveAuth = class {
|
|
|
187
266
|
}
|
|
188
267
|
);
|
|
189
268
|
if (!res.ok) {
|
|
190
|
-
throw new
|
|
269
|
+
throw new LiveAuthNetworkError("Lightning confirm failed");
|
|
191
270
|
}
|
|
192
271
|
const json = await res.json();
|
|
193
272
|
if (json.verified && json.token) {
|
|
@@ -199,10 +278,47 @@ var LiveAuth = class {
|
|
|
199
278
|
clearTimeout(timeoutId);
|
|
200
279
|
}
|
|
201
280
|
}
|
|
281
|
+
/* ======================================================
|
|
282
|
+
* UTILITIES
|
|
283
|
+
* ====================================================== */
|
|
284
|
+
canUsePow() {
|
|
285
|
+
try {
|
|
286
|
+
if (typeof window === "undefined") return false;
|
|
287
|
+
if (typeof Worker === "undefined") return false;
|
|
288
|
+
if (typeof URL === "undefined") return false;
|
|
289
|
+
if (typeof crypto === "undefined" || !crypto.subtle) return false;
|
|
290
|
+
return true;
|
|
291
|
+
} catch {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async fetchWithRetry(url, init, retries = 2, backoffMs = 500) {
|
|
296
|
+
let lastError;
|
|
297
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
298
|
+
try {
|
|
299
|
+
const res = await fetch(url, init);
|
|
300
|
+
return res;
|
|
301
|
+
} catch (err) {
|
|
302
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
303
|
+
if (attempt < retries) {
|
|
304
|
+
await sleep(backoffMs * Math.pow(2, attempt));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
throw new LiveAuthNetworkError(
|
|
309
|
+
`Request failed after ${retries + 1} attempts`,
|
|
310
|
+
lastError
|
|
311
|
+
);
|
|
312
|
+
}
|
|
202
313
|
};
|
|
203
314
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
204
315
|
// Annotate the CommonJS export names for ESM import in node:
|
|
205
316
|
0 && (module.exports = {
|
|
206
|
-
LiveAuth
|
|
317
|
+
LiveAuth,
|
|
318
|
+
LiveAuthCancelledError,
|
|
319
|
+
LiveAuthNetworkError,
|
|
320
|
+
LiveAuthPowTimeoutError,
|
|
321
|
+
LiveAuthPowUnsupportedError,
|
|
322
|
+
LiveAuthTimeoutError
|
|
207
323
|
});
|
|
208
324
|
//# sourceMappingURL=index.cjs.map
|