@fundedfast/sdk 1.3.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/CHANGELOG.md +104 -0
- package/README.md +352 -0
- package/dist/cjs/client.d.ts +130 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +362 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/index.d.ts +27 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/resources/admin.d.ts +597 -0
- package/dist/cjs/resources/admin.d.ts.map +1 -0
- package/dist/cjs/resources/admin.js +842 -0
- package/dist/cjs/resources/admin.js.map +1 -0
- package/dist/cjs/resources/public.d.ts +519 -0
- package/dist/cjs/resources/public.d.ts.map +1 -0
- package/dist/cjs/resources/public.js +588 -0
- package/dist/cjs/resources/public.js.map +1 -0
- package/dist/cjs/types.d.ts +651 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +11 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/webhooks.d.ts +104 -0
- package/dist/cjs/webhooks.d.ts.map +1 -0
- package/dist/cjs/webhooks.js +199 -0
- package/dist/cjs/webhooks.js.map +1 -0
- package/dist/esm/client.d.ts +130 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +355 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/index.d.ts +27 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/resources/admin.d.ts +597 -0
- package/dist/esm/resources/admin.d.ts.map +1 -0
- package/dist/esm/resources/admin.js +816 -0
- package/dist/esm/resources/admin.js.map +1 -0
- package/dist/esm/resources/public.d.ts +519 -0
- package/dist/esm/resources/public.d.ts.map +1 -0
- package/dist/esm/resources/public.js +578 -0
- package/dist/esm/resources/public.js.map +1 -0
- package/dist/esm/types.d.ts +651 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +10 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/webhooks.d.ts +104 -0
- package/dist/esm/webhooks.d.ts.map +1 -0
- package/dist/esm/webhooks.js +159 -0
- package/dist/esm/webhooks.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fundedfast/sdk/webhooks - Webhook Signature Verification
|
|
3
|
+
*
|
|
4
|
+
* Helpers for verifying FAST webhook deliveries in your backend.
|
|
5
|
+
* FAST signs all webhook payloads with HMAC-SHA256 using your webhook secret.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { verifyWebhookSignature, parseWebhookEvent } from '@fundedfast/sdk/webhooks';
|
|
10
|
+
*
|
|
11
|
+
* app.post('/webhooks/fast', express.raw({ type: 'application/json' }), async (req, res) => {
|
|
12
|
+
* const signature = req.headers['x-webhook-signature'] as string;
|
|
13
|
+
* const rawBody = req.body.toString('utf-8'); // the raw bytes, not parsed JSON
|
|
14
|
+
*
|
|
15
|
+
* // It is async: without `await` the check is a Promise, always truthy, and
|
|
16
|
+
* // every request passes.
|
|
17
|
+
* if (!await verifyWebhookSignature(rawBody, signature, process.env.FAST_WEBHOOK_SECRET!)) {
|
|
18
|
+
* return res.status(401).send('Invalid signature');
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* const event = parseWebhookEvent(rawBody);
|
|
22
|
+
* switch (event.eventType) {
|
|
23
|
+
* case 'challenge.completed':
|
|
24
|
+
* handleChallengeCompleted(event.userId, event.data);
|
|
25
|
+
* break;
|
|
26
|
+
* case 'funded_account.revoked':
|
|
27
|
+
* handleRevocation(event.userId, event.data);
|
|
28
|
+
* break;
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* res.status(200).send({ received: true });
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @module webhooks
|
|
36
|
+
*/
|
|
37
|
+
import type { WebhookPayload, WebhookEventType } from './types.js';
|
|
38
|
+
/**
|
|
39
|
+
* Verify the HMAC-SHA256 signature of a webhook payload.
|
|
40
|
+
*
|
|
41
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
42
|
+
* Works in Node.js (crypto module) and edge runtimes (Web Crypto API).
|
|
43
|
+
*
|
|
44
|
+
* @param rawBody - The raw request body as a string (NOT parsed JSON)
|
|
45
|
+
* @param signature - The X-Webhook-Signature header value
|
|
46
|
+
* @param secret - Your webhook secret (from tenant setup)
|
|
47
|
+
* @returns true if signature is valid
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Express with raw body parser
|
|
52
|
+
* app.use('/webhooks', express.raw({ type: 'application/json' }));
|
|
53
|
+
*
|
|
54
|
+
* app.post('/webhooks/fast', async (req, res) => {
|
|
55
|
+
* const rawBody = req.body.toString('utf-8');
|
|
56
|
+
* const sig = req.headers['x-webhook-signature'] as string;
|
|
57
|
+
*
|
|
58
|
+
* if (!await verifyWebhookSignature(rawBody, sig, WEBHOOK_SECRET)) {
|
|
59
|
+
* return res.status(401).json({ error: 'invalid_signature' });
|
|
60
|
+
* }
|
|
61
|
+
* // ... handle event
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function verifyWebhookSignature(rawBody: string, signature: string, secret: string): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Synchronous signature verification using Web Crypto (browser/edge compatible).
|
|
68
|
+
*
|
|
69
|
+
* NOTE: This is async because Web Crypto API is async.
|
|
70
|
+
* If you need sync verification in Node.js, import crypto directly:
|
|
71
|
+
*
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
74
|
+
* const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
|
|
75
|
+
* const valid = timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'));
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Parse a webhook event payload.
|
|
80
|
+
*
|
|
81
|
+
* @param rawBody - The raw request body as a string or parsed object
|
|
82
|
+
* @returns Typed webhook payload with eventId, eventType, userId, timestamp, and data
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const event = parseWebhookEvent(rawBody);
|
|
87
|
+
* console.log(event.eventType); // 'challenge.completed'
|
|
88
|
+
* console.log(event.data); // { challengeId: '...', balance: 105.50, ... }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function parseWebhookEvent<T = Record<string, unknown>>(rawBody: string | Record<string, unknown>): WebhookPayload<T>;
|
|
92
|
+
/**
|
|
93
|
+
* Check if an event type is one of the challenge lifecycle events.
|
|
94
|
+
*/
|
|
95
|
+
export declare function isChallengeEvent(eventType: WebhookEventType): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Check if an event type is one of the funded account lifecycle events.
|
|
98
|
+
*/
|
|
99
|
+
export declare function isFundedAccountEvent(eventType: WebhookEventType): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Check if an event type is one of the user lifecycle events.
|
|
102
|
+
*/
|
|
103
|
+
export declare function isUserEvent(eventType: WebhookEventType): boolean;
|
|
104
|
+
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAuClB;AAED;;;;;;;;;;;GAWG;AAIH;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAG3H;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAErE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAEzE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAEhE"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fundedfast/sdk/webhooks - Webhook Signature Verification
|
|
4
|
+
*
|
|
5
|
+
* Helpers for verifying FAST webhook deliveries in your backend.
|
|
6
|
+
* FAST signs all webhook payloads with HMAC-SHA256 using your webhook secret.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { verifyWebhookSignature, parseWebhookEvent } from '@fundedfast/sdk/webhooks';
|
|
11
|
+
*
|
|
12
|
+
* app.post('/webhooks/fast', express.raw({ type: 'application/json' }), async (req, res) => {
|
|
13
|
+
* const signature = req.headers['x-webhook-signature'] as string;
|
|
14
|
+
* const rawBody = req.body.toString('utf-8'); // the raw bytes, not parsed JSON
|
|
15
|
+
*
|
|
16
|
+
* // It is async: without `await` the check is a Promise, always truthy, and
|
|
17
|
+
* // every request passes.
|
|
18
|
+
* if (!await verifyWebhookSignature(rawBody, signature, process.env.FAST_WEBHOOK_SECRET!)) {
|
|
19
|
+
* return res.status(401).send('Invalid signature');
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* const event = parseWebhookEvent(rawBody);
|
|
23
|
+
* switch (event.eventType) {
|
|
24
|
+
* case 'challenge.completed':
|
|
25
|
+
* handleChallengeCompleted(event.userId, event.data);
|
|
26
|
+
* break;
|
|
27
|
+
* case 'funded_account.revoked':
|
|
28
|
+
* handleRevocation(event.userId, event.data);
|
|
29
|
+
* break;
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* res.status(200).send({ received: true });
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @module webhooks
|
|
37
|
+
*/
|
|
38
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
39
|
+
if (k2 === undefined) k2 = k;
|
|
40
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
41
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
42
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
43
|
+
}
|
|
44
|
+
Object.defineProperty(o, k2, desc);
|
|
45
|
+
}) : (function(o, m, k, k2) {
|
|
46
|
+
if (k2 === undefined) k2 = k;
|
|
47
|
+
o[k2] = m[k];
|
|
48
|
+
}));
|
|
49
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
50
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
51
|
+
}) : function(o, v) {
|
|
52
|
+
o["default"] = v;
|
|
53
|
+
});
|
|
54
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
55
|
+
var ownKeys = function(o) {
|
|
56
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
57
|
+
var ar = [];
|
|
58
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
59
|
+
return ar;
|
|
60
|
+
};
|
|
61
|
+
return ownKeys(o);
|
|
62
|
+
};
|
|
63
|
+
return function (mod) {
|
|
64
|
+
if (mod && mod.__esModule) return mod;
|
|
65
|
+
var result = {};
|
|
66
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
67
|
+
__setModuleDefault(result, mod);
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
})();
|
|
71
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
72
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
73
|
+
exports.parseWebhookEvent = parseWebhookEvent;
|
|
74
|
+
exports.isChallengeEvent = isChallengeEvent;
|
|
75
|
+
exports.isFundedAccountEvent = isFundedAccountEvent;
|
|
76
|
+
exports.isUserEvent = isUserEvent;
|
|
77
|
+
/**
|
|
78
|
+
* Verify the HMAC-SHA256 signature of a webhook payload.
|
|
79
|
+
*
|
|
80
|
+
* Uses timing-safe comparison to prevent timing attacks.
|
|
81
|
+
* Works in Node.js (crypto module) and edge runtimes (Web Crypto API).
|
|
82
|
+
*
|
|
83
|
+
* @param rawBody - The raw request body as a string (NOT parsed JSON)
|
|
84
|
+
* @param signature - The X-Webhook-Signature header value
|
|
85
|
+
* @param secret - Your webhook secret (from tenant setup)
|
|
86
|
+
* @returns true if signature is valid
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Express with raw body parser
|
|
91
|
+
* app.use('/webhooks', express.raw({ type: 'application/json' }));
|
|
92
|
+
*
|
|
93
|
+
* app.post('/webhooks/fast', async (req, res) => {
|
|
94
|
+
* const rawBody = req.body.toString('utf-8');
|
|
95
|
+
* const sig = req.headers['x-webhook-signature'] as string;
|
|
96
|
+
*
|
|
97
|
+
* if (!await verifyWebhookSignature(rawBody, sig, WEBHOOK_SECRET)) {
|
|
98
|
+
* return res.status(401).json({ error: 'invalid_signature' });
|
|
99
|
+
* }
|
|
100
|
+
* // ... handle event
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
async function verifyWebhookSignature(rawBody, signature, secret) {
|
|
105
|
+
if (!rawBody || !signature || !secret)
|
|
106
|
+
return false;
|
|
107
|
+
// SHA-256 hex is exactly 64 hex characters. Anything else is not a signature
|
|
108
|
+
// FAST produced; refuse it before parsing rather than let parseInt guess.
|
|
109
|
+
if (typeof signature !== 'string' || !/^[0-9a-f]{64}$/i.test(signature))
|
|
110
|
+
return false;
|
|
111
|
+
signature = signature.toLowerCase();
|
|
112
|
+
// Try Node.js crypto first (fastest path)
|
|
113
|
+
try {
|
|
114
|
+
const crypto = await Promise.resolve().then(() => __importStar(require('node:crypto')));
|
|
115
|
+
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
|
|
116
|
+
if (expected.length !== signature.length)
|
|
117
|
+
return false;
|
|
118
|
+
const a = new Uint8Array(expected.length / 2);
|
|
119
|
+
const b = new Uint8Array(signature.length / 2);
|
|
120
|
+
for (let i = 0; i < a.length; i++) {
|
|
121
|
+
a[i] = parseInt(expected.slice(i * 2, i * 2 + 2), 16);
|
|
122
|
+
b[i] = parseInt(signature.slice(i * 2, i * 2 + 2), 16);
|
|
123
|
+
}
|
|
124
|
+
return crypto.timingSafeEqual(a, b);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Not in Node.js - fall through to Web Crypto
|
|
128
|
+
}
|
|
129
|
+
// Web Crypto API (edge runtimes, Deno, Bun, Cloudflare Workers)
|
|
130
|
+
try {
|
|
131
|
+
const encoder = new TextEncoder();
|
|
132
|
+
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
133
|
+
const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(rawBody));
|
|
134
|
+
const expected = Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
135
|
+
return timingSafeCompare(expected, signature);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Synchronous signature verification using Web Crypto (browser/edge compatible).
|
|
143
|
+
*
|
|
144
|
+
* NOTE: This is async because Web Crypto API is async.
|
|
145
|
+
* If you need sync verification in Node.js, import crypto directly:
|
|
146
|
+
*
|
|
147
|
+
* ```typescript
|
|
148
|
+
* import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
149
|
+
* const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
|
|
150
|
+
* const valid = timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
// Re-export verifyWebhookSignature as the primary API - it works everywhere.
|
|
154
|
+
/**
|
|
155
|
+
* Parse a webhook event payload.
|
|
156
|
+
*
|
|
157
|
+
* @param rawBody - The raw request body as a string or parsed object
|
|
158
|
+
* @returns Typed webhook payload with eventId, eventType, userId, timestamp, and data
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const event = parseWebhookEvent(rawBody);
|
|
163
|
+
* console.log(event.eventType); // 'challenge.completed'
|
|
164
|
+
* console.log(event.data); // { challengeId: '...', balance: 105.50, ... }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
function parseWebhookEvent(rawBody) {
|
|
168
|
+
const parsed = typeof rawBody === 'string' ? JSON.parse(rawBody) : rawBody;
|
|
169
|
+
return parsed;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Check if an event type is one of the challenge lifecycle events.
|
|
173
|
+
*/
|
|
174
|
+
function isChallengeEvent(eventType) {
|
|
175
|
+
return eventType.startsWith('challenge.');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Check if an event type is one of the funded account lifecycle events.
|
|
179
|
+
*/
|
|
180
|
+
function isFundedAccountEvent(eventType) {
|
|
181
|
+
return eventType.startsWith('funded_account.');
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check if an event type is one of the user lifecycle events.
|
|
185
|
+
*/
|
|
186
|
+
function isUserEvent(eventType) {
|
|
187
|
+
return eventType.startsWith('user.');
|
|
188
|
+
}
|
|
189
|
+
// ---- Internals ----
|
|
190
|
+
function timingSafeCompare(a, b) {
|
|
191
|
+
if (a.length !== b.length)
|
|
192
|
+
return false;
|
|
193
|
+
let result = 0;
|
|
194
|
+
for (let i = 0; i < a.length; i++) {
|
|
195
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
196
|
+
}
|
|
197
|
+
return result === 0;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fundedfast/sdk - Client
|
|
3
|
+
*
|
|
4
|
+
* Production-grade HTTP client for the FAST platform API.
|
|
5
|
+
* Features: automatic retries with exponential backoff, rate limit awareness,
|
|
6
|
+
* request/response hooks, idempotency support, debug logging, and proper error handling.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { FastClient } from '@fundedfast/sdk';
|
|
11
|
+
*
|
|
12
|
+
* const fast = new FastClient({
|
|
13
|
+
* apiKey: process.env.FAST_API_KEY!,
|
|
14
|
+
* retry: { maxRetries: 3 },
|
|
15
|
+
* onResponse: ({ status, durationMs, correlationId }) => {
|
|
16
|
+
* metrics.histogram('fast.request.duration', durationMs, { status });
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const result = await fast.bets.validate({
|
|
21
|
+
* userId: 'player-42',
|
|
22
|
+
* externalBetId: 'BET-001',
|
|
23
|
+
* stakeAmount: 5.00,
|
|
24
|
+
* odds: 2.10,
|
|
25
|
+
* status: 'placed',
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @module client
|
|
30
|
+
*/
|
|
31
|
+
import type { FastClientConfig, FastError } from './types.js';
|
|
32
|
+
import { ChallengesApi, BetsApi, UsersApi, ReconciliationApi, EventsApi, SandboxApi, WidgetApi } from './resources/public.js';
|
|
33
|
+
import { AdminApi } from './resources/admin.js';
|
|
34
|
+
export declare const SDK_VERSION = "1.3.0";
|
|
35
|
+
/**
|
|
36
|
+
* Error thrown when the FAST API returns a non-2xx response.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* try {
|
|
41
|
+
* await fast.challenges.purchase({ userId: 'x', challengeTierId: 'invalid' });
|
|
42
|
+
* } catch (err) {
|
|
43
|
+
* if (err instanceof FastApiError) {
|
|
44
|
+
* console.log(err.status); // 400
|
|
45
|
+
* console.log(err.code); // 'validation_error'
|
|
46
|
+
* console.log(err.correlationId); // 'abc-123' (for support)
|
|
47
|
+
* console.log(err.isRetryable); // false
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare class FastApiError extends Error {
|
|
53
|
+
readonly status: number;
|
|
54
|
+
readonly code: string;
|
|
55
|
+
readonly correlationId: string;
|
|
56
|
+
readonly isRetryable: boolean;
|
|
57
|
+
readonly rateLimitReset?: number;
|
|
58
|
+
constructor(status: number, body: FastError, rateLimitReset?: number);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Error thrown when a request times out.
|
|
62
|
+
*/
|
|
63
|
+
export declare class FastTimeoutError extends Error {
|
|
64
|
+
readonly timeoutMs: number;
|
|
65
|
+
constructor(timeoutMs: number);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Error thrown when a network error occurs (DNS, connection refused, etc.)
|
|
69
|
+
*/
|
|
70
|
+
export declare class FastNetworkError extends Error {
|
|
71
|
+
readonly cause: Error;
|
|
72
|
+
constructor(cause: Error);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* FAST Platform API client.
|
|
76
|
+
*
|
|
77
|
+
* Provides typed access to all operator-facing endpoints with automatic retry,
|
|
78
|
+
* rate limit handling, and observability hooks.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const fast = new FastClient({ apiKey: 'key-...' });
|
|
83
|
+
*
|
|
84
|
+
* // Namespaced APIs
|
|
85
|
+
* const tiers = await fast.challenges.listTiers();
|
|
86
|
+
* const result = await fast.bets.validate(betEvent);
|
|
87
|
+
* const progress = await fast.users.getProgress('player-42');
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare class FastClient {
|
|
91
|
+
private readonly baseUrl;
|
|
92
|
+
private readonly apiKey;
|
|
93
|
+
private readonly timeout;
|
|
94
|
+
private readonly retryConfig;
|
|
95
|
+
private readonly onRequest?;
|
|
96
|
+
private readonly onResponse?;
|
|
97
|
+
private readonly _fetch;
|
|
98
|
+
private readonly customHeaders;
|
|
99
|
+
private readonly debug;
|
|
100
|
+
/** Challenge purchase and tier management */
|
|
101
|
+
readonly challenges: ChallengesApi;
|
|
102
|
+
/** Bet validation and ingestion */
|
|
103
|
+
readonly bets: BetsApi;
|
|
104
|
+
/** User progress, history, and withdrawals */
|
|
105
|
+
readonly users: UsersApi;
|
|
106
|
+
/** Bet event reconciliation */
|
|
107
|
+
readonly reconciliation: ReconciliationApi;
|
|
108
|
+
/** Real-time event streaming (SSE) */
|
|
109
|
+
readonly events: EventsApi;
|
|
110
|
+
/** Sandbox operations (staging only) */
|
|
111
|
+
readonly sandbox: SandboxApi;
|
|
112
|
+
/** Widget module and branding configuration */
|
|
113
|
+
readonly widget: WidgetApi;
|
|
114
|
+
/** Admin / backoffice operations (tenant management) */
|
|
115
|
+
readonly admin: AdminApi;
|
|
116
|
+
constructor(config: FastClientConfig);
|
|
117
|
+
/**
|
|
118
|
+
* Execute an authenticated request against the FAST API.
|
|
119
|
+
* Handles retries, timeouts, rate limits, and hooks automatically.
|
|
120
|
+
*
|
|
121
|
+
* @internal Use the namespaced APIs (challenges, bets, users, etc.) instead.
|
|
122
|
+
*/
|
|
123
|
+
request<T>(method: string, path: string, options?: {
|
|
124
|
+
body?: unknown;
|
|
125
|
+
query?: Record<string, string | undefined>;
|
|
126
|
+
idempotencyKey?: string;
|
|
127
|
+
}): Promise<T>;
|
|
128
|
+
private calculateDelay;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,SAAS,EAIV,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,aAAa,EACb,OAAO,EACP,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,SAAS,EACV,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAQhD,eAAO,MAAM,WAAW,UAAU,CAAC;AAgCnC;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,aAAa,EAAE,MAAM,CAAC;IACtC,SAAgB,WAAW,EAAE,OAAO,CAAC;IACrC,SAAgB,cAAc,CAAC,EAAE,MAAM,CAAC;gBAE5B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM;CASrE;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAEtB,SAAS,EAAE,MAAM;CAK9B;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAgB,KAAK,EAAE,KAAK,CAAC;gBAEjB,KAAK,EAAE,KAAK;CAKzB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAEhC,6CAA6C;IAC7C,SAAgB,UAAU,EAAE,aAAa,CAAC;IAC1C,mCAAmC;IACnC,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,8CAA8C;IAC9C,SAAgB,KAAK,EAAE,QAAQ,CAAC;IAChC,+BAA+B;IAC/B,SAAgB,cAAc,EAAE,iBAAiB,CAAC;IAClD,sCAAsC;IACtC,SAAgB,MAAM,EAAE,SAAS,CAAC;IAClC,wCAAwC;IACxC,SAAgB,OAAO,EAAE,UAAU,CAAC;IACpC,+CAA+C;IAC/C,SAAgB,MAAM,EAAE,SAAS,CAAC;IAClC,wDAAwD;IACxD,SAAgB,KAAK,EAAE,QAAQ,CAAC;gBAEpB,MAAM,EAAE,gBAAgB;IAwCpC;;;;;OAKG;IACG,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;QAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GACA,OAAO,CAAC,CAAC,CAAC;IAgKb,OAAO,CAAC,cAAc;CASvB"}
|