@bounded-sh/core 0.0.118 → 0.0.120-expo.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.
Files changed (36) hide show
  1. package/dist/client/operations.d.ts +19 -1
  2. package/dist/client/solana-operations.d.ts +6 -0
  3. package/dist/{index-l9LI3y1q.js → index-D7-5ecyu.js} +279 -217
  4. package/dist/index-D7-5ecyu.js.map +1 -0
  5. package/dist/{index-BXfRRAUZ.mjs → index-D93TEYGf.mjs} +279 -218
  6. package/dist/index-D93TEYGf.mjs.map +1 -0
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +2 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1 -1
  11. package/dist/{mirror-sync-DoH9ewTo.mjs → mirror-sync-DPMtQC3A.mjs} +2 -2
  12. package/dist/{mirror-sync-DoH9ewTo.mjs.map → mirror-sync-DPMtQC3A.mjs.map} +1 -1
  13. package/dist/{mirror-sync-DJVm0KKu.js → mirror-sync-DzbDh6G_.js} +2 -2
  14. package/dist/{mirror-sync-DJVm0KKu.js.map → mirror-sync-DzbDh6G_.js.map} +1 -1
  15. package/dist/{realtime-store-kZMPgwVB.js → realtime-store-C2Jz8YM0.js} +2 -2
  16. package/dist/{realtime-store-kZMPgwVB.js.map → realtime-store-C2Jz8YM0.js.map} +1 -1
  17. package/dist/{realtime-store-BreUReSo.mjs → realtime-store-FObAdw-J.mjs} +2 -2
  18. package/dist/{realtime-store-BreUReSo.mjs.map → realtime-store-FObAdw-J.mjs.map} +1 -1
  19. package/dist/{solana-message-HkOoUz8z.js → solana-message-CPotom18.js} +2 -2
  20. package/dist/{solana-message-HkOoUz8z.js.map → solana-message-CPotom18.js.map} +1 -1
  21. package/dist/{solana-message-CjI0h27k.mjs → solana-message-DqKp-y53.mjs} +2 -2
  22. package/dist/{solana-message-CjI0h27k.mjs.map → solana-message-DqKp-y53.mjs.map} +1 -1
  23. package/dist/{solana-operations-DFohVGz6.js → solana-operations-DsT1303T.js} +26 -13
  24. package/dist/solana-operations-DsT1303T.js.map +1 -0
  25. package/dist/{solana-operations-CD6pks4-.mjs → solana-operations-cwcuTNyk.mjs} +26 -14
  26. package/dist/solana-operations-cwcuTNyk.mjs.map +1 -0
  27. package/dist/{solana-v1-operations-ewIzFDeY.mjs → solana-v1-operations-Jzg3uAot.mjs} +3 -3
  28. package/dist/{solana-v1-operations-ewIzFDeY.mjs.map → solana-v1-operations-Jzg3uAot.mjs.map} +1 -1
  29. package/dist/{solana-v1-operations-bhDjo-5U.js → solana-v1-operations-qj0WA2tF.js} +3 -3
  30. package/dist/{solana-v1-operations-bhDjo-5U.js.map → solana-v1-operations-qj0WA2tF.js.map} +1 -1
  31. package/dist/types.d.ts +14 -0
  32. package/package.json +1 -1
  33. package/dist/index-BXfRRAUZ.mjs.map +0 -1
  34. package/dist/index-l9LI3y1q.js.map +0 -1
  35. package/dist/solana-operations-CD6pks4-.mjs.map +0 -1
  36. package/dist/solana-operations-DFohVGz6.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import type { AuthProvider, MirrorSync, SetResult, SolanaSubmittedSetResult, SolanaWriteRpc } from '../types';
1
+ import type { AuthProvider, SignerReadiness, MirrorSync, SetResult, SolanaSubmittedSetResult, SolanaWriteRpc } from '../types';
2
2
  import { type ClientConfig } from './config';
