@voidly/session 1.0.0 → 1.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/README.md CHANGED
@@ -1,10 +1,16 @@
1
1
  # @voidly/session
2
2
 
3
- A client for the Voidly private-hire session rail: a hirer commissions sealed
4
- work from a provider it has verified, pays for it on-chain with a pre-signed
5
- EIP-3009 authorization bound to the hire, and reads back the sealed result.
3
+ **Hire another agent and pay it for the work.** A hirer commissions sealed work
4
+ from a provider it has verified, pays on-chain with a pre-signed EIP-3009 USDC
5
+ authorization bound to that one hire, and reads back the sealed result.
6
6
 
7
- Both halves are here. The hirer builds and signs its own envelopes — the brief is
7
+ **This SDK does not custody funds.** Payment use requires caller-supplied signing
8
+ functions. The default flow has the payee submit the authorization; explicit
9
+ opt-in submission helpers can instead broadcast a caller-authorized transaction
10
+ or ask a facilitator to submit it. The Proofs commands below do none of these:
11
+ they do not invoke payment, wallet or key-generation functions.
12
+
13
+ Both halves ship. The hirer builds and signs its own envelopes — the brief is
8
14
  sealed to the provider's key before it leaves the machine, so nothing else is
9
15
  possible — and the provider half is the validators and builders a daemon needs.
10
16
  Which hires a provider accepts, and on what terms, is a daemon's own business and
@@ -14,25 +20,191 @@ is not in this package.
14
20
 
15
21
  ## Install
16
22
 
17
- > **This package is not on the public registry.** `npm install @voidly/session`
18
- > answers `E404`, and you did not mistype it: `package.json` declares
19
- > `private: true` and nothing has ever been published under this name. That is a
20
- > deliberate gate, and this document does not carry a date for lifting it.
21
- >
22
- > **Meanwhile, install the tarball.** Ask the operator who gave you this document
23
- > for one, or build it yourself from a checkout of the source tree:
23
+ ```bash
24
+ npm install --ignore-scripts --save-exact @voidly/session@1.1.0
25
+ ```
26
+
27
+ The package name is public. Check the exact version's registry metadata and its
28
+ linked public source before installation; a source checkout does not prove that
29
+ version has been published. If 1.1.0 is not released yet, use a locally reviewed
30
+ tarball for development rather than substituting another version.
31
+
32
+ ESM only. Node ≥ 18 or any runtime with WebCrypto, `fetch` and `TextEncoder`.
33
+ Two exact runtime dependencies: `tweetnacl@1.0.3` and `tweetnacl-util@0.15.1`.
34
+ The Proofs CLI requires Node ≥ 20.3. No install or postinstall hooks run. The
35
+ `--ignore-scripts` option suppresses dependency lifecycle hooks, not code you
36
+ explicitly execute after installation.
37
+
38
+ > **Building from a checkout instead?** Pack it yourself:
24
39
  >
25
40
  > ```bash
26
- > npm run build && npm pack # → voidly-session-1.0.0.tgz
27
- > npm install /path/to/voidly-session-1.0.0.tgz
41
+ > npm run build && npm pack # → voidly-session-1.1.0.tgz
42
+ > npm install --ignore-scripts --save-exact /path/to/voidly-session-1.1.0.tgz
28
43
  > ```
29
44
  >
30
- > Those are the same bytes `npm publish` would upload `npm run gate` scans that
31
- > tarball and nothing else so a hire that works against it works unchanged
32
- > against the published package on the day there is one.
45
+ > `npm run gate` inspects the actual packed bytes. A local build is not registry
46
+ > release evidence: verify the published artifact's integrity and source/build
47
+ > provenance separately. Provenance establishes origin, not harmlessness.
33
48
 
