@dopamint-fun/open-sdk 0.2.0-dev.1 → 0.2.0-dev.2

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/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ import { claimInviteLink, encodeClaimInvite, encodeClaimInviteCompact, mintClaim
23
23
  import { acceptAndAwaitAdmission } from "./offer.js";
24
24
  import { playTour, queueUntilSeated } from "./tour.js";
25
25
  import { joinRoomWhenComposed, MIN_ROOM_SEATS, openRoom, roomInvitePrompt, } from "./room.js";
26
- import { disputeHolding, JoinRefused, joinTransaction, leaveTransaction, listTournaments, matchmakingOverLine, planJoin, presentToTournament, readAgentEntry, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, } from "./openTournament.js";
26
+ import { disputeHolding, JoinRefused, joinTransaction, leaveTransaction, listTournaments, matchmakingOverLine, planJoin, presentToTournament, readAgentEntry, readAgentEntrySettled, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, } from "./openTournament.js";
27
27
  import { authorityOriginFromSessionBase, buildConsentRequest, digestForPrompt, settlementConsentPath, verifyConsentDisclosure, } from "./settlement.js";
28
28
  import { actionSigningBytes, joinSigningBytes, requireSessionVersion, resumeSigningBytes, SESSION_VERSION, } from "./sessionWire.js";
29
29
  import { describeNext, refusalMessageFromText } from "./refusal.js";
@@ -1471,8 +1471,16 @@ async function commandTournament(args) {
1471
1471
  return;
1472
1472
  }
1473
1473
  if (verb === "leave") {
1474
- if (entry?.state !== "queued")
1475
- fail(`this agent is ${entry?.state ?? "not in the book"}; only a queued agent can leave, and a seated one plays its table out`);
1474
+ /* An agent that queued a moment ago is on chain and not yet in the book,
1475
+ which is read a checkpoint behind it. Refusing on the first read told an
1476
+ agent that had just been printed `queued waiting` that it was not in the
1477
+ book at all, and the refusal's own `next` sent it to join again — which
1478
+ would queue an agent that is already queued. So an absent entry is
1479
+ waited out, briefly, before it is believed. */
1480
+ const settled = entry ??
1481
+ (await readAgentEntrySettled(productUrl, tournamentId, chip));
1482
+ if (settled?.state !== "queued")
1483
+ fail(`this agent is ${settled?.state ?? "not in the book"}; only a queued agent can leave, and a seated one plays its table out`);
1476
1484
  const executed = await sponsorAndExecute(client, leaveTransaction(overview, chip));
1477
1485
  console.log(`left ${executed.digest} ${executed.status}`);
1478
1486
  if (executed.status !== "success")
package/dist/index.d.ts CHANGED
@@ -17,5 +17,5 @@ export { handEquity, requiredEquity, cardCode, type HandEquity, type HandEquityO
17
17
  export { cardIndex, handCategory, scoreHand, HAND_CATEGORIES, RANK_ORDER, SUIT_ORDER, type BestFive, type HandCategory, } from "./handRank.js";
18
18
  export { DEFAULT_SEAT_STATE_FILE, loadSeatState, saveSeatState, type SeatSessionState, } from "./seatState.js";
19
19
  export { newSeatState, openTurn, submitTurn, type SeatStateCheckpoint, type SeatTurnOutcome, type SeatTurnPosition, } from "./seatTurn.js";
20
- export { chipAddressOf, joinTransaction, leaveTransaction, listTournaments, planJoin, presentToTournament, readAgentEntry, readPass, readOwner, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, tournamentPossessionSignature, JoinRefused, TournamentRefusal, TOURNAMENT_POSSESSION_SEAT, type JoinPlan, type SponsoredExecution, type TournamentAgentEntry, type TournamentPass, type TournamentPlay, type TournamentOwnerView, type TournamentOwnerAgent, type TournamentChainObjects, type TournamentClient, type TournamentOverview, type TournamentQueueEntry, } from "./openTournament.js";
20
+ export { chipAddressOf, joinTransaction, leaveTransaction, listTournaments, planJoin, presentToTournament, readAgentEntry, readAgentEntrySettled, BOOK_CATCHES_UP_MS, readPass, readOwner, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, tournamentPossessionSignature, JoinRefused, TournamentRefusal, TOURNAMENT_POSSESSION_SEAT, type JoinPlan, type SponsoredExecution, type TournamentAgentEntry, type TournamentPass, type TournamentPlay, type TournamentOwnerView, type TournamentOwnerAgent, type TournamentChainObjects, type TournamentClient, type TournamentOverview, type TournamentQueueEntry, } from "./openTournament.js";
21
21
  export { ClientRefusal, describeNext, refusalLines, refusalMessage, refusalMessageFromText, type RefusalBody, type RefusalNext, } from "./refusal.js";
package/dist/index.js CHANGED
@@ -29,5 +29,5 @@ export { handEquity, requiredEquity, cardCode, } from "./equity.js";
29
29
  export { cardIndex, handCategory, scoreHand, HAND_CATEGORIES, RANK_ORDER, SUIT_ORDER, } from "./handRank.js";
30
30
  export { DEFAULT_SEAT_STATE_FILE, loadSeatState, saveSeatState, } from "./seatState.js";
31
31
  export { newSeatState, openTurn, submitTurn, } from "./seatTurn.js";
32
- export { chipAddressOf, joinTransaction, leaveTransaction, listTournaments, planJoin, presentToTournament, readAgentEntry, readPass, readOwner, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, tournamentPossessionSignature, JoinRefused, TournamentRefusal, TOURNAMENT_POSSESSION_SEAT, } from "./openTournament.js";
32
+ export { chipAddressOf, joinTransaction, leaveTransaction, listTournaments, planJoin, presentToTournament, readAgentEntry, readAgentEntrySettled, BOOK_CATCHES_UP_MS, readPass, readOwner, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, tournamentPossessionSignature, JoinRefused, TournamentRefusal, TOURNAMENT_POSSESSION_SEAT, } from "./openTournament.js";
33
33
  export { ClientRefusal, describeNext, refusalLines, refusalMessage, refusalMessageFromText, } from "./refusal.js";
@@ -143,6 +143,28 @@ export declare function readTournamentMatches(productUrl: string, tournamentId:
143
143
  export declare function disputeHolding(productUrl: string, tournamentId: string, chipAddress: string, fetchImpl?: typeof fetch): Promise<number | undefined>;
144
144
  /** The agent's entry in the chip book, or `null` before its first redeem. */
145
145
  export declare function readAgentEntry(productUrl: string, tournamentId: string, chipAddress: string, fetchImpl?: typeof fetch): Promise<TournamentAgentEntry | null>;
146
+ /** How long a book read waits for a join that has just landed.
147
+ *
148
+ * The book is the chain's, read a checkpoint behind it: an agent whose
149
+ * `queue_join` succeeded a moment ago is on chain and not yet in the book.
150
+ * Measured at about a second on a local stack; this is generous enough to
151
+ * cover a slower one and short enough that an agent that really is absent is
152
+ * told so rather than left waiting. */
153
+ export declare const BOOK_CATCHES_UP_MS = 8000;
154
+ /** The agent's entry, waited for while the book catches up with the chain.
155
+ *
156
+ * For a caller that has just been told its join landed. A plain
157
+ * `readAgentEntry` answering `null` in that window is not "this agent never
158
+ * queued" — it is "the book has not seen the queue join yet", and the two are
159
+ * worth telling apart before refusing somebody. Absent for the whole bound is
160
+ * the first answer, and this returns `null` for it. */
161
+ export declare function readAgentEntrySettled(productUrl: string, tournamentId: string, chipAddress: string, options?: {
162
+ boundMs?: number;
163
+ pollMs?: number;
164
+ fetchImpl?: typeof fetch;
165
+ sleep?: (ms: number) => Promise<void>;
166
+ now?: () => number;
167
+ }): Promise<TournamentAgentEntry | null>;
146
168
  /** An owner's pass, or `null` when the owner has claimed none. */
147
169
  export declare function readPass(productUrl: string, tournamentId: string, owner: string, fetchImpl?: typeof fetch): Promise<TournamentPass | null>;
148
170
  /** An owner's side: its pass and every agent it has claimed, each with the
@@ -100,6 +100,37 @@ export async function readAgentEntry(productUrl, tournamentId, chipAddress, fetc
100
100
  throw new TournamentRefusal(status, json, "chip book read");
101
101
  return json;
102
102
  }
103
+ /** How long a book read waits for a join that has just landed.
104
+ *
105
+ * The book is the chain's, read a checkpoint behind it: an agent whose
106
+ * `queue_join` succeeded a moment ago is on chain and not yet in the book.
107
+ * Measured at about a second on a local stack; this is generous enough to
108
+ * cover a slower one and short enough that an agent that really is absent is
109
+ * told so rather than left waiting. */
110
+ export const BOOK_CATCHES_UP_MS = 8_000;
111
+ /** The agent's entry, waited for while the book catches up with the chain.
112
+ *
113
+ * For a caller that has just been told its join landed. A plain
114
+ * `readAgentEntry` answering `null` in that window is not "this agent never
115
+ * queued" — it is "the book has not seen the queue join yet", and the two are
116
+ * worth telling apart before refusing somebody. Absent for the whole bound is
117
+ * the first answer, and this returns `null` for it. */
118
+ export async function readAgentEntrySettled(productUrl, tournamentId, chipAddress, options = {}) {
119
+ const boundMs = options.boundMs ?? BOOK_CATCHES_UP_MS;
120
+ const pollMs = options.pollMs ?? 1_000;
121
+ const now = options.now ?? Date.now;
122
+ const sleep = options.sleep ??
123
+ ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
124
+ const deadline = now() + boundMs;
125
+ for (;;) {
126
+ const entry = await readAgentEntry(productUrl, tournamentId, chipAddress, options.fetchImpl ?? fetch);
127
+ if (entry)
128
+ return entry;
129
+ if (now() >= deadline)
130
+ return null;
131
+ await sleep(pollMs);
132
+ }
133
+ }
103
134
  /** An owner's pass, or `null` when the owner has claimed none. */
104
135
  export async function readPass(productUrl, tournamentId, owner, fetchImpl = fetch) {
105
136
  const { status, json } = await readJson(fetchImpl, `${base(productUrl)}${tournamentPath(tournamentId, `/passes/${owner}`)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dopamint-fun/open-sdk",
3
- "version": "0.2.0-dev.1",
3
+ "version": "0.2.0-dev.2",
4
4
  "description": "DOPA-OPEN client SDK: generate and hold your own agent key, sign registrations, and play a Participant Session",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {