@dopamint-fun/open-sdk 0.2.0-dev.6 → 0.2.0-dev.8
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 +7 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.js +21 -0
- package/dist/session.d.ts +12 -0
- package/dist/session.js +54 -1
- package/dist/settlement.d.ts +0 -1
- package/dist/settlement.js +0 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ 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
26
|
import { disputeHolding, JoinRefused, joinTransaction, leaveTransaction, listTournaments, matchmakingOverLine, planJoin, presentToTournament, readAgentEntry, readAgentEntrySettled, playsHeldBy, giveBackTransaction, readTournament, sponsorAndExecute, tournamentIdArg, } from "./openTournament.js";
|
|
27
|
-
import {
|
|
27
|
+
import { buildConsentRequest, DEFAULT_OPEN_API_BASE_URL, 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";
|
|
30
30
|
function fail(message) {
|
|
@@ -860,7 +860,12 @@ async function consentToTerminal(options) {
|
|
|
860
860
|
const record = JSON.parse(offerBody);
|
|
861
861
|
if (!record.admission)
|
|
862
862
|
fail("offer is not admitted; there is no execution to settle");
|
|
863
|
-
|
|
863
|
+
/* The settlement verbs live on the product origin — `/v1/authority/…` is
|
|
864
|
+
the product's public route, which forwards to the shard that admitted
|
|
865
|
+
the execution. The session's own origin serves `/v1/exec/` only, so
|
|
866
|
+
deriving the consent root from `session_base_url` asks a listener that
|
|
867
|
+
does not serve this spelling. */
|
|
868
|
+
const origin = options.productUrl.replace(/\/$/, "");
|
|
864
869
|
const path = settlementConsentPath(record.admission.execution_id);
|
|
865
870
|
const promptResponse = await fetch(`${origin}${path}`);
|
|
866
871
|
const promptText = await promptResponse.text();
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export { deriveAgentId, registerCanonicalPayload, registerPayloadDigest, type Re
|
|
|
3
3
|
export { canonicalIdentityPayload, nameAgent, parseIdentityFields, type AgentIdentityFields, type NameAgentArgs, } from "./identity.js";
|
|
4
4
|
export { actionSigningBytes, encodeActionFrame, encodeJoinFrame, encodeResumeFrame, joinSigningBytes, resumeSigningBytes, SESSION_VERSION, UnsupportedSessionVersionError, type ActionProposal, type ArtifactReference, type JoinRequest, type ResumeRequest, type SessionContext, } from "./sessionWire.js";
|
|
5
5
|
export { encodeAckFrame, SESSION_ERROR_NAMES, MAX_PREDICTION_PACING_MS, admitAuthorityEvent, applyPredictionGateStatus, decodeAuthorityMessage, freshSessionBoundary, predictionGateMessage, predictionGatePreparationOf, predictionGateTargetReceipt, sessionErrorHint, sessionErrorName, PredictionGateConflictError, SessionBoundaryError, type AcceptedSessionBoundary, type AuthorityMessage, type PredictionGateMessage, type PredictionGateOpening, type PredictionGatePreparation, type PredictionGateRelease, type PredictionGateStatus, type PredictionWindowRef, type ReceiptRef, type ResumeCursor, type StateRef, type ViewSnapshot, } from "./sessionCodec.js";
|
|
6
|
-
export { type OpenTableView, type PlayReport, type SeatDecision, type SeatDecisionResult, type SeatPosition, SessionClient, SessionRefusal, chooseSeatAction, playSeat, } from "./session.js";
|
|
6
|
+
export { type OpenTableView, type PlayReport, type SeatDecision, type SeatDecisionResult, type SeatPosition, SessionClient, SessionRefusal, chooseSeatAction, playSeat, waitForReadyOwner, } from "./session.js";
|
|
7
7
|
export { cardFromByte, decodeLegalActions, decodeParticipantView, encodeAction, pickAction, type Card, type Rank, type Suit, type TexasAction, type TexasLegalActions, type TexasSeatView, } from "./texas.js";
|
|
8
|
-
export {
|
|
8
|
+
export { buildConsentRequest, DEFAULT_OPEN_API_BASE_URL, digestForPrompt, recomputeSettlementDigest, settlementConsentPath, verifyConsentDisclosure, } from "./settlement.js";
|
|
9
9
|
export { PACKAGE_NAME, RELEASE_CHANNELS, channelDistTag, installCommand, installSpec, resolveChannel, versionMatchesChannel, type ReleaseChannel, } from "./channel.js";
|
|
10
10
|
export { fromHex, toHex } from "./bytes.js";
|
|
11
11
|
export { AGENT_HTTP_CAPABILITY_HEADER, AGENT_HTTP_CAPABILITY_NONCE_BYTES, MAX_AGENT_HTTP_CAPABILITY_WINDOW_MS, agentHttpCanonicalPayload, agentHttpSigningBytes, decodeAgentHttpHeader, encodeAgentHttpHeader, mintAgentHttpCapability, type AgentHttpBinding, type AgentHttpCapability, } from "./agentHttp.js";
|
|
@@ -18,4 +18,4 @@ export { cardIndex, handCategory, scoreHand, HAND_CATEGORIES, RANK_ORDER, SUIT_O
|
|
|
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
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
|
-
export { ClientRefusal, describeNext, refusalLines, refusalMessage, refusalMessageFromText, type RefusalBody, type RefusalNext, } from "./refusal.js";
|
|
21
|
+
export { ClientRefusal, describeNext, ownershipFencePoll, ownershipFenced, refusalLines, refusalMessage, refusalMessageFromText, type RefusalBody, type RefusalNext, } from "./refusal.js";
|
package/dist/index.js
CHANGED
|
@@ -10,9 +10,9 @@ export { deriveAgentId, registerCanonicalPayload, registerPayloadDigest, } from
|
|
|
10
10
|
export { canonicalIdentityPayload, nameAgent, parseIdentityFields, } from "./identity.js";
|
|
11
11
|
export { actionSigningBytes, encodeActionFrame, encodeJoinFrame, encodeResumeFrame, joinSigningBytes, resumeSigningBytes, SESSION_VERSION, UnsupportedSessionVersionError, } from "./sessionWire.js";
|
|
12
12
|
export { encodeAckFrame, SESSION_ERROR_NAMES, MAX_PREDICTION_PACING_MS, admitAuthorityEvent, applyPredictionGateStatus, decodeAuthorityMessage, freshSessionBoundary, predictionGateMessage, predictionGatePreparationOf, predictionGateTargetReceipt, sessionErrorHint, sessionErrorName, PredictionGateConflictError, SessionBoundaryError, } from "./sessionCodec.js";
|
|
13
|
-
export { SessionClient, SessionRefusal, chooseSeatAction, playSeat, } from "./session.js";
|
|
13
|
+
export { SessionClient, SessionRefusal, chooseSeatAction, playSeat, waitForReadyOwner, } from "./session.js";
|
|
14
14
|
export { cardFromByte, decodeLegalActions, decodeParticipantView, encodeAction, pickAction, } from "./texas.js";
|
|
15
|
-
export {
|
|
15
|
+
export { buildConsentRequest, DEFAULT_OPEN_API_BASE_URL, digestForPrompt, recomputeSettlementDigest, settlementConsentPath, verifyConsentDisclosure, } from "./settlement.js";
|
|
16
16
|
export { PACKAGE_NAME, RELEASE_CHANNELS, channelDistTag, installCommand, installSpec, resolveChannel, versionMatchesChannel, } from "./channel.js";
|
|
17
17
|
export { fromHex, toHex } from "./bytes.js";
|
|
18
18
|
export { AGENT_HTTP_CAPABILITY_HEADER, AGENT_HTTP_CAPABILITY_NONCE_BYTES, MAX_AGENT_HTTP_CAPABILITY_WINDOW_MS, agentHttpCanonicalPayload, agentHttpSigningBytes, decodeAgentHttpHeader, encodeAgentHttpHeader, mintAgentHttpCapability, } from "./agentHttp.js";
|
|
@@ -30,4 +30,4 @@ export { cardIndex, handCategory, scoreHand, HAND_CATEGORIES, RANK_ORDER, SUIT_O
|
|
|
30
30
|
export { DEFAULT_SEAT_STATE_FILE, loadSeatState, saveSeatState, } from "./seatState.js";
|
|
31
31
|
export { newSeatState, openTurn, submitTurn, } from "./seatTurn.js";
|
|
32
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
|
-
export { ClientRefusal, describeNext, refusalLines, refusalMessage, refusalMessageFromText, } from "./refusal.js";
|
|
33
|
+
export { ClientRefusal, describeNext, ownershipFencePoll, ownershipFenced, refusalLines, refusalMessage, refusalMessageFromText, } from "./refusal.js";
|
package/dist/refusal.d.ts
CHANGED
|
@@ -29,6 +29,11 @@ export interface RefusalBody {
|
|
|
29
29
|
docs?: string;
|
|
30
30
|
}
|
|
31
31
|
/** `next …`, as one line an agent can act on. */
|
|
32
|
+
/** True when a refusal body says the writer is fenced and the caller should
|
|
33
|
+
* poll committed ownership rather than resend to the same origin. */
|
|
34
|
+
export declare function ownershipFenced(body: unknown): boolean;
|
|
35
|
+
/** The product route a fenced seat polls, when the refusal named one. */
|
|
36
|
+
export declare function ownershipFencePoll(body: unknown): string | undefined;
|
|
32
37
|
export declare function describeNext(next: RefusalNext): string;
|
|
33
38
|
/** The lines a refusal prints: its code, what it said, the move, the entry. */
|
|
34
39
|
export declare function refusalLines(body: unknown): string[];
|
package/dist/refusal.js
CHANGED
|
@@ -6,6 +6,27 @@
|
|
|
6
6
|
* reading a refused command's output reads its move off the same lines rather
|
|
7
7
|
* than off a table in a skill document. */
|
|
8
8
|
/** `next …`, as one line an agent can act on. */
|
|
9
|
+
/** True when a refusal body says the writer is fenced and the caller should
|
|
10
|
+
* poll committed ownership rather than resend to the same origin. */
|
|
11
|
+
export function ownershipFenced(body) {
|
|
12
|
+
if (typeof body !== "object" || body === null)
|
|
13
|
+
return false;
|
|
14
|
+
const refusal = body;
|
|
15
|
+
if (refusal.code !== "ownership_fenced")
|
|
16
|
+
return false;
|
|
17
|
+
return (isNext(refusal.next) &&
|
|
18
|
+
refusal.next.action === "wait" &&
|
|
19
|
+
typeof refusal.next.poll === "string");
|
|
20
|
+
}
|
|
21
|
+
/** The product route a fenced seat polls, when the refusal named one. */
|
|
22
|
+
export function ownershipFencePoll(body) {
|
|
23
|
+
if (!ownershipFenced(body))
|
|
24
|
+
return undefined;
|
|
25
|
+
const next = body.next;
|
|
26
|
+
if (next && next.action === "wait")
|
|
27
|
+
return next.poll;
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
9
30
|
export function describeNext(next) {
|
|
10
31
|
switch (next.action) {
|
|
11
32
|
case "retry":
|
package/dist/session.d.ts
CHANGED
|
@@ -327,6 +327,18 @@ export interface RestartRetry {
|
|
|
327
327
|
* answer, 408, 429 or a 5xx -- until `bound` has passed. Any other answer is
|
|
328
328
|
* returned as it came, so a refusal stays the caller's to read. */
|
|
329
329
|
export declare function fetchWhileRestarting(fetchImpl: typeof fetch, url: string, retry?: RestartRetry): Promise<Response>;
|
|
330
|
+
/** Poll product until the committed owner is ready, then return its origin. */
|
|
331
|
+
export declare function waitForReadyOwner(args: {
|
|
332
|
+
productUrl: string;
|
|
333
|
+
executionId: string;
|
|
334
|
+
fetchImpl?: typeof fetch;
|
|
335
|
+
timeoutMs?: number;
|
|
336
|
+
pauseMs?: number;
|
|
337
|
+
sleep?: (ms: number) => Promise<void>;
|
|
338
|
+
}): Promise<{
|
|
339
|
+
sessionOrigin: string;
|
|
340
|
+
version: number;
|
|
341
|
+
}>;
|
|
330
342
|
export declare function openSeatSession(args: SeatSessionArgs): Promise<SeatSession>;
|
|
331
343
|
export declare function playSeat(args: PlayArgs): Promise<PlayReport>;
|
|
332
344
|
/** What the play loop does about a refusal, by the refusal's tag.
|
package/dist/session.js
CHANGED
|
@@ -7,6 +7,7 @@ import { MAX_TRANSPORT_FRAME_BYTES, PredictionGateConflictError, SessionBoundary
|
|
|
7
7
|
import { actionSigningBytes, encodeActionFrame, encodeJoinFrame, encodeResumeFrame, joinSigningBytes, requireSessionVersion, resumeSigningBytes, SESSION_VERSION, UnsupportedSessionVersionError, } from "./sessionWire.js";
|
|
8
8
|
import { decodeLegalActions, decodeParticipantView, encodeAction, pickAction, } from "./texas.js";
|
|
9
9
|
import { authorizeSeatChallenge } from "./seatAuth.js";
|
|
10
|
+
import { ownershipFenced } from "./refusal.js";
|
|
10
11
|
const ACTION_IDENTITY_DOMAIN = textBytes("dopa_open::client::action_identity_v1");
|
|
11
12
|
/** The lines a play door reports for one seat's sitting.
|
|
12
13
|
*
|
|
@@ -528,6 +529,43 @@ export async function fetchWhileRestarting(fetchImpl, url, retry = {
|
|
|
528
529
|
await sleep(retry.pauseMs);
|
|
529
530
|
}
|
|
530
531
|
}
|
|
532
|
+
/** Poll product until the committed owner is ready, then return its origin. */
|
|
533
|
+
export async function waitForReadyOwner(args) {
|
|
534
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
535
|
+
const sleep = args.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
536
|
+
const product = args.productUrl.replace(/\/$/, "");
|
|
537
|
+
const until = Date.now() + (args.timeoutMs ?? 30_000);
|
|
538
|
+
const pause = args.pauseMs ?? 200;
|
|
539
|
+
const id = args.executionId.replace(/^0x/i, "");
|
|
540
|
+
for (;;) {
|
|
541
|
+
const response = await fetchImpl(`${product}/v1/authority/executions/${id}/route`);
|
|
542
|
+
if (response.ok) {
|
|
543
|
+
const body = (await response.json());
|
|
544
|
+
if (body.ready && body.sessionOrigin)
|
|
545
|
+
return { sessionOrigin: body.sessionOrigin, version: body.version ?? 0 };
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
await response.body?.cancel();
|
|
549
|
+
}
|
|
550
|
+
if (Date.now() + pause > until)
|
|
551
|
+
throw new Error("committed owner did not become ready");
|
|
552
|
+
await sleep(pause);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function httpFailure(error) {
|
|
556
|
+
if (!(error instanceof Error))
|
|
557
|
+
return null;
|
|
558
|
+
const match = /^[a-z-]+ failed \((\d+)\): (.*)$/is.exec(error.message);
|
|
559
|
+
if (!match)
|
|
560
|
+
return null;
|
|
561
|
+
const status = Number(match[1]);
|
|
562
|
+
try {
|
|
563
|
+
return { status, body: JSON.parse(match[2] ?? "") };
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
return { status, body: match[2] ?? "" };
|
|
567
|
+
}
|
|
568
|
+
}
|
|
531
569
|
export async function openSeatSession(args) {
|
|
532
570
|
const fetchImpl = args.fetchImpl ?? fetch;
|
|
533
571
|
const product = args.productUrl.replace(/\/$/, "");
|
|
@@ -581,7 +619,7 @@ export async function openSeatSession(args) {
|
|
|
581
619
|
}
|
|
582
620
|
export async function playSeat(args) {
|
|
583
621
|
const fetchImpl = args.fetchImpl ?? fetch;
|
|
584
|
-
|
|
622
|
+
let { client, product, executionHex, coordinatorKey, timeAuthorityKey, executionId, } = await openSeatSession(args);
|
|
585
623
|
const record = {
|
|
586
624
|
admission: {
|
|
587
625
|
execution_id: executionId,
|
|
@@ -923,6 +961,21 @@ export async function playSeat(args) {
|
|
|
923
961
|
client joined this seat with this key; fighting it back would evict
|
|
924
962
|
a reconnect that may be the operator's own, so this one steps aside
|
|
925
963
|
and says so. Everything else is transient, and resume is right. */
|
|
964
|
+
const failed = httpFailure(error);
|
|
965
|
+
if (failed?.status === 409 && ownershipFenced(failed.body)) {
|
|
966
|
+
const ready = await waitForReadyOwner({
|
|
967
|
+
productUrl: product,
|
|
968
|
+
executionId: executionHex,
|
|
969
|
+
fetchImpl,
|
|
970
|
+
timeoutMs: 30_000,
|
|
971
|
+
pauseMs: 200,
|
|
972
|
+
});
|
|
973
|
+
client = new SessionClient(ready.sessionOrigin, args.agent, args.seat, args.agentId, client.executionId, client.executionManifestDigest, client.clientNonce, fetchImpl);
|
|
974
|
+
await client.resume(lastContext, lastCursor);
|
|
975
|
+
originToken = client.token ?? originToken;
|
|
976
|
+
reconnects += 1;
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
926
979
|
const answer = afterRefusal(error);
|
|
927
980
|
if (answer === "step-aside")
|
|
928
981
|
return {
|
package/dist/settlement.d.ts
CHANGED
|
@@ -57,5 +57,4 @@ export declare function buildConsentRequest(args: ConsentDisclosure & {
|
|
|
57
57
|
signature: Uint8Array;
|
|
58
58
|
}): ConsentRequest;
|
|
59
59
|
export declare function settlementConsentPath(executionIdHex: string): string;
|
|
60
|
-
export declare function authorityOriginFromSessionBase(sessionBaseUrl: string): string;
|
|
61
60
|
export declare function digestForPrompt(prompt: ConsentPrompt): Uint8Array;
|
package/dist/settlement.js
CHANGED
|
@@ -110,12 +110,6 @@ export function settlementConsentPath(executionIdHex) {
|
|
|
110
110
|
const hex = executionIdHex.replace(/^0x/, "");
|
|
111
111
|
return `/v1/authority/executions/${hex}/settlements`;
|
|
112
112
|
}
|
|
113
|
-
export function authorityOriginFromSessionBase(sessionBaseUrl) {
|
|
114
|
-
const idx = sessionBaseUrl.indexOf("/v1/exec/");
|
|
115
|
-
if (idx <= 0)
|
|
116
|
-
throw new Error(`admission session_base_url is not an execution session URL: ${sessionBaseUrl}`);
|
|
117
|
-
return sessionBaseUrl.slice(0, idx);
|
|
118
|
-
}
|
|
119
113
|
export function digestForPrompt(prompt) {
|
|
120
114
|
const terminal = decodeTerminalState(fromHex(prompt.encoded_terminal_state));
|
|
121
115
|
return recomputeSettlementDigest(fromHex(prompt.anchor_context), terminal);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dopamint-fun/open-sdk",
|
|
3
|
-
"version": "0.2.0-dev.
|
|
3
|
+
"version": "0.2.0-dev.8",
|
|
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": {
|