3
3
  import type { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
4
4
  /** Internal overrides for per-request auth and headers. */
@@ -47,6 +47,14 @@ export type GrantLane = {
47
47
  };
48
48
  export type SetOptions = {
49
49
  shouldSubmitTx?: boolean;
50
+ /**
51
+ * This write takes the wallet's signature (an onchain collection). The signer is then prepared
52
+ * BEFORE the transaction is built: a hosted embedded wallet whose 24-hour session has lapsed
53
+ * collects its emailed code first, so the code never runs inside the transaction's blockhash
54
+ * lifetime and no build is thrown away. Without it the SDK still copes, by building again after
55
+ * the code, at the cost of one sponsored build left to expire.
56
+ */
57
+ onchain?: boolean;
50
58
  /**
51
59
  * Called with the signed transaction's `submitted` receipt immediately BEFORE
52
60
  * it is broadcast (Solana lanes only). Persist it to reconcile the exact
@@ -389,6 +397,16 @@ export declare function setFile(path: string, file: File | null, options?: {
389
397
  }): Promise<FileUploadResult | FileDeleteResult>;
390
398
  export declare function signMessage(message: string): Promise<string>;
391
399
  export declare function signTransaction(transaction: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
400
+ /**
401
+ * Make the signed-in wallet ready to sign without delay, BEFORE the transaction it will sign
402
+ * exists. A hosted embedded wallet whose 24-hour signing session has lapsed collects its emailed
403
+ * code here; a transaction built before that code is dead by the time it is signed, because a
404
+ * blockhash lives about 33 seconds on mainnet (late 2026) and the code takes longer. `set` and
405
+ * `setMany` do this themselves before a wallet signature; call it directly before a flow that
406
+ * builds and signs outside them, such as a permit approval. Resolves `'established'` when a
407
+ * ceremony ran, else `'ready'`; a wallet that holds its own key always answers `'ready'`.
408
+ */
409
+ export declare function prepareToSign(): Promise<SignerReadiness>;
392
410
  export declare function signAndSubmitTransaction(transaction: Transaction | VersionedTransaction, feePayer?: PublicKey): Promise<string>;
393
411
  /** Refresh concrete paths, or index a confirmed transaction and read its requested paths. */
394
412
  export declare function syncItems(paths: string[], options?: SetOptions, transactionSignature?: string): Promise<any>;
@@ -19,6 +19,12 @@ export declare function encodeBase58(bytes: Uint8Array): string;
19
19
  /** true when the base64 wire is a SIMD-0385 v1 transaction (first byte 0x81). */
20
20
  export declare function isTransactionV1Base64(serializedTransaction: string): boolean;
21
21
  export declare function deriveTransactionSignature(signedTransaction: VersionedTransaction): string;
22
+ /**
23
+ * The send was refused because the transaction's blockhash is no longer current: the RPC's
24
+ * preflight simulation names it, and no byte entered the network. The one send failure a
25
+ * fresh build cures, since the bytes were right and only their lifetime ran out.
26
+ */
27
+ export declare function isExpiredBlockhashRejection(error: unknown): boolean;
22
28
  export declare function isDefinitiveSolanaSendFailure(error: unknown): boolean;
23
29
  /**
24
30
  * Whether a definitive Solana send/confirm failure is the BOUNDED PROGRAM
@@ -4307,7 +4307,7 @@ class ServerSessionManager {
4307
4307
  const sessionConfig = (_a = this.sessionConfig) !== null && _a !== void 0 ? _a : undefined;
4308
4308
  /* fetch nonce from auth API (bound to the snapshotted app+issuer) */
4309
4309
  const nonce = await genAuthNonce(sessionConfig);
4310
- const { genSolanaMessage } = await Promise.resolve().then(function () { return require('./solana-message-HkOoUz8z.js'); });
4310
+ const { genSolanaMessage } = await Promise.resolve().then(function () { return require('./solana-message-CPotom18.js'); });
4311
4311
  const message = await genSolanaMessage(address, nonce, sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.appId);
4312
4312
  /* sign the message */
4313
4313
  const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), kp.secretKey);
@@ -7679,7 +7679,7 @@ async function doReconnectWithNewAuth() {
7679
7679
  console.warn('[WS v2] Failed to clear HTTP read cache on auth change:', error);
7680
7680
  }
7681
7681
  try {
7682
- const { reconnectRealtimeStoreWithNewAuth } = await Promise.resolve().then(function () { return require('./realtime-store-kZMPgwVB.js'); });
7682
+ const { reconnectRealtimeStoreWithNewAuth } = await Promise.resolve().then(function () { return require('./realtime-store-C2Jz8YM0.js'); });
7683
7683
  await reconnectRealtimeStoreWithNewAuth();
7684
7684
  }
