@bounded-sh/core 0.0.67 → 0.0.69
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 +0 -1
- package/dist/client/config.d.ts +4 -8
- package/dist/client/operations.d.ts +0 -3
- package/dist/client/reconcile.d.ts +7 -16
- package/dist/client/subscribe-query.d.ts +12 -1
- package/dist/{index-TyXiW4Uf.mjs → index-B3aNfGi6.mjs} +80 -634
- package/dist/index-B3aNfGi6.mjs.map +1 -0
- package/dist/{index-DNZifL5j.js → index-DlJKTmRv.js} +81 -637
- package/dist/index-DlJKTmRv.js.map +1 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{realtime-store-CINyAkPw.js → realtime-store-CkgpUOrE.js} +2 -2
- package/dist/{realtime-store-CINyAkPw.js.map → realtime-store-CkgpUOrE.js.map} +1 -1
- package/dist/{realtime-store-CpbnXM7q.mjs → realtime-store-i8pxSuZE.mjs} +2 -2
- package/dist/{realtime-store-CpbnXM7q.mjs.map → realtime-store-i8pxSuZE.mjs.map} +1 -1
- package/dist/{solana-message-DXXwC95Z.mjs → solana-message-AXfv2U1S.mjs} +2 -2
- package/dist/{solana-message-DXXwC95Z.mjs.map → solana-message-AXfv2U1S.mjs.map} +1 -1
- package/dist/{solana-message-Bycv-L5n.js → solana-message-DnV4FQ__.js} +2 -2
- package/dist/{solana-message-Bycv-L5n.js.map → solana-message-DnV4FQ__.js.map} +1 -1
- package/dist/{solana-operations-ChHG25O0.mjs → solana-operations-Bte92rmq.mjs} +2 -2
- package/dist/{solana-operations-ChHG25O0.mjs.map → solana-operations-Bte92rmq.mjs.map} +1 -1
- package/dist/{solana-operations-Dm_4VnlB.js → solana-operations-DPul1dWo.js} +2 -2
- package/dist/{solana-operations-Dm_4VnlB.js.map → solana-operations-DPul1dWo.js.map} +1 -1
- package/dist/types.d.ts +21 -186
- package/dist/utils/session-events.d.ts +2 -2
- package/package.json +2 -2
- package/dist/index-DNZifL5j.js.map +0 -1
- package/dist/index-TyXiW4Uf.mjs.map +0 -1
- package/dist/utils/evm/evm-transaction-validation.d.ts +0 -46
|
@@ -687,8 +687,8 @@ function refreshedTokenMayReplaceStored(newIdToken, storedAddress, decodeBase64U
|
|
|
687
687
|
* event bus, so a session dying inside a session manager used to be invisible to
|
|
688
688
|
* the SDK: `setCurrentUser(null)` was only ever called by `logout()` and `init()`.
|
|
689
689
|
* The result was a UI that kept showing a connected wallet long after the session
|
|
690
|
-
* it was showing had been wiped, which is exactly what let
|
|
691
|
-
* review against a wallet the server no longer knew about.
|
|
690
|
+
* it was showing had been wiped, which is exactly what let a wallet-review UI
|
|
691
|
+
* freeze a review against a wallet the server no longer knew about.
|
|
692
692
|
*
|
|
693
693
|
* `js-sdk` registers a handler at init; core fires it ONLY when storage was
|
|
694
694
|
* actually cleared, never on a failed-but-preserved refresh. Firing on a
|
|
@@ -4045,7 +4045,7 @@ class ServerSessionManager {
|
|
|
4045
4045
|
const sessionConfig = (_a = this.sessionConfig) !== null && _a !== void 0 ? _a : undefined;
|
|
4046
4046
|
/* fetch nonce from auth API (bound to the snapshotted app+issuer) */
|
|
4047
4047
|
const nonce = await genAuthNonce(sessionConfig);
|
|
4048
|
-
const { genSolanaMessage } = await Promise.resolve().then(function () { return require('./solana-message-
|
|
4048
|
+
const { genSolanaMessage } = await Promise.resolve().then(function () { return require('./solana-message-DnV4FQ__.js'); });
|
|
4049
4049
|
const message = await genSolanaMessage(address, nonce, sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.appId);
|
|
4050
4050
|
/* sign the message */
|
|
4051
4051
|
const sigBytes = nacl.sign.detached(new TextEncoder().encode(message), kp.secretKey);
|
|
@@ -6777,7 +6777,7 @@ async function doReconnectWithNewAuth() {
|
|
|
6777
6777
|
console.warn('[WS v2] Failed to clear HTTP read cache on auth change:', error);
|
|
6778
6778
|
}
|
|
6779
6779
|
try {
|
|
6780
|
-
const { reconnectRealtimeStoreWithNewAuth } = await Promise.resolve().then(function () { return require('./realtime-store-
|
|
6780
|
+
const { reconnectRealtimeStoreWithNewAuth } = await Promise.resolve().then(function () { return require('./realtime-store-CkgpUOrE.js'); });
|
|
6781
6781
|
await reconnectRealtimeStoreWithNewAuth();
|
|
6782
6782
|
}
|
|
6783
6783
|
catch (error) {
|
|
@@ -6888,7 +6888,7 @@ async function runNamedQueriesOverSocket(appId, queries, isServer) {
|
|
|
6888
6888
|
return null; // timeout / disconnect / server error frame -> HTTP re-runs authoritatively
|
|
6889
6889
|
}
|
|
6890
6890
|
if ((data === null || data === void 0 ? void 0 : data.useHttp) === true)
|
|
6891
|
-
return null; // server deferred (onchain
|
|
6891
|
+
return null; // server deferred (onchain, cross-room, malformed)
|
|
6892
6892
|
if (Array.isArray(data === null || data === void 0 ? void 0 : data.queries))
|
|
6893
6893
|
return data.queries;
|
|
6894
6894
|
return null; // unexpected shape -> HTTP
|
|
@@ -7001,456 +7001,6 @@ async function wsIntentReliable(appId, roomRoutePath, intent, isServer) {
|
|
|
7001
7001
|
});
|
|
7002
7002
|
}
|
|
7003
7003
|
|
|
7004
|
-
/**
|
|
7005
|
-
* Selectors derived from the canonical BoundedRuntime signatures (BoundedTypes.sol):
|
|
7006
|
-
*
|
|
7007
|
-
* cast sig 'setDocuments(string,(string[],bool,(string,uint8,uint8,bytes)[])[])'
|
|
7008
|
-
* => 0x0827b094
|
|
7009
|
-
* cast sig 'setDocumentsAttested(string,(string[],bool,(string,uint8,uint8,bytes)[])[],(bytes32,uint256,uint256,uint8,bytes32,bytes32))'
|
|
7010
|
-
* => 0x87b111c4
|
|
7011
|
-
*
|
|
7012
|
-
* Keep the signatures beside the constants: changing either Solidity tuple is an
|
|
7013
|
-
* ABI break and must deliberately update these values and the Foundry goldens.
|
|
7014
|
-
*/
|
|
7015
|
-
const BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR = '0x0827b094';
|
|
7016
|
-
const BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR = '0x87b111c4';
|
|
7017
|
-
const SET_DOCUMENTS_SELECTOR = BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR.slice(2);
|
|
7018
|
-
const SET_DOCUMENTS_ATTESTED_SELECTOR = BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR.slice(2);
|
|
7019
|
-
const MAX_CALLDATA_BYTES = 1024 * 1024;
|
|
7020
|
-
const MAX_ARRAY_ITEMS = 2048;
|
|
7021
|
-
const BIGINT_ZERO = BigInt(0);
|
|
7022
|
-
const BIGINT_ONE = BigInt(1);
|
|
7023
|
-
const BIGINT_EIGHT = BigInt(8);
|
|
7024
|
-
const SECP256K1_N = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141');
|
|
7025
|
-
const SECP256K1_HALF_N = BigInt('0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0');
|
|
7026
|
-
function hexBytes(raw) {
|
|
7027
|
-
if (typeof raw !== 'string' || !/^0x[0-9a-fA-F]*$/.test(raw) || raw.length % 2 !== 0) {
|
|
7028
|
-
throw new Error('EVM transaction calldata must be even-length 0x hex');
|
|
7029
|
-
}
|
|
7030
|
-
const hex = raw.slice(2);
|
|
7031
|
-
if (hex.length / 2 > MAX_CALLDATA_BYTES)
|
|
7032
|
-
throw new Error('EVM transaction calldata exceeds the client safety limit');
|
|
7033
|
-
const out = new Uint8Array(hex.length / 2);
|
|
7034
|
-
for (let i = 0; i < out.length; i++)
|
|
7035
|
-
out[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
7036
|
-
return out;
|
|
7037
|
-
}
|
|
7038
|
-
class AbiReader {
|
|
7039
|
-
constructor(bytes) {
|
|
7040
|
-
this.bytes = bytes;
|
|
7041
|
-
this.maxRead = 0;
|
|
7042
|
-
this.dynamicPayloadBytes = 0;
|
|
7043
|
-
this.utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: false });
|
|
7044
|
-
}
|
|
7045
|
-
range(offset, length, label) {
|
|
7046
|
-
if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 0 || offset + length > this.bytes.length) {
|
|
7047
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label})`);
|
|
7048
|
-
}
|
|
7049
|
-
this.maxRead = Math.max(this.maxRead, offset + length);
|
|
7050
|
-
}
|
|
7051
|
-
word(offset, label) {
|
|
7052
|
-
this.range(offset, 32, label);
|
|
7053
|
-
let value = BIGINT_ZERO;
|
|
7054
|
-
for (let i = 0; i < 32; i++)
|
|
7055
|
-
value = (value << BIGINT_EIGHT) | BigInt(this.bytes[offset + i]);
|
|
7056
|
-
return value;
|
|
7057
|
-
}
|
|
7058
|
-
numberWord(offset, label, max = Number.MAX_SAFE_INTEGER) {
|
|
7059
|
-
const value = this.word(offset, label);
|
|
7060
|
-
if (value > BigInt(max))
|
|
7061
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label} too large)`);
|
|
7062
|
-
return Number(value);
|
|
7063
|
-
}
|
|
7064
|
-
offset(base, wordOffset, min, label) {
|
|
7065
|
-
const relative = this.numberWord(wordOffset, `${label} offset`, this.bytes.length);
|
|
7066
|
-
if (relative < min || relative % 32 !== 0)
|
|
7067
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label} offset)`);
|
|
7068
|
-
const absolute = base + relative;
|
|
7069
|
-
this.range(absolute, 0, label);
|
|
7070
|
-
return absolute;
|
|
7071
|
-
}
|
|
7072
|
-
dynamicBytes(at, label) {
|
|
7073
|
-
const length = this.numberWord(at, `${label} length`, MAX_CALLDATA_BYTES);
|
|
7074
|
-
this.dynamicPayloadBytes += length;
|
|
7075
|
-
// ABI offsets may alias. Cap the cumulative decoded payload so a malicious
|
|
7076
|
-
// 1 MB tail referenced by thousands of fields cannot amplify into a
|
|
7077
|
-
// multi-gigabyte allocation/UTF-8 decode in the wallet process.
|
|
7078
|
-
if (this.dynamicPayloadBytes > MAX_CALLDATA_BYTES) {
|
|
7079
|
-
throw new Error('Malformed EVM setDocuments calldata (dynamic payload amplification)');
|
|
7080
|
-
}
|
|
7081
|
-
const start = at + 32;
|
|
7082
|
-
const padded = Math.ceil(length / 32) * 32;
|
|
7083
|
-
this.range(start, padded, label);
|
|
7084
|
-
for (let i = start + length; i < start + padded; i++) {
|
|
7085
|
-
if (this.bytes[i] !== 0)
|
|
7086
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label} padding)`);
|
|
7087
|
-
}
|
|
7088
|
-
return this.bytes.slice(start, start + length);
|
|
7089
|
-
}
|
|
7090
|
-
dynamicEnd(at, label) {
|
|
7091
|
-
const length = this.numberWord(at, `${label} length`, MAX_CALLDATA_BYTES);
|
|
7092
|
-
const end = at + 32 + Math.ceil(length / 32) * 32;
|
|
7093
|
-
this.range(at + 32, Math.ceil(length / 32) * 32, label);
|
|
7094
|
-
return end;
|
|
7095
|
-
}
|
|
7096
|
-
string(at, label) {
|
|
7097
|
-
try {
|
|
7098
|
-
return this.utf8.decode(this.dynamicBytes(at, label));
|
|
7099
|
-
}
|
|
7100
|
-
catch (_a) {
|
|
7101
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label} utf8)`);
|
|
7102
|
-
}
|
|
7103
|
-
}
|
|
7104
|
-
finish() {
|
|
7105
|
-
if (this.maxRead !== this.bytes.length)
|
|
7106
|
-
throw new Error('Malformed EVM setDocuments calldata (unreferenced trailing bytes)');
|
|
7107
|
-
}
|
|
7108
|
-
}
|
|
7109
|
-
function assertCanonicalOffset(actual, expected, label) {
|
|
7110
|
-
if (actual !== expected)
|
|
7111
|
-
throw new Error(`Malformed EVM setDocuments calldata (${label} non-canonical offset)`);
|
|
7112
|
-
}
|
|
7113
|
-
function decodeStringArray(reader, at, label) {
|
|
7114
|
-
const count = reader.numberWord(at, `${label} count`, MAX_ARRAY_ITEMS);
|
|
7115
|
-
const head = at + 32;
|
|
7116
|
-
const min = count * 32;
|
|
7117
|
-
const out = [];
|
|
7118
|
-
let expectedTail = head + min;
|
|
7119
|
-
for (let i = 0; i < count; i++) {
|
|
7120
|
-
const itemAt = reader.offset(head, head + i * 32, min, `${label}[${i}]`);
|
|
7121
|
-
assertCanonicalOffset(itemAt, expectedTail, `${label}[${i}]`);
|
|
7122
|
-
out.push(reader.string(itemAt, `${label}[${i}]`));
|
|
7123
|
-
expectedTail = reader.dynamicEnd(itemAt, `${label}[${i}]`);
|
|
7124
|
-
}
|
|
7125
|
-
return { value: out, end: expectedTail };
|
|
7126
|
-
}
|
|
7127
|
-
function decodeFields(reader, at) {
|
|
7128
|
-
const count = reader.numberWord(at, 'fields count', MAX_ARRAY_ITEMS);
|
|
7129
|
-
const head = at + 32;
|
|
7130
|
-
const min = count * 32;
|
|
7131
|
-
const out = [];
|
|
7132
|
-
let expectedTail = head + min;
|
|
7133
|
-
for (let i = 0; i < count; i++) {
|
|
7134
|
-
const tuple = reader.offset(head, head + i * 32, min, `field[${i}]`);
|
|
7135
|
-
assertCanonicalOffset(tuple, expectedTail, `field[${i}]`);
|
|
7136
|
-
const nameAt = reader.offset(tuple, tuple, 128, `field[${i}].name`);
|
|
7137
|
-
assertCanonicalOffset(nameAt, tuple + 128, `field[${i}].name`);
|
|
7138
|
-
const name = reader.string(nameAt, `field[${i}].name`);
|
|
7139
|
-
const nameEnd = reader.dynamicEnd(nameAt, `field[${i}].name`);
|
|
7140
|
-
const ftype = reader.numberWord(tuple + 32, `field[${i}].ftype`, 255);
|
|
7141
|
-
const op = reader.numberWord(tuple + 64, `field[${i}].op`, 255);
|
|
7142
|
-
const valueAt = reader.offset(tuple, tuple + 96, 128, `field[${i}].value`);
|
|
7143
|
-
assertCanonicalOffset(valueAt, nameEnd, `field[${i}].value`);
|
|
7144
|
-
const value = reader.dynamicBytes(valueAt, `field[${i}].value`);
|
|
7145
|
-
expectedTail = reader.dynamicEnd(valueAt, `field[${i}].value`);
|
|
7146
|
-
out.push({ name, ftype, op, value });
|
|
7147
|
-
}
|
|
7148
|
-
return { value: out, end: expectedTail };
|
|
7149
|
-
}
|
|
7150
|
-
function decodeRuntimeWrite(rawData) {
|
|
7151
|
-
const bytes = hexBytes(rawData);
|
|
7152
|
-
if (bytes.length < 68)
|
|
7153
|
-
throw new Error('Malformed EVM setDocuments calldata');
|
|
7154
|
-
const selector = Array.from(bytes.slice(0, 4)).map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
7155
|
-
const kind = selector === SET_DOCUMENTS_SELECTOR
|
|
7156
|
-
? 'setDocuments'
|
|
7157
|
-
: selector === SET_DOCUMENTS_ATTESTED_SELECTOR
|
|
7158
|
-
? 'setDocumentsAttested'
|
|
7159
|
-
: null;
|
|
7160
|
-
if (!kind)
|
|
7161
|
-
throw new Error('EVM transaction is not a supported BoundedRuntime document write');
|
|
7162
|
-
const reader = new AbiReader(bytes);
|
|
7163
|
-
reader.maxRead = 4;
|
|
7164
|
-
const args = 4;
|
|
7165
|
-
// ExternalCallAttestation is a fully-static six-word tuple and is therefore
|
|
7166
|
-
// expanded inline into the top-level head: 2 dynamic offsets + 6 words.
|
|
7167
|
-
const headBytes = kind === 'setDocumentsAttested' ? 256 : 64;
|
|
7168
|
-
const appAt = reader.offset(args, args, headBytes, 'appId');
|
|
7169
|
-
assertCanonicalOffset(appAt, args + headBytes, 'appId');
|
|
7170
|
-
const opsAt = reader.offset(args, args + 32, headBytes, 'ops');
|
|
7171
|
-
const appId = reader.string(appAt, 'appId');
|
|
7172
|
-
const appEnd = reader.dynamicEnd(appAt, 'appId');
|
|
7173
|
-
assertCanonicalOffset(opsAt, appEnd, 'ops');
|
|
7174
|
-
const count = reader.numberWord(opsAt, 'ops count', MAX_ARRAY_ITEMS);
|
|
7175
|
-
const head = opsAt + 32;
|
|
7176
|
-
const min = count * 32;
|
|
7177
|
-
const ops = [];
|
|
7178
|
-
let expectedTail = head + min;
|
|
7179
|
-
for (let i = 0; i < count; i++) {
|
|
7180
|
-
const tuple = reader.offset(head, head + i * 32, min, `op[${i}]`);
|
|
7181
|
-
assertCanonicalOffset(tuple, expectedTail, `op[${i}]`);
|
|
7182
|
-
const pathAt = reader.offset(tuple, tuple, 96, `op[${i}].path`);
|
|
7183
|
-
assertCanonicalOffset(pathAt, tuple + 96, `op[${i}].path`);
|
|
7184
|
-
const deleteWord = reader.numberWord(tuple + 32, `op[${i}].isDelete`, 1);
|
|
7185
|
-
const fieldsAt = reader.offset(tuple, tuple + 64, 96, `op[${i}].fields`);
|
|
7186
|
-
const path = decodeStringArray(reader, pathAt, `op[${i}].path`);
|
|
7187
|
-
assertCanonicalOffset(fieldsAt, path.end, `op[${i}].fields`);
|
|
7188
|
-
const fields = decodeFields(reader, fieldsAt);
|
|
7189
|
-
expectedTail = fields.end;
|
|
7190
|
-
ops.push({
|
|
7191
|
-
pathSegments: path.value,
|
|
7192
|
-
isDelete: deleteWord === 1,
|
|
7193
|
-
fields: fields.value,
|
|
7194
|
-
});
|
|
7195
|
-
}
|
|
7196
|
-
let attestation;
|
|
7197
|
-
if (kind === 'setDocumentsAttested') {
|
|
7198
|
-
const callsHash = reader.word(args + 64, 'attestation.callsHash');
|
|
7199
|
-
const nonce = reader.word(args + 96, 'attestation.nonce');
|
|
7200
|
-
const deadline = reader.word(args + 128, 'attestation.deadline');
|
|
7201
|
-
const v = reader.numberWord(args + 160, 'attestation.v', 255);
|
|
7202
|
-
const r = reader.word(args + 192, 'attestation.r');
|
|
7203
|
-
const s = reader.word(args + 224, 'attestation.s');
|
|
7204
|
-
if (v !== 27 && v !== 28)
|
|
7205
|
-
throw new Error('Malformed EVM setDocuments calldata (attestation.v must be 27 or 28)');
|
|
7206
|
-
if (r === BIGINT_ZERO || r >= SECP256K1_N)
|
|
7207
|
-
throw new Error('Malformed EVM setDocuments calldata (attestation.r is not canonical)');
|
|
7208
|
-
if (s === BIGINT_ZERO || s > SECP256K1_HALF_N)
|
|
7209
|
-
throw new Error('Malformed EVM setDocuments calldata (attestation.s is not canonical low-s)');
|
|
7210
|
-
attestation = { callsHash, nonce, deadline, v, r, s };
|
|
7211
|
-
}
|
|
7212
|
-
if (expectedTail !== bytes.length)
|
|
7213
|
-
throw new Error('Malformed EVM setDocuments calldata (unreferenced trailing bytes)');
|
|
7214
|
-
reader.finish();
|
|
7215
|
-
return Object.assign({ kind, appId, ops }, (attestation ? { attestation } : {}));
|
|
7216
|
-
}
|
|
7217
|
-
/**
|
|
7218
|
-
* Fail closed unless calldata is a byte-for-byte canonical ABI encoding of one
|
|
7219
|
-
* supported BoundedRuntime write. This is the defense used by direct signer
|
|
7220
|
-
* surfaces; the higher-level write validator below additionally binds app/ops.
|
|
7221
|
-
*/
|
|
7222
|
-
function assertCanonicalBoundedRuntimeWriteCalldata(rawData) {
|
|
7223
|
-
decodeRuntimeWrite(rawData);
|
|
7224
|
-
}
|
|
7225
|
-
const MAX_EVM_DOCUMENT_PATH_UTF8_BYTES = 1024;
|
|
7226
|
-
function canonicalUtf8ByteLength(value) {
|
|
7227
|
-
let bytes = 0;
|
|
7228
|
-
for (let i = 0; i < value.length; i++) {
|
|
7229
|
-
const unit = value.charCodeAt(i);
|
|
7230
|
-
if (unit <= 0x7f)
|
|
7231
|
-
bytes += 1;
|
|
7232
|
-
else if (unit <= 0x7ff)
|
|
7233
|
-
bytes += 2;
|
|
7234
|
-
else if (unit >= 0xd800 && unit <= 0xdbff) {
|
|
7235
|
-
const low = value.charCodeAt(++i);
|
|
7236
|
-
if (!(low >= 0xdc00 && low <= 0xdfff))
|
|
7237
|
-
throw new Error(`Invalid EVM write path: ${value}`);
|
|
7238
|
-
bytes += 4;
|
|
7239
|
-
}
|
|
7240
|
-
else if (unit >= 0xdc00 && unit <= 0xdfff) {
|
|
7241
|
-
throw new Error(`Invalid EVM write path: ${value}`);
|
|
7242
|
-
}
|
|
7243
|
-
else
|
|
7244
|
-
bytes += 3;
|
|
7245
|
-
}
|
|
7246
|
-
return bytes;
|
|
7247
|
-
}
|
|
7248
|
-
function normalizedPathSegments(path) {
|
|
7249
|
-
if (typeof path !== 'string' || path.length === 0 ||
|
|
7250
|
-
canonicalUtf8ByteLength(path) > MAX_EVM_DOCUMENT_PATH_UTF8_BYTES) {
|
|
7251
|
-
throw new Error(`Invalid EVM write path: ${path}`);
|
|
7252
|
-
}
|
|
7253
|
-
const segments = path.split('/');
|
|
7254
|
-
if (segments.length < 2 || segments.length % 2 !== 0 ||
|
|
7255
|
-
segments[0].startsWith('__') ||
|
|
7256
|
-
segments.some((s) => !s || s === '.' || s === '..' || /[\\\u0000-\u001f\u007f]/.test(s))) {
|
|
7257
|
-
throw new Error(`Invalid EVM write path: ${path}`);
|
|
7258
|
-
}
|
|
7259
|
-
return segments;
|
|
7260
|
-
}
|
|
7261
|
-
function bytesBigInt(bytes, signed) {
|
|
7262
|
-
if (bytes.length !== 32)
|
|
7263
|
-
throw new Error('EVM field value is not one ABI word');
|
|
7264
|
-
let value = BIGINT_ZERO;
|
|
7265
|
-
for (const b of bytes)
|
|
7266
|
-
value = (value << BIGINT_EIGHT) | BigInt(b);
|
|
7267
|
-
if (signed && (value & (BIGINT_ONE << BigInt(255))) !== BIGINT_ZERO)
|
|
7268
|
-
value -= BIGINT_ONE << BigInt(256);
|
|
7269
|
-
return value;
|
|
7270
|
-
}
|
|
7271
|
-
function decodedAbiString(bytes) {
|
|
7272
|
-
const reader = new AbiReader(bytes);
|
|
7273
|
-
const at = reader.offset(0, 0, 32, 'field string');
|
|
7274
|
-
const value = reader.string(at, 'field string');
|
|
7275
|
-
reader.finish();
|
|
7276
|
-
return value;
|
|
7277
|
-
}
|
|
7278
|
-
function assertSetValue(field, expected) {
|
|
7279
|
-
if (field.op !== 0)
|
|
7280
|
-
throw new Error(`EVM field ${field.name} changes the requested SET action`);
|
|
7281
|
-
if (typeof expected === 'boolean') {
|
|
7282
|
-
if (field.ftype !== 3 || bytesBigInt(field.value, false) !== (expected ? BIGINT_ONE : BIGINT_ZERO))
|
|
7283
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7284
|
-
return;
|
|
7285
|
-
}
|
|
7286
|
-
if (typeof expected === 'number') {
|
|
7287
|
-
if (!Number.isFinite(expected))
|
|
7288
|
-
throw new Error(`EVM field ${field.name} is not finite`);
|
|
7289
|
-
if (Number.isInteger(expected)) {
|
|
7290
|
-
if (!Number.isSafeInteger(expected)) {
|
|
7291
|
-
throw new Error(`EVM field ${field.name} integer must be a safe number or canonical decimal string`);
|
|
7292
|
-
}
|
|
7293
|
-
const actual = field.ftype === 1 ? bytesBigInt(field.value, false) : field.ftype === 2 ? bytesBigInt(field.value, true) : null;
|
|
7294
|
-
if (actual === null || actual !== BigInt(expected))
|
|
7295
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7296
|
-
return;
|
|
7297
|
-
}
|
|
7298
|
-
if (field.ftype !== 4 || decodedAbiString(field.value) !== expected.toString())
|
|
7299
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7300
|
-
return;
|
|
7301
|
-
}
|
|
7302
|
-
if (typeof expected === 'bigint') {
|
|
7303
|
-
const actual = field.ftype === 1 ? bytesBigInt(field.value, false) : field.ftype === 2 ? bytesBigInt(field.value, true) : null;
|
|
7304
|
-
if (actual === null || actual !== expected)
|
|
7305
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7306
|
-
return;
|
|
7307
|
-
}
|
|
7308
|
-
if (typeof expected === 'string') {
|
|
7309
|
-
if (field.ftype === 4 && decodedAbiString(field.value) === expected)
|
|
7310
|
-
return;
|
|
7311
|
-
if ((field.ftype === 1 || field.ftype === 2) && expected.length <= 20 && /^-?(?:0|[1-9][0-9]*)$/.test(expected)) {
|
|
7312
|
-
const exact = BigInt(expected);
|
|
7313
|
-
if (exact >= BigInt(Number.MIN_SAFE_INTEGER) && exact <= BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
7314
|
-
throw new Error(`EVM field ${field.name} safe integer must be supplied as a number`);
|
|
7315
|
-
}
|
|
7316
|
-
const inRange = field.ftype === 1
|
|
7317
|
-
? exact >= BIGINT_ZERO && exact <= ((BIGINT_ONE << BigInt(64)) - BIGINT_ONE)
|
|
7318
|
-
: exact >= -(BIGINT_ONE << BigInt(63)) && exact <= ((BIGINT_ONE << BigInt(63)) - BIGINT_ONE);
|
|
7319
|
-
const actual = bytesBigInt(field.value, field.ftype === 2);
|
|
7320
|
-
if (inRange && actual === exact)
|
|
7321
|
-
return;
|
|
7322
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7323
|
-
}
|
|
7324
|
-
if (field.ftype === 5 && normalizeEvmAddress(expected)) {
|
|
7325
|
-
const word = field.value;
|
|
7326
|
-
if (word.length === 32 && word.slice(0, 12).every((b) => b === 0)) {
|
|
7327
|
-
const actual = `0x${Array.from(word.slice(12)).map((b) => b.toString(16).padStart(2, '0')).join('')}`;
|
|
7328
|
-
if (actual === normalizeEvmAddress(expected))
|
|
7329
|
-
return;
|
|
7330
|
-
}
|
|
7331
|
-
}
|
|
7332
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7333
|
-
}
|
|
7334
|
-
if (expected === undefined || expected === null) {
|
|
7335
|
-
throw new Error(`EVM field ${field.name} cannot be represented safely on EVM; use a document delete or omit the field`);
|
|
7336
|
-
}
|
|
7337
|
-
const json = JSON.stringify(expected);
|
|
7338
|
-
if (typeof json !== 'string' || field.ftype !== 4 || decodedAbiString(field.value) !== json) {
|
|
7339
|
-
throw new Error(`EVM field ${field.name} value mismatch`);
|
|
7340
|
-
}
|
|
7341
|
-
}
|
|
7342
|
-
function assertField(field, expected) {
|
|
7343
|
-
if (expected === null) {
|
|
7344
|
-
if (field.op !== 2 || field.ftype < 1 || field.ftype > 5 || field.value.length !== 0) {
|
|
7345
|
-
throw new Error(`EVM field ${field.name} deletion mismatch`);
|
|
7346
|
-
}
|
|
7347
|
-
return;
|
|
7348
|
-
}
|
|
7349
|
-
if (expected && typeof expected === 'object' && !Array.isArray(expected)) {
|
|
7350
|
-
const operation = expected.operation;
|
|
7351
|
-
if (operation === 'increment') {
|
|
7352
|
-
const delta = expected.value;
|
|
7353
|
-
const actual = field.ftype === 1 || field.ftype === 2
|
|
7354
|
-
? bytesBigInt(field.value, true)
|
|
7355
|
-
: null;
|
|
7356
|
-
if (!Number.isSafeInteger(delta) || field.op !== 3 || actual === null || actual !== BigInt(delta)) {
|
|
7357
|
-
throw new Error(`EVM field ${field.name} increment mismatch`);
|
|
7358
|
-
}
|
|
7359
|
-
return;
|
|
7360
|
-
}
|
|
7361
|
-
if (operation === 'time' && expected.value === 'now') {
|
|
7362
|
-
if (field.op !== 4 || (field.ftype !== 1 && field.ftype !== 2) || field.value.length !== 0) {
|
|
7363
|
-
throw new Error(`EVM field ${field.name} timestamp mismatch`);
|
|
7364
|
-
}
|
|
7365
|
-
return;
|
|
7366
|
-
}
|
|
7367
|
-
}
|
|
7368
|
-
assertSetValue(field, expected);
|
|
7369
|
-
}
|
|
7370
|
-
function assertOp(decoded, path, document) {
|
|
7371
|
-
const expectedSegments = normalizedPathSegments(path);
|
|
7372
|
-
if (decoded.pathSegments.length !== expectedSegments.length || decoded.pathSegments.some((s, i) => s !== expectedSegments[i])) {
|
|
7373
|
-
throw new Error(`EVM transaction path does not match requested write: ${path}`);
|
|
7374
|
-
}
|
|
7375
|
-
if (decoded.isDelete !== (document === null))
|
|
7376
|
-
throw new Error(`EVM transaction action does not match requested write: ${path}`);
|
|
7377
|
-
if (document === null) {
|
|
7378
|
-
if (decoded.fields.length !== 0)
|
|
7379
|
-
throw new Error(`EVM delete unexpectedly carries fields: ${path}`);
|
|
7380
|
-
return;
|
|
7381
|
-
}
|
|
7382
|
-
if (!document || typeof document !== 'object' || Array.isArray(document))
|
|
7383
|
-
throw new Error(`EVM document must be a plain object or null: ${path}`);
|
|
7384
|
-
const expectedEntries = Object.entries(document);
|
|
7385
|
-
if (expectedEntries.some(([name]) => name.startsWith('_')))
|
|
7386
|
-
throw new Error(`Reserved EVM field reached transaction validation: ${path}`);
|
|
7387
|
-
const expected = new Map(expectedEntries);
|
|
7388
|
-
const seen = new Set();
|
|
7389
|
-
for (const field of decoded.fields) {
|
|
7390
|
-
if (!field.name || seen.has(field.name) || !expected.has(field.name))
|
|
7391
|
-
throw new Error(`EVM transaction contains unexpected or duplicate field ${field.name}`);
|
|
7392
|
-
seen.add(field.name);
|
|
7393
|
-
assertField(field, expected.get(field.name));
|
|
7394
|
-
}
|
|
7395
|
-
const missing = [...expected.keys()].filter((name) => !seen.has(name));
|
|
7396
|
-
if (missing.length > 0)
|
|
7397
|
-
throw new Error(`EVM transaction omits requested fields: ${missing.join(', ')}`);
|
|
7398
|
-
}
|
|
7399
|
-
function zeroWei(raw) {
|
|
7400
|
-
if (raw === undefined || raw === null || raw === '')
|
|
7401
|
-
return true;
|
|
7402
|
-
if (typeof raw !== 'string' && typeof raw !== 'number')
|
|
7403
|
-
return false;
|
|
7404
|
-
try {
|
|
7405
|
-
return BigInt(raw) === BIGINT_ZERO;
|
|
7406
|
-
}
|
|
7407
|
-
catch (_a) {
|
|
7408
|
-
return false;
|
|
7409
|
-
}
|
|
7410
|
-
}
|
|
7411
|
-
/** Verify the untrusted 202 payload is exactly the governed write the app asked for. */
|
|
7412
|
-
function assertEvmTransactionMatchesWrite(transaction, context) {
|
|
7413
|
-
var _a, _b;
|
|
7414
|
-
if (!transaction || !Number.isSafeInteger(transaction.chainId) || transaction.chainId <= 0) {
|
|
7415
|
-
throw new Error('EVM transaction chainId is required');
|
|
7416
|
-
}
|
|
7417
|
-
const chainId = transaction.chainId;
|
|
7418
|
-
const policy = context.policy;
|
|
7419
|
-
if (!policy)
|
|
7420
|
-
throw new Error('EVM transaction signing requires an explicit runtime/chain policy');
|
|
7421
|
-
if (policy.chainId !== undefined && policy.chainId !== chainId)
|
|
7422
|
-
throw new Error(`EVM transaction chain ${chainId} does not match configured chain ${policy.chainId}`);
|
|
7423
|
-
const expectedRuntime = (_b = (_a = policy.runtimeAddresses) === null || _a === void 0 ? void 0 : _a[String(chainId)]) !== null && _b !== void 0 ? _b : (policy.chainId === chainId ? policy.runtimeAddress : undefined);
|
|
7424
|
-
const normalizedRuntime = normalizeEvmAddress(expectedRuntime);
|
|
7425
|
-
if (!normalizedRuntime)
|
|
7426
|
-
throw new Error(`No trusted BoundedRuntime address configured for EVM chain ${chainId}`);
|
|
7427
|
-
if (normalizeEvmAddress(transaction.to) !== normalizedRuntime)
|
|
7428
|
-
throw new Error('EVM transaction target is not the configured BoundedRuntime');
|
|
7429
|
-
if (!zeroWei(transaction.value))
|
|
7430
|
-
throw new Error('BoundedRuntime.setDocuments must not transfer native value');
|
|
7431
|
-
if (transaction.nonce !== undefined)
|
|
7432
|
-
throw new Error('Server-supplied EVM nonce is not accepted');
|
|
7433
|
-
const decoded = decodeRuntimeWrite(transaction.data);
|
|
7434
|
-
if (decoded.appId !== context.appId)
|
|
7435
|
-
throw new Error('EVM transaction appId does not match configured appId');
|
|
7436
|
-
if (decoded.ops.length !== context.documents.length)
|
|
7437
|
-
throw new Error('EVM transaction operation count does not match requested writes');
|
|
7438
|
-
// The worker's contract ABI groups upserts first and document deletes second.
|
|
7439
|
-
const expectedOps = [
|
|
7440
|
-
...context.documents.filter((entry) => entry.document !== null),
|
|
7441
|
-
...context.documents.filter((entry) => entry.document === null),
|
|
7442
|
-
];
|
|
7443
|
-
const paths = new Set();
|
|
7444
|
-
for (let i = 0; i < expectedOps.length; i++) {
|
|
7445
|
-
const expected = expectedOps[i];
|
|
7446
|
-
const canonicalPath = normalizedPathSegments(expected.destinationPath).join('/');
|
|
7447
|
-
if (paths.has(canonicalPath))
|
|
7448
|
-
throw new Error(`Duplicate EVM write path is not allowed: ${canonicalPath}`);
|
|
7449
|
-
paths.add(canonicalPath);
|
|
7450
|
-
assertOp(decoded.ops[i], canonicalPath, expected.document);
|
|
7451
|
-
}
|
|
7452
|
-
}
|
|
7453
|
-
|
|
7454
7004
|
/**
|
|
7455
7005
|
* Thrown when a user's wallet doesn't have enough SOL to cover the transaction.
|
|
7456
7006
|
* Apps can catch this to trigger an onramp/funding flow.
|
|
@@ -8566,12 +8116,12 @@ async function set(path, document, options) {
|
|
|
8566
8116
|
* state appears only under `observation`/`mirrorSync` once actually observed.
|
|
8567
8117
|
*/
|
|
8568
8118
|
async function setMany(many, options) {
|
|
8569
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l
|
|
8119
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
8570
8120
|
// Returns the data that was set, or undefined if the document was already set.
|
|
8571
8121
|
try {
|
|
8572
8122
|
// A server WalletClient threads its immutable config snapshot; the default
|
|
8573
8123
|
// path reads the mutable process-global init() config. This keeps the app-id
|
|
8574
|
-
// bound into an on-chain 202 write (
|
|
8124
|
+
// bound into an on-chain 202 write (Solana/offchain) on the wallet
|
|
8575
8125
|
// client's original app after a later global init() (CTA-05).
|
|
8576
8126
|
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();
|
|
8577
8127
|
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;
|
|
@@ -8640,13 +8190,18 @@ async function setMany(many, options) {
|
|
|
8640
8190
|
throw new Error(`Expected exactly one on-chain transaction, received ${Array.isArray(transactions) ? transactions.length : 0}`);
|
|
8641
8191
|
}
|
|
8642
8192
|
const curTx = transactions[0];
|
|
8643
|
-
|
|
8193
|
+
// The EVM onchain data plane is retired: no worker mints an EVM 202 any
|
|
8194
|
+
// more. A payload that still carries one is an unexpected response and
|
|
8195
|
+
// fails loudly BEFORE anything is signed - never silently ignored.
|
|
8196
|
+
if ((curTx === null || curTx === void 0 ? void 0 : curTx.evmTransaction) != null) {
|
|
8197
|
+
throw new Error('Unsupported 202 transaction shape: the write response carried an evmTransaction, ' +
|
|
8198
|
+
'but EVM onchain writes are no longer supported. Nothing was signed or submitted.');
|
|
8199
|
+
}
|
|
8644
8200
|
const hasSerializedSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.serializedTransaction) != null;
|
|
8645
8201
|
const hasBuiltSolanaTarget = (curTx === null || curTx === void 0 ? void 0 : curTx.transactionArgs) != null || (curTx === null || curTx === void 0 ? void 0 : curTx.remainingAccounts) != null ||
|
|
8646
8202
|
(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;
|
|
8647
|
-
if (
|
|
8648
|
-
(
|
|
8649
|
-
throw new Error('Ambiguous on-chain write response mixes EVM and/or Solana transaction target formats');
|
|
8203
|
+
if (hasSerializedSolanaTarget && hasBuiltSolanaTarget) {
|
|
8204
|
+
throw new Error('Ambiguous on-chain write response mixes Solana transaction target formats');
|
|
8650
8205
|
}
|
|
8651
8206
|
const expectedWritePaths = documents.map(d => d.destinationPath);
|
|
8652
8207
|
const requestedDocuments = buildRequestedDocuments(documents);
|
|
@@ -8659,67 +8214,13 @@ async function setMany(many, options) {
|
|
|
8659
8214
|
throw new Error('The write response carried no execution-chain tag, so this receipt could not state where the write ran. ' +
|
|
8660
8215
|
'Nothing was signed or submitted.');
|
|
8661
8216
|
}
|
|
8662
|
-
|
|
8663
|
-
// `transactions[0].evmTransaction` (the EVM twin of Solana's pre-built
|
|
8664
|
-
// `serializedTransaction`). WORKER 202 CONTRACT (field name + shape the
|
|
8665
|
-
// worker side must emit to match):
|
|
8666
|
-
// { transactions: [ { evmTransaction: {
|
|
8667
|
-
// to, data, value?, chainId, gas?, maxFeePerGas?, maxPriorityFeePerGas?, nonce?
|
|
8668
|
-
// } } ] }
|
|
8669
|
-
// We hand it to the EVM auth provider's runTransaction(evmTx, undefined, options)
|
|
8670
|
-
// (eth_sendTransaction — the wallet signs + submits). syncItems below is
|
|
8671
|
-
// identical to the Solana path.
|
|
8672
|
-
if (curTx.evmTransaction) {
|
|
8673
|
-
assertEvmTransactionMatchesWrite(curTx.evmTransaction, {
|
|
8674
|
-
appId: config.appId,
|
|
8675
|
-
documents,
|
|
8676
|
-
policy: (_o = (_m = (_l = options === null || options === void 0 ? void 0 : options._overrides) === null || _l === void 0 ? void 0 : _l._evmTransactionPolicy) !== null && _m !== void 0 ? _m : config.evmWalletConfig) !== null && _o !== void 0 ? _o : null,
|
|
8677
|
-
});
|
|
8678
|
-
const evmChain = workerChain;
|
|
8679
|
-
const evmOutcome = await handleEvmTransaction(curTx.evmTransaction, authProvider, options);
|
|
8680
|
-
// CAPTURE THE RECEIPT FIRST. Mirror synchronization comes after, and its
|
|
8681
|
-
// failure can never turn a landed transaction into a thrown error that
|
|
8682
|
-
// invites the caller to submit the same write twice.
|
|
8683
|
-
if (evmOutcome.outcome === 'confirmed') {
|
|
8684
|
-
const mirrorSync = await attemptMirrorSync(expectedWritePaths, options);
|
|
8685
|
-
return {
|
|
8686
|
-
status: 'confirmed', appId, requestedDocuments, chain: evmChain,
|
|
8687
|
-
transactionId: evmOutcome.transactionSignature,
|
|
8688
|
-
blockNumber: evmOutcome.blockNumber,
|
|
8689
|
-
mirrorSync,
|
|
8690
|
-
};
|
|
8691
|
-
}
|
|
8692
|
-
// An unknown confirmation outcome is NOT a mirror question: nothing is
|
|
8693
|
-
// known to have landed, so no synchronization is attempted.
|
|
8694
|
-
if (evmOutcome.transactionSignature === null) {
|
|
8695
|
-
return {
|
|
8696
|
-
status: 'submitted', appId, requestedDocuments, chain: evmChain,
|
|
8697
|
-
transactionId: null,
|
|
8698
|
-
confirmation: { state: 'unknown', reason: evmOutcome.reason, reconcilable: false },
|
|
8699
|
-
};
|
|
8700
|
-
}
|
|
8701
|
-
if ('fence' in evmOutcome && evmOutcome.fence) {
|
|
8702
|
-
return {
|
|
8703
|
-
status: 'submitted', appId, requestedDocuments, chain: evmChain,
|
|
8704
|
-
transactionId: evmOutcome.transactionSignature,
|
|
8705
|
-
fence: evmOutcome.fence,
|
|
8706
|
-
confirmation: { state: 'unknown', reason: evmOutcome.reason },
|
|
8707
|
-
};
|
|
8708
|
-
}
|
|
8709
|
-
return {
|
|
8710
|
-
status: 'submitted', appId, requestedDocuments, chain: evmChain,
|
|
8711
|
-
transactionId: evmOutcome.transactionSignature,
|
|
8712
|
-
rebroadcastable: false,
|
|
8713
|
-
confirmation: { state: 'unknown', reason: evmOutcome.reason },
|
|
8714
|
-
};
|
|
8715
|
-
}
|
|
8716
|
-
else if (curTx.serializedTransaction) {
|
|
8217
|
+
if (curTx.serializedTransaction) {
|
|
8717
8218
|
if (!SOLANA_CHAIN_TAGS.has(workerChain)) {
|
|
8718
8219
|
throw new Error(`The write response reported execution chain "${workerChain}" for a Solana transaction. ` +
|
|
8719
8220
|
'Nothing was signed or submitted.');
|
|
8720
8221
|
}
|
|
8721
8222
|
const solanaChain = workerChain;
|
|
8722
|
-
const { handlePreBuiltTransaction } = await Promise.resolve().then(function () { return require('./solana-operations-
|
|
8223
|
+
const { handlePreBuiltTransaction } = await Promise.resolve().then(function () { return require('./solana-operations-DPul1dWo.js'); });
|
|
8723
8224
|
const solanaOutcome = await handlePreBuiltTransaction(curTx, authProvider, options, expectedWritePaths);
|
|
8724
8225
|
// `shouldSubmitTx: false` signed WITHOUT sending — no signature exists,
|
|
8725
8226
|
// and there is nothing to mirror, so no synchronization is attempted.
|
|
@@ -8753,7 +8254,7 @@ async function setMany(many, options) {
|
|
|
8753
8254
|
};
|
|
8754
8255
|
}
|
|
8755
8256
|
else {
|
|
8756
|
-
throw new Error('Unsupported 202 transaction shape: expected serializedTransaction
|
|
8257
|
+
throw new Error('Unsupported 202 transaction shape: expected serializedTransaction');
|
|
8757
8258
|
}
|
|
8758
8259
|
}
|
|
8759
8260
|
else if (setResponse.status === 200) {
|
|
@@ -8774,7 +8275,7 @@ async function setMany(many, options) {
|
|
|
8774
8275
|
observation: observationFromDirectCommit(documents.map(d => d.destinationPath), receipt === null || receipt === void 0 ? void 0 : receipt.observation),
|
|
8775
8276
|
// A worker predating the batch receipt reports no lane. Say so rather
|
|
8776
8277
|
// than inventing one — and never discard a committed write's receipt.
|
|
8777
|
-
chain: ((
|
|
8278
|
+
chain: ((_l = readWorkerChainTag(receipt)) !== null && _l !== void 0 ? _l : 'unknown'),
|
|
8778
8279
|
transactionId: typeof rawTransactionId === 'string' && rawTransactionId.length > 0 ? rawTransactionId : null,
|
|
8779
8280
|
};
|
|
8780
8281
|
}
|
|
@@ -8785,18 +8286,6 @@ async function setMany(many, options) {
|
|
|
8785
8286
|
catch (error) {
|
|
8786
8287
|
throw error;
|
|
8787
8288
|
}
|
|
8788
|
-
// EVM onchain write: hand the worker's pre-built EIP-1559 tx to the EVM auth
|
|
8789
|
-
// provider, which eth_sendTransaction-s it (the wallet signs + submits in one
|
|
8790
|
-
// step). Mirrors handlePreBuiltTransaction's shape but routes through the EVM
|
|
8791
|
-
// slot of runTransaction (Solana slot undefined). shouldSubmitTx is honored by
|
|
8792
|
-
// the provider itself.
|
|
8793
|
-
async function handleEvmTransaction(evmTransaction, authProvider, options) {
|
|
8794
|
-
const result = await authProvider.runTransaction(evmTransaction, undefined, options);
|
|
8795
|
-
if ((result === null || result === void 0 ? void 0 : result.lane) !== 'evm') {
|
|
8796
|
-
throw new Error('The EVM auth provider returned a non-EVM transaction outcome');
|
|
8797
|
-
}
|
|
8798
|
-
return result;
|
|
8799
|
-
}
|
|
8800
8289
|
}
|
|
8801
8290
|
/**
|
|
8802
8291
|
* Extract the document/collection path from a cache key. Keys are
|
|
@@ -9050,7 +8539,6 @@ var operations = /*#__PURE__*/Object.freeze({
|
|
|
9050
8539
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
9051
8540
|
const DEFAULT_MAX_ATTEMPTS = 20;
|
|
9052
8541
|
const DEFAULT_POLL_INTERVAL_MS = 3000;
|
|
9053
|
-
const DEFAULT_MIN_REBROADCAST_INTERVAL_MS = 15000;
|
|
9054
8542
|
/** Mirror read after a late confirmation. No settle delay: the tx already landed. */
|
|
9055
8543
|
const RECONCILE_MIRROR_SETTLE_MS = 0;
|
|
9056
8544
|
function errorText(error) {
|
|
@@ -9060,12 +8548,6 @@ function errorText(error) {
|
|
|
9060
8548
|
function isSolanaSubmitted(receipt) {
|
|
9061
8549
|
return receipt.status === 'submitted' && 'signedTransaction' in receipt;
|
|
9062
8550
|
}
|
|
9063
|
-
function isEvmFencedSubmitted(receipt) {
|
|
9064
|
-
return receipt.status === 'submitted' && 'fence' in receipt && !('signedTransaction' in receipt);
|
|
9065
|
-
}
|
|
9066
|
-
function isEvmHashKnownSubmitted(receipt) {
|
|
9067
|
-
return receipt.status === 'submitted' && receipt.rebroadcastable === false;
|
|
9068
|
-
}
|
|
9069
8551
|
/**
|
|
9070
8552
|
* The Solana execution lane a client config REQUIRES, or `null` when the config
|
|
9071
8553
|
* carries no constraint. Only a positive contradiction rejects a receipt — an
|
|
@@ -9090,7 +8572,6 @@ function requiredSolanaChain(config) {
|
|
|
9090
8572
|
* a global re-`init()` could otherwise poll the wrong app's endpoints entirely.
|
|
9091
8573
|
*/
|
|
9092
8574
|
function assertReceiptMatchesContext(receipt, config) {
|
|
9093
|
-
var _a;
|
|
9094
8575
|
if (!receipt.appId || typeof receipt.appId !== 'string') {
|
|
9095
8576
|
throw new Error('This write receipt carries no appId and cannot be reconciled.');
|
|
9096
8577
|
}
|
|
@@ -9103,22 +8584,6 @@ function assertReceiptMatchesContext(receipt, config) {
|
|
|
9103
8584
|
if (required && required !== receipt.chain) {
|
|
9104
8585
|
throw new Error(`This write receipt ran on "${receipt.chain}" but the bound client targets "${required}".`);
|
|
9105
8586
|
}
|
|
9106
|
-
return;
|
|
9107
|
-
}
|
|
9108
|
-
const fence = receipt.fence;
|
|
9109
|
-
if (fence && typeof fence.chainId === 'number') {
|
|
9110
|
-
const evm = config.evmWalletConfig;
|
|
9111
|
-
const configured = new Set();
|
|
9112
|
-
if (evm && typeof evm.chainId === 'number')
|
|
9113
|
-
configured.add(evm.chainId);
|
|
9114
|
-
for (const id of Object.keys((_a = evm === null || evm === void 0 ? void 0 : evm.runtimeAddresses) !== null && _a !== void 0 ? _a : {})) {
|
|
9115
|
-
const parsed = Number(id);
|
|
9116
|
-
if (Number.isSafeInteger(parsed))
|
|
9117
|
-
configured.add(parsed);
|
|
9118
|
-
}
|
|
9119
|
-
if (configured.size > 0 && !configured.has(fence.chainId)) {
|
|
9120
|
-
throw new Error(`This write receipt ran on EVM chain ${fence.chainId}, which the bound client does not configure.`);
|
|
9121
|
-
}
|
|
9122
8587
|
}
|
|
9123
8588
|
}
|
|
9124
8589
|
function stillSubmitted(receipt, reason) {
|
|
@@ -9235,67 +8700,18 @@ async function reconcileSolana(receipt, config, options) {
|
|
|
9235
8700
|
};
|
|
9236
8701
|
}
|
|
9237
8702
|
/**
|
|
9238
|
-
*
|
|
9239
|
-
* client reconciles with its own identity and RPC. There is deliberately NO
|
|
9240
|
-
* EVM retry-safe terminal state: nonce advancement is not proof the write did
|
|
9241
|
-
* not execute, and plain JSON-RPC offers no transaction-by-sender-and-nonce
|
|
9242
|
-
* lookup, so a `submitted` EVM receipt either confirms or stays `submitted`.
|
|
9243
|
-
*/
|
|
9244
|
-
async function reconcileEvm(receipt, provider, options) {
|
|
9245
|
-
if (!provider || typeof provider.reconcileEvmTransaction !== 'function') {
|
|
9246
|
-
return stillSubmitted(receipt, 'no EVM reconciliation transport is available on the bound auth provider');
|
|
9247
|
-
}
|
|
9248
|
-
const fenced = isEvmFencedSubmitted(receipt) ? receipt.fence : undefined;
|
|
9249
|
-
const allowRebroadcast = Boolean(fenced) && (options === null || options === void 0 ? void 0 : options.allowRebroadcast) !== false;
|
|
9250
|
-
let outcome;
|
|
9251
|
-
try {
|
|
9252
|
-
outcome = await provider.reconcileEvmTransaction({
|
|
9253
|
-
transactionHash: receipt.transactionId,
|
|
9254
|
-
fence: fenced,
|
|
9255
|
-
allowRebroadcast,
|
|
9256
|
-
});
|
|
9257
|
-
}
|
|
9258
|
-
catch (error) {
|
|
9259
|
-
return stillSubmitted(receipt, `EVM reconciliation failed: ${errorText(error)}`);
|
|
9260
|
-
}
|
|
9261
|
-
if (outcome.state === 'failed') {
|
|
9262
|
-
// Landed and reverted: a genuine failure, never `submitted`.
|
|
9263
|
-
throw new Error(outcome.reason);
|
|
9264
|
-
}
|
|
9265
|
-
if (outcome.state === 'confirmed') {
|
|
9266
|
-
if (typeof outcome.blockNumber !== 'number') {
|
|
9267
|
-
return stillSubmitted(receipt, 'the EVM receipt reported success without a block number, so confirmation could not be stated');
|
|
9268
|
-
}
|
|
9269
|
-
const confirmed = {
|
|
9270
|
-
status: 'confirmed',
|
|
9271
|
-
appId: receipt.appId,
|
|
9272
|
-
requestedDocuments: receipt.requestedDocuments,
|
|
9273
|
-
chain: receipt.chain,
|
|
9274
|
-
transactionId: receipt.transactionId,
|
|
9275
|
-
blockNumber: outcome.blockNumber,
|
|
9276
|
-
mirrorSync: await mirrorFor(receipt, options),
|
|
9277
|
-
};
|
|
9278
|
-
return confirmed;
|
|
9279
|
-
}
|
|
9280
|
-
if (outcome.state === 'absent_after_expiry') {
|
|
9281
|
-
// Defensive: no EVM lane may report a retry-safe terminal state.
|
|
9282
|
-
return stillSubmitted(receipt, 'the EVM transport reported absence, which is not proof an EVM write did not execute');
|
|
9283
|
-
}
|
|
9284
|
-
return stillSubmitted(receipt, outcome.reason);
|
|
9285
|
-
}
|
|
9286
|
-
/**
|
|
9287
|
-
* Poll the SAME signature/hash a `submitted` receipt carries and return the
|
|
8703
|
+
* Poll the SAME signature a `submitted` receipt carries and return the
|
|
9288
8704
|
* resulting `SetResult`.
|
|
9289
8705
|
*
|
|
9290
8706
|
* - Terminal receipts (`committed`, `confirmed`, `expired_not_landed`,
|
|
9291
8707
|
* `signed`) are returned unchanged; nothing was left open.
|
|
9292
|
-
* -
|
|
9293
|
-
* rejected immediately: no identifier exists to poll.
|
|
8708
|
+
* - A `submitted` receipt with no transaction identifier (`transactionId:
|
|
8709
|
+
* null`) is rejected immediately: no identifier exists to poll.
|
|
9294
8710
|
* - A transaction that landed and FAILED throws, exactly as it would have on
|
|
9295
8711
|
* the original write.
|
|
9296
8712
|
*/
|
|
9297
8713
|
async function reconcileSetResult(receipt, options) {
|
|
9298
|
-
var _a, _b
|
|
8714
|
+
var _a, _b;
|
|
9299
8715
|
if (!receipt || typeof receipt !== 'object' || typeof receipt.status !== 'string') {
|
|
9300
8716
|
throw new Error('reconcileSetResult requires a write receipt returned by set/setMany.');
|
|
9301
8717
|
}
|
|
@@ -9311,23 +8727,21 @@ async function reconcileSetResult(receipt, options) {
|
|
|
9311
8727
|
if (isSolanaSubmitted(receipt)) {
|
|
9312
8728
|
return reconcileSolana(receipt, config, options);
|
|
9313
8729
|
}
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
return reconcileEvm(receipt, provider, options);
|
|
9317
|
-
}
|
|
8730
|
+
// Anything else (e.g. a legacy serialized receipt from a retired lane) has no
|
|
8731
|
+
// reconciliation transport any more; say so rather than guessing.
|
|
9318
8732
|
return stillSubmitted(receipt, 'this receipt shape has no reconciliation lane');
|
|
9319
8733
|
}
|
|
9320
8734
|
/**
|
|
9321
8735
|
* Reconcile repeatedly until the receipt leaves `submitted` or the bound is hit.
|
|
9322
8736
|
*
|
|
9323
8737
|
* The bound is mandatory, because some states are permanently non-terminal by
|
|
9324
|
-
* design: an
|
|
9325
|
-
*
|
|
9326
|
-
*
|
|
9327
|
-
*
|
|
8738
|
+
* design: an RPC that can never observe the signature or the expiry never
|
|
8739
|
+
* resolves. On exhaustion (or abort) this returns the LATEST `submitted`
|
|
8740
|
+
* receipt with its identifier intact rather than hanging or throwing the
|
|
8741
|
+
* identifier away.
|
|
9328
8742
|
*/
|
|
9329
8743
|
async function waitForSetResult(receipt, options) {
|
|
9330
|
-
var _a, _b, _c, _d
|
|
8744
|
+
var _a, _b, _c, _d;
|
|
9331
8745
|
if (receipt && typeof receipt === 'object' && receipt.status === 'submitted' && receipt.transactionId === null) {
|
|
9332
8746
|
// Rejected immediately rather than polled: there is nothing to poll.
|
|
9333
8747
|
return reconcileSetResult(receipt, options);
|
|
@@ -9335,21 +8749,14 @@ async function waitForSetResult(receipt, options) {
|
|
|
9335
8749
|
const timeoutMs = (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_TIMEOUT_MS;
|
|
9336
8750
|
const maxAttempts = (_b = options === null || options === void 0 ? void 0 : options.maxAttempts) !== null && _b !== void 0 ? _b : DEFAULT_MAX_ATTEMPTS;
|
|
9337
8751
|
const pollIntervalMs = (_c = options === null || options === void 0 ? void 0 : options.pollIntervalMs) !== null && _c !== void 0 ? _c : DEFAULT_POLL_INTERVAL_MS;
|
|
9338
|
-
const minRebroadcastIntervalMs = (_d = options === null || options === void 0 ? void 0 : options.minRebroadcastIntervalMs) !== null && _d !== void 0 ? _d : DEFAULT_MIN_REBROADCAST_INTERVAL_MS;
|
|
9339
|
-
const rebroadcastPermitted = (options === null || options === void 0 ? void 0 : options.allowRebroadcast) !== false;
|
|
9340
8752
|
const startedAt = Date.now();
|
|
9341
8753
|
let current = receipt;
|
|
9342
8754
|
let attempts = 0;
|
|
9343
|
-
let lastRebroadcastAt = -Infinity;
|
|
9344
8755
|
while (attempts < maxAttempts && Date.now() - startedAt < timeoutMs) {
|
|
9345
|
-
if ((
|
|
8756
|
+
if ((_d = options === null || options === void 0 ? void 0 : options.signal) === null || _d === void 0 ? void 0 : _d.aborted)
|
|
9346
8757
|
return current;
|
|
9347
|
-
const now = Date.now();
|
|
9348
|
-
const allowRebroadcast = rebroadcastPermitted && (now - lastRebroadcastAt >= minRebroadcastIntervalMs);
|
|
9349
|
-
if (allowRebroadcast)
|
|
9350
|
-
lastRebroadcastAt = now;
|
|
9351
8758
|
attempts++;
|
|
9352
|
-
current = await reconcileSetResult(current,
|
|
8759
|
+
current = await reconcileSetResult(current, options);
|
|
9353
8760
|
if (current.status !== 'submitted')
|
|
9354
8761
|
return current;
|
|
9355
8762
|
if (attempts >= maxAttempts)
|
|
@@ -9617,9 +9024,40 @@ function sortDeep(value) {
|
|
|
9617
9024
|
}
|
|
9618
9025
|
return value;
|
|
9619
9026
|
}
|
|
9620
|
-
/**
|
|
9027
|
+
/**
|
|
9028
|
+
* Key-sorted deep copy that mirrors the JSON wire form byte-for-byte. Unlike
|
|
9029
|
+
* `sortDeep`, it assigns into NULL-PROTOTYPE objects so an own `__proto__` key is
|
|
9030
|
+
* kept as an ordinary JSON property instead of being swallowed by
|
|
9031
|
+
* `Object.prototype`'s `__proto__` setter (which would mutate the prototype and
|
|
9032
|
+
* drop the property, diverging from what `JSON.stringify` actually emits).
|
|
9033
|
+
*/
|
|
9034
|
+
function sortDeepWire(value) {
|
|
9035
|
+
if (Array.isArray(value))
|
|
9036
|
+
return value.map(sortDeepWire);
|
|
9037
|
+
if (value && typeof value === 'object') {
|
|
9038
|
+
const out = Object.create(null);
|
|
9039
|
+
for (const k of Object.keys(value).sort())
|
|
9040
|
+
out[k] = sortDeepWire(value[k]);
|
|
9041
|
+
return out;
|
|
9042
|
+
}
|
|
9043
|
+
return value;
|
|
9044
|
+
}
|
|
9045
|
+
/**
|
|
9046
|
+
* Deterministic key-sorted serialization of query args, canonicalizing the EXACT
|
|
9047
|
+
* JSON wire representation the request serializer sends. Args are first projected
|
|
9048
|
+
* through `JSON.parse(JSON.stringify(...))` so `toJSON` runs (a `Date` becomes its
|
|
9049
|
+
* ISO string, not `{}`) and functions/`undefined` are dropped exactly as the wire
|
|
9050
|
+
* does, then key-sorted with null-prototype objects so an own `__proto__` key
|
|
9051
|
+
* round-trips as a property. This makes the dedupe key match what the server
|
|
9052
|
+
* actually receives, so two subscriptions can share a poller only when their wire
|
|
9053
|
+
* inputs are identical. Cyclic structures and other values the wire cannot
|
|
9054
|
+
* serialize (e.g. `BigInt`) are rejected by `JSON.stringify` here, exactly as they
|
|
9055
|
+
* would be on the wire.
|
|
9056
|
+
*/
|
|
9621
9057
|
function canonicalizeArgs(args) {
|
|
9622
|
-
|
|
9058
|
+
var _a;
|
|
9059
|
+
const wire = JSON.parse((_a = JSON.stringify(args !== null && args !== void 0 ? args : null)) !== null && _a !== void 0 ? _a : 'null');
|
|
9060
|
+
return JSON.stringify(sortDeepWire(wire));
|
|
9623
9061
|
}
|
|
9624
9062
|
/**
|
|
9625
9063
|
* Deterministic key-sorted serialization of a query RESULT for change detection.
|
|
@@ -10223,7 +9661,7 @@ function toMillis(seconds) {
|
|
|
10223
9661
|
|
|
10224
9662
|
/** SIWS message creation is async already, so its onchain module can be lazy. */
|
|
10225
9663
|
async function genSolanaMessage(address, nonce) {
|
|
10226
|
-
const implementation = await Promise.resolve().then(function () { return require('./solana-message-
|
|
9664
|
+
const implementation = await Promise.resolve().then(function () { return require('./solana-message-DnV4FQ__.js'); });
|
|
10227
9665
|
return implementation.genSolanaMessage(address, nonce);
|
|
10228
9666
|
}
|
|
10229
9667
|
|
|
@@ -10293,7 +9731,14 @@ async function invoke(name, args = {}, opts = {}) {
|
|
|
10293
9731
|
const controller = new AbortController();
|
|
10294
9732
|
const timeoutMs = (_e = opts.timeoutMs) !== null && _e !== void 0 ? _e : 60000;
|
|
10295
9733
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
9734
|
+
// `fetch` resolves as soon as the response HEADERS arrive, not when the body
|
|
9735
|
+
// has been received, so the abort timer must stay armed across `res.text()`
|
|
9736
|
+
// too. Clearing it in a `finally` that covers both the fetch AND the body read
|
|
9737
|
+
// means a dispatcher/network that returns headers then stalls (or drip-feeds)
|
|
9738
|
+
// the body is torn down at `timeoutMs` instead of leaving `invoke` pending
|
|
9739
|
+
// forever and accumulating open connections (DS3-0432).
|
|
10296
9740
|
let res;
|
|
9741
|
+
let text;
|
|
10297
9742
|
try {
|
|
10298
9743
|
res = await fetch(`${base}/invoke`, {
|
|
10299
9744
|
method: 'POST',
|
|
@@ -10301,17 +9746,18 @@ async function invoke(name, args = {}, opts = {}) {
|
|
|
10301
9746
|
body: JSON.stringify({ appId: config.appId, functionName: name, args }),
|
|
10302
9747
|
signal: controller.signal,
|
|
10303
9748
|
});
|
|
9749
|
+
text = await res.text();
|
|
10304
9750
|
}
|
|
10305
9751
|
catch (err) {
|
|
10306
|
-
clearTimeout(timer);
|
|
10307
9752
|
if ((err === null || err === void 0 ? void 0 : err.name) === 'AbortError') {
|
|
10308
9753
|
throw new FunctionInvokeError(`Function "${name}" invocation timed out after ${timeoutMs}ms`);
|
|
10309
9754
|
}
|
|
10310
9755
|
throw new FunctionInvokeError(`Failed to reach the functions dispatcher: ${(_f = err === null || err === void 0 ? void 0 : err.message) !== null && _f !== void 0 ? _f : String(err)}`);
|
|
10311
9756
|
}
|
|
10312
|
-
|
|
9757
|
+
finally {
|
|
9758
|
+
clearTimeout(timer);
|
|
9759
|
+
}
|
|
10313
9760
|
let body = null;
|
|
10314
|
-
const text = await res.text();
|
|
10315
9761
|
if (text) {
|
|
10316
9762
|
try {
|
|
10317
9763
|
body = JSON.parse(text);
|
|
@@ -10692,8 +10138,6 @@ function defineLiveModule(mod) {
|
|
|
10692
10138
|
|
|
10693
10139
|
exports.AUTH_CHANGED_CODE = AUTH_CHANGED_CODE;
|
|
10694
10140
|
exports.AUTH_EXPIRED_CODE = AUTH_EXPIRED_CODE;
|
|
10695
|
-
exports.BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR = BOUNDED_RUNTIME_SET_DOCUMENTS_ATTESTED_SELECTOR;
|
|
10696
|
-
exports.BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR = BOUNDED_RUNTIME_SET_DOCUMENTS_SELECTOR;
|
|
10697
10141
|
exports.BoundedDeclineError = BoundedDeclineError;
|
|
10698
10142
|
exports.DECLINE_EVENT_NAME = DECLINE_EVENT_NAME;
|
|
10699
10143
|
exports.DEFAULT_QUERY_POLL_INTERVAL_MS = DEFAULT_QUERY_POLL_INTERVAL_MS;
|
|
@@ -10710,8 +10154,6 @@ exports.SessionEnvironmentError = SessionEnvironmentError;
|
|
|
10710
10154
|
exports.UNSUPPORTED_ENVIRONMENT_CODE = UNSUPPORTED_ENVIRONMENT_CODE;
|
|
10711
10155
|
exports.WebSessionManager = WebSessionManager;
|
|
10712
10156
|
exports.aggregate = aggregate;
|
|
10713
|
-
exports.assertCanonicalBoundedRuntimeWriteCalldata = assertCanonicalBoundedRuntimeWriteCalldata;
|
|
10714
|
-
exports.assertEvmTransactionMatchesWrite = assertEvmTransactionMatchesWrite;
|
|
10715
10157
|
exports.bufferExports = bufferExports;
|
|
10716
10158
|
exports.canonicalizeArgs = canonicalizeArgs;
|
|
10717
10159
|
exports.canonicalizeResult = canonicalizeResult;
|
|
@@ -10737,8 +10179,10 @@ exports.getCachedData = getCachedData;
|
|
|
10737
10179
|
exports.getConfig = getConfig;
|
|
10738
10180
|
exports.getConfiguredAppId = getConfiguredAppId;
|
|
10739
10181
|
exports.getFiles = getFiles;
|
|
10182
|
+
exports.getFreshAuthToken = getFreshAuthToken;
|
|
10740
10183
|
exports.getIdToken = getIdToken;
|
|
10741
10184
|
exports.getMany = getMany;
|
|
10185
|
+
exports.getSessionGeneration = getSessionGeneration;
|
|
10742
10186
|
exports.getWebhookKeysUrl = getWebhookKeysUrl;
|
|
10743
10187
|
exports.hasActiveConnection = hasActiveConnection;
|
|
10744
10188
|
exports.increment = increment;
|
|
@@ -10778,4 +10222,4 @@ exports.toMillis = toMillis;
|
|
|
10778
10222
|
exports.toSeconds = toSeconds;
|
|
10779
10223
|
exports.waitForSetResult = waitForSetResult;
|
|
10780
10224
|
exports.withEffects = withEffects;
|
|
10781
|
-
//# sourceMappingURL=index-
|
|
10225
|
+
//# sourceMappingURL=index-DlJKTmRv.js.map
|