34
- ESM only. Node ≥ 18 or any runtime with WebCrypto, `fetch` and `TextEncoder`.
35
- Two runtime dependencies: `tweetnacl` and `tweetnacl-util`.
49
+ ---
50
+
51
+ ## Start without a wallet: exercise the installed SDK
52
+
53
+ The website flow is released separately from this package. Follow the current
54
+ page's availability state; installing the SDK alone does not enable saving.
55
+
56
+ Review the installed source and respect your execution environment's permissions.
57
+ You do not need a Proofs token or any other credential for these commands. Do not
58
+ disable an agent's safeguards if it refuses to install or run software.
59
+
60
+ First, verify a signed public fixture with the installed SDK:
61
+
62
+ ```bash
63
+ node node_modules/@voidly/session/dist/proofsCli.mjs self-test
64
+ ```
65
+
66
+ This offline check verifies a signature, rejects the wrong identity pin, rejects
67
+ a modified manifest, and checks canonical hashing. It makes no network requests.
68
+ `ok: true` means the fixture checks passed, not that a live provider is healthy or
69
+ a proof has been saved. It is useful before integrating a provider into an agent.
70
+
71
+ For a fresh public check, open [Voidpay Proofs](https://voidly.ai/pay/proofs),
72
+ finish setup, then start the public exercise in the browser. The short deadline
73
+ begins at that point, not during installation. Supply the browser's public JSON
74
+ to the installed command's standard input:
75
+
76
+ ```bash
77
+ node node_modules/@voidly/session/dist/proofsCli.mjs public-check < public-exercise.json
78
+ ```
79
+
80
+ The command makes two public HTTPS GET requests, only to the fixed provider index
81
+ and manifest endpoints. It does not accept alternate URLs, follow redirects,
82
+ read environment variables, read or write files, post results, or access a
83
+ wallet. Network responses and input have byte and time limits. The shell opens
84
+ the explicit input file in the example; the command itself reads standard input.
85
+
86
+ Return the resulting JSON to the originating Proofs page, preview it, and choose
87
+ **Save proof**. Saving requires the browser owner's authorization and independent
88
+ server checks. Nothing is saved or published merely by running the command.
89
+ The server does not treat public result data as proof that someone installed this
90
+ package, is an AI agent, or is a unique person.
91
+
92
+ After a successful save, use its event identifier to render the same artwork
93
+ locally for display or an explicit save in your chat environment:
94
+
95
+ ```bash
96
+ node node_modules/@voidly/session/dist/proofsCli.mjs artwork YOUR_SAVED_EVENT_ID
97
+ ```
98
+
99
+ The command accepts exactly 32 lowercase hexadecimal characters and prints SVG
100
+ to standard output. It does not contact a server or verify that the identifier
101
+ belongs to a saved proof. Artwork is decorative; the signed receipt is separate.
102
+ The event identifier is not embedded in the SVG. Public sharing remains a choice
103
+ on the website. A hosted workspace's installation may be temporary; retain the
104
+ starter project only if you choose to do so.
105
+
106
+ Applications can use the same functions from `@voidly/session/proofs`:
107
+
108
+ ```ts
109
+ import { runSessionsSelfTest, runPublicExercise } from "@voidly/session/proofs";
110
+
111
+ export async function checkPublicData(publicExerciseJson: string) {
112
+ const selfTest = await runSessionsSelfTest();
113
+ if (!selfTest.ok) throw new Error("SDK self-test failed");
114
+ // Bounded, non-secret JSON from the originating page.
115
+ return runPublicExercise(publicExerciseJson);
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Quickstart — hire, pay, read back
122
+
123
+ Five calls. This is the whole default path; everything after this section is
124
+ the *why*, and the failure modes you are agreeing to when you skip it.
125
+
126
+ ```ts
127
+ import {
128
+ fetchVerifiedProvider,
129
+ buildHire,
130
+ buildReceivePaymentAuthorization,
131
+ submitHire,
132
+ recoverResult,
133
+ x402SessionAccountCaip10,
134
+ } from "@voidly/session";
135
+
136
+ // 1. VERIFY. `expectedProviderDid` is a pin and it is required — there is no
137
+ // unpinned arm. The brief gets sealed to whatever key this returns.
138
+ const found = await fetchVerifiedProvider({
139
+ manifestUrl, expectedProviderDid, fetchImpl: fetch,
140
+ });
141
+ if (!found.ok) throw new Error(found.reason);
142
+
143
+ // 2. HIRE. Every money field is COPIED off the signed manifest. A price you
144
+ // type yourself is refused by name — see "the price is not yours to type".
145
+ const SERVICE_REF = "voidly.observatory.query/v1";
146
+ const offering = found.provider.manifest.services.find((s) => s.ref === SERVICE_REF);
147
+ if (!offering) throw new Error(`provider does not offer ${SERVICE_REF}`);
148
+
149
+ const hire = await buildHire({
150
+ hirer: { did, signingPublicKeyBase64, sign }, // `sign` is Ed25519, detached
151
+ provider: found.provider,
152
+ service: { ref: SERVICE_REF },
153
+ task: { brief: "…" },
154
+ price: {
155
+ chain: offering.price.chain,
156
+ asset: offering.price.asset,
157
+ // the ONE field that is yours: the account the money leaves
158
+ payerAccount: x402SessionAccountCaip10(offering.price.chain, payer)!,
159
+ payeeAccount: offering.price.payee_account,
160
+ minAmount: offering.price.min_amount,
161
+ maxAmount: offering.price.max_amount,
162
+ },
163
+ ttl: { offerMs: 30 * 60_000, grantMs: 10 * 60_000 },
164
+ nowMs: Date.now(),
165
+ });
166
+ if (!hire.ok) throw new Error(hire.reason);
167
+
168
+ // 3. SIGN THE PAYMENT. The RECEIVE variant: only the payee named in it can
169
+ // spend it. Every money-steering field is derived from the grant.
170
+ const paid = await buildReceivePaymentAuthorization({
171
+ grant: hire.wire.grant,
172
+ grantHash: hire.keep.grant_hash,
173
+ nowMs: Date.now(),
174
+ sign: signReceive, // your wallet's EIP-712 signer
175
+ });
176
+ if (!paid.ok) throw new Error(paid.reason);
177
+
178
+ // 4. SUBMIT. Returns "accepted" only after the countersignature verifies.
179
+ const out = await submitHire({
180
+ url: found.provider.manifest.accept_url,
181
+ wire: hire.wire,
182
+ grantHash: hire.keep.grant_hash,
183
+ authorization: paid.authorization,
184
+ sign, nowMs: Date.now(), fetchImpl: fetch,
185
+ });
186
+ if (out.kind !== "accepted") throw new Error(out.kind);
187
+
188
+ // 5. NOTHING. The provider spends the authorization and writes its own
189
+ // settlement pointer. You do not pay gas, and you do not send a hint.
190
+
191
+ // 6. READ IT BACK. Poll while `no_result` — that is the normal answer until
192
+ // the provider has delivered.
193
+ const read = await recoverResult({
194
+ endpoint: { baseUrl: found.provider.manifest.worker_base_url },
195
+ wire: hire.wire,
196
+ grantHash: hire.keep.grant_hash,
197
+ sessionKey: hire.keep.sessionKey,
198
+ sign, nowMs: Date.now(),
199
+ });
200
+ if (read.kind === "opened") console.log(read.result);
201
+ ```
202
+
203
+ **Before you ship that:** the price fields are compared with `===` and no
204
+ normalisation ([why](#the-price-is-not-yours-to-type)), the two payment
205
+ variants share one nonce and are alternatives rather than steps
206
+ ([the fork](#the-fork-who-settles-the-payment)), and `ok: true` is a narrower
207
+ claim than it looks ([what it does not mean](#what-oktrue-does-not-mean)).
36
208
 
37
209
  ---
38
210
 
@@ -97,7 +269,12 @@ the opt-out path only; here, retrying with a fresh clock never succeeds.
97
269
 
98
270
  ---
99
271
 
100
- ## A hire, end to end — the default
272
+ ## The same hire, annotated
273
+
274
+ The Quickstart above with every refusal reason spelled out at the line that
275
+ raises it. Same calls, same order — read this one before you go to production,
276
+ and read it in full if a call came back `ok: false` and you want the name of
277
+ what you tripped.
101
278
 
102
279
  ```ts
103
280
  import {
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export declare function acceptHire(input: {
19
19
  reason: string;
20
20
  }>;
21
21
  type AccountSpellingRefuseDetail = "grant_payer_account_not_canonical" | "grant_payee_account_not_canonical";
22
+ export declare const AGENT_IDENTITY_PATH_PREFIX = "/v1/agent/identity/";
22
23
  export type AssembleAuthorizationRefusal = HireRefuseDetail | SignRefusal | "grant_hash_mismatch" | "authorization_asset_not_frozen_usdc" | "valid_after_not_safe_integer" | "authorization_entry_point_mismatch";
23
24
  export declare function assembleSignedReceiveAuthorization(input: AssembleSignedTransferAuthorizationInput): Promise<AssembleSignedReceiveAuthorizationResult>;
24
25
  export type AssembleSignedReceiveAuthorizationResult = {
@@ -230,7 +231,36 @@ export declare function canonicalBytes(value: unknown): Uint8Array;
230
231
  export declare function canonicalize(value: unknown): string;
231
232
  declare const CAPSULE_ALG = "x25519-xsalsa20-poly1305+xsalsa20-poly1305";
232
233
  export declare const CAPSULE_NONCE_LENGTH = 24;
234
+ export declare function checkPartiesRegistered(input: CheckPartiesRegisteredInput): Promise<CheckPartiesRegisteredResult>;
235
+ export interface CheckPartiesRegisteredInput {
236
+ readonly registryBaseUrl: string;
237
+ readonly hirerDid: string;
238
+ readonly providerDid: string;
239
+ readonly hirerSigningPublicKeyBase64?: string;
240
+ readonly fetchImpl: FetchLike;
241
+ readonly signal?: AbortSignal;
242
+ }
243
+ export type CheckPartiesRegisteredResult = {
244
+ readonly ok: true;
245
+ } | {
246
+ readonly ok: false;
247
+ readonly reason: PartiesRegisteredRefusal;
248
+ readonly detail: string;
249
+ };
233
250
  export declare function checkSingleAuthorizationRelay(request: TransactionRequest, context?: SingleAuthorizationRelayContext): SingleAuthorizationCheck;
251
+ export declare function classifySessionStatus(word: string): SessionProgress;
252
+ export declare function closeOutSessionKeep(input: {
253
+ readonly fs: SessionKeepFs;
254
+ readonly dir: string;
255
+ readonly grantHash: string;
256
+ readonly sessionKey: SessionKey;
257
+ }): {
258
+ readonly ok: true;
259
+ readonly erased: boolean;
260
+ } | {
261
+ readonly ok: false;
262
+ readonly reason: SessionKeepRefusal;
263
+ };
234
264
  export declare function compareDecimalStrings(a: string, b: string): number | null;
235
265
  type CostRefusal = "estimate_unavailable" | "gas_price_unavailable" | "balance_unavailable" | "relayer_cannot_pay_gas";
236
266
  export declare function createFacilitatorSubmitter(input: FacilitatorSubmitterInput): PaymentSubmitter;
@@ -244,11 +274,47 @@ export declare function decideFromSupported(args: {
244
274
  readonly httpStatus: number | null;
245
275
  }): FacilitatorPreflightResult;
246
276
  export declare function decodeRevertReason(data: unknown): string | null;
277
+ export declare function defaultSessionKeepDir(homeDir: string): string;
247
278
  export declare function deriveDidFromSigningKey(signingPublicKey: Uint8Array): string;
248
279
  export declare function destroySessionKey(key: SessionKey): void;
249
280
  export type DiscoveryTransportReason = "manifest_unreachable" | "manifest_not_json";
281
+ export declare function driveSettlementHint(input: DriveSettlementHintInput): Promise<DriveSettlementHintResult>;
282
+ export interface DriveSettlementHintInput {
283
+ readonly hintUrl: string;
284
+ readonly statusBaseUrl: string;
285
+ readonly grant: TaskGrantEnvelope;
286
+ readonly grantHash: string;
287
+ readonly evidence: unknown;
288
+ readonly sign: Signer;
289
+ readonly now: () => number;
290
+ readonly sleep: SleepLike;
291
+ readonly fetchImpl: FetchLike;
292
+ readonly maxAttempts?: number;
293
+ readonly pollIntervalMs?: number;
294
+ readonly deadlineMs?: number;
295
+ readonly signal?: AbortSignal;
296
+ }
297
+ export interface DriveSettlementHintResult {
298
+ readonly ok: boolean;
299
+ readonly outcome: DriveSettlementOutcome;
300
+ readonly attempts: readonly SettlementHintAttempt[];
301
+ readonly lastStatus: string | null;
302
+ readonly detail: string;
303
+ }
304
+ export type DriveSettlementOutcome = "settled" | "provider_relaying" | "session_terminal" | "hint_refused" | "unbuildable" | "status_unrecognized" | "budget_exhausted";
250
305
  export declare function encodeSessionProviderProof(envelope: SessionProviderProofEnvelope, signatureBase64: string): string;
251
306
  export declare function envelopeHash(env: object): Promise<string>;
307
+ export declare function eraseSessionKeep(input: {
308
+ readonly fs: SessionKeepFs;
309
+ readonly dir: string;
310
+ readonly grantHash: string;
311
+ }): {
312
+ readonly ok: true;
313
+ readonly erased: boolean;
314
+ } | {
315
+ readonly ok: false;
316
+ readonly reason: SessionKeepRefusal;
317
+ };
252
318
  export declare function estimateRelayCost(input: {
253
319
  readonly rpc: ReadOnlyEvmRpc;
254
320
  readonly request: TransactionRequest;
@@ -350,6 +416,23 @@ export declare const KNOWN_ASSET_TRANSFER_METHODS: readonly [
350
416
  "permit2",
351
417
  "erc7710"
352
418
  ];
419
+ export declare function listSessionKeeps(input: {
420
+ readonly fs: SessionKeepFs;
421
+ readonly dir: string;
422
+ }): string[];
423
+ export declare function loadSessionKeep(input: {
424
+ readonly fs: SessionKeepFs;
425
+ readonly dir: string;
426
+ readonly grantHash: string;
427
+ }): Promise<LoadSessionKeepOutcome>;
428
+ export type LoadSessionKeepOutcome = {
429
+ readonly ok: true;
430
+ readonly keep: SessionKeepRecord;
431
+ readonly path: string;
432
+ } | {
433
+ readonly ok: false;
434
+ readonly reason: SessionKeepRefusal;
435
+ };
353
436
  export type ManifestRejectReason = "manifest_not_object" | "manifest_schema_mismatch" | "manifest_unexpected_field" | "manifest_field_malformed" | "manifest_signature_missing" | "manifest_signature_malformed" | "manifest_signature_invalid" | "manifest_did_not_derived" | "manifest_did_not_pinned";
354
437
  export interface MatchedKind {
355
438
  readonly x402Version: number;
@@ -397,6 +480,7 @@ export type OpenDeliveredResultOutcome = {
397
480
  reason: OpenDeliveredResultRefusal;
398
481
  };
399
482
  export type OpenDeliveredResultRefusal = "grant_hash_mismatch" | SessionResultRejectReason | "delivery_grant_mismatch";
483
+ export type PartiesRegisteredRefusal = "hirer_unregistered" | "hirer_key_not_registered" | "provider_unregistered" | "registry_unreadable";
400
484
  export interface PayeeRelayBroadcasterInput {
401
485
  readonly rpc: ReadOnlyEvmRpc;
402
486
  readonly relayerAddress: string;
@@ -449,6 +533,22 @@ export interface PaymentSubmitter {
449
533
  readonly kind: "facilitator" | "self";
450
534
  submit(signed: SignedTransferAuthorization): Promise<SubmitResult>;
451
535
  }
536
+ export declare function persistSessionKeep(input: {
537
+ readonly fs: SessionKeepFs;
538
+ readonly dir: string;
539
+ readonly grantHash: string;
540
+ readonly endpointBaseUrl: string;
541
+ readonly wire: HireWire;
542
+ readonly sessionKey: SessionKey;
543
+ readonly nowMs: number;
544
+ }): Promise<PersistSessionKeepOutcome>;
545
+ export type PersistSessionKeepOutcome = {
546
+ readonly ok: true;
547
+ readonly path: string;
548
+ } | {
549
+ readonly ok: false;
550
+ readonly reason: SessionKeepRefusal;
551
+ };
452
552
  export declare function postDeliver(ep: SessionEndpoint, input: {
453
553
  wire: HireWire;
454
554
  receipt: TaskDeliveryReceipt;
@@ -546,6 +646,8 @@ export declare const PROVIDER_MANIFEST_KEYS: readonly [
546
646
  "accept_url",
547
647
  "hire_message_schema",
548
648
  "worker_base_url",
649
+ "hint_url",
650
+ "relays",
549
651
  "grant_ttl_ms",
550
652
  "acceptance_ttl_ms",
551
653
  "services",
@@ -564,6 +666,11 @@ export interface ProviderManifest {
564
666
  readonly accept_url: string;
565
667
  readonly hire_message_schema: typeof SESSION_HIRE_SCHEMA;
566
668
  readonly worker_base_url: string;
669
+ readonly hint_url?: string;
670
+ readonly relays?: {
671
+ readonly provider_submits: boolean;
672
+ readonly accepted_entry_points: readonly AuthorizationEntryPoint[];
673
+ };
567
674
  readonly grant_ttl_ms: {
568
675
  readonly min: number;
569
676
  readonly max: number;
@@ -596,6 +703,15 @@ export type ProviderOpenResult = {
596
703
  kind: "unopenable";
597
704
  };
598
705
  export type ProviderTermsRejectReason = "provider_not_verified" | "provider_service_not_offered" | "provider_price_chain_not_offered" | "provider_price_asset_not_offered" | "provider_payee_not_manifested" | "provider_price_below_manifest_floor" | "provider_price_above_manifest_ceiling" | "provider_grant_ttl_below_manifest_floor" | "provider_grant_ttl_above_manifest_ceiling";
706
+ export declare function pruneSessionKeeps(input: {
707
+ readonly fs: SessionKeepFs;
708
+ readonly dir: string;
709
+ readonly nowMs: number;
710
+ readonly recoveryTtlMs: number;
711
+ }): {
712
+ readonly erased: string[];
713
+ readonly kept: string[];
714
+ };
599
715
  export declare const READ_ONLY_RPC_METHODS: readonly string[];
600
716
  export interface ReadOnlyEvmRpc {
601
717
  readonly url: string;
@@ -606,6 +722,22 @@ export interface ReadOnlyEvmRpcInput {
606
722
  readonly fetchImpl: FetchLike;
607
723
  readonly signal?: AbortSignal;
608
724
  }
725
+ export declare function readSessionStatus(input: ReadSessionStatusInput): Promise<ReadSessionStatusResult>;
726
+ export interface ReadSessionStatusInput {
727
+ readonly statusBaseUrl: string;
728
+ readonly grantHash: string;
729
+ readonly fetchImpl: FetchLike;
730
+ readonly signal?: AbortSignal;
731
+ }
732
+ export type ReadSessionStatusRefusal = "status_unknown" | "status_unreadable" | "status_grant_hash_malformed";
733
+ export type ReadSessionStatusResult = {
734
+ readonly ok: true;
735
+ readonly status: string;
736
+ } | {
737
+ readonly ok: false;
738
+ readonly reason: ReadSessionStatusRefusal;
739
+ readonly detail: string;
740
+ };
609
741
  export declare const RECEIVE_WITH_AUTHORIZATION_SELECTOR = "0xef55bec6";
610
742
  export declare const RECEIVE_WITH_AUTHORIZATION_TYPEHASH = "0xd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8";
611
743
  export interface ReceiveAuthorizationTypedData {
@@ -850,6 +982,9 @@ export type SendRelayTransaction = (transaction: {
850
982
  declare const SESSION_HIRE_ACCEPTED_SCHEMA = "voidly-session-hire-accepted/v1";
851
983
  declare const SESSION_HIRE_REFUSED_SCHEMA = "voidly-session-hire-refused/v1";
852
984
  declare const SESSION_HIRE_SCHEMA = "voidly-session-hire/v1";
985
+ export declare const SESSION_KEEP_DIR_MODE = 448;
986
+ export declare const SESSION_KEEP_FILE_MODE = 384;
987
+ export declare const SESSION_KEEP_VERSION: 1;
853
988
  declare const SESSION_OFFER_SCHEMA = "voidly-session-offer/v1";
854
989
  export declare const SESSION_PATHS: Readonly<{
855
990
  readonly redeem: "/v1/pay/session/redeem";
@@ -863,6 +998,7 @@ export declare const SESSION_PROVIDER_PROOF_SCHEMA = "voidly-session-provider-re
863
998
  export declare const SESSION_RAIL_BLOCK_TIME_MS = 2000;
864
999
  export declare const SESSION_RAIL_MIN_CONFIRMATIONS = 12;
865
1000
  declare const SESSION_REATTEST_PROOF_SCHEMA = "voidly-session-provider-reattestation/v1";
1001
+ export declare const SESSION_STATUS_PATH_PREFIX = "/session/status/";
866
1002
  export declare class SessionCryptoUnavailableError extends Error {
867
1003
  readonly code = "session_crypto_unavailable";
868
1004
  constructor(message: string);
@@ -897,6 +1033,30 @@ export type SessionHireRefused = {
897
1033
  reason: HireRefuseReason;
898
1034
  detail: ReceivedHireRefuseDetail;
899
1035
  };
1036
+ export interface SessionKeepFs {
1037
+ mkdirSync(path: string, options: {
1038
+ recursive: true;
1039
+ mode: number;
1040
+ }): unknown;
1041
+ chmodSync(path: string, mode: number): void;
1042
+ openSync(path: string, flags: string, mode?: number): number;
1043
+ writeSync(fd: number, data: string): unknown;
1044
+ fsyncSync(fd: number): void;
1045
+ closeSync(fd: number): void;
1046
+ renameSync(from: string, to: string): void;
1047
+ existsSync(path: string): boolean;
1048
+ readFileSync(path: string, encoding: "utf-8"): string;
1049
+ readdirSync(path: string): string[];
1050
+ unlinkSync(path: string): void;
1051
+ }
1052
+ export interface SessionKeepRecord {
1053
+ readonly grantHash: string;
1054
+ readonly endpointBaseUrl: string;
1055
+ readonly wire: HireWire;
1056
+ readonly sessionKey: SessionKey;
1057
+ readonly createdAtMs: number;
1058
+ }
1059
+ export type SessionKeepRefusal = "session_key_unavailable" | "session_key_wrong_length" | "grant_hash_unusable" | "grant_hash_mismatch" | "endpoint_unusable" | "wire_unusable" | "serialization_would_not_restore" | "not_found" | "unreadable" | "version_unsupported" | "malformed" | "io_failed";
900
1060
  export type SessionKey = SessionKeyHandle;
901
1061
  declare class SessionKeyHandle {
902
1062
  #private;
@@ -925,6 +1085,7 @@ interface SessionParty {
925
1085
  readonly did: string;
926
1086
  readonly signingPublicKey: Uint8Array;
927
1087
  }
1088
+ export type SessionProgress = "unpaid" | "awaiting_settlement" | "opened" | "provider_relaying" | "terminal" | "unrecognized";
928
1089
  export declare function sessionProviderProofEnvelope(input: SessionProviderProofFields): SessionProviderProofEnvelope;
929
1090
  export interface SessionProviderProofEnvelope {
930
1091
  schema: SessionProviderProofSchema;
@@ -958,8 +1119,17 @@ export declare class SessionUsageError extends Error {
958
1119
  constructor(message: string);
959
1120
  }
960
1121
  export declare const SETTLEMENT_BINDING_DOMAIN = "voidly-session-settlement-binding/v1|";
1122
+ export declare const SETTLEMENT_EXPIRY_MARGIN_MS: number;
961
1123
  declare const SETTLEMENT_HINT_SCHEMA: "voidly.session.settlement-hint/v1";
1124
+ export declare const SETTLEMENT_MAX_HINT_ATTEMPTS = 8;
1125
+ export declare const SETTLEMENT_POLL_INTERVAL_MS: number;
962
1126
  export declare function settlementBindingReference(grantHash: string): Promise<string>;
1127
+ export interface SettlementHintAttempt {
1128
+ readonly attempt: number;
1129
+ readonly atMs: number;
1130
+ readonly result: SubmitSettlementHintResult;
1131
+ readonly statusWord: string | null;
1132
+ }
963
1133
  export interface SettlementHintEnvelope {
964
1134
  readonly schema: typeof SETTLEMENT_HINT_SCHEMA;
965
1135
  readonly grant_hash: string;
@@ -967,6 +1137,13 @@ export interface SettlementHintEnvelope {
967
1137
  readonly evidence_hash: string;
968
1138
  readonly issued_at: string;
969
1139
  }
1140
+ type SettlementHintTarget = {
1141
+ readonly provider: VerifiedProvider;
1142
+ readonly url?: string;
1143
+ } | {
1144
+ readonly provider?: undefined;
1145
+ readonly url: string;
1146
+ };
970
1147
  export type SettlementLookupResult = {
971
1148
  readonly kind: "found";
972
1149
  readonly transactionHash: string;
@@ -1091,6 +1268,15 @@ export type SingleAuthorizationCheck = {
1091
1268
  export interface SingleAuthorizationRelayContext {
1092
1269
  readonly relayerAddress?: string;
1093
1270
  }
1271
+ export type SleepLike = (ms: number) => Promise<void>;
1272
+ export interface StoredSessionKeep {
1273
+ readonly v: typeof SESSION_KEEP_VERSION;
1274
+ readonly grant_hash: string;
1275
+ readonly endpoint_base_url: string;
1276
+ readonly wire: HireWire;
1277
+ readonly session_key_base64: string;
1278
+ readonly created_at_ms: number;
1279
+ }
1094
1280
  export declare function submitHire(input: {
1095
1281
  readonly url: string;
1096
1282
  readonly wire: HireWire;
@@ -1129,7 +1315,8 @@ export type SubmitResult = {
1129
1315
  detail: string;
1130
1316
  };
1131
1317
  export declare function submitSettlementHint(input: {
1132
- readonly url: string;
1318
+ readonly provider?: VerifiedProvider;
1319
+ readonly url?: string;
1133
1320
  readonly grant: TaskGrantEnvelope;
1134
1321
  readonly grantHash: string;
1135
1322
  readonly evidence: unknown;
@@ -1137,8 +1324,8 @@ export declare function submitSettlementHint(input: {
1137
1324
  readonly nowMs: number;
1138
1325
  readonly fetchImpl: FetchLike;
1139
1326
  readonly signal?: AbortSignal;
1140
- }): Promise<SubmitSettlementHintResult>;
1141
- export type SubmitSettlementHintRefusal = "grant_hash_mismatch" | "provider_did_unusable" | "evidence_unusable" | "signature_failed";
1327
+ } & SettlementHintTarget): Promise<SubmitSettlementHintResult>;
1328
+ export type SubmitSettlementHintRefusal = "grant_hash_mismatch" | "hint_url_unpublished" | "hint_url_conflict" | "provider_did_unusable" | "evidence_unusable" | "signature_failed";
1142
1329
  export type SubmitSettlementHintResult = {
1143
1330
  kind: "acknowledged";
1144
1331
  status: number;