7685
7685
  catch (error) {
@@ -8898,7 +8898,7 @@ function buildRequestedDocuments(documents) {
8898
8898
  /** Best-effort readback, including a failure to load its lazy implementation. */
8899
8899
  async function attemptMirrorSync(paths, options, transactionSignature) {
8900
8900
  try {
8901
- const mirror = await Promise.resolve().then(function () { return require('./mirror-sync-DJVm0KKu.js'); });
8901
+ const mirror = await Promise.resolve().then(function () { return require('./mirror-sync-DzbDh6G_.js'); });
8902
8902
  return await mirror.attemptMirrorSync(paths, options, transactionSignature);
8903
8903
  }
8904
8904
  catch (error) {
@@ -8996,237 +8996,280 @@ async function set(path, document, options) {
8996
8996
  * state appears only under `observation`/`mirrorSync` once actually observed.
8997
8997
  */
8998
8998
  async function setMany(many, options) {
8999
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9000
- // Returns the data that was set, or undefined if the document was already set.
9001
- try {
9002
- // A server WalletClient threads its immutable config snapshot; the default
9003
- // path reads the mutable process-global init() config. This keeps the app-id
9004
- // bound into an on-chain 202 write (Solana/offchain) on the wallet
9005
- // client's original app after a later global init() (CTA-05).
9006
- const config = (_b = (_a = options === null || options === void 0 ? void 0 : options._overrides) === null || _a === void 0 ? void 0 : _a._config) !== null && _b !== void 0 ? _b : await getConfig();
9007
- const authProvider = (_d = (_c = options === null || options === void 0 ? void 0 : options._overrides) === null || _c === void 0 ? void 0 : _c.authProvider) !== null && _d !== void 0 ? _d : config.authProvider;
9008
- if (!authProvider) {
9009
- throw new Error('Auth provider not initialized');
9010
- }
9011
- let documents = [];
9012
- const pathsToInvalidate = new Set();
9013
- for (const { path, document: documentWithReservedFields } of many) {
9014
- // for setting, we should remove any pieces of the document that start with '_' as they are internal and shouldn't be updated. The API would block it if it is one of the reserved ones
9015
- let document = documentWithReservedFields;
9016
- if (documentWithReservedFields) {
9017
- document = Object.fromEntries(Object.entries(documentWithReservedFields).filter(([key]) => !key.startsWith('_')));
9018
- }
9019
- const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
9020
- pathsToInvalidate.add(normalizedPath);
9021
- const pathIsDocument = normalizedPath.split("/").length % 2 === 0;
9022
- let curItemId = "";
9023
- if (pathIsDocument) {
9024
- curItemId = normalizedPath.split("/").pop() ? normalizedPath.split("/").pop() : "";
9025
- }
9026
- else {
9027
- curItemId = Math.random().toString(36).slice(2).substring(0, 12);
9028
- }
9029
- // if the path is a document, we need to append the document id to the path
9030
- const collectionPath = pathIsDocument ? normalizedPath.split("/").slice(0, -1).join("/") : normalizedPath;
9031
- pathsToInvalidate.add(collectionPath);
9032
- let destinationPath = collectionPath;
9033
- if (curItemId && curItemId.length > 0) {
9034
- destinationPath = `${destinationPath}/${curItemId}`;
9035
- }
9036
- documents.push({ destinationPath, document });
9037
- }
9038
- let setResponse;
8999
+ var _a, _b, _c, _d, _e, _f;
9000
+ // A server WalletClient threads its immutable config snapshot; the default
9001
+ // path reads the mutable process-global init() config. This keeps the app-id
9002
+ // bound into an on-chain 202 write (Solana/offchain) on the wallet
9003
+ // client's original app after a later global init() (CTA-05).
9004
+ const config = (_b = (_a = options === null || options === void 0 ? void 0 : options._overrides) === null || _a === void 0 ? void 0 : _a._config) !== null && _b !== void 0 ? _b : await getConfig();
9005
+ const authProvider = (_d = (_c = options === null || options === void 0 ? void 0 : options._overrides) === null || _c === void 0 ? void 0 : _c.authProvider) !== null && _d !== void 0 ? _d : config.authProvider;
9006
+ if (!authProvider) {
9007
+ throw new Error('Auth provider not initialized');
9008
+ }
9009
+ const { documents, pathsToInvalidate } = normalizeWriteBatch(many);
9010
+ // A grant lane's credential is single-use, so its write is built exactly once, and its signer
9011
+ // is prepared the way it always was: inside the approval.
9012
+ const grantLane = (_e = options === null || options === void 0 ? void 0 : options._overrides) === null || _e === void 0 ? void 0 : _e._grantLane;
9013
+ if ((options === null || options === void 0 ? void 0 : options.onchain) && !grantLane) {
9014
+ // The caller knows the wallet will sign: the signer is prepared before the first build, so a
9015
+ // first-time emailed code never runs inside a transaction's lifetime and no build is wasted.
9039
9016
  try {
9040
- // SIMD-0385: tell the worker which Solana transaction formats this client
9041
- // can sign, so it builds v1 only for a client that can complete it.
9042
- const clientTransactionVersions = await resolveClientTransactionVersions(authProvider);
9043
- setResponse = await makeApiRequest('PUT', `items`, { documents, clientTransactionVersions }, options === null || options === void 0 ? void 0 : options._overrides);
9017
+ await ((_f = authProvider.prepareToSign) === null || _f === void 0 ? void 0 : _f.call(authProvider));
9044
9018
  }
9045
9019
  catch (error) {
9046
- if ((error === null || error === void 0 ? void 0 : error.statusCode) === 402 && (error === null || error === void 0 ? void 0 : error.error) === 'INSUFFICIENT_BALANCE') {
9047
- const deficitLamports = Number((_e = error.deficitLamports) !== null && _e !== void 0 ? _e : 0);
9048
- const deficitSol = Number((_f = error.deficitSol) !== null && _f !== void 0 ? _f : deficitLamports / 1000000000);
9049
- throw markWriteNotApplied(new InsufficientBalanceError(String((_g = error.address) !== null && _g !== void 0 ? _g : ''), Number((_h = error.balanceLamports) !== null && _h !== void 0 ? _h : 0), Number((_j = error.estimatedCostLamports) !== null && _j !== void 0 ? _j : 0), deficitLamports, deficitSol), 'before_broadcast');
9050
- }
9051
- // The server answered and refused the write (a rule or invariant denial, a bad request, no
9052
- // session, a rate limit): nothing was built, signed or committed. A network failure, a 5xx,
9053
- // a 408 or a 499 may follow a commit the response never reported, so those stay untagged.
9054
- if (DEFINITIVE_WRITE_REFUSAL_STATUSES.has(Number(error === null || error === void 0 ? void 0 : error.statusCode))) {
9055
- throw markWriteNotApplied(error, 'before_broadcast');
9056
- }
9057
- throw error;
9020
+ throw markWriteNotApplied(error, 'before_broadcast');
9058
9021
  }
9022
+ }
9023
+ // Each reason to build again is spent once: the wallet's own ceremony (the build it ran beside is
9024
+ // dying), and a send refused because the blockhash expired (a long pause on the approve card).
9025
+ const rebuilds = { ceremony: !grantLane, expiry: !grantLane };
9026
+ for (;;) {
9027
+ const setResponse = await requestWrite(documents, authProvider, options);
9059
9028
  // Invalidate caches and pending requests for affected paths
9060
9029
  pathsToInvalidate.forEach(path => {
9061
9030
  clearCacheByPrefix(path);
9062
9031
  });
9063
- if (setResponse.status === 202) {
9064
- // This means that the document needs to be set on-chain (or signed for offchain),
9065
- // the API did nothing and gave us the required info to run this transaction.
9066
- // Until something is sent, every failure below is definitively not applied.
9067
- let sending = false;
9032
+ if (setResponse.status === 200)
9033
+ return directCommitResult(setResponse, documents);
9034
+ if (setResponse.status !== 202)
9035
+ throw new Error(`Failed to set document: ${setResponse}`);
9036
+ const outcome = await completePreparedWrite(setResponse, documents, config, authProvider, options, rebuilds);
9037
+ if (!isRebuild(outcome))
9038
+ return outcome;
9039
+ rebuilds[outcome.rebuild] = false;
9040
+ }
9041
+ }
9042
+ /** The caller's batch as the worker takes it, plus every read-cache prefix the write touches. */
9043
+ function normalizeWriteBatch(many) {
9044
+ const documents = [];
9045
+ const pathsToInvalidate = new Set();
9046
+ for (const { path, document: documentWithReservedFields } of many) {
9047
+ // for setting, we should remove any pieces of the document that start with '_' as they are internal and shouldn't be updated. The API would block it if it is one of the reserved ones
9048
+ let document = documentWithReservedFields;
9049
+ if (documentWithReservedFields) {
9050
+ document = Object.fromEntries(Object.entries(documentWithReservedFields).filter(([key]) => !key.startsWith('_')));
9051
+ }
9052
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
9053
+ pathsToInvalidate.add(normalizedPath);
9054
+ const pathIsDocument = normalizedPath.split("/").length % 2 === 0;
9055
+ let curItemId = "";
9056
+ if (pathIsDocument) {
9057
+ curItemId = normalizedPath.split("/").pop() ? normalizedPath.split("/").pop() : "";
9058
+ }
9059
+ else {
9060
+ curItemId = Math.random().toString(36).slice(2).substring(0, 12);
9061
+ }
9062
+ // if the path is a document, we need to append the document id to the path
9063
+ const collectionPath = pathIsDocument ? normalizedPath.split("/").slice(0, -1).join("/") : normalizedPath;
9064
+ pathsToInvalidate.add(collectionPath);
9065
+ let destinationPath = collectionPath;
9066
+ if (curItemId && curItemId.length > 0) {
9067
+ destinationPath = `${destinationPath}/${curItemId}`;
9068
+ }
9069
+ documents.push({ destinationPath, document });
9070
+ }
9071
+ return { documents, pathsToInvalidate };
9072
+ }
9073
+ /** The write PUT: a direct commit (200), a transaction to sign (202), or a definitive refusal. */
9074
+ async function requestWrite(documents, authProvider, options) {
9075
+ var _a, _b, _c, _d, _e;
9076
+ try {
9077
+ // SIMD-0385: tell the worker which Solana transaction formats this client
9078
+ // can sign, so it builds v1 only for a client that can complete it.
9079
+ const clientTransactionVersions = await resolveClientTransactionVersions(authProvider);
9080
+ return await makeApiRequest('PUT', `items`, { documents, clientTransactionVersions }, options === null || options === void 0 ? void 0 : options._overrides);
9081
+ }
9082
+ catch (error) {
9083
+ if ((error === null || error === void 0 ? void 0 : error.statusCode) === 402 && (error === null || error === void 0 ? void 0 : error.error) === 'INSUFFICIENT_BALANCE') {
9084
+ const deficitLamports = Number((_a = error.deficitLamports) !== null && _a !== void 0 ? _a : 0);
9085
+ const deficitSol = Number((_b = error.deficitSol) !== null && _b !== void 0 ? _b : deficitLamports / 1000000000);
9086
+ throw markWriteNotApplied(new InsufficientBalanceError(String((_c = error.address) !== null && _c !== void 0 ? _c : ''), Number((_d = error.balanceLamports) !== null && _d !== void 0 ? _d : 0), Number((_e = error.estimatedCostLamports) !== null && _e !== void 0 ? _e : 0), deficitLamports, deficitSol), 'before_broadcast');
9087
+ }
9088
+ // The server answered and refused the write (a rule or invariant denial, a bad request, no
9089
+ // session, a rate limit): nothing was built, signed or committed. A network failure, a 5xx,
9090
+ // a 408 or a 499 may follow a commit the response never reported, so those stay untagged.
9091
+ if (DEFINITIVE_WRITE_REFUSAL_STATUSES.has(Number(error === null || error === void 0 ? void 0 : error.statusCode))) {
9092
+ throw markWriteNotApplied(error, 'before_broadcast');
9093
+ }
9094
+ throw error;
9095
+ }
9096
+ }
9097
+ function isRebuild(outcome) {
9098
+ return 'rebuild' in outcome;
9099
+ }
9100
+ /**
9101
+ * Finish a 202: the worker built the transaction (or the poofnet approval) and did nothing
9102
+ * else; the wallet signs it here and, on a real chain, it is broadcast. Until something is
9103
+ * sent, every failure is definitively not applied. `rebuilds` says which reasons to build
9104
+ * again are still open.
9105
+ */
9106
+ async function completePreparedWrite(setResponse, documents, config, authProvider, options, rebuilds) {
9107
+ var _a, _b, _c;
9108
+ let sending = false;
9109
+ try {
9110
+ const { transactions, offchainTransaction } = setResponse.data;
9111
+ // Handle offchain transaction flow (for 'offchain' protocol apps)
9112
+ if (offchainTransaction && Array.isArray(transactions) && transactions.length > 0) {
9113
+ throw new Error('Ambiguous write response mixes offchain and onchain transaction targets');
9114
+ }
9115
+ if (offchainTransaction) {
9116
+ // Offchain signing is retired: no server mints this envelope any more
9117
+ // (the realtime worker commits poofnet writes directly). Fail loudly
9118
+ // rather than silently ignoring a payload the caller was asked to sign.
9119
+ throw new Error('Unsupported 202 transaction shape: offchain signing is retired');
9120
+ }
9121
+ // Handle Solana on-chain transaction flow
9122
+ if (!Array.isArray(transactions) || transactions.length !== 1) {
9123
+ throw new Error(`Expected exactly one on-chain transaction, received ${Array.isArray(transactions) ? transactions.length : 0}`);
9124
+ }
9125
+ const curTx = transactions[0];
9126
+ // The EVM onchain data plane is retired: no worker mints an EVM 202 any
9127
+ // more. A payload that still carries one is an unexpected response and
9128
+ // fails loudly BEFORE anything is signed - never silently ignored.
9129
+ if ((curTx === null || curTx === void 0 ? void 0 : curTx.evmTransaction) != null) {
9130
+ throw new Error('Unsupported 202 transaction shape: the write response carried an evmTransaction, ' +
9131
+ 'but EVM onchain writes are no longer supported. Nothing was signed or submitted.');
9132
+ }
9133
+ const hasSerializedSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.serializedTransaction) != null;
9134
+ const hasBuiltSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.transactionArgs) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.remainingAccounts) != null ||
9135
+ (curTx === null || curTx === void 0 ? void 0 : curTx.idl) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.txData) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.preInstructions) != null;
9136
+ if (hasSerializedSolanaTarget && hasBuiltSolanaTarget) {
9137
+ throw new Error('Ambiguous on-chain write response mixes Solana transaction target formats');
9138
+ }
9139
+ // All requested paths (writes AND deletes), in request order. Used for the
9140
+ // post-confirm mirror read-back, which correlates every requested path.
9141
+ // The pre-sign validation derives its own full expected intent from
9142
+ // `documents` (see below) and needs nothing from this list.
9143
+ const requestedPaths = documents.map(d => d.destinationPath);
9144
+ const requestedDocuments = buildRequestedDocuments(documents);
9145
+ const appId = config.appId;
9146
+ // The lane comes verbatim from the worker, and is read BEFORE anything is
9147
+ // signed or submitted: a missing tag fails closed while nothing has been
9148
+ // broadcast, instead of stranding a landed transaction with no receipt.
9149
+ const workerChain = readWorkerChainTag((_a = setResponse.data) === null || _a === void 0 ? void 0 : _a.receipt, setResponse.data, curTx);
9150
+ if (!workerChain) {
9151
+ throw new Error('The write response carried no execution-chain tag, so this receipt could not state where the write ran. ' +
9152
+ 'Nothing was signed or submitted.');
9153
+ }
9154
+ const grantLane = (_b = options === null || options === void 0 ? void 0 : options._overrides) === null || _b === void 0 ? void 0 : _b._grantLane;
9155
+ grantLane === null || grantLane === void 0 ? void 0 : grantLane.assertLane(workerChain);
9156
+ // The wallet's own ceremony runs now, before it sees a transaction: a hosted embedded
9157
+ // wallet whose 24-hour signing session has lapsed collects its emailed code here, and that
9158
+ // outlives the blockhash the worker just minted. A ceremony that ran means this build is
9159
+ // already dying, so the write is built again and the wallet signs the fresh one in one click.
9160
+ // (A caller that passed `onchain` prepared the signer before the build, so this normally
9161
+ // answers 'ready' at once. It runs the ceremony here only when that preparation could not
9162
+ // reach the signer; the build it then replaces is left to expire unsigned.)
9163
+ if (rebuilds.ceremony && await ((_c = authProvider.prepareToSign) === null || _c === void 0 ? void 0 : _c.call(authProvider)) === 'established')
9164
+ return { rebuild: 'ceremony' };
9165
+ if (workerChain === 'realtime_offchain') {
9166
+ // Poofnet: the wallet signs the worker's unsendable approval message and
9167
+ // the worker verifies and commits it. Nothing is submitted to any chain.
9168
+ if (typeof curTx.serializedTransaction !== 'string' || typeof curTx.poofnetIntentId !== 'string') {
9169
+ throw new Error('Unsupported 202 transaction shape: a poofnet write needs serializedTransaction and poofnetIntentId');
9170
+ }
9171
+ const { signPoofnetTransaction, buildExpectedWriteIntent } = await Promise.resolve().then(function () { return require('./solana-operations-DsT1303T.js'); });
9172
+ const signedTransaction = await signPoofnetTransaction(curTx.serializedTransaction, authProvider, options, buildExpectedWriteIntent(documents));
9173
+ // Signing-only, exactly as on a real chain: signed and NOT committed.
9174
+ if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
9175
+ return {
9176
+ status: 'signed', appId, requestedDocuments: buildRequestedDocuments(documents),
9177
+ chain: 'realtime_offchain', transactionId: null, signedTransaction,
9178
+ poofnetIntentId: curTx.poofnetIntentId,
9179
+ };
9180
+ }
9181
+ // A grant lane's first credential is spent by the PUT that built this approval, so the
9182
+ // commit's is minted now, before `sending`: failing to mint sends nothing.
9183
+ const commitHeaders = await (grantLane === null || grantLane === void 0 ? void 0 : grantLane.commitHeaders());
9184
+ // The commit PUT is the one ambiguous step of this lane: a lost response may follow a
9185
+ // commit, so a transport failure or a 5xx stays untagged (read the path back). A 4xx is
9186
+ // realtime stating it committed nothing (the intent expired or was taken, the signer did
9187
+ // not match, a rule refused it), as for the first PUT. 408 and 499 are a proxy's words,
9188
+ // not realtime's, and may follow a commit, so they stay ambiguous too.
9189
+ sending = true;
9190
+ let commitResponse;
9068
9191
  try {
9069
- const { transactions, offchainTransaction } = setResponse.data;
9070
- // Handle offchain transaction flow (for 'offchain' protocol apps)
9071
- if (offchainTransaction && Array.isArray(transactions) && transactions.length > 0) {
9072
- throw new Error('Ambiguous write response mixes offchain and onchain transaction targets');
9073
- }
9074
- if (offchainTransaction) {
9075
- // Offchain signing is retired: no server mints this envelope any more
9076
- // (the realtime worker commits poofnet writes directly). Fail loudly
9077
- // rather than silently ignoring a payload the caller was asked to sign.
9078
- throw new Error('Unsupported 202 transaction shape: offchain signing is retired');
9079
- }
9080
- // Handle Solana on-chain transaction flow
9081
- if (!Array.isArray(transactions) || transactions.length !== 1) {
9082
- throw new Error(`Expected exactly one on-chain transaction, received ${Array.isArray(transactions) ? transactions.length : 0}`);
9083
- }
9084
- const curTx = transactions[0];
9085
- // The EVM onchain data plane is retired: no worker mints an EVM 202 any
9086
- // more. A payload that still carries one is an unexpected response and
9087
- // fails loudly BEFORE anything is signed - never silently ignored.
9088
- if ((curTx === null || curTx === void 0 ? void 0 : curTx.evmTransaction) != null) {
9089
- throw new Error('Unsupported 202 transaction shape: the write response carried an evmTransaction, ' +
9090
- 'but EVM onchain writes are no longer supported. Nothing was signed or submitted.');
9091
- }
9092
- const hasSerializedSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.serializedTransaction) != null;
9093
- const hasBuiltSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.transactionArgs) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.remainingAccounts) != null ||
9094
- (curTx === null || curTx === void 0 ? void 0 : curTx.idl) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.txData) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.preInstructions) != null;
9095
- if (hasSerializedSolanaTarget && hasBuiltSolanaTarget) {
9096
- throw new Error('Ambiguous on-chain write response mixes Solana transaction target formats');
9097
- }
9098
- // All requested paths (writes AND deletes), in request order. Used for the
9099
- // post-confirm mirror read-back, which correlates every requested path.
9100
- // The pre-sign validation derives its own full expected intent from
9101
- // `documents` (see below) and needs nothing from this list.
9102
- const requestedPaths = documents.map(d => d.destinationPath);
9103
- const requestedDocuments = buildRequestedDocuments(documents);
9104
- const appId = config.appId;
9105
- // The lane comes verbatim from the worker, and is read BEFORE anything is
9106
- // signed or submitted: a missing tag fails closed while nothing has been
9107
- // broadcast, instead of stranding a landed transaction with no receipt.
9108
- const workerChain = readWorkerChainTag((_k = setResponse.data) === null || _k === void 0 ? void 0 : _k.receipt, setResponse.data, curTx);
9109
- if (!workerChain) {
9110
- throw new Error('The write response carried no execution-chain tag, so this receipt could not state where the write ran. ' +
9111
- 'Nothing was signed or submitted.');
9112
- }
9113
- const grantLane = (_l = options === null || options === void 0 ? void 0 : options._overrides) === null || _l === void 0 ? void 0 : _l._grantLane;
9114
- grantLane === null || grantLane === void 0 ? void 0 : grantLane.assertLane(workerChain);
9115
- if (workerChain === 'realtime_offchain') {
9116
- // Poofnet: the wallet signs the worker's unsendable approval message and
9117
- // the worker verifies and commits it. Nothing is submitted to any chain.
9118
- if (typeof curTx.serializedTransaction !== 'string' || typeof curTx.poofnetIntentId !== 'string') {
9119
- throw new Error('Unsupported 202 transaction shape: a poofnet write needs serializedTransaction and poofnetIntentId');
9120
- }
9121
- const { signPoofnetTransaction, buildExpectedWriteIntent } = await Promise.resolve().then(function () { return require('./solana-operations-DFohVGz6.js'); });
9122
- const signedTransaction = await signPoofnetTransaction(curTx.serializedTransaction, authProvider, options, buildExpectedWriteIntent(documents));
9123
- // Signing-only, exactly as on a real chain: signed and NOT committed.
9124
- if ((options === null || options === void 0 ? void 0 : options.shouldSubmitTx) === false) {
9125
- return {
9126
- status: 'signed', appId, requestedDocuments: buildRequestedDocuments(documents),
9127
- chain: 'realtime_offchain', transactionId: null, signedTransaction,
9128
- poofnetIntentId: curTx.poofnetIntentId,
9129
- };
9130
- }
9131
- // A grant lane's first credential is spent by the PUT that built this approval, so the
9132
- // commit's is minted now, before `sending`: failing to mint sends nothing.
9133
- const commitHeaders = await (grantLane === null || grantLane === void 0 ? void 0 : grantLane.commitHeaders());
9134
- // The commit PUT is the one ambiguous step of this lane: a lost response may follow a
9135
- // commit, so a transport failure or a 5xx stays untagged (read the path back). A 4xx is
9136
- // realtime stating it committed nothing (the intent expired or was taken, the signer did
9137
- // not match, a rule refused it), as for the first PUT. 408 and 499 are a proxy's words,
9138
- // not realtime's, and may follow a commit, so they stay ambiguous too.
9139
- sending = true;
9140
- let commitResponse;
9141
- try {
9142
- commitResponse = await makeApiRequest('PUT', 'items/signed', { intentId: curTx.poofnetIntentId, signedTransaction }, commitHeaders ? Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options._overrides), { _getAuthHeaders: async () => commitHeaders }) : options === null || options === void 0 ? void 0 : options._overrides);
9143
- if (commitResponse.status !== 200) {
9144
- throw Object.assign(new Error(`Poofnet signed write was not committed (status ${commitResponse.status})`), { statusCode: commitResponse.status });
9145
- }
9146
- }
9147
- catch (error) {
9148
- const status = Number(error === null || error === void 0 ? void 0 : error.statusCode);
9149
- throw status >= 400 && status < 500 && status !== 408 && status !== 499 ? markWriteNotApplied(error, 'broadcast_rejected') : error;
9150
- }
9151
- return directCommitResult(commitResponse, documents);
9152
- }
9153
- if (curTx.serializedTransaction) {
9154
- if (!SOLANA_CHAIN_TAGS.has(workerChain)) {
9155
- throw new Error(`The write response reported execution chain "${workerChain}" for a Solana transaction. ` +
9156
- 'Nothing was signed or submitted.');
9157
- }
9158
- const solanaChain = workerChain;
9159
- const { handlePreBuiltTransaction, buildExpectedWriteIntent } = await Promise.resolve().then(function () { return require('./solana-operations-DFohVGz6.js'); });
9160
- // OA-0001: derive the expected intent from OUR OWN request (the one
9161
- // ground truth a tampered builder response cannot change) so the
9162
- // validator can reject any transaction whose operation semantics
9163
- // diverge from it BEFORE the wallet is asked to sign.
9164
- const expectedIntent = buildExpectedWriteIntent(documents);
9165
- const onBroadcast = options === null || options === void 0 ? void 0 : options.onBroadcast;
9166
- const solanaOutcome = await handlePreBuiltTransaction(curTx, authProvider, options, expectedIntent, onBroadcast && (async (signed) => {
9167
- await onBroadcast({
9168
- status: 'submitted', appId, requestedDocuments, chain: solanaChain,
9169
- transactionId: signed.transactionSignature,
9170
- signedTransaction: signed.signedTransaction,
9171
- fence: signed.fence,
9172
- confirmation: { state: 'unknown', reason: 'about to broadcast' },
9173
- });
9174
- }));
9175
- // Past this point the bytes may be on the network: nothing is tagged here.
9176
- sending = true;
9177
- // `shouldSubmitTx: false` signed WITHOUT sending — no signature exists,
9178
- // and there is nothing to mirror, so no synchronization is attempted.
9179
- if (solanaOutcome.outcome === 'signed') {
9180
- return {
9181
- status: 'signed', appId, requestedDocuments, chain: solanaChain,
9182
- transactionId: null,
9183
- signedTransaction: solanaOutcome.signedTransaction,
9184
- fence: solanaOutcome.fence,
9185
- };
9186
- }
9187
- if (solanaOutcome.outcome === 'submitted') {
9188
- return {
9189
- status: 'submitted', appId, requestedDocuments, chain: solanaChain,
9190
- transactionId: solanaOutcome.transactionSignature,
9191
- signedTransaction: solanaOutcome.signedTransaction,
9192
- fence: solanaOutcome.fence,
9193
- confirmation: { state: 'unknown', reason: solanaOutcome.reason },
9194
- };
9195
- }
9196
- // Confirmed: the receipt is already complete, so the mirror read is a
9197
- // best-effort enrichment reported in `mirrorSync`, never a rejection.
9198
- const mirrorSync = grantLane
9199
- ? { observed: false, reason: 'not attempted: a venue grant authorizes only the write' }
9200
- : await attemptMirrorSync(requestedPaths, Object.assign(Object.assign({}, options), { _overrides: Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options._overrides), { _config: config }) }), solanaOutcome.transactionSignature);
9201
- return {
9202
- status: 'confirmed', appId, requestedDocuments, chain: solanaChain,
9203
- transactionId: solanaOutcome.transactionSignature,
9204
- signedTransaction: solanaOutcome.signedTransaction,
9205
- fence: solanaOutcome.fence,
9206
- confirmationContextSlot: solanaOutcome.confirmationContextSlot,
9207
- mirrorSync,
9208
- };
9209
- }
9210
- else {
9211
- throw new Error('Unsupported 202 transaction shape: expected serializedTransaction');
9192
+ commitResponse = await makeApiRequest('PUT', 'items/signed', { intentId: curTx.poofnetIntentId, signedTransaction }, commitHeaders ? Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options._overrides), { _getAuthHeaders: async () => commitHeaders }) : options === null || options === void 0 ? void 0 : options._overrides);
9193
+ if (commitResponse.status !== 200) {
9194
+ throw Object.assign(new Error(`Poofnet signed write was not committed (status ${commitResponse.status})`), { statusCode: commitResponse.status });
9212
9195
  }
