@holdem-api/holdem-sdk 0.0.0-stage → 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 +72 -3
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/ranges.d.ts +11 -0
- package/dist/ranges.d.ts.map +1 -0
- package/dist/ranges.js +31 -0
- package/dist/ranges.js.map +1 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +10 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +69 -0
- package/dist/validation.js.map +1 -0
- package/package.json +34 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Justin Baker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,72 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Holdem SDK
|
|
2
|
+
|
|
3
|
+
Server-side JavaScript/TypeScript client for Node.js 20+. Zero runtime dependencies, ESM and TypeScript declarations. All requests use `POST /api/actions`.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { HoldemClient, RangeStore } from '@holdem-api/holdem-sdk'
|
|
7
|
+
import type { PublicPolicy } from '@holdem-api/holdem-sdk'
|
|
8
|
+
|
|
9
|
+
const holdem = new HoldemClient({
|
|
10
|
+
apiKey: process.env.HOLDEM_API_KEY!,
|
|
11
|
+
baseUrl: process.env.HOLDEM_API_URL!, // origin without /api
|
|
12
|
+
})
|
|
13
|
+
const ranges = new RangeStore()
|
|
14
|
+
|
|
15
|
+
async function decide(handId: string, playerId: string, policy: PublicPolicy) {
|
|
16
|
+
const result = await holdem.actions({
|
|
17
|
+
policy,
|
|
18
|
+
hand: 'AsAh',
|
|
19
|
+
range: ranges.get(handId, playerId),
|
|
20
|
+
// opponentRanges: [ranges.get(handId, opponentId) ?? null],
|
|
21
|
+
})
|
|
22
|
+
// Your engine executes result.chosenAction, sampling sizes/weights on aggression.
|
|
23
|
+
// Only AFTER successful execution of that action:
|
|
24
|
+
// ranges.record(handId, playerId, result, executedAction)
|
|
25
|
+
return result
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`predictActions` is an alias with the same request and response. This replaces the original unpublished SDK's legacy state-based prediction, separate range-update, and equity methods.
|
|
30
|
+
|
|
31
|
+
Supply the exact public encoder output as `policy`: schemaVersion `holdem-public-board-joint-v1`, 316 context features, chronological history of at most 512 events with 32 features each, and legalMask `[fold, passive, aggressive]`. Use the API/parser public encoder; an ordinary game snapshot is not that encoding. Context has board slots (260), actor (9), street (4), six log-scaled amounts/counts, nine public seat records (36), and remaining opponents / 9. Amount scaling is `log1p(max(0,value))/log1p(400)`.
|
|
32
|
+
|
|
33
|
+
## Complete response
|
|
34
|
+
|
|
35
|
+
- `equity`, `uniformEquity`, `equityBasis`, optional `opponentEquity`.
|
|
36
|
+
- `output`: hand-specific action probabilities; `population`: public model targets.
|
|
37
|
+
- `chosenAction`: sampled fold/call/raise or check/bet. No size is sampled.
|
|
38
|
+
- `sizes` and `weights`: conditional aggression sizing distribution. Your engine applies legal payments, raises, all-ins and side pots.
|
|
39
|
+
- `range`: normalized actor posterior conditioned on chosenAction.
|
|
40
|
+
- `expectedValues`: simplified uniform heads-up showdown benchmark in BB. Assumes one caller, no fold equity, no future betting, no rake or side pots; not strategic or opponent-range-aware EV.
|
|
41
|
+
- Optional `learnedExpectedValues`: experimental observed-action historical returns, only when configured on the API server. Not validated counterfactual action values.
|
|
42
|
+
- `improvementPotential`, `improvement`, allocation identifiers, and all additional server fields are preserved.
|
|
43
|
+
|
|
44
|
+
## Ranges
|
|
45
|
+
|
|
46
|
+
`WeightedRange` maps exact two-card combos to nonnegative weights. Omit `range` for a uniform board-compatible actor population. Pass a prior to track a reached range; the actual hand must have positive mass. Do not initialize a range with just the known hand. Optional `opponentRanges` has one map or null (uniform) per remaining opponent; never send revealed opponents' actual cards.
|
|
47
|
+
|
|
48
|
+
`RangeStore` provides `set`, `get`, `record`, and `clear(handId?)`. It copies snapshots and isolates each hand/player. It is in memory; persist snapshots using your application's database if they must survive restarts. Explicitly record a posterior only after executing chosenAction. A different action requires a different posterior that this request did not return. Serialize calls/updates per player to prevent stale writes. Clear completed hands. The API itself stores no ranges. This SDK does not infer ranges for observed opponent actions.
|
|
49
|
+
|
|
50
|
+
## Errors
|
|
51
|
+
|
|
52
|
+
`HoldemValidationError` rejects local invalid input before sending. `HoldemApiError` includes status and body. `HoldemResponseError` rejects malformed successful responses. `HoldemTransportError` wraps network, timeout and cancellation failures. Methods accept `{signal}` as the second argument. Default timeout is 60 seconds and covers body reading. No automatic retries. Keys use `x-api-key`; keep credentials on your backend.
|
|
53
|
+
|
|
54
|
+
## Build, package and publish
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
npm ci
|
|
58
|
+
npm test
|
|
59
|
+
npm pack
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The package is configured for public publication as `@holdem-api/holdem-sdk` under the MIT license. For publication:
|
|
63
|
+
|
|
64
|
+
1. Create or obtain access to the `holdem-api` npm organization. The package name is configured as `@holdem-api/holdem-sdk`. The public access setting and MIT license are already configured.
|
|
65
|
+
2. Run `npm login` and complete npm's browser authentication/2FA.
|
|
66
|
+
3. Run `npm test` and `npm pack --dry-run` to inspect contents.
|
|
67
|
+
4. Run `npm publish --access public` and complete any npm verification prompt.
|
|
68
|
+
5. In the consuming project, run `npm install @holdem-api/holdem-sdk`.
|
|
69
|
+
|
|
70
|
+
Do not put credentials in source or the package. Before publishing another release, bump the version with `npm version patch` (requires a clean git checkout) or edit the version and update the lockfile.
|
|
71
|
+
|
|
72
|
+
For a live smoke test, set HOLDEM_API_KEY and HOLDEM_API_URL, place a valid encoded request in a JSON file, then run `node examples/quickstart.mjs path/to/request.json`. This consumes API quota.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { HoldemValidationError } from './validation.js';
|
|
3
|
+
import type { CallOptions, ClientOptions, ActionsInput, ActionsResult } from './types.js';
|
|
4
|
+
export { RangeStore } from './ranges.js';
|
|
5
|
+
export declare class HoldemApiError extends Error {
|
|
6
|
+
readonly status: number;
|
|
7
|
+
readonly body: unknown;
|
|
8
|
+
constructor(message: string, status: number, body: unknown);
|
|
9
|
+
}
|
|
10
|
+
export declare class HoldemTransportError extends Error {
|
|
11
|
+
constructor(message: string, cause: unknown);
|
|
12
|
+
}
|
|
13
|
+
export declare class HoldemResponseError extends Error {
|
|
14
|
+
readonly status: number;
|
|
15
|
+
constructor(status: number);
|
|
16
|
+
}
|
|
17
|
+
/** Server-side client. Credentials are sent only in the x-api-key header. No automatic retries. */
|
|
18
|
+
export declare class HoldemClient {
|
|
19
|
+
private readonly baseUrl;
|
|
20
|
+
private readonly apiKey;
|
|
21
|
+
private readonly timeoutMs;
|
|
22
|
+
private readonly transport;
|
|
23
|
+
constructor(config: ClientOptions);
|
|
24
|
+
/** Returns the complete action response without dropping analysis or optional fields. */
|
|
25
|
+
actions(input: ActionsInput, call?: CallOptions): Promise<ActionsResult>;
|
|
26
|
+
/** Alias for actions; uses the same /api/actions contract. */
|
|
27
|
+
predictActions(input: ActionsInput, call?: CallOptions): Promise<ActionsResult>;
|
|
28
|
+
private post;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEzF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,qBAAa,cAAe,SAAQ,KAAK;aACM,MAAM,EAAE,MAAM;aAAkB,IAAI,EAAE,OAAO;gBAA9E,OAAO,EAAE,MAAM,EAAkB,MAAM,EAAE,MAAM,EAAkB,IAAI,EAAE,OAAO;CAG3F;AACD,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAC5C;AACD,qBAAa,mBAAoB,SAAQ,KAAK;aAChB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAC3C;AAkBD,mGAAmG;AACnG,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;gBACvC,MAAM,EAAE,aAAa;IAWjC,yFAAyF;IACnF,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAI9E,8DAA8D;IACxD,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;YAGvE,IAAI;CA2BnB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { HoldemValidationError } from './validation.js';
|
|
3
|
+
import { check, validateActions, range } from './validation.js';
|
|
4
|
+
export { RangeStore } from './ranges.js';
|
|
5
|
+
export class HoldemApiError extends Error {
|
|
6
|
+
status;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, status, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.body = body;
|
|
12
|
+
this.name = 'HoldemApiError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class HoldemTransportError extends Error {
|
|
16
|
+
constructor(message, cause) { super(message, { cause }); this.name = 'HoldemTransportError'; }
|
|
17
|
+
}
|
|
18
|
+
export class HoldemResponseError extends Error {
|
|
19
|
+
status;
|
|
20
|
+
constructor(status) {
|
|
21
|
+
super('Holdem API returned an invalid response');
|
|
22
|
+
this.status = status;
|
|
23
|
+
this.name = 'HoldemResponseError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const object = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
27
|
+
const probability = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1;
|
|
28
|
+
function validActions(v) {
|
|
29
|
+
if (!object(v) || v.ok !== true || typeof v.facingBet !== 'boolean' || !object(v.output))
|
|
30
|
+
return false;
|
|
31
|
+
const keys = v.facingBet ? ['fold', 'call', 'raise'] : ['check', 'bet'];
|
|
32
|
+
const output = v.output;
|
|
33
|
+
if (!keys.every(k => probability(output[k])) || Math.abs(keys.reduce((s, k) => s + Number(output[k]), 0) - 1) > 1e-6)
|
|
34
|
+
return false;
|
|
35
|
+
if (!keys.includes(String(v.chosenAction)) || !(Number(output[String(v.chosenAction)]) > 0))
|
|
36
|
+
return false;
|
|
37
|
+
try {
|
|
38
|
+
range(v.range, []);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return object(v.range) && Math.abs(Object.values(v.range).reduce((s, n) => s + Number(n), 0) - 1) < 1e-6 &&
|
|
44
|
+
typeof v.requestId === 'string' && typeof v.hand === 'string' && probability(v.equity) && probability(v.uniformEquity) &&
|
|
45
|
+
typeof v.equityBasis === 'string' && object(v.expectedValues) && object(v.expectedValues.output) &&
|
|
46
|
+
object(v.population) && ['fold', 'passive', 'aggressive'].every(k => probability(v.population[k])) &&
|
|
47
|
+
Array.isArray(v.sizes) && v.sizes.every(x => typeof x === 'string') &&
|
|
48
|
+
Array.isArray(v.weights) && v.weights.length === v.sizes.length && v.weights.every(probability);
|
|
49
|
+
}
|
|
50
|
+
/** Server-side client. Credentials are sent only in the x-api-key header. No automatic retries. */
|
|
51
|
+
export class HoldemClient {
|
|
52
|
+
baseUrl;
|
|
53
|
+
apiKey;
|
|
54
|
+
timeoutMs;
|
|
55
|
+
transport;
|
|
56
|
+
constructor(config) {
|
|
57
|
+
check(typeof config.apiKey === 'string' && config.apiKey.trim().length > 0, 'apiKey is required');
|
|
58
|
+
let url;
|
|
59
|
+
try {
|
|
60
|
+
url = new URL(config.baseUrl);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error('baseUrl must be an absolute HTTP(S) URL');
|
|
64
|
+
}
|
|
65
|
+
check(['http:', 'https:'].includes(url.protocol) && !url.username && !url.password && !url.search && !url.hash, 'Invalid baseUrl');
|
|
66
|
+
this.baseUrl = url.href.replace(/\/$/, '');
|
|
67
|
+
this.apiKey = config.apiKey;
|
|
68
|
+
this.timeoutMs = config.timeoutMs ?? 60_000;
|
|
69
|
+
check(Number.isInteger(this.timeoutMs) && this.timeoutMs > 0 && this.timeoutMs <= 2147483647, 'Invalid timeoutMs');
|
|
70
|
+
this.transport = config.fetch ?? globalThis.fetch;
|
|
71
|
+
check(typeof this.transport === 'function', 'fetch is required');
|
|
72
|
+
}
|
|
73
|
+
/** Returns the complete action response without dropping analysis or optional fields. */
|
|
74
|
+
async actions(input, call) {
|
|
75
|
+
validateActions(input);
|
|
76
|
+
return this.post('/api/actions', input, validActions, call);
|
|
77
|
+
}
|
|
78
|
+
/** Alias for actions; uses the same /api/actions contract. */
|
|
79
|
+
async predictActions(input, call) {
|
|
80
|
+
return this.actions(input, call);
|
|
81
|
+
}
|
|
82
|
+
async post(path, payload, valid, call) {
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
const abort = () => controller.abort(call?.signal?.reason);
|
|
85
|
+
if (call?.signal?.aborted)
|
|
86
|
+
abort();
|
|
87
|
+
else
|
|
88
|
+
call?.signal?.addEventListener('abort', abort, { once: true });
|
|
89
|
+
const timer = setTimeout(() => controller.abort(new Error('Holdem request timed out')), this.timeoutMs);
|
|
90
|
+
try {
|
|
91
|
+
let response;
|
|
92
|
+
let body;
|
|
93
|
+
try {
|
|
94
|
+
response = await this.transport(`${this.baseUrl}${path}`, {
|
|
95
|
+
method: 'POST', redirect: 'error', signal: controller.signal,
|
|
96
|
+
headers: { 'Content-Type': 'application/json', 'x-api-key': this.apiKey },
|
|
97
|
+
body: JSON.stringify(payload),
|
|
98
|
+
});
|
|
99
|
+
const raw = await response.text();
|
|
100
|
+
try {
|
|
101
|
+
body = JSON.parse(raw);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
body = null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (cause) {
|
|
108
|
+
throw new HoldemTransportError('Holdem request failed, timed out, or was cancelled', cause);
|
|
109
|
+
}
|
|
110
|
+
if (!response.ok || (object(body) && body.ok === false)) {
|
|
111
|
+
throw new HoldemApiError(`Holdem API request failed (${response.status})`, response.status, body);
|
|
112
|
+
}
|
|
113
|
+
if (!valid(body))
|
|
114
|
+
throw new HoldemResponseError(response.status);
|
|
115
|
+
return body;
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
call?.signal?.removeEventListener('abort', abort);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/ranges.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ActionType, ActionsResult, WeightedRange } from './types.js';
|
|
2
|
+
/** In-memory ranges keyed by hand and player. Persist get() snapshots in your application if needed. */
|
|
3
|
+
export declare class RangeStore {
|
|
4
|
+
private readonly hands;
|
|
5
|
+
get(handId: string, playerId: string): WeightedRange | undefined;
|
|
6
|
+
set(handId: string, playerId: string, value: WeightedRange): void;
|
|
7
|
+
/** Call after the engine executes the returned action. Serialize updates per player. */
|
|
8
|
+
record(handId: string, playerId: string, result: ActionsResult, executedAction: ActionType): void;
|
|
9
|
+
clear(handId?: string): void;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=ranges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranges.d.ts","sourceRoot":"","sources":["../src/ranges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG1E,wGAAwG;AACxG,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAC,SAAS;IAI9D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAOjE,wFAAwF;IACxF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,GAAG,IAAI;IAIjG,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;CAI7B"}
|
package/dist/ranges.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { check, range } from './validation.js';
|
|
2
|
+
/** In-memory ranges keyed by hand and player. Persist get() snapshots in your application if needed. */
|
|
3
|
+
export class RangeStore {
|
|
4
|
+
hands = new Map();
|
|
5
|
+
get(handId, playerId) {
|
|
6
|
+
const value = this.hands.get(handId)?.get(playerId);
|
|
7
|
+
return value === undefined ? undefined : { ...value };
|
|
8
|
+
}
|
|
9
|
+
set(handId, playerId, value) {
|
|
10
|
+
check(handId.length > 0 && playerId.length > 0, 'handId and playerId are required');
|
|
11
|
+
range(value, []);
|
|
12
|
+
let players = this.hands.get(handId);
|
|
13
|
+
if (!players) {
|
|
14
|
+
players = new Map();
|
|
15
|
+
this.hands.set(handId, players);
|
|
16
|
+
}
|
|
17
|
+
players.set(playerId, { ...value });
|
|
18
|
+
}
|
|
19
|
+
/** Call after the engine executes the returned action. Serialize updates per player. */
|
|
20
|
+
record(handId, playerId, result, executedAction) {
|
|
21
|
+
check(executedAction === result.chosenAction, 'Range is conditioned on chosenAction; executed action differs');
|
|
22
|
+
this.set(handId, playerId, result.range);
|
|
23
|
+
}
|
|
24
|
+
clear(handId) {
|
|
25
|
+
if (handId === undefined)
|
|
26
|
+
this.hands.clear();
|
|
27
|
+
else
|
|
28
|
+
this.hands.delete(handId);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ranges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranges.js","sourceRoot":"","sources":["../src/ranges.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAE9C,wGAAwG;AACxG,MAAM,OAAO,UAAU;IACJ,KAAK,GAAG,IAAI,GAAG,EAAsC,CAAA;IACtE,GAAG,CAAC,MAAc,EAAE,QAAgB;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;QACnD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAA;IACvD,CAAC;IACD,GAAG,CAAC,MAAc,EAAE,QAAgB,EAAE,KAAoB;QACxD,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,kCAAkC,CAAC,CAAA;QACnF,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QAChB,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;YAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;IACrC,CAAC;IACD,wFAAwF;IACxF,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,MAAqB,EAAE,cAA0B;QACxF,KAAK,CAAC,cAAc,KAAK,MAAM,CAAC,YAAY,EAAE,+DAA+D,CAAC,CAAA;QAC9G,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1C,CAAC;IACD,KAAK,CAAC,MAAe;QACnB,IAAI,MAAM,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;;YACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAChC,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export type Rank = '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'T' | 'J' | 'Q' | 'K' | 'A';
|
|
2
|
+
export type Card = `${Rank}${'c' | 'd' | 'h' | 's'}`;
|
|
3
|
+
export type WeightedRange = Readonly<Record<string, number>>;
|
|
4
|
+
export type ActionType = 'fold' | 'check' | 'call' | 'bet' | 'raise';
|
|
5
|
+
export type PlayerStyle = 'tight-passive' | 'tight-aggressive' | 'loose-passive' | 'loose-aggressive';
|
|
6
|
+
/** Exact public encoder output. No private-card features. */
|
|
7
|
+
export interface PublicPolicy {
|
|
8
|
+
schemaVersion: 'holdem-public-board-joint-v1';
|
|
9
|
+
context: readonly number[];
|
|
10
|
+
history: readonly (readonly number[])[];
|
|
11
|
+
legalMask: readonly [0 | 1, 0 | 1, 0 | 1];
|
|
12
|
+
}
|
|
13
|
+
export interface ActionsInput {
|
|
14
|
+
policy: PublicPolicy;
|
|
15
|
+
hand: string;
|
|
16
|
+
range?: WeightedRange;
|
|
17
|
+
opponentRanges?: readonly (WeightedRange | null)[];
|
|
18
|
+
gateSlope?: number;
|
|
19
|
+
style?: PlayerStyle;
|
|
20
|
+
policyVersion?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CallOptions {
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}
|
|
25
|
+
export interface ClientOptions {
|
|
26
|
+
apiKey: string;
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
fetch?: typeof globalThis.fetch;
|
|
30
|
+
}
|
|
31
|
+
export type ActionOutput<T> = {
|
|
32
|
+
fold: T;
|
|
33
|
+
call: T;
|
|
34
|
+
raise: T;
|
|
35
|
+
} | {
|
|
36
|
+
check: T;
|
|
37
|
+
bet: T;
|
|
38
|
+
};
|
|
39
|
+
export interface ExpectedValues {
|
|
40
|
+
units: 'BB';
|
|
41
|
+
model: string;
|
|
42
|
+
output: ActionOutput<number | null>;
|
|
43
|
+
sizing: {
|
|
44
|
+
size: string;
|
|
45
|
+
paymentBB: number | null;
|
|
46
|
+
evBB: number | null;
|
|
47
|
+
}[];
|
|
48
|
+
assumptions?: string[];
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface ActionsResult {
|
|
52
|
+
ok: true;
|
|
53
|
+
requestId: string;
|
|
54
|
+
hand: string;
|
|
55
|
+
equity: number;
|
|
56
|
+
uniformEquity: number;
|
|
57
|
+
equityBasis: 'uniform-heads-up' | 'opponent-ranges-pot-share';
|
|
58
|
+
facingBet: boolean;
|
|
59
|
+
output: ActionOutput<number>;
|
|
60
|
+
chosenAction: ActionType;
|
|
61
|
+
/** Posterior conditioned on chosenAction; save only after executing that action. */
|
|
62
|
+
range: Record<string, number>;
|
|
63
|
+
population: {
|
|
64
|
+
fold: number;
|
|
65
|
+
passive: number;
|
|
66
|
+
aggressive: number;
|
|
67
|
+
};
|
|
68
|
+
sizes: string[];
|
|
69
|
+
weights: number[];
|
|
70
|
+
expectedValues: ExpectedValues;
|
|
71
|
+
learnedExpectedValues?: ExpectedValues;
|
|
72
|
+
opponentEquity?: {
|
|
73
|
+
equity: number;
|
|
74
|
+
[key: string]: unknown;
|
|
75
|
+
};
|
|
76
|
+
improvementPotential: number;
|
|
77
|
+
improvement: {
|
|
78
|
+
method: string;
|
|
79
|
+
equityGainThreshold: number;
|
|
80
|
+
samplesPerNextCard: number | null;
|
|
81
|
+
applicable: boolean;
|
|
82
|
+
samplesPerCandidate?: number;
|
|
83
|
+
};
|
|
84
|
+
gateSlope: number;
|
|
85
|
+
allocationVersion: string;
|
|
86
|
+
allocationCalibration: string;
|
|
87
|
+
allocationPopulation: string;
|
|
88
|
+
policyVersion?: string;
|
|
89
|
+
style?: PlayerStyle;
|
|
90
|
+
[key: string]: unknown;
|
|
91
|
+
}
|
|
92
|
+
export type PredictActionsInput = ActionsInput;
|
|
93
|
+
export type PredictActionsResult = ActionsResult;
|
|
94
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ActionsInput, WeightedRange } from './types.js';
|
|
2
|
+
export declare class HoldemValidationError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function check(condition: unknown, message: string): asserts condition;
|
|
6
|
+
export declare function amount(value: number, label: string): void;
|
|
7
|
+
export declare function cards(values: readonly string[]): void;
|
|
8
|
+
export declare function range(value: WeightedRange | undefined, board: readonly string[]): void;
|
|
9
|
+
export declare function validateActions(input: ActionsInput): void;
|
|
10
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC7D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAC5B;AACD,wBAAgB,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAE5E;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEzD;AACD,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAGrD;AACD,wBAAgB,KAAK,CAAC,KAAK,EAAE,aAAa,GAAC,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAcpF;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CA0BzD"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export class HoldemValidationError extends Error {
|
|
2
|
+
constructor(message) { super(message); this.name = 'HoldemValidationError'; }
|
|
3
|
+
}
|
|
4
|
+
export function check(condition, message) {
|
|
5
|
+
if (!condition)
|
|
6
|
+
throw new HoldemValidationError(message);
|
|
7
|
+
}
|
|
8
|
+
export function amount(value, label) {
|
|
9
|
+
check(Number.isFinite(value) && value >= 0, `${label} must be finite and nonnegative`);
|
|
10
|
+
}
|
|
11
|
+
export function cards(values) {
|
|
12
|
+
check(Array.isArray(values) && values.every(c => typeof c === 'string' && /^[2-9TJQKA][cdhs]$/.test(c)), 'Invalid card notation');
|
|
13
|
+
check(new Set(values).size === values.length, 'Duplicate physical card');
|
|
14
|
+
}
|
|
15
|
+
export function range(value, board) {
|
|
16
|
+
if (value === undefined)
|
|
17
|
+
return;
|
|
18
|
+
check(value !== null && typeof value === 'object' && !Array.isArray(value), 'Range must be a combo-weight map');
|
|
19
|
+
let mass = 0;
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
for (const [combo, weight] of Object.entries(value)) {
|
|
22
|
+
check(/^[2-9TJQKA][cdhs][2-9TJQKA][cdhs]$/.test(combo), `Invalid combo: ${combo}`);
|
|
23
|
+
const pair = [combo.slice(0, 2), combo.slice(2)];
|
|
24
|
+
cards(pair);
|
|
25
|
+
amount(weight, 'Range weight');
|
|
26
|
+
const key = pair.slice().sort().join('');
|
|
27
|
+
check(!seen.has(key), `Duplicate reversed combo: ${combo}`);
|
|
28
|
+
seen.add(key);
|
|
29
|
+
if (!pair.some(c => board.includes(c)))
|
|
30
|
+
mass += weight;
|
|
31
|
+
}
|
|
32
|
+
check(Number.isFinite(mass) && mass > 0, 'Range must have positive unblocked mass');
|
|
33
|
+
}
|
|
34
|
+
export function validateActions(input) {
|
|
35
|
+
check(input && typeof input === 'object', 'Actions input is required');
|
|
36
|
+
const policy = input.policy;
|
|
37
|
+
check(policy && policy.schemaVersion === 'holdem-public-board-joint-v1', 'Invalid public policy schema');
|
|
38
|
+
check(Array.isArray(policy.context) && policy.context.length === 316 && policy.context.every(Number.isFinite), 'context requires 316 finite features');
|
|
39
|
+
check(Array.isArray(policy.history) && policy.history.length <= 512 && policy.history.every(row => Array.isArray(row) && row.length === 32 && row.every(Number.isFinite)), 'history requires at most 512 events of 32 finite features');
|
|
40
|
+
check(Array.isArray(policy.legalMask) && policy.legalMask.length === 3 && policy.legalMask.every(x => x === 0 || x === 1) && policy.legalMask.some(x => x === 1), 'Invalid legalMask');
|
|
41
|
+
check(typeof input.hand === 'string' && /^[2-9TJQKA][cdhs][2-9TJQKA][cdhs]$/.test(input.hand), 'hand requires an exact combo');
|
|
42
|
+
const board = [];
|
|
43
|
+
let empty = false;
|
|
44
|
+
for (let slot = 0; slot < 5; slot++) {
|
|
45
|
+
const block = policy.context.slice(slot * 52, (slot + 1) * 52);
|
|
46
|
+
check(block.every(x => x === 0 || x === 1) && block.reduce((s, n) => s + n, 0) <= 1, 'Board slots must be one-hot or empty');
|
|
47
|
+
const index = block.indexOf(1);
|
|
48
|
+
if (index < 0)
|
|
49
|
+
empty = true;
|
|
50
|
+
else {
|
|
51
|
+
check(!empty, 'Board slots must be contiguous');
|
|
52
|
+
board.push('23456789TJQKA'[Math.floor(index / 4)] + 'cdhs'[index % 4]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
cards([input.hand.slice(0, 2), input.hand.slice(2), ...board]);
|
|
56
|
+
range(input.range, board);
|
|
57
|
+
if (input.range)
|
|
58
|
+
check((input.range[input.hand] ?? input.range[input.hand.slice(2) + input.hand.slice(0, 2)] ?? 0) > 0, 'Hand must have positive range weight');
|
|
59
|
+
if (input.opponentRanges !== undefined) {
|
|
60
|
+
check(Array.isArray(input.opponentRanges) && Math.abs(input.opponentRanges.length - policy.context[315] * 9) < 1e-6, 'opponentRanges must match remaining opponents');
|
|
61
|
+
input.opponentRanges.forEach(r => { if (r !== null)
|
|
62
|
+
range(r, board); });
|
|
63
|
+
}
|
|
64
|
+
if (input.gateSlope !== undefined)
|
|
65
|
+
check(Number.isFinite(input.gateSlope) && input.gateSlope > 0 && input.gateSlope <= 200, 'gateSlope must be in (0, 200]');
|
|
66
|
+
if (input.style !== undefined)
|
|
67
|
+
check(['tight-passive', 'tight-aggressive', 'loose-passive', 'loose-aggressive'].includes(input.style), 'Invalid style');
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@holdem-api/holdem-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@holdem-api/holdem-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed server-side client for Holdem API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
24
|
+
"test": "npm run build && node --test test/client.test.mjs",
|
|
25
|
+
"prepack": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "5.7.3"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|