rollhub-dice 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 +21 -0
- package/README.md +167 -0
- package/dist/cjs/client.d.ts +20 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +107 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/errors.d.ts +21 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +49 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +14 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types.d.ts +58 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/verify.d.ts +19 -0
- package/dist/cjs/verify.d.ts.map +1 -0
- package/dist/cjs/verify.js +25 -0
- package/dist/cjs/verify.js.map +1 -0
- package/dist/esm/client.d.ts +20 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +107 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/errors.d.ts +21 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +49 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/types.d.ts +58 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/verify.d.ts +19 -0
- package/dist/esm/verify.d.ts.map +1 -0
- package/dist/esm/verify.js +25 -0
- package/dist/esm/verify.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rollhub
|
|
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
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# rollhub-dice
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/rollhub-dice)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
JavaScript/TypeScript SDK for the **Rollhub Dice Agent API** — provably fair dice betting for AI agents.
|
|
7
|
+
|
|
8
|
+
> **Requires Node.js 18+** (uses native `fetch` and `crypto`).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install rollhub-dice
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { DiceAgent } from 'rollhub-dice';
|
|
20
|
+
|
|
21
|
+
const agent = new DiceAgent({ apiKey: 'rh_sk_...' });
|
|
22
|
+
|
|
23
|
+
const result = await agent.bet({
|
|
24
|
+
target: 0.5,
|
|
25
|
+
direction: 'over',
|
|
26
|
+
amount: 100, // cents
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log(result.roll, result.win, result.payout);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Register a New Agent
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { DiceAgent } from 'rollhub-dice';
|
|
36
|
+
|
|
37
|
+
const agent = await DiceAgent.register('your-solana-wallet-address');
|
|
38
|
+
// agent is ready to use — API key is configured automatically
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API Reference
|
|
42
|
+
|
|
43
|
+
### `new DiceAgent(options)`
|
|
44
|
+
|
|
45
|
+
| Option | Type | Required | Default |
|
|
46
|
+
| --------- | -------- | -------- | ---------------------------------- |
|
|
47
|
+
| `apiKey` | `string` | ✅ | |
|
|
48
|
+
| `baseUrl` | `string` | | `https://agent.rollhub.com/api/v1` |
|
|
49
|
+
|
|
50
|
+
### `DiceAgent.register(walletAddress, baseUrl?)`
|
|
51
|
+
|
|
52
|
+
Register a new agent. Returns a configured `DiceAgent` instance.
|
|
53
|
+
|
|
54
|
+
### `agent.balance()`
|
|
55
|
+
|
|
56
|
+
Returns current balance.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const bal = await agent.balance();
|
|
60
|
+
// { balance_usd: "10.00", balance_cents: 1000, currency: "USD" }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `agent.bet(options)`
|
|
64
|
+
|
|
65
|
+
Place a dice bet.
|
|
66
|
+
|
|
67
|
+
| Option | Type | Required | Default |
|
|
68
|
+
| ------------- | ---------------------- | -------- | ------------------- |
|
|
69
|
+
| `target` | `number` | ✅ | |
|
|
70
|
+
| `direction` | `'over'` \| `'under'` | ✅ | |
|
|
71
|
+
| `amount` | `number` (cents) | ✅ | |
|
|
72
|
+
| `clientSecret`| `string` | | `crypto.randomUUID()` |
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
{
|
|
78
|
+
bet_id: 1,
|
|
79
|
+
roll: 0.7234,
|
|
80
|
+
win: true,
|
|
81
|
+
payout: 198,
|
|
82
|
+
multiplier: 1.98,
|
|
83
|
+
balance: 1098,
|
|
84
|
+
proof: {
|
|
85
|
+
server_secret: "...",
|
|
86
|
+
client_secret: "...",
|
|
87
|
+
nonce: 1,
|
|
88
|
+
server_seed_hash: "..."
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `agent.bets()`
|
|
94
|
+
|
|
95
|
+
Get bet history.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const history = await agent.bets();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `agent.verify(betId)`
|
|
102
|
+
|
|
103
|
+
Verify a past bet server-side.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const result = await agent.verify(42);
|
|
107
|
+
// { bet_id: 42, verified: true, ... }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Provably Fair Verification
|
|
111
|
+
|
|
112
|
+
Every bet returns a `proof` object. You can verify rolls locally:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { verifyRoll } from 'rollhub-dice';
|
|
116
|
+
|
|
117
|
+
const { roll, hashValid } = verifyRoll({
|
|
118
|
+
serverSecret: proof.server_secret,
|
|
119
|
+
clientSecret: proof.client_secret,
|
|
120
|
+
nonce: proof.nonce,
|
|
121
|
+
serverSeedHash: proof.server_seed_hash,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
console.log(roll); // computed roll value
|
|
125
|
+
console.log(hashValid); // true if server_seed_hash matches
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**How it works:**
|
|
129
|
+
|
|
130
|
+
1. Before your bet, the server commits to a `server_seed_hash` (SHA-256 of the secret).
|
|
131
|
+
2. You provide a `client_secret` (auto-generated if omitted).
|
|
132
|
+
3. The roll is `HMAC-SHA256(server_secret, client_secret + ":" + nonce)` → first 8 hex chars → number in [0, 1).
|
|
133
|
+
4. After the bet, the server reveals the `server_secret` so you can verify.
|
|
134
|
+
|
|
135
|
+
## Error Handling
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { DiceAgent, RollhubError, AuthenticationError, RateLimitError } from 'rollhub-dice';
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
await agent.bet({ target: 0.5, direction: 'over', amount: 100 });
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (err instanceof AuthenticationError) {
|
|
144
|
+
console.error('Bad API key');
|
|
145
|
+
} else if (err instanceof RateLimitError) {
|
|
146
|
+
console.error(`Rate limited, retry in ${err.retryAfter}s`);
|
|
147
|
+
} else if (err instanceof RollhubError) {
|
|
148
|
+
console.error(`API error ${err.status}: ${err.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## TypeScript
|
|
154
|
+
|
|
155
|
+
Full TypeScript support with exported types:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import type { BetOptions, BetResult, Balance, VerifyResult } from 'rollhub-dice';
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Zero Dependencies
|
|
162
|
+
|
|
163
|
+
This package uses only Node.js built-ins (`fetch`, `crypto`). No external dependencies.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DiceAgentOptions, Balance, BetOptions, BetResult, Bet, VerifyResult } from './types.js';
|
|
2
|
+
export declare class DiceAgent {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
constructor(options: DiceAgentOptions);
|
|
6
|
+
/**
|
|
7
|
+
* Register a new agent with a wallet address and return a configured DiceAgent.
|
|
8
|
+
*/
|
|
9
|
+
static register(walletAddress: string, baseUrl?: string): Promise<DiceAgent>;
|
|
10
|
+
/** Get current balance. */
|
|
11
|
+
balance(): Promise<Balance>;
|
|
12
|
+
/** Place a dice bet. */
|
|
13
|
+
bet(options: BetOptions): Promise<BetResult>;
|
|
14
|
+
/** Get bet history. */
|
|
15
|
+
bets(): Promise<Bet[]>;
|
|
16
|
+
/** Verify a past bet by ID. */
|
|
17
|
+
verify(betId: number): Promise<VerifyResult>;
|
|
18
|
+
private request;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,OAAO,EACP,UAAU,EACV,SAAS,EACT,GAAG,EACH,YAAY,EACb,MAAM,YAAY,CAAC;AAYpB,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,gBAAgB;IAKrC;;OAEG;WACU,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAWlF,2BAA2B;IACrB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,wBAAwB;IAClB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IASlD,uBAAuB;IACjB,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAK5B,+BAA+B;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YAIpC,OAAO;CAatB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiceAgent = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://agent.rollhub.com/api/v1';
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const RETRY_DELAY_MS = 1000;
|
|
9
|
+
class DiceAgent {
|
|
10
|
+
apiKey;
|
|
11
|
+
baseUrl;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.apiKey = options.apiKey;
|
|
14
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register a new agent with a wallet address and return a configured DiceAgent.
|
|
18
|
+
*/
|
|
19
|
+
static async register(walletAddress, baseUrl) {
|
|
20
|
+
const url = `${(baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '')}/register`;
|
|
21
|
+
const res = await fetchWithRetry(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
body: JSON.stringify({ wallet_address: walletAddress }),
|
|
25
|
+
});
|
|
26
|
+
const data = (await handleResponse(res));
|
|
27
|
+
return new DiceAgent({ apiKey: data.api_key, baseUrl });
|
|
28
|
+
}
|
|
29
|
+
/** Get current balance. */
|
|
30
|
+
async balance() {
|
|
31
|
+
return this.request('GET', '/balance');
|
|
32
|
+
}
|
|
33
|
+
/** Place a dice bet. */
|
|
34
|
+
async bet(options) {
|
|
35
|
+
return this.request('POST', '/dice', {
|
|
36
|
+
target: options.target,
|
|
37
|
+
direction: options.direction,
|
|
38
|
+
amount: options.amount,
|
|
39
|
+
client_secret: options.clientSecret ?? (0, node_crypto_1.randomUUID)(),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Get bet history. */
|
|
43
|
+
async bets() {
|
|
44
|
+
const data = await this.request('GET', '/bets');
|
|
45
|
+
return data.bets;
|
|
46
|
+
}
|
|
47
|
+
/** Verify a past bet by ID. */
|
|
48
|
+
async verify(betId) {
|
|
49
|
+
return this.request('GET', `/verify/${betId}`);
|
|
50
|
+
}
|
|
51
|
+
async request(method, path, body) {
|
|
52
|
+
const url = `${this.baseUrl}${path}`;
|
|
53
|
+
const init = {
|
|
54
|
+
method,
|
|
55
|
+
headers: {
|
|
56
|
+
'X-API-Key': this.apiKey,
|
|
57
|
+
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
58
|
+
},
|
|
59
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
60
|
+
};
|
|
61
|
+
const res = await fetchWithRetry(url, init);
|
|
62
|
+
return handleResponse(res);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.DiceAgent = DiceAgent;
|
|
66
|
+
async function fetchWithRetry(url, init, attempt = 0) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(url, init);
|
|
69
|
+
if (res.status >= 500 && attempt < MAX_RETRIES) {
|
|
70
|
+
await sleep(RETRY_DELAY_MS * 2 ** attempt);
|
|
71
|
+
return fetchWithRetry(url, init, attempt + 1);
|
|
72
|
+
}
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (attempt < MAX_RETRIES) {
|
|
77
|
+
await sleep(RETRY_DELAY_MS * 2 ** attempt);
|
|
78
|
+
return fetchWithRetry(url, init, attempt + 1);
|
|
79
|
+
}
|
|
80
|
+
throw new errors_js_1.NetworkError('Request failed after retries', err);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function handleResponse(res) {
|
|
84
|
+
let body;
|
|
85
|
+
try {
|
|
86
|
+
body = await res.json();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
body = undefined;
|
|
90
|
+
}
|
|
91
|
+
if (res.ok)
|
|
92
|
+
return body;
|
|
93
|
+
const msg = typeof body === 'object' && body !== null && 'error' in body
|
|
94
|
+
? String(body.error)
|
|
95
|
+
: `HTTP ${res.status}`;
|
|
96
|
+
if (res.status === 401)
|
|
97
|
+
throw new errors_js_1.AuthenticationError(msg);
|
|
98
|
+
if (res.status === 429) {
|
|
99
|
+
const retry = Number(res.headers.get('retry-after')) || 1;
|
|
100
|
+
throw new errors_js_1.RateLimitError(retry);
|
|
101
|
+
}
|
|
102
|
+
throw new errors_js_1.RollhubError(msg, res.status, 'API_ERROR', body);
|
|
103
|
+
}
|
|
104
|
+
function sleep(ms) {
|
|
105
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class RollhubError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly code: string;
|
|
4
|
+
readonly body: unknown;
|
|
5
|
+
constructor(message: string, status: number, code: string, body?: unknown);
|
|
6
|
+
}
|
|
7
|
+
export declare class AuthenticationError extends RollhubError {
|
|
8
|
+
constructor(message?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class InsufficientBalanceError extends RollhubError {
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class RateLimitError extends RollhubError {
|
|
14
|
+
readonly retryAfter: number;
|
|
15
|
+
constructor(retryAfter?: number);
|
|
16
|
+
}
|
|
17
|
+
export declare class NetworkError extends Error {
|
|
18
|
+
readonly cause: unknown;
|
|
19
|
+
constructor(message: string, cause?: unknown);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,IAAI,EAAE,OAAO,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAO1E;AAED,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,OAAO,SAA+B;CAInD;AAED,qBAAa,wBAAyB,SAAQ,YAAY;gBAC5C,OAAO,SAAyB;CAI7C;AAED,qBAAa,cAAe,SAAQ,YAAY;IAC9C,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,UAAU,SAAI;CAK3B;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,KAAK,EAAE,OAAO,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkError = exports.RateLimitError = exports.InsufficientBalanceError = exports.AuthenticationError = exports.RollhubError = void 0;
|
|
4
|
+
class RollhubError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, status, code, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'RollhubError';
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.body = body;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.RollhubError = RollhubError;
|
|
17
|
+
class AuthenticationError extends RollhubError {
|
|
18
|
+
constructor(message = 'Invalid or missing API key') {
|
|
19
|
+
super(message, 401, 'AUTHENTICATION_ERROR');
|
|
20
|
+
this.name = 'AuthenticationError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.AuthenticationError = AuthenticationError;
|
|
24
|
+
class InsufficientBalanceError extends RollhubError {
|
|
25
|
+
constructor(message = 'Insufficient balance') {
|
|
26
|
+
super(message, 400, 'INSUFFICIENT_BALANCE');
|
|
27
|
+
this.name = 'InsufficientBalanceError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.InsufficientBalanceError = InsufficientBalanceError;
|
|
31
|
+
class RateLimitError extends RollhubError {
|
|
32
|
+
retryAfter;
|
|
33
|
+
constructor(retryAfter = 1) {
|
|
34
|
+
super(`Rate limited. Retry after ${retryAfter}s`, 429, 'RATE_LIMITED');
|
|
35
|
+
this.name = 'RateLimitError';
|
|
36
|
+
this.retryAfter = retryAfter;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.RateLimitError = RateLimitError;
|
|
40
|
+
class NetworkError extends Error {
|
|
41
|
+
cause;
|
|
42
|
+
constructor(message, cause) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'NetworkError';
|
|
45
|
+
this.cause = cause;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.NetworkError = NetworkError;
|
|
49
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IACrB,MAAM,CAAS;IACf,IAAI,CAAS;IACb,IAAI,CAAU;IAE9B,YAAY,OAAe,EAAE,MAAc,EAAE,IAAY,EAAE,IAAc;QACvE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAZD,oCAYC;AAED,MAAa,mBAAoB,SAAQ,YAAY;IACnD,YAAY,OAAO,GAAG,4BAA4B;QAChD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AALD,kDAKC;AAED,MAAa,wBAAyB,SAAQ,YAAY;IACxD,YAAY,OAAO,GAAG,sBAAsB;QAC1C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AALD,4DAKC;AAED,MAAa,cAAe,SAAQ,YAAY;IAC9B,UAAU,CAAS;IAEnC,YAAY,UAAU,GAAG,CAAC;QACxB,KAAK,CAAC,6BAA6B,UAAU,GAAG,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AARD,wCAQC;AAED,MAAa,YAAa,SAAQ,KAAK;IACrB,KAAK,CAAU;IAE/B,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AARD,oCAQC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DiceAgent } from './client.js';
|
|
2
|
+
export { verifyRoll } from './verify.js';
|
|
3
|
+
export { RollhubError, AuthenticationError, InsufficientBalanceError, RateLimitError, NetworkError, } from './errors.js';
|
|
4
|
+
export type { DiceAgentOptions, RegisterResponse, Balance, BetOptions, BetResult, BetProof, Bet, VerifyResult, } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,SAAS,EACT,QAAQ,EACR,GAAG,EACH,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkError = exports.RateLimitError = exports.InsufficientBalanceError = exports.AuthenticationError = exports.RollhubError = exports.verifyRoll = exports.DiceAgent = void 0;
|
|
4
|
+
var client_js_1 = require("./client.js");
|
|
5
|
+
Object.defineProperty(exports, "DiceAgent", { enumerable: true, get: function () { return client_js_1.DiceAgent; } });
|
|
6
|
+
var verify_js_1 = require("./verify.js");
|
|
7
|
+
Object.defineProperty(exports, "verifyRoll", { enumerable: true, get: function () { return verify_js_1.verifyRoll; } });
|
|
8
|
+
var errors_js_1 = require("./errors.js");
|
|
9
|
+
Object.defineProperty(exports, "RollhubError", { enumerable: true, get: function () { return errors_js_1.RollhubError; } });
|
|
10
|
+
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_js_1.AuthenticationError; } });
|
|
11
|
+
Object.defineProperty(exports, "InsufficientBalanceError", { enumerable: true, get: function () { return errors_js_1.InsufficientBalanceError; } });
|
|
12
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_js_1.RateLimitError; } });
|
|
13
|
+
Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_js_1.NetworkError; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,yCAAyC;AAAhC,uGAAA,UAAU,OAAA;AACnB,yCAMqB;AALnB,yGAAA,YAAY,OAAA;AACZ,gHAAA,mBAAmB,OAAA;AACnB,qHAAA,wBAAwB,OAAA;AACxB,2GAAA,cAAc,OAAA;AACd,yGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface DiceAgentOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface RegisterResponse {
|
|
6
|
+
api_key: string;
|
|
7
|
+
server_seed_hash: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Balance {
|
|
10
|
+
balance_usd: string;
|
|
11
|
+
balance_cents: number;
|
|
12
|
+
currency: string;
|
|
13
|
+
}
|
|
14
|
+
export interface BetOptions {
|
|
15
|
+
target: number;
|
|
16
|
+
direction: 'over' | 'under';
|
|
17
|
+
amount: number;
|
|
18
|
+
clientSecret?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BetProof {
|
|
21
|
+
server_secret: string;
|
|
22
|
+
client_secret: string;
|
|
23
|
+
nonce: number;
|
|
24
|
+
server_seed_hash: string;
|
|
25
|
+
}
|
|
26
|
+
export interface BetResult {
|
|
27
|
+
bet_id: number;
|
|
28
|
+
roll: number;
|
|
29
|
+
win: boolean;
|
|
30
|
+
payout: number;
|
|
31
|
+
multiplier: number;
|
|
32
|
+
balance: number;
|
|
33
|
+
proof: BetProof;
|
|
34
|
+
}
|
|
35
|
+
export interface Bet {
|
|
36
|
+
bet_id: number;
|
|
37
|
+
target: number;
|
|
38
|
+
direction: 'over' | 'under';
|
|
39
|
+
amount: number;
|
|
40
|
+
roll: number;
|
|
41
|
+
win: boolean;
|
|
42
|
+
payout: number;
|
|
43
|
+
multiplier: number;
|
|
44
|
+
client_secret: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
}
|
|
47
|
+
export interface VerifyResult {
|
|
48
|
+
bet_id: number;
|
|
49
|
+
verified: boolean;
|
|
50
|
+
roll: number;
|
|
51
|
+
target: number;
|
|
52
|
+
direction: 'over' | 'under';
|
|
53
|
+
server_secret: string;
|
|
54
|
+
client_secret: string;
|
|
55
|
+
nonce: number;
|
|
56
|
+
server_seed_hash: string;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a provably fair dice roll.
|
|
3
|
+
*
|
|
4
|
+
* The roll is computed as:
|
|
5
|
+
* HMAC-SHA256(serverSecret, clientSecret + ":" + nonce)
|
|
6
|
+
* The first 8 hex chars are converted to a number in [0, 1).
|
|
7
|
+
*
|
|
8
|
+
* The server_seed_hash should equal SHA-256(serverSecret).
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyRoll(params: {
|
|
11
|
+
serverSecret: string;
|
|
12
|
+
clientSecret: string;
|
|
13
|
+
nonce: number;
|
|
14
|
+
serverSeedHash: string;
|
|
15
|
+
}): {
|
|
16
|
+
roll: number;
|
|
17
|
+
hashValid: boolean;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAavC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyRoll = verifyRoll;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
/**
|
|
6
|
+
* Verify a provably fair dice roll.
|
|
7
|
+
*
|
|
8
|
+
* The roll is computed as:
|
|
9
|
+
* HMAC-SHA256(serverSecret, clientSecret + ":" + nonce)
|
|
10
|
+
* The first 8 hex chars are converted to a number in [0, 1).
|
|
11
|
+
*
|
|
12
|
+
* The server_seed_hash should equal SHA-256(serverSecret).
|
|
13
|
+
*/
|
|
14
|
+
function verifyRoll(params) {
|
|
15
|
+
const { serverSecret, clientSecret, nonce, serverSeedHash } = params;
|
|
16
|
+
// Verify the server seed hash
|
|
17
|
+
const computedHash = (0, node_crypto_1.createHash)('sha256').update(serverSecret).digest('hex');
|
|
18
|
+
const hashValid = computedHash === serverSeedHash;
|
|
19
|
+
// Compute the roll
|
|
20
|
+
const message = `${clientSecret}:${nonce}`;
|
|
21
|
+
const hmac = (0, node_crypto_1.createHmac)('sha256', serverSecret).update(message).digest('hex');
|
|
22
|
+
const roll = parseInt(hmac.slice(0, 8), 16) / 0x100000000;
|
|
23
|
+
return { roll, hashValid };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":";;AAWA,gCAkBC;AA7BD,6CAAqD;AAErD;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,MAK1B;IACC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAErE,8BAA8B;IAC9B,MAAM,YAAY,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,YAAY,KAAK,cAAc,CAAC;IAElD,mBAAmB;IACnB,MAAM,OAAO,GAAG,GAAG,YAAY,IAAI,KAAK,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,WAAW,CAAC;IAE1D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DiceAgentOptions, Balance, BetOptions, BetResult, Bet, VerifyResult } from './types.js';
|
|
2
|
+
export declare class DiceAgent {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
constructor(options: DiceAgentOptions);
|
|
6
|
+
/**
|
|
7
|
+
* Register a new agent with a wallet address and return a configured DiceAgent.
|
|
8
|
+
*/
|
|
9
|
+
static register(walletAddress: string, baseUrl?: string): Promise<DiceAgent>;
|
|
10
|
+
/** Get current balance. */
|
|
11
|
+
balance(): Promise<Balance>;
|
|
12
|
+
/** Place a dice bet. */
|
|
13
|
+
bet(options: BetOptions): Promise<BetResult>;
|
|
14
|
+
/** Get bet history. */
|
|
15
|
+
bets(): Promise<Bet[]>;
|
|
16
|
+
/** Verify a past bet by ID. */
|
|
17
|
+
verify(betId: number): Promise<VerifyResult>;
|
|
18
|
+
private request;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,OAAO,EACP,UAAU,EACV,SAAS,EACT,GAAG,EACH,YAAY,EACb,MAAM,YAAY,CAAC;AAYpB,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,gBAAgB;IAKrC;;OAEG;WACU,QAAQ,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAWlF,2BAA2B;IACrB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,wBAAwB;IAClB,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IASlD,uBAAuB;IACjB,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAK5B,+BAA+B;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YAIpC,OAAO;CAatB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiceAgent = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://agent.rollhub.com/api/v1';
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const RETRY_DELAY_MS = 1000;
|
|
9
|
+
class DiceAgent {
|
|
10
|
+
apiKey;
|
|
11
|
+
baseUrl;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.apiKey = options.apiKey;
|
|
14
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register a new agent with a wallet address and return a configured DiceAgent.
|
|
18
|
+
*/
|
|
19
|
+
static async register(walletAddress, baseUrl) {
|
|
20
|
+
const url = `${(baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '')}/register`;
|
|
21
|
+
const res = await fetchWithRetry(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
body: JSON.stringify({ wallet_address: walletAddress }),
|
|
25
|
+
});
|
|
26
|
+
const data = (await handleResponse(res));
|
|
27
|
+
return new DiceAgent({ apiKey: data.api_key, baseUrl });
|
|
28
|
+
}
|
|
29
|
+
/** Get current balance. */
|
|
30
|
+
async balance() {
|
|
31
|
+
return this.request('GET', '/balance');
|
|
32
|
+
}
|
|
33
|
+
/** Place a dice bet. */
|
|
34
|
+
async bet(options) {
|
|
35
|
+
return this.request('POST', '/dice', {
|
|
36
|
+
target: options.target,
|
|
37
|
+
direction: options.direction,
|
|
38
|
+
amount: options.amount,
|
|
39
|
+
client_secret: options.clientSecret ?? (0, node_crypto_1.randomUUID)(),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Get bet history. */
|
|
43
|
+
async bets() {
|
|
44
|
+
const data = await this.request('GET', '/bets');
|
|
45
|
+
return data.bets;
|
|
46
|
+
}
|
|
47
|
+
/** Verify a past bet by ID. */
|
|
48
|
+
async verify(betId) {
|
|
49
|
+
return this.request('GET', `/verify/${betId}`);
|
|
50
|
+
}
|
|
51
|
+
async request(method, path, body) {
|
|
52
|
+
const url = `${this.baseUrl}${path}`;
|
|
53
|
+
const init = {
|
|
54
|
+
method,
|
|
55
|
+
headers: {
|
|
56
|
+
'X-API-Key': this.apiKey,
|
|
57
|
+
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
58
|
+
},
|
|
59
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
60
|
+
};
|
|
61
|
+
const res = await fetchWithRetry(url, init);
|
|
62
|
+
return handleResponse(res);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.DiceAgent = DiceAgent;
|
|
66
|
+
async function fetchWithRetry(url, init, attempt = 0) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(url, init);
|
|
69
|
+
if (res.status >= 500 && attempt < MAX_RETRIES) {
|
|
70
|
+
await sleep(RETRY_DELAY_MS * 2 ** attempt);
|
|
71
|
+
return fetchWithRetry(url, init, attempt + 1);
|
|
72
|
+
}
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
if (attempt < MAX_RETRIES) {
|
|
77
|
+
await sleep(RETRY_DELAY_MS * 2 ** attempt);
|
|
78
|
+
return fetchWithRetry(url, init, attempt + 1);
|
|
79
|
+
}
|
|
80
|
+
throw new errors_js_1.NetworkError('Request failed after retries', err);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function handleResponse(res) {
|
|
84
|
+
let body;
|
|
85
|
+
try {
|
|
86
|
+
body = await res.json();
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
body = undefined;
|
|
90
|
+
}
|
|
91
|
+
if (res.ok)
|
|
92
|
+
return body;
|
|
93
|
+
const msg = typeof body === 'object' && body !== null && 'error' in body
|
|
94
|
+
? String(body.error)
|
|
95
|
+
: `HTTP ${res.status}`;
|
|
96
|
+
if (res.status === 401)
|
|
97
|
+
throw new errors_js_1.AuthenticationError(msg);
|
|
98
|
+
if (res.status === 429) {
|
|
99
|
+
const retry = Number(res.headers.get('retry-after')) || 1;
|
|
100
|
+
throw new errors_js_1.RateLimitError(retry);
|
|
101
|
+
}
|
|
102
|
+
throw new errors_js_1.RollhubError(msg, res.status, 'API_ERROR', body);
|
|
103
|
+
}
|
|
104
|
+
function sleep(ms) {
|
|
105
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class RollhubError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly code: string;
|
|
4
|
+
readonly body: unknown;
|
|
5
|
+
constructor(message: string, status: number, code: string, body?: unknown);
|
|
6
|
+
}
|
|
7
|
+
export declare class AuthenticationError extends RollhubError {
|
|
8
|
+
constructor(message?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class InsufficientBalanceError extends RollhubError {
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
13
|
+
export declare class RateLimitError extends RollhubError {
|
|
14
|
+
readonly retryAfter: number;
|
|
15
|
+
constructor(retryAfter?: number);
|
|
16
|
+
}
|
|
17
|
+
export declare class NetworkError extends Error {
|
|
18
|
+
readonly cause: unknown;
|
|
19
|
+
constructor(message: string, cause?: unknown);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,IAAI,EAAE,OAAO,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAO1E;AAED,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,OAAO,SAA+B;CAInD;AAED,qBAAa,wBAAyB,SAAQ,YAAY;gBAC5C,OAAO,SAAyB;CAI7C;AAED,qBAAa,cAAe,SAAQ,YAAY;IAC9C,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,UAAU,SAAI;CAK3B;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,KAAK,EAAE,OAAO,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkError = exports.RateLimitError = exports.InsufficientBalanceError = exports.AuthenticationError = exports.RollhubError = void 0;
|
|
4
|
+
class RollhubError extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, status, code, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'RollhubError';
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.body = body;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.RollhubError = RollhubError;
|
|
17
|
+
class AuthenticationError extends RollhubError {
|
|
18
|
+
constructor(message = 'Invalid or missing API key') {
|
|
19
|
+
super(message, 401, 'AUTHENTICATION_ERROR');
|
|
20
|
+
this.name = 'AuthenticationError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.AuthenticationError = AuthenticationError;
|
|
24
|
+
class InsufficientBalanceError extends RollhubError {
|
|
25
|
+
constructor(message = 'Insufficient balance') {
|
|
26
|
+
super(message, 400, 'INSUFFICIENT_BALANCE');
|
|
27
|
+
this.name = 'InsufficientBalanceError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.InsufficientBalanceError = InsufficientBalanceError;
|
|
31
|
+
class RateLimitError extends RollhubError {
|
|
32
|
+
retryAfter;
|
|
33
|
+
constructor(retryAfter = 1) {
|
|
34
|
+
super(`Rate limited. Retry after ${retryAfter}s`, 429, 'RATE_LIMITED');
|
|
35
|
+
this.name = 'RateLimitError';
|
|
36
|
+
this.retryAfter = retryAfter;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.RateLimitError = RateLimitError;
|
|
40
|
+
class NetworkError extends Error {
|
|
41
|
+
cause;
|
|
42
|
+
constructor(message, cause) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'NetworkError';
|
|
45
|
+
this.cause = cause;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.NetworkError = NetworkError;
|
|
49
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;IACrB,MAAM,CAAS;IACf,IAAI,CAAS;IACb,IAAI,CAAU;IAE9B,YAAY,OAAe,EAAE,MAAc,EAAE,IAAY,EAAE,IAAc;QACvE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAZD,oCAYC;AAED,MAAa,mBAAoB,SAAQ,YAAY;IACnD,YAAY,OAAO,GAAG,4BAA4B;QAChD,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AALD,kDAKC;AAED,MAAa,wBAAyB,SAAQ,YAAY;IACxD,YAAY,OAAO,GAAG,sBAAsB;QAC1C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AALD,4DAKC;AAED,MAAa,cAAe,SAAQ,YAAY;IAC9B,UAAU,CAAS;IAEnC,YAAY,UAAU,GAAG,CAAC;QACxB,KAAK,CAAC,6BAA6B,UAAU,GAAG,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AARD,wCAQC;AAED,MAAa,YAAa,SAAQ,KAAK;IACrB,KAAK,CAAU;IAE/B,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AARD,oCAQC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DiceAgent } from './client.js';
|
|
2
|
+
export { verifyRoll } from './verify.js';
|
|
3
|
+
export { RollhubError, AuthenticationError, InsufficientBalanceError, RateLimitError, NetworkError, } from './errors.js';
|
|
4
|
+
export type { DiceAgentOptions, RegisterResponse, Balance, BetOptions, BetResult, BetProof, Bet, VerifyResult, } from './types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,cAAc,EACd,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,SAAS,EACT,QAAQ,EACR,GAAG,EACH,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NetworkError = exports.RateLimitError = exports.InsufficientBalanceError = exports.AuthenticationError = exports.RollhubError = exports.verifyRoll = exports.DiceAgent = void 0;
|
|
4
|
+
var client_js_1 = require("./client.js");
|
|
5
|
+
Object.defineProperty(exports, "DiceAgent", { enumerable: true, get: function () { return client_js_1.DiceAgent; } });
|
|
6
|
+
var verify_js_1 = require("./verify.js");
|
|
7
|
+
Object.defineProperty(exports, "verifyRoll", { enumerable: true, get: function () { return verify_js_1.verifyRoll; } });
|
|
8
|
+
var errors_js_1 = require("./errors.js");
|
|
9
|
+
Object.defineProperty(exports, "RollhubError", { enumerable: true, get: function () { return errors_js_1.RollhubError; } });
|
|
10
|
+
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_js_1.AuthenticationError; } });
|
|
11
|
+
Object.defineProperty(exports, "InsufficientBalanceError", { enumerable: true, get: function () { return errors_js_1.InsufficientBalanceError; } });
|
|
12
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_js_1.RateLimitError; } });
|
|
13
|
+
Object.defineProperty(exports, "NetworkError", { enumerable: true, get: function () { return errors_js_1.NetworkError; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,yCAAyC;AAAhC,uGAAA,UAAU,OAAA;AACnB,yCAMqB;AALnB,yGAAA,YAAY,OAAA;AACZ,gHAAA,mBAAmB,OAAA;AACnB,qHAAA,wBAAwB,OAAA;AACxB,2GAAA,cAAc,OAAA;AACd,yGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "module" }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface DiceAgentOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface RegisterResponse {
|
|
6
|
+
api_key: string;
|
|
7
|
+
server_seed_hash: string;
|
|
8
|
+
}
|
|
9
|
+
export interface Balance {
|
|
10
|
+
balance_usd: string;
|
|
11
|
+
balance_cents: number;
|
|
12
|
+
currency: string;
|
|
13
|
+
}
|
|
14
|
+
export interface BetOptions {
|
|
15
|
+
target: number;
|
|
16
|
+
direction: 'over' | 'under';
|
|
17
|
+
amount: number;
|
|
18
|
+
clientSecret?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BetProof {
|
|
21
|
+
server_secret: string;
|
|
22
|
+
client_secret: string;
|
|
23
|
+
nonce: number;
|
|
24
|
+
server_seed_hash: string;
|
|
25
|
+
}
|
|
26
|
+
export interface BetResult {
|
|
27
|
+
bet_id: number;
|
|
28
|
+
roll: number;
|
|
29
|
+
win: boolean;
|
|
30
|
+
payout: number;
|
|
31
|
+
multiplier: number;
|
|
32
|
+
balance: number;
|
|
33
|
+
proof: BetProof;
|
|
34
|
+
}
|
|
35
|
+
export interface Bet {
|
|
36
|
+
bet_id: number;
|
|
37
|
+
target: number;
|
|
38
|
+
direction: 'over' | 'under';
|
|
39
|
+
amount: number;
|
|
40
|
+
roll: number;
|
|
41
|
+
win: boolean;
|
|
42
|
+
payout: number;
|
|
43
|
+
multiplier: number;
|
|
44
|
+
client_secret: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
}
|
|
47
|
+
export interface VerifyResult {
|
|
48
|
+
bet_id: number;
|
|
49
|
+
verified: boolean;
|
|
50
|
+
roll: number;
|
|
51
|
+
target: number;
|
|
52
|
+
direction: 'over' | 'under';
|
|
53
|
+
server_secret: string;
|
|
54
|
+
client_secret: string;
|
|
55
|
+
nonce: number;
|
|
56
|
+
server_seed_hash: string;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a provably fair dice roll.
|
|
3
|
+
*
|
|
4
|
+
* The roll is computed as:
|
|
5
|
+
* HMAC-SHA256(serverSecret, clientSecret + ":" + nonce)
|
|
6
|
+
* The first 8 hex chars are converted to a number in [0, 1).
|
|
7
|
+
*
|
|
8
|
+
* The server_seed_hash should equal SHA-256(serverSecret).
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyRoll(params: {
|
|
11
|
+
serverSecret: string;
|
|
12
|
+
clientSecret: string;
|
|
13
|
+
nonce: number;
|
|
14
|
+
serverSeedHash: string;
|
|
15
|
+
}): {
|
|
16
|
+
roll: number;
|
|
17
|
+
hashValid: boolean;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAavC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyRoll = verifyRoll;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
/**
|
|
6
|
+
* Verify a provably fair dice roll.
|
|
7
|
+
*
|
|
8
|
+
* The roll is computed as:
|
|
9
|
+
* HMAC-SHA256(serverSecret, clientSecret + ":" + nonce)
|
|
10
|
+
* The first 8 hex chars are converted to a number in [0, 1).
|
|
11
|
+
*
|
|
12
|
+
* The server_seed_hash should equal SHA-256(serverSecret).
|
|
13
|
+
*/
|
|
14
|
+
function verifyRoll(params) {
|
|
15
|
+
const { serverSecret, clientSecret, nonce, serverSeedHash } = params;
|
|
16
|
+
// Verify the server seed hash
|
|
17
|
+
const computedHash = (0, node_crypto_1.createHash)('sha256').update(serverSecret).digest('hex');
|
|
18
|
+
const hashValid = computedHash === serverSeedHash;
|
|
19
|
+
// Compute the roll
|
|
20
|
+
const message = `${clientSecret}:${nonce}`;
|
|
21
|
+
const hmac = (0, node_crypto_1.createHmac)('sha256', serverSecret).update(message).digest('hex');
|
|
22
|
+
const roll = parseInt(hmac.slice(0, 8), 16) / 0x100000000;
|
|
23
|
+
return { roll, hashValid };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":";;AAWA,gCAkBC;AA7BD,6CAAqD;AAErD;;;;;;;;GAQG;AACH,SAAgB,UAAU,CAAC,MAK1B;IACC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAErE,8BAA8B;IAC9B,MAAM,YAAY,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,YAAY,KAAK,cAAc,CAAC;IAElD,mBAAmB;IACnB,MAAM,OAAO,GAAG,GAAG,YAAY,IAAI,KAAK,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,WAAW,CAAC;IAE1D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rollhub-dice",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JavaScript/TypeScript SDK for the Rollhub Dice Agent API — provably fair dice betting",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/esm/index.d.ts",
|
|
12
|
+
"default": "./dist/esm/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/cjs/index.d.ts",
|
|
16
|
+
"default": "./dist/cjs/index.js"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "npm run build:esm && npm run build:cjs",
|
|
27
|
+
"build:esm": "tsc -p tsconfig.json",
|
|
28
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"dice",
|
|
33
|
+
"casino",
|
|
34
|
+
"gambling",
|
|
35
|
+
"ai",
|
|
36
|
+
"agent",
|
|
37
|
+
"provably-fair",
|
|
38
|
+
"crypto",
|
|
39
|
+
"solana"
|
|
40
|
+
],
|
|
41
|
+
"author": "Rollhub",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/rollhub/rollhub-dice-js"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^25.3.0",
|
|
52
|
+
"typescript": "^5.9.3"
|
|
53
|
+
}
|
|
54
|
+
}
|