9213
9196
  }
9214
9197
  catch (error) {
9215
- // The Solana lane tags its own broadcast and on-chain failures; anything
9216
- // untagged from it, and every poofnet step before the commit PUT, failed
9217
- // before a single byte was sent.
9218
- throw sending ? error : markWriteNotApplied(error, 'before_broadcast');
9198
+ const status = Number(error === null || error === void 0 ? void 0 : error.statusCode);
9199
+ throw status >= 400 && status < 500 && status !== 408 && status !== 499 ? markWriteNotApplied(error, 'broadcast_rejected') : error;
9219
9200
  }
9201
+ return directCommitResult(commitResponse, documents);
9220
9202
  }
9221
- else if (setResponse.status === 200) {
9222
- return directCommitResult(setResponse, documents);
9203
+ if (curTx.serializedTransaction) {
9204
+ if (!SOLANA_CHAIN_TAGS.has(workerChain)) {
9205
+ throw new Error(`The write response reported execution chain "${workerChain}" for a Solana transaction. ` +
9206
+ 'Nothing was signed or submitted.');
9207
+ }
9208
+ const solanaChain = workerChain;
9209
+ const { handlePreBuiltTransaction, buildExpectedWriteIntent } = await Promise.resolve().then(function () { return require('./solana-operations-DsT1303T.js'); });
9210
+ // OA-0001: derive the expected intent from OUR OWN request (the one
9211
+ // ground truth a tampered builder response cannot change) so the
9212
+ // validator can reject any transaction whose operation semantics
9213
+ // diverge from it BEFORE the wallet is asked to sign.
9214
+ const expectedIntent = buildExpectedWriteIntent(documents);
9215
+ const onBroadcast = options === null || options === void 0 ? void 0 : options.onBroadcast;
9216
+ const solanaOutcome = await handlePreBuiltTransaction(curTx, authProvider, options, expectedIntent, onBroadcast && (async (signed) => {
9217
+ await onBroadcast({
9218
+ status: 'submitted', appId, requestedDocuments, chain: solanaChain,
9219
+ transactionId: signed.transactionSignature,
9220
+ signedTransaction: signed.signedTransaction,
9221
+ fence: signed.fence,
9222
+ confirmation: { state: 'unknown', reason: 'about to broadcast' },
9223
+ });
9224
+ }));
9225
+ // Past this point the bytes may be on the network: nothing is tagged here.
9226
+ sending = true;
9227
+ // `shouldSubmitTx: false` signed WITHOUT sending — no signature exists,
9228
+ // and there is nothing to mirror, so no synchronization is attempted.
9229
+ if (solanaOutcome.outcome === 'signed') {
9230
+ return {
9231
+ status: 'signed', appId, requestedDocuments, chain: solanaChain,
9232
+ transactionId: null,
9233
+ signedTransaction: solanaOutcome.signedTransaction,
9234
+ fence: solanaOutcome.fence,
9235
+ };
9236
+ }
9237
+ if (solanaOutcome.outcome === 'submitted') {
9238
+ return {
9239
+ status: 'submitted', appId, requestedDocuments, chain: solanaChain,
9240
+ transactionId: solanaOutcome.transactionSignature,
9241
+ signedTransaction: solanaOutcome.signedTransaction,
9242
+ fence: solanaOutcome.fence,
9243
+ confirmation: { state: 'unknown', reason: solanaOutcome.reason },
9244
+ };
9245
+ }
9246
+ // Confirmed: the receipt is already complete, so the mirror read is a
9247
+ // best-effort enrichment reported in `mirrorSync`, never a rejection.
9248
+ const mirrorSync = grantLane
9249
+ ? { observed: false, reason: 'not attempted: a venue grant authorizes only the write' }
9250
+ : await attemptMirrorSync(requestedPaths, Object.assign(Object.assign({}, options), { _overrides: Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options._overrides), { _config: config }) }), solanaOutcome.transactionSignature);
9251
+ return {
9252
+ status: 'confirmed', appId, requestedDocuments, chain: solanaChain,
9253
+ transactionId: solanaOutcome.transactionSignature,
9254
+ signedTransaction: solanaOutcome.signedTransaction,
9255
+ fence: solanaOutcome.fence,
9256
+ confirmationContextSlot: solanaOutcome.confirmationContextSlot,
9257
+ mirrorSync,
9258
+ };
9223
9259
  }
