@dopamint-fun/open-sdk 0.1.0-dev.0 → 0.2.0-dev.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/README.md +8 -1
- package/dist/acceptance.d.ts +6 -0
- package/dist/acceptance.js +34 -0
- package/dist/channel.d.ts +7 -6
- package/dist/channel.js +20 -16
- package/dist/claim.d.ts +19 -1
- package/dist/claim.js +47 -4
- package/dist/cli.js +866 -57
- package/dist/decide.d.ts +16 -0
- package/dist/decide.js +122 -0
- package/dist/equity.d.ts +34 -0
- package/dist/equity.js +99 -0
- package/dist/handRank.d.ts +36 -0
- package/dist/handRank.js +170 -0
- package/dist/identity.js +2 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.js +14 -3
- package/dist/keypair.js +8 -1
- package/dist/offer.d.ts +7 -0
- package/dist/offer.js +38 -7
- package/dist/openTournament.d.ts +211 -0
- package/dist/openTournament.js +337 -0
- package/dist/refusal.d.ts +45 -0
- package/dist/refusal.js +84 -0
- package/dist/room.d.ts +66 -0
- package/dist/room.js +154 -0
- package/dist/seatState.d.ts +91 -0
- package/dist/seatState.js +137 -0
- package/dist/seatTurn.d.ts +138 -0
- package/dist/seatTurn.js +442 -0
- package/dist/session.d.ts +158 -5
- package/dist/session.js +365 -25
- package/dist/sessionCodec.d.ts +6 -0
- package/dist/sessionCodec.js +34 -3
- package/dist/sessionWire.d.ts +20 -0
- package/dist/sessionWire.js +44 -0
- package/dist/tour.d.ts +55 -4
- package/dist/tour.js +88 -11
- package/package.json +1 -1
package/dist/session.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface PlayReport {
|
|
|
18
18
|
terminalCommitment?: string;
|
|
19
19
|
executionId: string;
|
|
20
20
|
sessionBaseUrl: string;
|
|
21
|
+
/** Whether this seat lost its last chip before the sitting ended. */
|
|
22
|
+
eliminated: boolean;
|
|
21
23
|
}
|
|
22
24
|
/** The lines a play door reports for one seat's sitting.
|
|
23
25
|
*
|
|
@@ -26,6 +28,25 @@ export interface PlayReport {
|
|
|
26
28
|
* document recommends - omitted the terminal values `consent` requires, so
|
|
27
29
|
* the recommended path could not reach settlement. */
|
|
28
30
|
export declare function playReportLines(report: PlayReport): string[];
|
|
31
|
+
/** How often a seat with nothing to decide reads the public table.
|
|
32
|
+
*
|
|
33
|
+
* A seat that is out of the hand, or out of the sitting, is sent views with no
|
|
34
|
+
* legal actions for as long as the others play, and the table used to be read
|
|
35
|
+
* only when there was a decision to make -- so a busted seat read nothing and
|
|
36
|
+
* printed nothing for the rest of the sitting. Slow, because the read is the
|
|
37
|
+
* same one the anonymous cap counts. */
|
|
38
|
+
export declare const IDLE_TABLE_READ_MS = 5000;
|
|
39
|
+
/** Watches the public table for this seat losing its last chip.
|
|
40
|
+
*
|
|
41
|
+
* Out means no chips and not all in: a seat all in with nothing behind is
|
|
42
|
+
* still in the hand, and only once the hand has settled against it does its
|
|
43
|
+
* stack read zero with no bet out. `observe` answers true exactly once, the
|
|
44
|
+
* first time it sees that, so the line it drives is printed once however many
|
|
45
|
+
* hands the others go on to play. */
|
|
46
|
+
export declare function eliminationWatch(seat: number): {
|
|
47
|
+
readonly eliminated: boolean;
|
|
48
|
+
observe(table: OpenTableView | null): boolean;
|
|
49
|
+
};
|
|
29
50
|
export declare class SessionRefusal extends Error {
|
|
30
51
|
readonly tag: number;
|
|
31
52
|
readonly retryable: boolean;
|
|
@@ -35,6 +56,10 @@ export declare class SessionRefusal extends Error {
|
|
|
35
56
|
retryable: boolean;
|
|
36
57
|
}, detail?: string);
|
|
37
58
|
}
|
|
59
|
+
/** How long a seat keeps asking for discovery from an origin that is not
|
|
60
|
+
* answering: long enough to outlast a deployment restarting behind it, short
|
|
61
|
+
* enough that a seat whose authority is truly gone still stops. */
|
|
62
|
+
export declare const DISCOVERY_RETRY_BOUND_MS = 90000;
|
|
38
63
|
/** The public table, as the spectator snapshot shows it to everyone.
|
|
39
64
|
*
|
|
40
65
|
* Read once per turn beside the seat's own view, so a decision has the board,
|
|
@@ -104,6 +129,9 @@ export interface PlayArgs {
|
|
|
104
129
|
number: number;
|
|
105
130
|
stack: number | null;
|
|
106
131
|
}) => void;
|
|
132
|
+
/** Called once, when this seat loses its last chip. The loop goes on to the
|
|
133
|
+
* terminal: the sitting still needs this seat's consent. */
|
|
134
|
+
onEliminated?: () => void;
|
|
107
135
|
/** Filler picker for a seat nobody is deciding for. See `decide`. */
|
|
108
136
|
strategy?: "fold-heavy" | "all-in";
|
|
109
137
|
/** The seat's own judgement, called once per turn. See `decide`. */
|
|
@@ -120,9 +148,13 @@ export interface SeatPosition {
|
|
|
120
148
|
view: ViewSnapshot;
|
|
121
149
|
/** Which seat this is, as the authority cut the view. */
|
|
122
150
|
seat: number;
|
|
123
|
-
/** The seat's own two cards
|
|
124
|
-
* the
|
|
125
|
-
|
|
151
|
+
/** The seat's own two cards as `turn` prints them, rank then suit: `["Ah",
|
|
152
|
+
* "Kd"]`; null once it is out of the hand. One shape on both doors, so a
|
|
153
|
+
* decision written against one runs against the other. */
|
|
154
|
+
hole: [string, string] | null;
|
|
155
|
+
/** The same two cards decoded, for a decision that wants rank and suit as
|
|
156
|
+
* values. Read from the view's tail, exactly — see `decodeParticipantView`. */
|
|
157
|
+
holeCards: [Card, Card] | null;
|
|
126
158
|
/** The execution this seat is playing in, `0x`-prefixed. */
|
|
127
159
|
executionId: string;
|
|
128
160
|
/** The public table at this turn, or null where the read did not answer. */
|
|
@@ -199,7 +231,34 @@ export declare class SessionClient {
|
|
|
199
231
|
eventsAfter: bigint;
|
|
200
232
|
private readonly fetchImpl;
|
|
201
233
|
constructor(baseUrl: string, agent: AgentKeypair, seat: number, participantId: Uint8Array, executionId: Uint8Array, executionManifestDigest: Uint8Array, clientNonce: Uint8Array, fetchImpl?: typeof fetch);
|
|
234
|
+
/** How long discovery keeps asking an authority that is not answering.
|
|
235
|
+
*
|
|
236
|
+
* Public so a test can shorten it; nothing else should need to. */
|
|
237
|
+
discoveryRetry: {
|
|
238
|
+
boundMs: number;
|
|
239
|
+
pauseMs: number;
|
|
240
|
+
sleep: (ms: number) => Promise<void>;
|
|
241
|
+
};
|
|
202
242
|
private url;
|
|
243
|
+
/** Requires the authority's published discovery to host the current session
|
|
244
|
+
* contract, before any challenge, signature, or session request.
|
|
245
|
+
*
|
|
246
|
+
* Discovery is a compatibility predicate over published facts, never an
|
|
247
|
+
* authenticity claim: the join handshake is still the admission decision.
|
|
248
|
+
* The body is read under the same bound the shared binding enforces, so a
|
|
249
|
+
* hostile pre-join answer cannot stream into this process. A document that
|
|
250
|
+
* names no compatible contract is final -- an authority that cannot host
|
|
251
|
+
* the session does not become able to by asking again.
|
|
252
|
+
*
|
|
253
|
+
* An origin that did not answer with a document is another matter, and is
|
|
254
|
+
* asked again within `discoveryRetry`. A seat reconnects at whatever moment
|
|
255
|
+
* its stream dropped, and a deployment restarting behind that origin
|
|
256
|
+
* answers 404, 502 or nothing for a few seconds. Taken as final, one such
|
|
257
|
+
* answer ended a seat mid-sitting while its table played on without it, and
|
|
258
|
+
* the clock folded every turn it had left. */
|
|
259
|
+
private requireCompatibleDiscovery;
|
|
260
|
+
private answeredDiscovery;
|
|
261
|
+
private readBoundedDiscovery;
|
|
203
262
|
challenge(): Promise<Uint8Array>;
|
|
204
263
|
private postWire;
|
|
205
264
|
join(): Promise<{
|
|
@@ -217,7 +276,7 @@ export declare class SessionClient {
|
|
|
217
276
|
wire: Uint8Array;
|
|
218
277
|
}>;
|
|
219
278
|
startSubmit(wire: Uint8Array): Promise<Response>;
|
|
220
|
-
acknowledge(context: SessionContext, cursor: ResumeCursor): Promise<void>;
|
|
279
|
+
acknowledge(context: SessionContext, cursor: ResumeCursor, originToken: string): Promise<void>;
|
|
221
280
|
resume(context: SessionContext, cursor: ResumeCursor): Promise<void>;
|
|
222
281
|
answerSeatAuth(challenge: {
|
|
223
282
|
context: SessionContext;
|
|
@@ -227,6 +286,48 @@ export declare class SessionClient {
|
|
|
227
286
|
coordinatorPublicKey: Uint8Array;
|
|
228
287
|
}, coordinatorKey: Uint8Array, timeAuthorityKey: Uint8Array, pending: PendingProposal): Promise<void>;
|
|
229
288
|
}
|
|
289
|
+
/** Everything a seat needs before it can play, from the offer it was admitted
|
|
290
|
+
* through.
|
|
291
|
+
*
|
|
292
|
+
* Lifted out of `playSeat` so the loop and the two short commands (`turn`,
|
|
293
|
+
* `act`) cannot drift on what they check. Every field here is re-derived from
|
|
294
|
+
* the arena on each call, which is what lets a seat be rebuilt in a fresh
|
|
295
|
+
* process: the only things that cannot be re-derived are the client nonce and
|
|
296
|
+
* the resume cursor, and those are what the seat state file keeps. */
|
|
297
|
+
export interface SeatSession {
|
|
298
|
+
client: SessionClient;
|
|
299
|
+
product: string;
|
|
300
|
+
executionHex: string;
|
|
301
|
+
coordinatorKey: Uint8Array;
|
|
302
|
+
timeAuthorityKey: Uint8Array;
|
|
303
|
+
sessionBaseUrl: string;
|
|
304
|
+
executionId: string;
|
|
305
|
+
}
|
|
306
|
+
export interface SeatSessionArgs {
|
|
307
|
+
productUrl: string;
|
|
308
|
+
offerId: string;
|
|
309
|
+
seat: number;
|
|
310
|
+
agent: AgentKeypair;
|
|
311
|
+
agentId: Uint8Array;
|
|
312
|
+
coordinatorKey?: Uint8Array;
|
|
313
|
+
timeAuthorityKey?: Uint8Array;
|
|
314
|
+
/** Stable across processes: the session is keyed by it, and a fresh one
|
|
315
|
+
* would resume nothing. Omitted only on the very first join. */
|
|
316
|
+
clientNonce?: Uint8Array;
|
|
317
|
+
fetchImpl?: typeof fetch;
|
|
318
|
+
/** Bounds on reading the offer through a product restart; tests shorten it. */
|
|
319
|
+
restartRetry?: RestartRetry;
|
|
320
|
+
}
|
|
321
|
+
export interface RestartRetry {
|
|
322
|
+
boundMs: number;
|
|
323
|
+
pauseMs: number;
|
|
324
|
+
sleep?: (ms: number) => Promise<void>;
|
|
325
|
+
}
|
|
326
|
+
/** A GET asked again while the origin answers as a restarting one does -- no
|
|
327
|
+
* answer, 408, 429 or a 5xx -- until `bound` has passed. Any other answer is
|
|
328
|
+
* returned as it came, so a refusal stays the caller's to read. */
|
|
329
|
+
export declare function fetchWhileRestarting(fetchImpl: typeof fetch, url: string, retry?: RestartRetry): Promise<Response>;
|
|
330
|
+
export declare function openSeatSession(args: SeatSessionArgs): Promise<SeatSession>;
|
|
230
331
|
export declare function playSeat(args: PlayArgs): Promise<PlayReport>;
|
|
231
332
|
/** What the play loop does about a refusal, by the refusal's tag.
|
|
232
333
|
*
|
|
@@ -246,6 +347,22 @@ export interface OpenAgentNaming {
|
|
|
246
347
|
* Two surfaces printed the same card two ways, and every agent normalised
|
|
247
348
|
* them itself. */
|
|
248
349
|
export declare function normaliseCardCode(code: string): string;
|
|
350
|
+
/** What the terminal disclosure says one seat takes off the table, read off
|
|
351
|
+
* the spectator snapshot's status.
|
|
352
|
+
*
|
|
353
|
+
* Read rather than assumed: consent checks the seat's chips against it before
|
|
354
|
+
* it signs, and a number a client invented would be refused there. The
|
|
355
|
+
* disclosure is published a moment after the seat sees the terminal, so this
|
|
356
|
+
* waits for it, bounded well inside the consent window.
|
|
357
|
+
*
|
|
358
|
+
* Signed as the seat where a capability is given. A private room's snapshot
|
|
359
|
+
* answers only its seats and owning wallets, so an anonymous read of it never
|
|
360
|
+
* finds an entitlement at all, and a room whose seats read that way never
|
|
361
|
+
* settles. A playground or tournament sitting ignores the capability. */
|
|
362
|
+
export declare function readDisclosedEntitlement(fetchImpl: typeof fetch, product: string, executionId: string, seat: number, capability?: ReadCapability, options?: {
|
|
363
|
+
attempts?: number;
|
|
364
|
+
pauseMs?: number;
|
|
365
|
+
}): Promise<bigint | undefined>;
|
|
249
366
|
/** The public table for one execution, as the spectator snapshot shows it.
|
|
250
367
|
*
|
|
251
368
|
* Best-effort: a read that does not answer is null, never a throw -- the
|
|
@@ -254,7 +371,43 @@ export declare function normaliseCardCode(code: string): string;
|
|
|
254
371
|
*
|
|
255
372
|
* `names` is filled as agents are met and read from after that, so who is
|
|
256
373
|
* in a seat costs one custody read per agent per sitting. */
|
|
257
|
-
|
|
374
|
+
/** What the product says has become of a sitting.
|
|
375
|
+
*
|
|
376
|
+
* `over` is the answer a seat needs: there are no more turns in it, whether
|
|
377
|
+
* because it played out, is being settled, or ended badly. `live` means the
|
|
378
|
+
* table is still running and a seat that cannot attach has a real problem.
|
|
379
|
+
* `unknown` is not a guess -- the product could not say, or could not be
|
|
380
|
+
* reached, and telling an agent its match is over on that basis would be
|
|
381
|
+
* worse than telling it nothing. */
|
|
382
|
+
export type OpenSittingStatus = {
|
|
383
|
+
state: "over";
|
|
384
|
+
detail: "completed" | "settling" | "failed";
|
|
385
|
+
} | {
|
|
386
|
+
state: "live";
|
|
387
|
+
} | {
|
|
388
|
+
state: "unknown";
|
|
389
|
+
};
|
|
390
|
+
/** Read a sitting's status off the public history surface.
|
|
391
|
+
*
|
|
392
|
+
* Its own read rather than part of `readPublicTable`, because that answers
|
|
393
|
+
* what is on the table right now and returns nothing at all once the table is
|
|
394
|
+
* gone -- which is precisely the moment this question is being asked. */
|
|
395
|
+
export declare function readSittingStatus(fetchImpl: typeof fetch, product: string, executionHex: string): Promise<OpenSittingStatus>;
|
|
396
|
+
/** Mints the agent capability for one read, bound to its method and target.
|
|
397
|
+
*
|
|
398
|
+
* A callback rather than a header, because a capability is single-use and
|
|
399
|
+
* signed over the exact request: one minted for the previous poll authorizes
|
|
400
|
+
* nothing here. Null is an answer -- a reader with no key reads anonymously,
|
|
401
|
+
* which is all a playground sitting ever needs. */
|
|
402
|
+
export type ReadCapability = (method: string, requestTarget: string) => Promise<string | null>;
|
|
403
|
+
/** The capability `readPublicTable` asks for, minted on this agent's own key.
|
|
404
|
+
*
|
|
405
|
+
* A private room's live view is owner-session-only unless the reader holds a
|
|
406
|
+
* seat at that room, and the seat says so with the same signature every other
|
|
407
|
+
* Product API call carries. A playground sitting ignores one, so a seat can
|
|
408
|
+
* send it without having to know which kind of table it sat down at. */
|
|
409
|
+
export declare function agentReadCapability(agent: AgentKeypair, agentId: Uint8Array): ReadCapability;
|
|
410
|
+
export declare function readPublicTable(fetchImpl: typeof fetch, product: string, executionHex: string, names?: Map<string, OpenAgentNaming | null>, capability?: ReadCapability): Promise<OpenTableView | null>;
|
|
258
411
|
/** What has been said in one hand, oldest first. Best-effort, like the
|
|
259
412
|
* table: an empty list where the read did not answer. */
|
|
260
413
|
export declare function readTableTalk(fetchImpl: typeof fetch, product: string, executionHex: string, handIndex: number): Promise<OpenTableTalkLine[]>;
|