@liveauth-labs/sdk 0.1.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 +0 -0
- package/README.md +103 -0
- package/dist/index.cjs +208 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +47 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +180 -0
- package/dist/index.js.map +1 -0
- package/dist/pow.worker.cjs +24 -0
- package/dist/pow.worker.cjs.map +1 -0
- package/dist/pow.worker.d.cts +2 -0
- package/dist/pow.worker.d.ts +2 -0
- package/dist/pow.worker.js +22 -0
- package/dist/pow.worker.js.map +1 -0
- package/package.json +29 -0
package/LICENSE
ADDED
|
File without changes
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# LiveAuth – Developer Portal Documentation
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
LiveAuth verifies humans economically instead of heuristically.
|
|
6
|
+
|
|
7
|
+
Instead of CAPTCHAs or tracking, LiveAuth asks the browser to perform a short
|
|
8
|
+
cryptographic proof. If that fails or is skipped, it falls back to a small
|
|
9
|
+
Bitcoin Lightning payment.
|
|
10
|
+
|
|
11
|
+
No cookies.
|
|
12
|
+
No fingerprinting.
|
|
13
|
+
No behavioral profiling.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What LiveAuth Does
|
|
18
|
+
|
|
19
|
+
When a user clicks “Verify”:
|
|
20
|
+
|
|
21
|
+
1. **Browser attempts Proof-of-Work (PoW)**
|
|
22
|
+
– Takes ~200–800ms for a real device
|
|
23
|
+
– Bots pay CPU / battery cost
|
|
24
|
+
|
|
25
|
+
2. **If PoW fails → Lightning fallback**
|
|
26
|
+
– Small payment (e.g. 21 sats)
|
|
27
|
+
– Real economic cost to bots
|
|
28
|
+
|
|
29
|
+
3. **LiveAuth returns a short-lived JWT**
|
|
30
|
+
– Verifiable on your backend
|
|
31
|
+
– No user identity required
|
|
32
|
+
|
|
33
|
+
Most humans never see the Lightning step.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Installation (JavaScript)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @liveauth/sdk
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Basic Usage
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { LiveAuth } from '@liveauth/sdk';
|
|
49
|
+
|
|
50
|
+
const liveauth = new LiveAuth({
|
|
51
|
+
publicKey: 'la_pk_XXXXXXXX'
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const result = await liveauth.verify();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Example Result
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
{
|
|
63
|
+
token: "eyJhbGciOi...",
|
|
64
|
+
method: "pow",
|
|
65
|
+
solveMs: 412,
|
|
66
|
+
difficultyBits: 18
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Verifying on Your Backend
|
|
73
|
+
|
|
74
|
+
Send the JWT to your backend and verify it using your LiveAuth secret key.
|
|
75
|
+
|
|
76
|
+
The token includes:
|
|
77
|
+
|
|
78
|
+
- projectId
|
|
79
|
+
- projectPublicKey
|
|
80
|
+
- authType (pow or lightning)
|
|
81
|
+
- short expiration (default: 10 minutes)
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Why LiveAuth
|
|
86
|
+
|
|
87
|
+
| CAPTCHA | LiveAuth |
|
|
88
|
+
|-------|----------|
|
|
89
|
+
| Tracks behavior | No tracking |
|
|
90
|
+
| ML heuristics | Cryptography |
|
|
91
|
+
| CAPTCHA farms | Real economic cost |
|
|
92
|
+
| Bad UX | Invisible to humans |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Debug Mode
|
|
97
|
+
|
|
98
|
+
Add `?liveauth_debug=1` to your URL to see:
|
|
99
|
+
|
|
100
|
+
- Verification method
|
|
101
|
+
- PoW difficulty
|
|
102
|
+
- Solve time
|
|
103
|
+
- Lightning fallback (demo mode)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
LiveAuth: () => LiveAuth
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(src_exports);
|
|
26
|
+
|
|
27
|
+
// src/errors.ts
|
|
28
|
+
var LiveAuthTimeoutError = class extends Error {
|
|
29
|
+
constructor(message = "Lightning verification timed out") {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "LiveAuthTimeoutError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var LiveAuthCancelledError = class extends Error {
|
|
35
|
+
constructor(message = "Lightning verification cancelled") {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "LiveAuthCancelledError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/index.ts
|
|
42
|
+
var import_meta = {};
|
|
43
|
+
var LiveAuth = class {
|
|
44
|
+
constructor(config) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
if (!config.publicKey) {
|
|
47
|
+
throw new Error("LiveAuth: publicKey is required");
|
|
48
|
+
}
|
|
49
|
+
this.baseUrl = config.baseUrl ?? "https://api.liveauth.app";
|
|
50
|
+
this.headers = {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
"X-LW-Public": config.publicKey
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/* ======================================================
|
|
56
|
+
* PUBLIC ENTRYPOINT
|
|
57
|
+
* ====================================================== */
|
|
58
|
+
async verify() {
|
|
59
|
+
const startedAt = performance.now();
|
|
60
|
+
const challenge = await this.getPowChallenge();
|
|
61
|
+
const solution = await this.solvePow(challenge);
|
|
62
|
+
const verifyRes = await this.verifyPow({
|
|
63
|
+
challengeHex: challenge.challengeHex,
|
|
64
|
+
nonce: solution.nonce,
|
|
65
|
+
hashHex: solution.hashHex,
|
|
66
|
+
expiresAtUnix: challenge.expiresAtUnix,
|
|
67
|
+
sig: challenge.sig
|
|
68
|
+
});
|
|
69
|
+
if (verifyRes.verified && verifyRes.token) {
|
|
70
|
+
return {
|
|
71
|
+
method: "pow",
|
|
72
|
+
token: verifyRes.token,
|
|
73
|
+
solveMs: Math.round(performance.now() - startedAt),
|
|
74
|
+
difficultyBits: challenge.difficultyBits
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (verifyRes.fallback === "lightning") {
|
|
78
|
+
const lightning = await this.startLightning();
|
|
79
|
+
return {
|
|
80
|
+
method: "lightning",
|
|
81
|
+
lightning
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
throw new Error("LiveAuth: verification failed");
|
|
85
|
+
}
|
|
86
|
+
/* ======================================================
|
|
87
|
+
* POW FLOW
|
|
88
|
+
* ====================================================== */
|
|
89
|
+
async getPowChallenge() {
|
|
90
|
+
const res = await fetch(`${this.baseUrl}/api/public/pow/challenge`, {
|
|
91
|
+
headers: this.headers
|
|
92
|
+
});
|
|
93
|
+
if (!res.ok) throw new Error("PoW challenge failed");
|
|
94
|
+
return res.json();
|
|
95
|
+
}
|
|
96
|
+
async verifyPow(req) {
|
|
97
|
+
const res = await fetch(`${this.baseUrl}/api/public/pow/verify`, {
|
|
98
|
+
method: "POST",
|
|
99
|
+
headers: this.headers,
|
|
100
|
+
body: JSON.stringify(req)
|
|
101
|
+
});
|
|
102
|
+
if (!res.ok) throw new Error("PoW verify failed");
|
|
103
|
+
return res.json();
|
|
104
|
+
}
|
|
105
|
+
/* ======================================================
|
|
106
|
+
* POW SOLVER (WORKER)
|
|
107
|
+
* ====================================================== */
|
|
108
|
+
solvePow(challenge) {
|
|
109
|
+
if (!this.canUsePow()) {
|
|
110
|
+
return Promise.reject(
|
|
111
|
+
new Error("LiveAuth: PoW not supported in this environment")
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const worker = new Worker(
|
|
116
|
+
new URL("./pow.worker.js", import_meta.url),
|
|
117
|
+
{ type: "module" }
|
|
118
|
+
);
|
|
119
|
+
worker.onmessage = (e) => {
|
|
120
|
+
worker.terminate();
|
|
121
|
+
resolve(e.data);
|
|
122
|
+
};
|
|
123
|
+
worker.onerror = (e) => {
|
|
124
|
+
worker.terminate();
|
|
125
|
+
reject(e);
|
|
126
|
+
};
|
|
127
|
+
worker.postMessage({
|
|
128
|
+
projectPublicKey: challenge.projectPublicKey,
|
|
129
|
+
challengeHex: challenge.challengeHex,
|
|
130
|
+
targetHex: challenge.targetHex
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/* ======================================================
|
|
135
|
+
* LIGHTNING FALLBACK
|
|
136
|
+
* ====================================================== */
|
|
137
|
+
async startLightning() {
|
|
138
|
+
const res = await fetch(`${this.baseUrl}/api/public/auth/start`, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: this.headers,
|
|
141
|
+
body: JSON.stringify({ userHint: "browser" })
|
|
142
|
+
});
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
throw new Error("Lightning auth start failed");
|
|
145
|
+
}
|
|
146
|
+
return res.json();
|
|
147
|
+
}
|
|
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
|
+
async pollLightning(sessionId, options) {
|
|
159
|
+
const timeoutMs = options?.timeoutMs ?? 5 * 6e4;
|
|
160
|
+
const intervalMs = options?.intervalMs ?? 2e3;
|
|
161
|
+
const externalSignal = options?.signal;
|
|
162
|
+
const controller = new AbortController();
|
|
163
|
+
const signal = controller.signal;
|
|
164
|
+
if (externalSignal) {
|
|
165
|
+
if (externalSignal.aborted) {
|
|
166
|
+
throw new LiveAuthCancelledError();
|
|
167
|
+
}
|
|
168
|
+
externalSignal.addEventListener("abort", () => {
|
|
169
|
+
controller.abort();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const timeoutId = setTimeout(() => {
|
|
173
|
+
controller.abort();
|
|
174
|
+
}, timeoutMs);
|
|
175
|
+
try {
|
|
176
|
+
while (true) {
|
|
177
|
+
if (signal.aborted) {
|
|
178
|
+
throw externalSignal?.aborted ? new LiveAuthCancelledError() : new LiveAuthTimeoutError();
|
|
179
|
+
}
|
|
180
|
+
const res = await fetch(
|
|
181
|
+
`${this.baseUrl}/api/public/auth/confirm`,
|
|
182
|
+
{
|
|
183
|
+
method: "POST",
|
|
184
|
+
headers: this.headers,
|
|
185
|
+
body: JSON.stringify({ sessionId }),
|
|
186
|
+
signal
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
if (!res.ok) {
|
|
190
|
+
throw new Error("Lightning confirm failed");
|
|
191
|
+
}
|
|
192
|
+
const json = await res.json();
|
|
193
|
+
if (json.verified && json.token) {
|
|
194
|
+
return json.token;
|
|
195
|
+
}
|
|
196
|
+
await sleep(intervalMs);
|
|
197
|
+
}
|
|
198
|
+
} finally {
|
|
199
|
+
clearTimeout(timeoutId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
204
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
205
|
+
0 && (module.exports = {
|
|
206
|
+
LiveAuth
|
|
207
|
+
});
|
|
208
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts"],"sourcesContent":["import type {\n LiveAuthResult,\n VerifyOptions,\n PowChallengeResponse,\n PowVerifyRequest,\n PowVerifyResponse,\n PowSolution,\n AuthStartResponse,\n AuthConfirmResponse,\n LiveAuthConfig, LightningStart\n} from './types';\nimport {LiveAuthCancelledError, LiveAuthTimeoutError} from \"./errors\";\n\nexport class LiveAuth {\n private readonly baseUrl: string;\n private readonly headers: HeadersInit;\n\n constructor(private readonly config: LiveAuthConfig) {\n if (!config.publicKey) {\n throw new Error('LiveAuth: publicKey is required');\n }\n\n this.baseUrl = config.baseUrl ?? 'https://api.liveauth.app';\n\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-LW-Public': config.publicKey\n };\n }\n\n /* ======================================================\n * PUBLIC ENTRYPOINT\n * ====================================================== */\n\n async verify(): Promise<LiveAuthResult> {\n const startedAt = performance.now();\n\n const challenge = await this.getPowChallenge();\n const solution = await this.solvePow(challenge);\n\n const verifyRes = await this.verifyPow({\n challengeHex: challenge.challengeHex,\n nonce: solution.nonce,\n hashHex: solution.hashHex,\n expiresAtUnix: challenge.expiresAtUnix,\n sig: challenge.sig\n });\n\n if (verifyRes.verified && verifyRes.token) {\n return {\n method: 'pow',\n token: verifyRes.token,\n solveMs: Math.round(performance.now() - startedAt),\n difficultyBits: challenge.difficultyBits\n };\n }\n\n if (verifyRes.fallback === 'lightning') {\n const lightning = await this.startLightning();\n return {\n method: 'lightning',\n lightning\n };\n }\n\n throw new Error('LiveAuth: verification failed');\n }\n\n /* ======================================================\n * POW FLOW\n * ====================================================== */\n\n private async getPowChallenge(): Promise<PowChallengeResponse> {\n const res = await fetch(`${this.baseUrl}/api/public/pow/challenge`, {\n headers: this.headers\n });\n\n if (!res.ok) throw new Error('PoW challenge failed');\n return res.json();\n }\n\n private async verifyPow(req: PowVerifyRequest): Promise<PowVerifyResponse> {\n const res = await fetch(`${this.baseUrl}/api/public/pow/verify`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify(req)\n });\n\n if (!res.ok) throw new Error('PoW verify failed');\n return res.json();\n }\n\n /* ======================================================\n * POW SOLVER (WORKER)\n * ====================================================== */\n\n private solvePow(challenge: PowChallengeResponse): Promise<PowSolution> {\n if (!this.canUsePow()) {\n return Promise.reject(\n new Error('LiveAuth: PoW not supported in this environment')\n );\n }\n\n return new Promise((resolve, reject) => {\n const worker = new Worker(\n new URL('./pow.worker.js', import.meta.url),\n {type: 'module'}\n );\n\n worker.onmessage = e => {\n worker.terminate();\n resolve(e.data);\n };\n\n worker.onerror = e => {\n worker.terminate();\n reject(e);\n };\n\n worker.postMessage({\n projectPublicKey: challenge.projectPublicKey,\n challengeHex: challenge.challengeHex,\n targetHex: challenge.targetHex\n });\n });\n }\n\n /* ======================================================\n * LIGHTNING FALLBACK\n * ====================================================== */\n\n private async startLightning(): Promise<LightningStart> {\n const res = await fetch(`${this.baseUrl}/api/public/auth/start`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({userHint: 'browser'})\n });\n\n if (!res.ok) {\n throw new Error('Lightning auth start failed');\n }\n\n return res.json();\n }\n\n private canUsePow(): boolean {\n try {\n // SSR / Node guard\n if (typeof window === 'undefined') return false;\n\n // Worker support\n if (typeof Worker === 'undefined') return false;\n\n // Basic URL support (needed for module workers)\n if (typeof URL === 'undefined') return false;\n\n return true;\n } catch {\n return false;\n }\n }\n\n async pollLightning(\n sessionId: string,\n options?: {\n timeoutMs?: number;\n signal?: AbortSignal;\n intervalMs?: number;\n }\n ): Promise<string> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60_000; // 5 min\n const intervalMs = options?.intervalMs ?? 2000;\n const externalSignal = options?.signal;\n\n const controller = new AbortController();\n const signal = controller.signal;\n\n // If caller passes a signal, bridge it\n if (externalSignal) {\n if (externalSignal.aborted) {\n throw new LiveAuthCancelledError();\n }\n\n externalSignal.addEventListener('abort', () => {\n controller.abort();\n });\n }\n\n // Timeout enforcement\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeoutMs);\n\n try {\n while (true) {\n if (signal.aborted) {\n throw externalSignal?.aborted\n ? new LiveAuthCancelledError()\n : new LiveAuthTimeoutError();\n }\n\n const res = await fetch(\n `${this.baseUrl}/api/public/auth/confirm`,\n {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({sessionId}),\n signal\n }\n );\n\n if (!res.ok) {\n throw new Error('Lightning confirm failed');\n }\n\n const json = await res.json();\n\n if (json.verified && json.token) {\n return json.token;\n }\n\n await sleep(intervalMs);\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n\n}\n\n/* ======================================================\n * UTILS\n * ====================================================== */\n\nconst sleep = (ms: number) =>\n new Promise(resolve => setTimeout(resolve, ms));\n","export class LiveAuthTimeoutError extends Error {\n constructor(message = 'Lightning verification timed out') {\n super(message);\n this.name = 'LiveAuthTimeoutError';\n }\n}\n\nexport class LiveAuthCancelledError extends Error {\n constructor(message = 'Lightning verification cancelled') {\n super(message);\n this.name = 'LiveAuthCancelledError';\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
interface LiveAuthConfig {
|
|
2
|
+
/** Public project key (browser-safe) */
|
|
3
|
+
publicKey: string;
|
|
4
|
+
/** Optional API base URL (defaults to liveauth.app) */
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
interface LiveAuthDiagnostics {
|
|
8
|
+
reason?: 'forced_lightning' | 'pow_unsupported' | 'pow_failed' | 'pow_server_fallback' | 'unknown';
|
|
9
|
+
detail?: string;
|
|
10
|
+
}
|
|
11
|
+
interface LightningStart {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
invoice: string | null;
|
|
14
|
+
amountSats: number;
|
|
15
|
+
expiresAtUnix: number;
|
|
16
|
+
mode: 'TEST' | 'LIVE';
|
|
17
|
+
}
|
|
18
|
+
type LiveAuthResult = {
|
|
19
|
+
method: 'pow';
|
|
20
|
+
token: string;
|
|
21
|
+
solveMs: number;
|
|
22
|
+
difficultyBits: number;
|
|
23
|
+
diagnostics?: LiveAuthDiagnostics;
|
|
24
|
+
} | {
|
|
25
|
+
method: 'lightning';
|
|
26
|
+
lightning: LightningStart;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
declare class LiveAuth {
|
|
30
|
+
private readonly config;
|
|
31
|
+
private readonly baseUrl;
|
|
32
|
+
private readonly headers;
|
|
33
|
+
constructor(config: LiveAuthConfig);
|
|
34
|
+
verify(): Promise<LiveAuthResult>;
|
|
35
|
+
private getPowChallenge;
|
|
36
|
+
private verifyPow;
|
|
37
|
+
private solvePow;
|
|
38
|
+
private startLightning;
|
|
39
|
+
private canUsePow;
|
|
40
|
+
pollLightning(sessionId: string, options?: {
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
intervalMs?: number;
|
|
44
|
+
}): Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { LiveAuth };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
interface LiveAuthConfig {
|
|
2
|
+
/** Public project key (browser-safe) */
|
|
3
|
+
publicKey: string;
|
|
4
|
+
/** Optional API base URL (defaults to liveauth.app) */
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
interface LiveAuthDiagnostics {
|
|
8
|
+
reason?: 'forced_lightning' | 'pow_unsupported' | 'pow_failed' | 'pow_server_fallback' | 'unknown';
|
|
9
|
+
detail?: string;
|
|
10
|
+
}
|
|
11
|
+
interface LightningStart {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
invoice: string | null;
|
|
14
|
+
amountSats: number;
|
|
15
|
+
expiresAtUnix: number;
|
|
16
|
+
mode: 'TEST' | 'LIVE';
|
|
17
|
+
}
|
|
18
|
+
type LiveAuthResult = {
|
|
19
|
+
method: 'pow';
|
|
20
|
+
token: string;
|
|
21
|
+
solveMs: number;
|
|
22
|
+
difficultyBits: number;
|
|
23
|
+
diagnostics?: LiveAuthDiagnostics;
|
|
24
|
+
} | {
|
|
25
|
+
method: 'lightning';
|
|
26
|
+
lightning: LightningStart;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
declare class LiveAuth {
|
|
30
|
+
private readonly config;
|
|
31
|
+
private readonly baseUrl;
|
|
32
|
+
private readonly headers;
|
|
33
|
+
constructor(config: LiveAuthConfig);
|
|
34
|
+
verify(): Promise<LiveAuthResult>;
|
|
35
|
+
private getPowChallenge;
|
|
36
|
+
private verifyPow;
|
|
37
|
+
private solvePow;
|
|
38
|
+
private startLightning;
|
|
39
|
+
private canUsePow;
|
|
40
|
+
pollLightning(sessionId: string, options?: {
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
intervalMs?: number;
|
|
44
|
+
}): Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { LiveAuth };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var LiveAuthTimeoutError = class extends Error {
|
|
3
|
+
constructor(message = "Lightning verification timed out") {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "LiveAuthTimeoutError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var LiveAuthCancelledError = class extends Error {
|
|
9
|
+
constructor(message = "Lightning verification cancelled") {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "LiveAuthCancelledError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/index.ts
|
|
16
|
+
var LiveAuth = class {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
if (!config.publicKey) {
|
|
20
|
+
throw new Error("LiveAuth: publicKey is required");
|
|
21
|
+
}
|
|
22
|
+
this.baseUrl = config.baseUrl ?? "https://api.liveauth.app";
|
|
23
|
+
this.headers = {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"X-LW-Public": config.publicKey
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/* ======================================================
|
|
29
|
+
* PUBLIC ENTRYPOINT
|
|
30
|
+
* ====================================================== */
|
|
31
|
+
async verify() {
|
|
32
|
+
const startedAt = performance.now();
|
|
33
|
+
const challenge = await this.getPowChallenge();
|
|
34
|
+
const solution = await this.solvePow(challenge);
|
|
35
|
+
const verifyRes = await this.verifyPow({
|
|
36
|
+
challengeHex: challenge.challengeHex,
|
|
37
|
+
nonce: solution.nonce,
|
|
38
|
+
hashHex: solution.hashHex,
|
|
39
|
+
expiresAtUnix: challenge.expiresAtUnix,
|
|
40
|
+
sig: challenge.sig
|
|
41
|
+
});
|
|
42
|
+
if (verifyRes.verified && verifyRes.token) {
|
|
43
|
+
return {
|
|
44
|
+
method: "pow",
|
|
45
|
+
token: verifyRes.token,
|
|
46
|
+
solveMs: Math.round(performance.now() - startedAt),
|
|
47
|
+
difficultyBits: challenge.difficultyBits
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (verifyRes.fallback === "lightning") {
|
|
51
|
+
const lightning = await this.startLightning();
|
|
52
|
+
return {
|
|
53
|
+
method: "lightning",
|
|
54
|
+
lightning
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
throw new Error("LiveAuth: verification failed");
|
|
58
|
+
}
|
|
59
|
+
/* ======================================================
|
|
60
|
+
* POW FLOW
|
|
61
|
+
* ====================================================== */
|
|
62
|
+
async getPowChallenge() {
|
|
63
|
+
const res = await fetch(`${this.baseUrl}/api/public/pow/challenge`, {
|
|
64
|
+
headers: this.headers
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) throw new Error("PoW challenge failed");
|
|
67
|
+
return res.json();
|
|
68
|
+
}
|
|
69
|
+
async verifyPow(req) {
|
|
70
|
+
const res = await fetch(`${this.baseUrl}/api/public/pow/verify`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: this.headers,
|
|
73
|
+
body: JSON.stringify(req)
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) throw new Error("PoW verify failed");
|
|
76
|
+
return res.json();
|
|
77
|
+
}
|
|
78
|
+
/* ======================================================
|
|
79
|
+
* POW SOLVER (WORKER)
|
|
80
|
+
* ====================================================== */
|
|
81
|
+
solvePow(challenge) {
|
|
82
|
+
if (!this.canUsePow()) {
|
|
83
|
+
return Promise.reject(
|
|
84
|
+
new Error("LiveAuth: PoW not supported in this environment")
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const worker = new Worker(
|
|
89
|
+
new URL("./pow.worker.js", import.meta.url),
|
|
90
|
+
{ type: "module" }
|
|
91
|
+
);
|
|
92
|
+
worker.onmessage = (e) => {
|
|
93
|
+
worker.terminate();
|
|
94
|
+
resolve(e.data);
|
|
95
|
+
};
|
|
96
|
+
worker.onerror = (e) => {
|
|
97
|
+
worker.terminate();
|
|
98
|
+
reject(e);
|
|
99
|
+
};
|
|
100
|
+
worker.postMessage({
|
|
101
|
+
projectPublicKey: challenge.projectPublicKey,
|
|
102
|
+
challengeHex: challenge.challengeHex,
|
|
103
|
+
targetHex: challenge.targetHex
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/* ======================================================
|
|
108
|
+
* LIGHTNING FALLBACK
|
|
109
|
+
* ====================================================== */
|
|
110
|
+
async startLightning() {
|
|
111
|
+
const res = await fetch(`${this.baseUrl}/api/public/auth/start`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: this.headers,
|
|
114
|
+
body: JSON.stringify({ userHint: "browser" })
|
|
115
|
+
});
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
throw new Error("Lightning auth start failed");
|
|
118
|
+
}
|
|
119
|
+
return res.json();
|
|
120
|
+
}
|
|
121
|
+
canUsePow() {
|
|
122
|
+
try {
|
|
123
|
+
if (typeof window === "undefined") return false;
|
|
124
|
+
if (typeof Worker === "undefined") return false;
|
|
125
|
+
if (typeof URL === "undefined") return false;
|
|
126
|
+
return true;
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async pollLightning(sessionId, options) {
|
|
132
|
+
const timeoutMs = options?.timeoutMs ?? 5 * 6e4;
|
|
133
|
+
const intervalMs = options?.intervalMs ?? 2e3;
|
|
134
|
+
const externalSignal = options?.signal;
|
|
135
|
+
const controller = new AbortController();
|
|
136
|
+
const signal = controller.signal;
|
|
137
|
+
if (externalSignal) {
|
|
138
|
+
if (externalSignal.aborted) {
|
|
139
|
+
throw new LiveAuthCancelledError();
|
|
140
|
+
}
|
|
141
|
+
externalSignal.addEventListener("abort", () => {
|
|
142
|
+
controller.abort();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const timeoutId = setTimeout(() => {
|
|
146
|
+
controller.abort();
|
|
147
|
+
}, timeoutMs);
|
|
148
|
+
try {
|
|
149
|
+
while (true) {
|
|
150
|
+
if (signal.aborted) {
|
|
151
|
+
throw externalSignal?.aborted ? new LiveAuthCancelledError() : new LiveAuthTimeoutError();
|
|
152
|
+
}
|
|
153
|
+
const res = await fetch(
|
|
154
|
+
`${this.baseUrl}/api/public/auth/confirm`,
|
|
155
|
+
{
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: this.headers,
|
|
158
|
+
body: JSON.stringify({ sessionId }),
|
|
159
|
+
signal
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
if (!res.ok) {
|
|
163
|
+
throw new Error("Lightning confirm failed");
|
|
164
|
+
}
|
|
165
|
+
const json = await res.json();
|
|
166
|
+
if (json.verified && json.token) {
|
|
167
|
+
return json.token;
|
|
168
|
+
}
|
|
169
|
+
await sleep(intervalMs);
|
|
170
|
+
}
|
|
171
|
+
} finally {
|
|
172
|
+
clearTimeout(timeoutId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
177
|
+
export {
|
|
178
|
+
LiveAuth
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/index.ts"],"sourcesContent":["export class LiveAuthTimeoutError extends Error {\n constructor(message = 'Lightning verification timed out') {\n super(message);\n this.name = 'LiveAuthTimeoutError';\n }\n}\n\nexport class LiveAuthCancelledError extends Error {\n constructor(message = 'Lightning verification cancelled') {\n super(message);\n this.name = 'LiveAuthCancelledError';\n }\n}\n","import type {\n LiveAuthResult,\n VerifyOptions,\n PowChallengeResponse,\n PowVerifyRequest,\n PowVerifyResponse,\n PowSolution,\n AuthStartResponse,\n AuthConfirmResponse,\n LiveAuthConfig, LightningStart\n} from './types';\nimport {LiveAuthCancelledError, LiveAuthTimeoutError} from \"./errors\";\n\nexport class LiveAuth {\n private readonly baseUrl: string;\n private readonly headers: HeadersInit;\n\n constructor(private readonly config: LiveAuthConfig) {\n if (!config.publicKey) {\n throw new Error('LiveAuth: publicKey is required');\n }\n\n this.baseUrl = config.baseUrl ?? 'https://api.liveauth.app';\n\n this.headers = {\n 'Content-Type': 'application/json',\n 'X-LW-Public': config.publicKey\n };\n }\n\n /* ======================================================\n * PUBLIC ENTRYPOINT\n * ====================================================== */\n\n async verify(): Promise<LiveAuthResult> {\n const startedAt = performance.now();\n\n const challenge = await this.getPowChallenge();\n const solution = await this.solvePow(challenge);\n\n const verifyRes = await this.verifyPow({\n challengeHex: challenge.challengeHex,\n nonce: solution.nonce,\n hashHex: solution.hashHex,\n expiresAtUnix: challenge.expiresAtUnix,\n sig: challenge.sig\n });\n\n if (verifyRes.verified && verifyRes.token) {\n return {\n method: 'pow',\n token: verifyRes.token,\n solveMs: Math.round(performance.now() - startedAt),\n difficultyBits: challenge.difficultyBits\n };\n }\n\n if (verifyRes.fallback === 'lightning') {\n const lightning = await this.startLightning();\n return {\n method: 'lightning',\n lightning\n };\n }\n\n throw new Error('LiveAuth: verification failed');\n }\n\n /* ======================================================\n * POW FLOW\n * ====================================================== */\n\n private async getPowChallenge(): Promise<PowChallengeResponse> {\n const res = await fetch(`${this.baseUrl}/api/public/pow/challenge`, {\n headers: this.headers\n });\n\n if (!res.ok) throw new Error('PoW challenge failed');\n return res.json();\n }\n\n private async verifyPow(req: PowVerifyRequest): Promise<PowVerifyResponse> {\n const res = await fetch(`${this.baseUrl}/api/public/pow/verify`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify(req)\n });\n\n if (!res.ok) throw new Error('PoW verify failed');\n return res.json();\n }\n\n /* ======================================================\n * POW SOLVER (WORKER)\n * ====================================================== */\n\n private solvePow(challenge: PowChallengeResponse): Promise<PowSolution> {\n if (!this.canUsePow()) {\n return Promise.reject(\n new Error('LiveAuth: PoW not supported in this environment')\n );\n }\n\n return new Promise((resolve, reject) => {\n const worker = new Worker(\n new URL('./pow.worker.js', import.meta.url),\n {type: 'module'}\n );\n\n worker.onmessage = e => {\n worker.terminate();\n resolve(e.data);\n };\n\n worker.onerror = e => {\n worker.terminate();\n reject(e);\n };\n\n worker.postMessage({\n projectPublicKey: challenge.projectPublicKey,\n challengeHex: challenge.challengeHex,\n targetHex: challenge.targetHex\n });\n });\n }\n\n /* ======================================================\n * LIGHTNING FALLBACK\n * ====================================================== */\n\n private async startLightning(): Promise<LightningStart> {\n const res = await fetch(`${this.baseUrl}/api/public/auth/start`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({userHint: 'browser'})\n });\n\n if (!res.ok) {\n throw new Error('Lightning auth start failed');\n }\n\n return res.json();\n }\n\n private canUsePow(): boolean {\n try {\n // SSR / Node guard\n if (typeof window === 'undefined') return false;\n\n // Worker support\n if (typeof Worker === 'undefined') return false;\n\n // Basic URL support (needed for module workers)\n if (typeof URL === 'undefined') return false;\n\n return true;\n } catch {\n return false;\n }\n }\n\n async pollLightning(\n sessionId: string,\n options?: {\n timeoutMs?: number;\n signal?: AbortSignal;\n intervalMs?: number;\n }\n ): Promise<string> {\n const timeoutMs = options?.timeoutMs ?? 5 * 60_000; // 5 min\n const intervalMs = options?.intervalMs ?? 2000;\n const externalSignal = options?.signal;\n\n const controller = new AbortController();\n const signal = controller.signal;\n\n // If caller passes a signal, bridge it\n if (externalSignal) {\n if (externalSignal.aborted) {\n throw new LiveAuthCancelledError();\n }\n\n externalSignal.addEventListener('abort', () => {\n controller.abort();\n });\n }\n\n // Timeout enforcement\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeoutMs);\n\n try {\n while (true) {\n if (signal.aborted) {\n throw externalSignal?.aborted\n ? new LiveAuthCancelledError()\n : new LiveAuthTimeoutError();\n }\n\n const res = await fetch(\n `${this.baseUrl}/api/public/auth/confirm`,\n {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({sessionId}),\n signal\n }\n );\n\n if (!res.ok) {\n throw new Error('Lightning confirm failed');\n }\n\n const json = await res.json();\n\n if (json.verified && json.token) {\n return json.token;\n }\n\n await sleep(intervalMs);\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n\n}\n\n/* ======================================================\n * UTILS\n * ====================================================== */\n\nconst sleep = (ms: number) =>\n new Promise(resolve => setTimeout(resolve, ms));\n"],"mappings":";AAAO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC5C,YAAY,UAAU,oCAAoC;AACtD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;AAEO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAC9C,YAAY,UAAU,oCAAoC;AACtD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;;;ACCO,IAAM,WAAN,MAAe;AAAA,EAIlB,YAA6B,QAAwB;AAAxB;AACzB,QAAI,CAAC,OAAO,WAAW;AACnB,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACrD;AAEA,SAAK,UAAU,OAAO,WAAW;AAEjC,SAAK,UAAU;AAAA,MACX,gBAAgB;AAAA,MAChB,eAAe,OAAO;AAAA,IAC1B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAkC;AACpC,UAAM,YAAY,YAAY,IAAI;AAElC,UAAM,YAAY,MAAM,KAAK,gBAAgB;AAC7C,UAAM,WAAW,MAAM,KAAK,SAAS,SAAS;AAE9C,UAAM,YAAY,MAAM,KAAK,UAAU;AAAA,MACnC,cAAc,UAAU;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,SAAS,SAAS;AAAA,MAClB,eAAe,UAAU;AAAA,MACzB,KAAK,UAAU;AAAA,IACnB,CAAC;AAED,QAAI,UAAU,YAAY,UAAU,OAAO;AACvC,aAAO;AAAA,QACH,QAAQ;AAAA,QACR,OAAO,UAAU;AAAA,QACjB,SAAS,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;AAAA,QACjD,gBAAgB,UAAU;AAAA,MAC9B;AAAA,IACJ;AAEA,QAAI,UAAU,aAAa,aAAa;AACpC,YAAM,YAAY,MAAM,KAAK,eAAe;AAC5C,aAAO;AAAA,QACH,QAAQ;AAAA,QACR;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAiD;AAC3D,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,6BAA6B;AAAA,MAChE,SAAS,KAAK;AAAA,IAClB,CAAC;AAED,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,sBAAsB;AACnD,WAAO,IAAI,KAAK;AAAA,EACpB;AAAA,EAEA,MAAc,UAAU,KAAmD;AACvE,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,0BAA0B;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,MACd,MAAM,KAAK,UAAU,GAAG;AAAA,IAC5B,CAAC;AAED,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,mBAAmB;AAChD,WAAO,IAAI,KAAK;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS,WAAuD;AACpE,QAAI,CAAC,KAAK,UAAU,GAAG;AACnB,aAAO,QAAQ;AAAA,QACX,IAAI,MAAM,iDAAiD;AAAA,MAC/D;AAAA,IACJ;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,YAAM,SAAS,IAAI;AAAA,QACf,IAAI,IAAI,mBAAmB,YAAY,GAAG;AAAA,QAC1C,EAAC,MAAM,SAAQ;AAAA,MACnB;AAEA,aAAO,YAAY,OAAK;AACpB,eAAO,UAAU;AACjB,gBAAQ,EAAE,IAAI;AAAA,MAClB;AAEA,aAAO,UAAU,OAAK;AAClB,eAAO,UAAU;AACjB,eAAO,CAAC;AAAA,MACZ;AAEA,aAAO,YAAY;AAAA,QACf,kBAAkB,UAAU;AAAA,QAC5B,cAAc,UAAU;AAAA,QACxB,WAAW,UAAU;AAAA,MACzB,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAA0C;AACpD,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,0BAA0B;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,MACd,MAAM,KAAK,UAAU,EAAC,UAAU,UAAS,CAAC;AAAA,IAC9C,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,IAAI,MAAM,6BAA6B;AAAA,IACjD;AAEA,WAAO,IAAI,KAAK;AAAA,EACpB;AAAA,EAEQ,YAAqB;AACzB,QAAI;AAEA,UAAI,OAAO,WAAW,YAAa,QAAO;AAG1C,UAAI,OAAO,WAAW,YAAa,QAAO;AAG1C,UAAI,OAAO,QAAQ,YAAa,QAAO;AAEvC,aAAO;AAAA,IACX,QAAQ;AACJ,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAEA,MAAM,cACF,WACA,SAKe;AACf,UAAM,YAAY,SAAS,aAAa,IAAI;AAC5C,UAAM,aAAa,SAAS,cAAc;AAC1C,UAAM,iBAAiB,SAAS;AAEhC,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,SAAS,WAAW;AAG1B,QAAI,gBAAgB;AAChB,UAAI,eAAe,SAAS;AACxB,cAAM,IAAI,uBAAuB;AAAA,MACrC;AAEA,qBAAe,iBAAiB,SAAS,MAAM;AAC3C,mBAAW,MAAM;AAAA,MACrB,CAAC;AAAA,IACL;AAGA,UAAM,YAAY,WAAW,MAAM;AAC/B,iBAAW,MAAM;AAAA,IACrB,GAAG,SAAS;AAEZ,QAAI;AACA,aAAO,MAAM;AACT,YAAI,OAAO,SAAS;AAChB,gBAAM,gBAAgB,UAChB,IAAI,uBAAuB,IAC3B,IAAI,qBAAqB;AAAA,QACnC;AAEA,cAAM,MAAM,MAAM;AAAA,UACd,GAAG,KAAK,OAAO;AAAA,UACf;AAAA,YACI,QAAQ;AAAA,YACR,SAAS,KAAK;AAAA,YACd,MAAM,KAAK,UAAU,EAAC,UAAS,CAAC;AAAA,YAChC;AAAA,UACJ;AAAA,QACJ;AAEA,YAAI,CAAC,IAAI,IAAI;AACT,gBAAM,IAAI,MAAM,0BAA0B;AAAA,QAC9C;AAEA,cAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,YAAI,KAAK,YAAY,KAAK,OAAO;AAC7B,iBAAO,KAAK;AAAA,QAChB;AAEA,cAAM,MAAM,UAAU;AAAA,MAC1B;AAAA,IACJ,UAAE;AACE,mBAAa,SAAS;AAAA,IAC1B;AAAA,EACJ;AAGJ;AAMA,IAAM,QAAQ,CAAC,OACX,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// src/pow.worker.ts
|
|
4
|
+
self.onmessage = async (e) => {
|
|
5
|
+
const { projectPublicKey, challengeHex, targetHex } = e.data;
|
|
6
|
+
let nonce = 0;
|
|
7
|
+
while (true) {
|
|
8
|
+
const input = `${projectPublicKey}:${challengeHex}:${nonce}`;
|
|
9
|
+
const hash = await sha256Hex(input);
|
|
10
|
+
if (hash <= targetHex) {
|
|
11
|
+
postMessage({ nonce, hashHex: hash });
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
nonce++;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
async function sha256Hex(input) {
|
|
18
|
+
const buf = await crypto.subtle.digest(
|
|
19
|
+
"SHA-256",
|
|
20
|
+
new TextEncoder().encode(input)
|
|
21
|
+
);
|
|
22
|
+
return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=pow.worker.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pow.worker.ts"],"sourcesContent":["self.onmessage = async e => {\n const { projectPublicKey, challengeHex, targetHex } = e.data;\n\n let nonce = 0;\n\n while (true) {\n const input = `${projectPublicKey}:${challengeHex}:${nonce}`;\n const hash = await sha256Hex(input);\n\n if (hash <= targetHex) {\n postMessage({ nonce, hashHex: hash });\n return;\n }\n\n nonce++;\n }\n};\n\nasync function sha256Hex(input: string): Promise<string> {\n const buf = await crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(input)\n );\n\n return [...new Uint8Array(buf)]\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n"],"mappings":";;;AAAA,KAAK,YAAY,OAAM,MAAK;AACxB,QAAM,EAAE,kBAAkB,cAAc,UAAU,IAAI,EAAE;AAExD,MAAI,QAAQ;AAEZ,SAAO,MAAM;AACT,UAAM,QAAQ,GAAG,gBAAgB,IAAI,YAAY,IAAI,KAAK;AAC1D,UAAM,OAAO,MAAM,UAAU,KAAK;AAElC,QAAI,QAAQ,WAAW;AACnB,kBAAY,EAAE,OAAO,SAAS,KAAK,CAAC;AACpC;AAAA,IACJ;AAEA;AAAA,EACJ;AACJ;AAEA,eAAe,UAAU,OAAgC;AACrD,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC5B;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,EAClC;AAEA,SAAO,CAAC,GAAG,IAAI,WAAW,GAAG,CAAC,EACzB,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACxC,KAAK,EAAE;AAChB;","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/pow.worker.ts
|
|
2
|
+
self.onmessage = async (e) => {
|
|
3
|
+
const { projectPublicKey, challengeHex, targetHex } = e.data;
|
|
4
|
+
let nonce = 0;
|
|
5
|
+
while (true) {
|
|
6
|
+
const input = `${projectPublicKey}:${challengeHex}:${nonce}`;
|
|
7
|
+
const hash = await sha256Hex(input);
|
|
8
|
+
if (hash <= targetHex) {
|
|
9
|
+
postMessage({ nonce, hashHex: hash });
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
nonce++;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
async function sha256Hex(input) {
|
|
16
|
+
const buf = await crypto.subtle.digest(
|
|
17
|
+
"SHA-256",
|
|
18
|
+
new TextEncoder().encode(input)
|
|
19
|
+
);
|
|
20
|
+
return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=pow.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pow.worker.ts"],"sourcesContent":["self.onmessage = async e => {\n const { projectPublicKey, challengeHex, targetHex } = e.data;\n\n let nonce = 0;\n\n while (true) {\n const input = `${projectPublicKey}:${challengeHex}:${nonce}`;\n const hash = await sha256Hex(input);\n\n if (hash <= targetHex) {\n postMessage({ nonce, hashHex: hash });\n return;\n }\n\n nonce++;\n }\n};\n\nasync function sha256Hex(input: string): Promise<string> {\n const buf = await crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(input)\n );\n\n return [...new Uint8Array(buf)]\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n"],"mappings":";AAAA,KAAK,YAAY,OAAM,MAAK;AACxB,QAAM,EAAE,kBAAkB,cAAc,UAAU,IAAI,EAAE;AAExD,MAAI,QAAQ;AAEZ,SAAO,MAAM;AACT,UAAM,QAAQ,GAAG,gBAAgB,IAAI,YAAY,IAAI,KAAK;AAC1D,UAAM,OAAO,MAAM,UAAU,KAAK;AAElC,QAAI,QAAQ,WAAW;AACnB,kBAAY,EAAE,OAAO,SAAS,KAAK,CAAC;AACpC;AAAA,IACJ;AAEA;AAAA,EACJ;AACJ;AAEA,eAAe,UAAU,OAAgC;AACrD,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC5B;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,EAClC;AAEA,SAAO,CAAC,GAAG,IAAI,WAAW,GAAG,CAAC,EACzB,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EACxC,KAAK,EAAE;AAChB;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@liveauth-labs/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"captcha",
|
|
23
|
+
"proof-of-work",
|
|
24
|
+
"lightning",
|
|
25
|
+
"bitcoin",
|
|
26
|
+
"bot-protection",
|
|
27
|
+
"auth"
|
|
28
|
+
]
|
|
29
|
+
}
|