9224
9260
  else {
9225
- throw new Error(`Failed to set document: ${setResponse}`);
9261
+ throw new Error('Unsupported 202 transaction shape: expected serializedTransaction');
9226
9262
  }
9227
9263
  }
9228
9264
  catch (error) {
9229
- throw error;
9265
+ // The blockhash died before the send: the RPC refused the bytes in preflight, so nothing
9266
+ // entered the network. The worker builds a fresh one and the wallet signs it again.
9267
+ if (rebuilds.expiry && (await Promise.resolve().then(function () { return require('./solana-operations-DsT1303T.js'); })).isExpiredBlockhashRejection(error))
9268
+ return { rebuild: 'expiry' };
9269
+ // The Solana lane tags its own broadcast and on-chain failures; anything
9270
+ // untagged from it, and every poofnet step before the commit PUT, failed
9271
+ // before a single byte was sent.
9272
+ throw sending ? error : markWriteNotApplied(error, 'before_broadcast');
9230
9273
  }
9231
9274
  }
9232
9275
  /**
@@ -9462,6 +9505,23 @@ async function signTransaction(transaction) {
9462
9505
  }
9463
9506
  return config.authProvider.signTransaction(transaction);
9464
9507
  }
9508
+ /**
9509
+ * Make the signed-in wallet ready to sign without delay, BEFORE the transaction it will sign
9510
+ * exists. A hosted embedded wallet whose 24-hour signing session has lapsed collects its emailed
9511
+ * code here; a transaction built before that code is dead by the time it is signed, because a
9512
+ * blockhash lives about 33 seconds on mainnet (late 2026) and the code takes longer. `set` and
9513
+ * `setMany` do this themselves before a wallet signature; call it directly before a flow that
9514
+ * builds and signs outside them, such as a permit approval. Resolves `'established'` when a
9515
+ * ceremony ran, else `'ready'`; a wallet that holds its own key always answers `'ready'`.
9516
+ */
9517
+ async function prepareToSign() {
9518
+ var _a, _b, _c;
9519
+ const config = await getConfig();
9520
+ if (!config.authProvider) {
9521
+ throw new Error('Auth provider not initialized. Please call init() first.');
9522
+ }
9523
+ return (_c = (await ((_b = (_a = config.authProvider).prepareToSign) === null || _b === void 0 ? void 0 : _b.call(_a)))) !== null && _c !== void 0 ? _c : 'ready';
9524
+ }
9465
9525
  async function signAndSubmitTransaction(transaction, feePayer) {
9466
9526
  const config = await getConfig();
9467
9527
  if (!config.authProvider) {
@@ -9482,6 +9542,7 @@ var operations = /*#__PURE__*/Object.freeze({
9482
9542
  getFiles: getFiles,
9483
9543
  getMany: getMany,
9484
9544
  onReadCacheAuthChange: onReadCacheAuthChange,
9545
+ prepareToSign: prepareToSign,
9485
9546
  queryAggregate: queryAggregate,
9486
9547
  runExpression: runExpression,
9487
9548
  runExpressionMany: runExpressionMany,
@@ -11044,7 +11105,7 @@ function toMillis(seconds) {
11044
11105
 
11045
11106
  /** SIWS message creation is async already, so its onchain module can be lazy. */
11046
11107
  async function genSolanaMessage(address, nonce) {
11047
- const implementation = await Promise.resolve().then(function () { return require('./solana-message-HkOoUz8z.js'); });
11108
+ const implementation = await Promise.resolve().then(function () { return require('./solana-message-CPotom18.js'); });
11048
11109
  return implementation.genSolanaMessage(address, nonce);
11049
11110
  }
11050
11111
 
@@ -11669,6 +11730,7 @@ exports.normalizeEvmAddress = normalizeEvmAddress;
11669
11730
  exports.now = now;
11670
11731
  exports.onSessionChange = onSessionChange;
11671
11732
  exports.onSessionCleared = onSessionCleared;
11733
+ exports.prepareToSign = prepareToSign;
11672
11734
  exports.queryAggregate = queryAggregate;
11673
11735
  exports.reconcileSetResult = reconcileSetResult;
11674
11736
  exports.reconnectWithNewAuth = reconnectWithNewAuth;
@@ -11699,4 +11761,4 @@ exports.toSeconds = toSeconds;
11699
11761
  exports.waitForSetResult = waitForSetResult;
11700
11762
  exports.withEffects = withEffects;
11701
11763
  exports.writeNotAppliedPhase = writeNotAppliedPhase;
11702
- //# sourceMappingURL=index-l9LI3y1q.js.map
11764
+ //# sourceMappingURL=index-D7-5ecyu.js.map