@usearete/react 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1479,7 +1479,7 @@ const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
1479
1479
 
1480
1480
  const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
1481
1481
 
1482
- const err = (strm, errorCode) => {
1482
+ const err$1 = (strm, errorCode) => {
1483
1483
  strm.msg = messages[errorCode];
1484
1484
  return errorCode;
1485
1485
  };
@@ -2796,7 +2796,7 @@ const deflateStateCheck = (strm) => {
2796
2796
  const deflateResetKeep = (strm) => {
2797
2797
 
2798
2798
  if (deflateStateCheck(strm)) {
2799
- return err(strm, Z_STREAM_ERROR$2);
2799
+ return err$1(strm, Z_STREAM_ERROR$2);
2800
2800
  }
2801
2801
 
2802
2802
  strm.total_in = strm.total_out = 0;
@@ -2870,7 +2870,7 @@ const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => {
2870
2870
  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 ||
2871
2871
  windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
2872
2872
  strategy < 0 || strategy > Z_FIXED || (windowBits === 8 && wrap !== 1)) {
2873
- return err(strm, Z_STREAM_ERROR$2);
2873
+ return err$1(strm, Z_STREAM_ERROR$2);
2874
2874
  }
2875
2875
 
2876
2876
 
@@ -2975,7 +2975,7 @@ const deflateInit = (strm, level) => {
2975
2975
  const deflate$2 = (strm, flush) => {
2976
2976
 
2977
2977
  if (deflateStateCheck(strm) || flush > Z_BLOCK$1 || flush < 0) {
2978
- return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2;
2978
+ return strm ? err$1(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2;
2979
2979
  }
2980
2980
 
2981
2981
  const s = strm.state;
@@ -2983,7 +2983,7 @@ const deflate$2 = (strm, flush) => {
2983
2983
  if (!strm.output ||
2984
2984
  (strm.avail_in !== 0 && !strm.input) ||
2985
2985
  (s.status === FINISH_STATE && flush !== Z_FINISH$3)) {
2986
- return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2);
2986
+ return err$1(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2);
2987
2987
  }
2988
2988
 
2989
2989
  const old_flush = s.last_flush;
@@ -3009,12 +3009,12 @@ const deflate$2 = (strm, flush) => {
3009
3009
  */
3010
3010
  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
3011
3011
  flush !== Z_FINISH$3) {
3012
- return err(strm, Z_BUF_ERROR$1);
3012
+ return err$1(strm, Z_BUF_ERROR$1);
3013
3013
  }
3014
3014
 
3015
3015
  /* User must not provide more input after the first FINISH: */
3016
3016
  if (s.status === FINISH_STATE && strm.avail_in !== 0) {
3017
- return err(strm, Z_BUF_ERROR$1);
3017
+ return err$1(strm, Z_BUF_ERROR$1);
3018
3018
  }
3019
3019
 
3020
3020
  /* Write the header */
@@ -3336,7 +3336,7 @@ const deflateEnd = (strm) => {
3336
3336
 
3337
3337
  strm.state = null;
3338
3338
 
3339
- return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3;
3339
+ return status === BUSY_STATE ? err$1(strm, Z_DATA_ERROR$2) : Z_OK$3;
3340
3340
  };
3341
3341
 
3342
3342
 
@@ -6762,6 +6762,453 @@ var inflate_1$1 = {
6762
6762
  const { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1;
6763
6763
  var inflate_1 = inflate;
6764
6764
 
6765
+ /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
6766
+ /**
6767
+ * 4KB JS implementation of ed25519 EdDSA signatures.
6768
+ * Compliant with RFC8032, FIPS 186-5 & ZIP215.
6769
+ * @module
6770
+ * @example
6771
+ * ```js
6772
+ import * as ed from '@noble/ed25519';
6773
+ (async () => {
6774
+ const privKey = ed.utils.randomPrivateKey();
6775
+ const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
6776
+ const pubKey = await ed.getPublicKeyAsync(privKey); // Sync methods are also present
6777
+ const signature = await ed.signAsync(message, privKey);
6778
+ const isValid = await ed.verifyAsync(signature, message, pubKey);
6779
+ })();
6780
+ ```
6781
+ */
6782
+ /**
6783
+ * Curve params. ed25519 is twisted edwards curve. Equation is −x² + y² = -a + dx²y².
6784
+ * * P = `2n**255n - 19n` // field over which calculations are done
6785
+ * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points
6786
+ * * h = 8 // cofactor
6787
+ * * a = `Fp.create(BigInt(-1))` // equation param
6788
+ * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param
6789
+ * * Gx, Gy are coordinates of Generator / base point
6790
+ */
6791
+ const ed25519_CURVE = {
6792
+ p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
6793
+ n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
6794
+ h: 8n,
6795
+ a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
6796
+ d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
6797
+ Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
6798
+ Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
6799
+ };
6800
+ const { p: P, n: N, Gx, Gy, a: _a, d: _d } = ed25519_CURVE;
6801
+ const h = 8n; // cofactor
6802
+ const L = 32; // field / group byte length
6803
+ const L2 = 64;
6804
+ // Helpers and Precomputes sections are reused between libraries
6805
+ // ## Helpers
6806
+ // ----------
6807
+ // error helper, messes-up stack trace
6808
+ const err = (m = '') => {
6809
+ throw new Error(m);
6810
+ };
6811
+ const isBig = (n) => typeof n === 'bigint'; // is big integer
6812
+ const isStr = (s) => typeof s === 'string'; // is string
6813
+ const isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
6814
+ /** assert is Uint8Array (of specific length) */
6815
+ const abytes = (a, l) => !isBytes(a) || (typeof l === 'number' && l > 0 && a.length !== l)
6816
+ ? err('Uint8Array expected')
6817
+ : a;
6818
+ /** create Uint8Array */
6819
+ const u8n = (len) => new Uint8Array(len);
6820
+ const u8fr = (buf) => Uint8Array.from(buf);
6821
+ const padh = (n, pad) => n.toString(16).padStart(pad, '0');
6822
+ const bytesToHex = (b) => Array.from(abytes(b))
6823
+ .map((e) => padh(e, 2))
6824
+ .join('');
6825
+ const C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters
6826
+ const _ch = (ch) => {
6827
+ if (ch >= C._0 && ch <= C._9)
6828
+ return ch - C._0; // '2' => 50-48
6829
+ if (ch >= C.A && ch <= C.F)
6830
+ return ch - (C.A - 10); // 'B' => 66-(65-10)
6831
+ if (ch >= C.a && ch <= C.f)
6832
+ return ch - (C.a - 10); // 'b' => 98-(97-10)
6833
+ return;
6834
+ };
6835
+ const hexToBytes = (hex) => {
6836
+ const e = 'hex invalid';
6837
+ if (!isStr(hex))
6838
+ return err(e);
6839
+ const hl = hex.length;
6840
+ const al = hl / 2;
6841
+ if (hl % 2)
6842
+ return err(e);
6843
+ const array = u8n(al);
6844
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
6845
+ // treat each char as ASCII
6846
+ const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16
6847
+ const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char
6848
+ if (n1 === undefined || n2 === undefined)
6849
+ return err(e);
6850
+ array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9
6851
+ }
6852
+ return array;
6853
+ };
6854
+ /** normalize hex or ui8a to ui8a */
6855
+ const toU8 = (a, len) => abytes(isStr(a) ? hexToBytes(a) : u8fr(abytes(a)), len);
6856
+ const big = BigInt;
6857
+ const arange = (n, min, max, msg = 'bad number: out of range') => isBig(n) && min <= n && n < max ? n : err(msg);
6858
+ /** modular division */
6859
+ const M = (a, b = P) => {
6860
+ const r = a % b;
6861
+ return r >= 0n ? r : b + r;
6862
+ };
6863
+ /** Modular inversion using eucledian GCD (non-CT). No negative exponent for now. */
6864
+ // prettier-ignore
6865
+ const invert = (num, md) => {
6866
+ if (num === 0n || md <= 0n)
6867
+ err('no inverse n=' + num + ' mod=' + md);
6868
+ let a = M(num, md), b = md, x = 0n, u = 1n;
6869
+ while (a !== 0n) {
6870
+ const q = b / a, r = b % a;
6871
+ const m = x - u * q;
6872
+ b = a, a = r, x = u, u = m;
6873
+ }
6874
+ return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point
6875
+ };
6876
+ const apoint = (p) => (p instanceof Point ? p : err('Point expected'));
6877
+ // ## End of Helpers
6878
+ // -----------------
6879
+ const B256 = 2n ** 256n;
6880
+ /** Point in XYZT extended coordinates. */
6881
+ class Point {
6882
+ static BASE;
6883
+ static ZERO;
6884
+ ex;
6885
+ ey;
6886
+ ez;
6887
+ et;
6888
+ constructor(ex, ey, ez, et) {
6889
+ const max = B256;
6890
+ this.ex = arange(ex, 0n, max);
6891
+ this.ey = arange(ey, 0n, max);
6892
+ this.ez = arange(ez, 1n, max);
6893
+ this.et = arange(et, 0n, max);
6894
+ Object.freeze(this);
6895
+ }
6896
+ static fromAffine(p) {
6897
+ return new Point(p.x, p.y, 1n, M(p.x * p.y));
6898
+ }
6899
+ /** RFC8032 5.1.3: Uint8Array to Point. */
6900
+ static fromBytes(hex, zip215 = false) {
6901
+ const d = _d;
6902
+ // Copy array to not mess it up.
6903
+ const normed = u8fr(abytes(hex, L));
6904
+ // adjust first LE byte = last BE byte
6905
+ const lastByte = hex[31];
6906
+ normed[31] = lastByte & ~0x80;
6907
+ const y = bytesToNumLE(normed);
6908
+ // zip215=true: 0 <= y < 2^256
6909
+ // zip215=false, RFC8032: 0 <= y < 2^255-19
6910
+ const max = zip215 ? B256 : P;
6911
+ arange(y, 0n, max);
6912
+ const y2 = M(y * y); // y²
6913
+ const u = M(y2 - 1n); // u=y²-1
6914
+ const v = M(d * y2 + 1n); // v=dy²+1
6915
+ let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root
6916
+ if (!isValid)
6917
+ err('bad point: y not sqrt'); // not square root: bad point
6918
+ const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate
6919
+ const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
6920
+ if (!zip215 && x === 0n && isLastByteOdd)
6921
+ err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1
6922
+ if (isLastByteOdd !== isXOdd)
6923
+ x = M(-x);
6924
+ return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy
6925
+ }
6926
+ /** Checks if the point is valid and on-curve. */
6927
+ assertValidity() {
6928
+ const a = _a;
6929
+ const d = _d;
6930
+ const p = this;
6931
+ if (p.is0())
6932
+ throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
6933
+ // Equation in affine coordinates: ax² + y² = 1 + dx²y²
6934
+ // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
6935
+ const { ex: X, ey: Y, ez: Z, et: T } = p;
6936
+ const X2 = M(X * X); // X²
6937
+ const Y2 = M(Y * Y); // Y²
6938
+ const Z2 = M(Z * Z); // Z²
6939
+ const Z4 = M(Z2 * Z2); // Z⁴
6940
+ const aX2 = M(X2 * a); // aX²
6941
+ const left = M(Z2 * M(aX2 + Y2)); // (aX² + Y²)Z²
6942
+ const right = M(Z4 + M(d * M(X2 * Y2))); // Z⁴ + dX²Y²
6943
+ if (left !== right)
6944
+ throw new Error('bad point: equation left != right (1)');
6945
+ // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
6946
+ const XY = M(X * Y);
6947
+ const ZT = M(Z * T);
6948
+ if (XY !== ZT)
6949
+ throw new Error('bad point: equation left != right (2)');
6950
+ return this;
6951
+ }
6952
+ /** Equality check: compare points P&Q. */
6953
+ equals(other) {
6954
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
6955
+ const { ex: X2, ey: Y2, ez: Z2 } = apoint(other); // checks class equality
6956
+ const X1Z2 = M(X1 * Z2);
6957
+ const X2Z1 = M(X2 * Z1);
6958
+ const Y1Z2 = M(Y1 * Z2);
6959
+ const Y2Z1 = M(Y2 * Z1);
6960
+ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
6961
+ }
6962
+ is0() {
6963
+ return this.equals(I);
6964
+ }
6965
+ /** Flip point over y coordinate. */
6966
+ negate() {
6967
+ return new Point(M(-this.ex), this.ey, this.ez, M(-this.et));
6968
+ }
6969
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
6970
+ double() {
6971
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
6972
+ const a = _a;
6973
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
6974
+ const A = M(X1 * X1);
6975
+ const B = M(Y1 * Y1);
6976
+ const C = M(2n * M(Z1 * Z1));
6977
+ const D = M(a * A);
6978
+ const x1y1 = X1 + Y1;
6979
+ const E = M(M(x1y1 * x1y1) - A - B);
6980
+ const G = D + B;
6981
+ const F = G - C;
6982
+ const H = D - B;
6983
+ const X3 = M(E * F);
6984
+ const Y3 = M(G * H);
6985
+ const T3 = M(E * H);
6986
+ const Z3 = M(F * G);
6987
+ return new Point(X3, Y3, Z3, T3);
6988
+ }
6989
+ /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
6990
+ add(other) {
6991
+ const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
6992
+ const { ex: X2, ey: Y2, ez: Z2, et: T2 } = apoint(other); // doesn't check if other on-curve
6993
+ const a = _a;
6994
+ const d = _d;
6995
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
6996
+ const A = M(X1 * X2);
6997
+ const B = M(Y1 * Y2);
6998
+ const C = M(T1 * d * T2);
6999
+ const D = M(Z1 * Z2);
7000
+ const E = M((X1 + Y1) * (X2 + Y2) - A - B);
7001
+ const F = M(D - C);
7002
+ const G = M(D + C);
7003
+ const H = M(B - a * A);
7004
+ const X3 = M(E * F);
7005
+ const Y3 = M(G * H);
7006
+ const T3 = M(E * H);
7007
+ const Z3 = M(F * G);
7008
+ return new Point(X3, Y3, Z3, T3);
7009
+ }
7010
+ /**
7011
+ * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
7012
+ * Uses {@link wNAF} for base point.
7013
+ * Uses fake point to mitigate side-channel leakage.
7014
+ * @param n scalar by which point is multiplied
7015
+ * @param safe safe mode guards against timing attacks; unsafe mode is faster
7016
+ */
7017
+ multiply(n, safe = true) {
7018
+ if (!safe && (n === 0n || this.is0()))
7019
+ return I;
7020
+ arange(n, 1n, N);
7021
+ if (n === 1n)
7022
+ return this;
7023
+ if (this.equals(G))
7024
+ return wNAF(n).p;
7025
+ // init result point & fake point
7026
+ let p = I;
7027
+ let f = G;
7028
+ for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
7029
+ // if bit is present, add to point
7030
+ // if not present, add to fake, for timing safety
7031
+ if (n & 1n)
7032
+ p = p.add(d);
7033
+ else if (safe)
7034
+ f = f.add(d);
7035
+ }
7036
+ return p;
7037
+ }
7038
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
7039
+ toAffine() {
7040
+ const { ex: x, ey: y, ez: z } = this;
7041
+ // fast-paths for ZERO point OR Z=1
7042
+ if (this.equals(I))
7043
+ return { x: 0n, y: 1n };
7044
+ const iz = invert(z, P);
7045
+ // (Z * Z^-1) must be 1, otherwise bad math
7046
+ if (M(z * iz) !== 1n)
7047
+ err('invalid inverse');
7048
+ // x = X*Z^-1; y = Y*Z^-1
7049
+ return { x: M(x * iz), y: M(y * iz) };
7050
+ }
7051
+ toBytes() {
7052
+ const { x, y } = this.assertValidity().toAffine();
7053
+ const b = numTo32bLE(y);
7054
+ // store sign in first LE byte
7055
+ b[31] |= x & 1n ? 0x80 : 0;
7056
+ return b;
7057
+ }
7058
+ toHex() {
7059
+ return bytesToHex(this.toBytes());
7060
+ } // encode to hex string
7061
+ clearCofactor() {
7062
+ return this.multiply(big(h), false);
7063
+ }
7064
+ isSmallOrder() {
7065
+ return this.clearCofactor().is0();
7066
+ }
7067
+ isTorsionFree() {
7068
+ // multiply by big number CURVE.n
7069
+ let p = this.multiply(N / 2n, false).double(); // ensures the point is not "bad".
7070
+ if (N % 2n)
7071
+ p = p.add(this); // P^(N+1) // P*N == (P*(N/2))*2+P
7072
+ return p.is0();
7073
+ }
7074
+ static fromHex(hex, zip215) {
7075
+ return Point.fromBytes(toU8(hex), zip215);
7076
+ }
7077
+ get x() {
7078
+ return this.toAffine().x;
7079
+ }
7080
+ get y() {
7081
+ return this.toAffine().y;
7082
+ }
7083
+ toRawBytes() {
7084
+ return this.toBytes();
7085
+ }
7086
+ }
7087
+ /** Generator / base point */
7088
+ const G = new Point(Gx, Gy, 1n, M(Gx * Gy));
7089
+ /** Identity / zero point */
7090
+ const I = new Point(0n, 1n, 1n, 0n);
7091
+ // Static aliases
7092
+ Point.BASE = G;
7093
+ Point.ZERO = I;
7094
+ const numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), L2)).reverse();
7095
+ const bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));
7096
+ const pow2 = (x, power) => {
7097
+ // pow2(x, 4) == x^(2^4)
7098
+ let r = x;
7099
+ while (power-- > 0n) {
7100
+ r *= r;
7101
+ r %= P;
7102
+ }
7103
+ return r;
7104
+ };
7105
+ // prettier-ignore
7106
+ const pow_2_252_3 = (x) => {
7107
+ const x2 = (x * x) % P; // x^2, bits 1
7108
+ const b2 = (x2 * x) % P; // x^3, bits 11
7109
+ const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111
7110
+ const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111
7111
+ const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)
7112
+ const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)
7113
+ const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)
7114
+ const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)
7115
+ const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)
7116
+ const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)
7117
+ const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)
7118
+ const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.
7119
+ return { pow_p_5_8, b2 };
7120
+ };
7121
+ const RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // √-1
7122
+ // for sqrt comp
7123
+ // prettier-ignore
7124
+ const uvRatio = (u, v) => {
7125
+ const v3 = M(v * v * v); // v³
7126
+ const v7 = M(v3 * v3 * v); // v⁷
7127
+ const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv⁷)^(p-5)/8
7128
+ let x = M(u * v3 * pow); // (uv³)(uv⁷)^(p-5)/8
7129
+ const vx2 = M(v * x * x); // vx²
7130
+ const root1 = x; // First root candidate
7131
+ const root2 = M(x * RM1); // Second root candidate; RM1 is √-1
7132
+ const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
7133
+ const useRoot2 = vx2 === M(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)
7134
+ const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx² = -u√-1
7135
+ if (useRoot1)
7136
+ x = root1;
7137
+ if (useRoot2 || noRoot)
7138
+ x = root2; // We return root2 anyway, for const-time
7139
+ if ((M(x) & 1n) === 1n)
7140
+ x = M(-x); // edIsNegative
7141
+ return { isValid: useRoot1 || useRoot2, value: x };
7142
+ };
7143
+ // ## Precomputes
7144
+ // --------------
7145
+ const W = 8; // W is window size
7146
+ const scalarBits = 256;
7147
+ const pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8
7148
+ const pwindowSize = 2 ** (W - 1); // 128 for W=8
7149
+ const precompute = () => {
7150
+ const points = [];
7151
+ let p = G;
7152
+ let b = p;
7153
+ for (let w = 0; w < pwindows; w++) {
7154
+ b = p;
7155
+ points.push(b);
7156
+ for (let i = 1; i < pwindowSize; i++) {
7157
+ b = b.add(p);
7158
+ points.push(b);
7159
+ } // i=1, bc we skip 0
7160
+ p = b.double();
7161
+ }
7162
+ return points;
7163
+ };
7164
+ let Gpows = undefined; // precomputes for base point G
7165
+ // const-time negate
7166
+ const ctneg = (cnd, p) => {
7167
+ const n = p.negate();
7168
+ return cnd ? n : p;
7169
+ };
7170
+ /**
7171
+ * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by
7172
+ * caching multiples of G (base point). Cache is stored in 32MB of RAM.
7173
+ * Any time `G.multiply` is done, precomputes are used.
7174
+ * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.
7175
+ *
7176
+ * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,
7177
+ * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.
7178
+ *
7179
+ * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
7180
+ */
7181
+ const wNAF = (n) => {
7182
+ const comp = Gpows || (Gpows = precompute());
7183
+ let p = I;
7184
+ let f = G; // f must be G, or could become I in the end
7185
+ const pow_2_w = 2 ** W; // 256 for W=8
7186
+ const maxNum = pow_2_w; // 256 for W=8
7187
+ const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111
7188
+ const shiftBy = big(W); // 8 for W=8
7189
+ for (let w = 0; w < pwindows; w++) {
7190
+ let wbits = Number(n & mask); // extract W bits.
7191
+ n >>= shiftBy; // shift number by W bits.
7192
+ if (wbits > pwindowSize) {
7193
+ wbits -= maxNum;
7194
+ n += 1n;
7195
+ } // split if bits > max: +224 => 256-32
7196
+ const off = w * pwindowSize;
7197
+ const offF = off; // offsets, evaluate both
7198
+ const offP = off + Math.abs(wbits) - 1;
7199
+ const isEven = w % 2 !== 0; // conditions, evaluate both
7200
+ const isNeg = wbits < 0;
7201
+ if (wbits === 0) {
7202
+ // off == I: can't add it. Adding random offF instead.
7203
+ f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point
7204
+ }
7205
+ else {
7206
+ p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point
7207
+ }
7208
+ }
7209
+ return { p, f }; // return both real and fake points for JIT
7210
+ };
7211
+
6765
7212
  const DEFAULT_MAX_ENTRIES_PER_VIEW = 10000;
6766
7213
  const DEFAULT_CONFIG = {
6767
7214
  reconnectIntervals: [1000, 2000, 4000, 8000, 16000],
@@ -6944,6 +7391,11 @@ function isHostedAreteWebsocketUrl(websocketUrl) {
6944
7391
  return false;
6945
7392
  }
6946
7393
  }
7394
+ /**
7395
+ * Historical sentinel accepted for back-compat: connecting with this URL is
7396
+ * treated the same as passing no WebSocket URL at all (HTTP-only mode).
7397
+ */
7398
+ const DISABLED_WEBSOCKET_URL = 'ws://127.0.0.1/__arete_disabled__';
6947
7399
  class ConnectionManager {
6948
7400
  constructor(config) {
6949
7401
  this.ws = null;
@@ -6959,11 +7411,11 @@ class ConnectionManager {
6959
7411
  this.stateHandlers = new Set();
6960
7412
  this.socketIssueHandlers = new Set();
6961
7413
  this.reconnectForTokenRefresh = false;
6962
- if (!config.websocketUrl) {
6963
- throw new AreteError('websocketUrl is required', 'INVALID_CONFIG');
6964
- }
6965
- this.websocketUrl = config.websocketUrl;
6966
- this.hostedAreteUrl = isHostedAreteWebsocketUrl(config.websocketUrl);
7414
+ const websocketUrl = config.websocketUrl && config.websocketUrl !== DISABLED_WEBSOCKET_URL
7415
+ ? config.websocketUrl
7416
+ : null;
7417
+ this.websocketUrl = websocketUrl;
7418
+ this.hostedAreteUrl = websocketUrl !== null && isHostedAreteWebsocketUrl(websocketUrl);
6967
7419
  this.reconnectIntervals = config.reconnectIntervals ?? DEFAULT_CONFIG.reconnectIntervals;
6968
7420
  this.maxReconnectAttempts =
6969
7421
  config.maxReconnectAttempts ?? DEFAULT_CONFIG.maxReconnectAttempts;
@@ -7055,7 +7507,7 @@ class ConnectionManager {
7055
7507
  }
7056
7508
  createTokenEndpointRequestBody() {
7057
7509
  return {
7058
- websocket_url: this.websocketUrl,
7510
+ websocket_url: this.websocketUrl ?? '',
7059
7511
  };
7060
7512
  }
7061
7513
  async fetchTokenFromEndpoint(tokenEndpoint) {
@@ -7209,14 +7661,21 @@ class ConnectionManager {
7209
7661
  this.ws.close(1000, 'token refresh');
7210
7662
  }
7211
7663
  buildAuthUrl(token) {
7664
+ const websocketUrl = this.requireWebsocketUrl();
7212
7665
  if (this.authConfig?.tokenTransport === 'bearer') {
7213
- return this.websocketUrl;
7666
+ return websocketUrl;
7214
7667
  }
7215
7668
  if (!token) {
7216
- return this.websocketUrl;
7669
+ return websocketUrl;
7670
+ }
7671
+ const separator = websocketUrl.includes('?') ? '&' : '?';
7672
+ return `${websocketUrl}${separator}${DEFAULT_QUERY_PARAMETER}=${encodeURIComponent(token)}`;
7673
+ }
7674
+ requireWebsocketUrl() {
7675
+ if (this.websocketUrl === null) {
7676
+ throw new AreteError('WebSocket transport is disabled (client was connected with transport: "http"); views and subscriptions are unavailable', 'WEBSOCKET_DISABLED');
7217
7677
  }
7218
- const separator = this.websocketUrl.includes('?') ? '&' : '?';
7219
- return `${this.websocketUrl}${separator}${DEFAULT_QUERY_PARAMETER}=${encodeURIComponent(token)}`;
7678
+ return this.websocketUrl;
7220
7679
  }
7221
7680
  createWebSocket(url, token) {
7222
7681
  if (this.authConfig?.tokenTransport === 'bearer') {
@@ -7236,6 +7695,12 @@ class ConnectionManager {
7236
7695
  getState() {
7237
7696
  return this.currentState;
7238
7697
  }
7698
+ async getHttpAuthToken(forceRefresh = false) {
7699
+ return this.getOrRefreshToken(forceRefresh);
7700
+ }
7701
+ clearHttpAuthToken() {
7702
+ this.clearTokenState();
7703
+ }
7239
7704
  onFrame(handler) {
7240
7705
  this.frameHandlers.add(handler);
7241
7706
  return () => {
@@ -7271,6 +7736,7 @@ class ConnectionManager {
7271
7736
  return issue;
7272
7737
  }
7273
7738
  async connect() {
7739
+ this.requireWebsocketUrl();
7274
7740
  if (this.ws?.readyState === WebSocket.OPEN ||
7275
7741
  this.ws?.readyState === WebSocket.CONNECTING ||
7276
7742
  this.currentState === 'connecting') {
@@ -7415,6 +7881,7 @@ class ConnectionManager {
7415
7881
  }
7416
7882
  }
7417
7883
  subscribe(subscription) {
7884
+ this.requireWebsocketUrl();
7418
7885
  const subKey = this.makeSubKey(subscription);
7419
7886
  if (this.currentState === 'connected' && this.ws?.readyState === WebSocket.OPEN) {
7420
7887
  if (this.activeSubscriptions.has(subKey)) {
@@ -7518,16 +7985,20 @@ class ConnectionManager {
7518
7985
  }
7519
7986
  }
7520
7987
 
7521
- function isObject$1(item) {
7988
+ const INTERNAL_SEQ_FIELD = '__seq';
7989
+ function isObject(item) {
7522
7990
  return item !== null && typeof item === 'object' && !Array.isArray(item);
7523
7991
  }
7524
- function deepMergeWithAppend$1(target, source, appendPaths, currentPath = '') {
7525
- if (!isObject$1(target) || !isObject$1(source)) {
7992
+ function deepMergeWithAppend(target, source, appendPaths, currentPath = '') {
7993
+ if (!isObject(target) || !isObject(source)) {
7526
7994
  return source;
7527
7995
  }
7528
7996
  const result = { ...target };
7529
7997
  for (const key in source) {
7530
7998
  const sourceValue = source[key];
7999
+ if (sourceValue === undefined) {
8000
+ continue;
8001
+ }
7531
8002
  const targetValue = result[key];
7532
8003
  const fieldPath = currentPath ? `${currentPath}.${key}` : key;
7533
8004
  if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
@@ -7538,8 +8009,8 @@ function deepMergeWithAppend$1(target, source, appendPaths, currentPath = '') {
7538
8009
  result[key] = sourceValue;
7539
8010
  }
7540
8011
  }
7541
- else if (isObject$1(sourceValue) && isObject$1(targetValue)) {
7542
- result[key] = deepMergeWithAppend$1(targetValue, sourceValue, appendPaths, fieldPath);
8012
+ else if (isObject(sourceValue) && isObject(targetValue)) {
8013
+ result[key] = deepMergeWithAppend(targetValue, sourceValue, appendPaths, fieldPath);
7543
8014
  }
7544
8015
  else {
7545
8016
  result[key] = sourceValue;
@@ -7547,6 +8018,36 @@ function deepMergeWithAppend$1(target, source, appendPaths, currentPath = '') {
7547
8018
  }
7548
8019
  return result;
7549
8020
  }
8021
+ function stripUndefinedProperties(value) {
8022
+ if (Array.isArray(value)) {
8023
+ return value.map(item => stripUndefinedProperties(item));
8024
+ }
8025
+ if (!isObject(value)) {
8026
+ return value;
8027
+ }
8028
+ const result = {};
8029
+ for (const [key, nestedValue] of Object.entries(value)) {
8030
+ if (nestedValue === undefined) {
8031
+ continue;
8032
+ }
8033
+ result[key] = stripUndefinedProperties(nestedValue);
8034
+ }
8035
+ return result;
8036
+ }
8037
+ function toCamelCaseSegment(value) {
8038
+ if (value === '_seq') {
8039
+ return INTERNAL_SEQ_FIELD;
8040
+ }
8041
+ const pascal = value
8042
+ .split(/[_.-]/)
8043
+ .filter(segment => segment.length > 0)
8044
+ .map(segment => segment[0].toUpperCase() + segment.slice(1))
8045
+ .join('');
8046
+ if (pascal.length === 0) {
8047
+ return value;
8048
+ }
8049
+ return pascal[0].toLowerCase() + pascal.slice(1);
8050
+ }
7550
8051
  class FrameProcessor {
7551
8052
  constructor(storage, config = {}) {
7552
8053
  this.pendingUpdates = [];
@@ -7558,9 +8059,10 @@ class FrameProcessor {
7558
8059
  : config.maxEntriesPerView;
7559
8060
  this.flushIntervalMs = config.flushIntervalMs ?? 0;
7560
8061
  this.schemas = config.schemas;
8062
+ this.patchSchemas = config.patchSchemas;
7561
8063
  }
7562
- getSchema(viewPath) {
7563
- const schemas = this.schemas;
8064
+ getSchema(viewPath, patch = false) {
8065
+ const schemas = patch ? this.patchSchemas : this.schemas;
7564
8066
  if (!schemas)
7565
8067
  return null;
7566
8068
  const entityName = viewPath.split('/')[0];
@@ -7569,19 +8071,86 @@ class FrameProcessor {
7569
8071
  const entityKey = entityName;
7570
8072
  return schemas[entityKey] ?? null;
7571
8073
  }
7572
- validateEntity(viewPath, data) {
7573
- const schema = this.getSchema(viewPath);
8074
+ normalizeEntity(viewPath, data, patch = false) {
8075
+ const schema = this.getSchema(viewPath, patch)
8076
+ ?? (!patch ? null : this.getSchema(viewPath));
7574
8077
  if (!schema)
7575
- return true;
8078
+ return data;
7576
8079
  const result = schema.safeParse(data);
7577
8080
  if (!result.success) {
7578
8081
  console.warn('[Arete] Frame validation failed:', {
7579
8082
  view: viewPath,
7580
8083
  error: result.error,
7581
8084
  });
7582
- return false;
8085
+ return null;
7583
8086
  }
7584
- return true;
8087
+ return stripUndefinedProperties(result.data);
8088
+ }
8089
+ hasSchema(viewPath) {
8090
+ return this.getSchema(viewPath) !== null;
8091
+ }
8092
+ normalizePathSegment(viewPath, segment) {
8093
+ if (!this.hasSchema(viewPath)) {
8094
+ return segment;
8095
+ }
8096
+ return toCamelCaseSegment(segment);
8097
+ }
8098
+ normalizePath(viewPath, path) {
8099
+ if (!this.hasSchema(viewPath)) {
8100
+ return path;
8101
+ }
8102
+ return path
8103
+ .split('.')
8104
+ .filter(segment => segment.length > 0)
8105
+ .map(segment => this.normalizePathSegment(viewPath, segment))
8106
+ .join('.');
8107
+ }
8108
+ normalizeSortConfig(viewPath, sort) {
8109
+ if (!this.hasSchema(viewPath)) {
8110
+ return sort;
8111
+ }
8112
+ return {
8113
+ ...sort,
8114
+ field: sort.field.map(segment => this.normalizePathSegment(viewPath, segment)),
8115
+ };
8116
+ }
8117
+ normalizeAppendPaths(viewPath, append) {
8118
+ if (!append || append.length === 0 || !this.hasSchema(viewPath)) {
8119
+ return append ?? [];
8120
+ }
8121
+ return append.map(path => this.normalizePath(viewPath, path));
8122
+ }
8123
+ extractSeq(data) {
8124
+ if (!isObject(data)) {
8125
+ return undefined;
8126
+ }
8127
+ const seq = data._seq;
8128
+ if (typeof seq === 'string') {
8129
+ return seq;
8130
+ }
8131
+ if (typeof seq === 'number' && Number.isFinite(seq)) {
8132
+ return String(seq);
8133
+ }
8134
+ return undefined;
8135
+ }
8136
+ getInternalSeq(data) {
8137
+ if (!isObject(data)) {
8138
+ return undefined;
8139
+ }
8140
+ const seq = data[INTERNAL_SEQ_FIELD];
8141
+ return typeof seq === 'string' ? seq : undefined;
8142
+ }
8143
+ attachInternalSeq(viewPath, data, seq) {
8144
+ if (!seq || !this.hasSchema(viewPath) || !isObject(data)) {
8145
+ return data;
8146
+ }
8147
+ Object.defineProperty(data, INTERNAL_SEQ_FIELD, {
8148
+ value: seq,
8149
+ enumerable: false,
8150
+ configurable: true,
8151
+ writable: true,
8152
+ });
8153
+ return data;
7585
8154
  }
7586
8155
  handleFrame(frame) {
7587
8156
  if (this.flushIntervalMs === 0) {
@@ -7667,7 +8236,9 @@ class FrameProcessor {
7667
8236
  }
7668
8237
  handleSubscribedFrame(frame) {
7669
8238
  if (this.storage.setViewConfig && frame.sort) {
7670
- this.storage.setViewConfig(frame.view, { sort: frame.sort });
8239
+ this.storage.setViewConfig(frame.view, {
8240
+ sort: this.normalizeSortConfig(frame.view, frame.sort),
8241
+ });
7671
8242
  }
7672
8243
  }
7673
8244
  handleSnapshotFrame(frame) {
@@ -7677,17 +8248,19 @@ class FrameProcessor {
7677
8248
  handleSnapshotFrameWithoutEnforce(frame) {
7678
8249
  const viewPath = frame.entity;
7679
8250
  for (const entity of frame.data) {
7680
- if (!this.validateEntity(viewPath, entity.data)) {
8251
+ const normalized = this.normalizeEntity(viewPath, entity.data);
8252
+ if (normalized === null) {
7681
8253
  continue;
7682
8254
  }
8255
+ const nextValue = this.attachInternalSeq(viewPath, normalized, this.extractSeq(entity.data));
7683
8256
  const previousValue = this.storage.get(viewPath, entity.key);
7684
- this.storage.set(viewPath, entity.key, entity.data);
8257
+ this.storage.set(viewPath, entity.key, nextValue);
7685
8258
  this.storage.notifyUpdate(viewPath, entity.key, {
7686
8259
  type: 'upsert',
7687
8260
  key: entity.key,
7688
- data: entity.data,
8261
+ data: nextValue,
7689
8262
  });
7690
- this.emitRichUpdate(viewPath, entity.key, previousValue, entity.data, 'upsert');
8263
+ this.emitRichUpdate(viewPath, entity.key, previousValue, nextValue, 'upsert');
7691
8264
  }
7692
8265
  }
7693
8266
  handleEntityFrame(frame) {
@@ -7700,33 +8273,39 @@ class FrameProcessor {
7700
8273
  switch (frame.op) {
7701
8274
  case 'create':
7702
8275
  case 'upsert':
7703
- if (!this.validateEntity(viewPath, frame.data)) {
8276
+ {
8277
+ const normalized = this.normalizeEntity(viewPath, frame.data);
8278
+ if (normalized === null) {
8279
+ break;
8280
+ }
8281
+ const nextValue = this.attachInternalSeq(viewPath, normalized, frame.seq ?? this.extractSeq(frame.data));
8282
+ this.storage.set(viewPath, frame.key, nextValue);
8283
+ this.storage.notifyUpdate(viewPath, frame.key, {
8284
+ type: 'upsert',
8285
+ key: frame.key,
8286
+ data: nextValue,
8287
+ });
8288
+ this.emitRichUpdate(viewPath, frame.key, previousValue, nextValue, frame.op);
7704
8289
  break;
7705
8290
  }
7706
- this.storage.set(viewPath, frame.key, frame.data);
7707
- this.storage.notifyUpdate(viewPath, frame.key, {
7708
- type: 'upsert',
7709
- key: frame.key,
7710
- data: frame.data,
7711
- });
7712
- this.emitRichUpdate(viewPath, frame.key, previousValue, frame.data, frame.op);
7713
- break;
7714
8291
  case 'patch': {
7715
8292
  const existing = this.storage.get(viewPath, frame.key);
7716
- const appendPaths = frame.append ?? [];
7717
- const merged = existing
7718
- ? deepMergeWithAppend$1(existing, frame.data, appendPaths)
7719
- : frame.data;
7720
- if (!this.validateEntity(viewPath, merged)) {
8293
+ const normalizedPatch = this.normalizeEntity(viewPath, frame.data, true);
8294
+ if (normalizedPatch === null) {
7721
8295
  break;
7722
8296
  }
7723
- this.storage.set(viewPath, frame.key, merged);
8297
+ const appendPaths = this.normalizeAppendPaths(viewPath, frame.append);
8298
+ const merged = existing
8299
+ ? deepMergeWithAppend(existing, normalizedPatch, appendPaths)
8300
+ : normalizedPatch;
8301
+ const nextValue = this.attachInternalSeq(viewPath, merged, frame.seq ?? this.extractSeq(frame.data) ?? this.getInternalSeq(existing));
8302
+ this.storage.set(viewPath, frame.key, nextValue);
7724
8303
  this.storage.notifyUpdate(viewPath, frame.key, {
7725
8304
  type: 'patch',
7726
8305
  key: frame.key,
7727
- data: frame.data,
8306
+ data: normalizedPatch,
7728
8307
  });
7729
- this.emitRichUpdate(viewPath, frame.key, previousValue, merged, 'patch', frame.data);
8308
+ this.emitRichUpdate(viewPath, frame.key, previousValue, nextValue, 'patch', normalizedPatch);
7730
8309
  break;
7731
8310
  }
7732
8311
  case 'delete':
@@ -7759,7 +8338,7 @@ class FrameProcessor {
7759
8338
  }
7760
8339
  }
7761
8340
 
7762
- let ViewData$1 = class ViewData {
8341
+ class ViewData {
7763
8342
  constructor() {
7764
8343
  this.entities = new Map();
7765
8344
  this.accessOrder = [];
@@ -7813,7 +8392,7 @@ let ViewData$1 = class ViewData {
7813
8392
  this.entities.clear();
7814
8393
  this.accessOrder = [];
7815
8394
  }
7816
- };
8395
+ }
7817
8396
  class MemoryAdapter {
7818
8397
  constructor(_config = {}) {
7819
8398
  this.views = new Map();
@@ -7861,7 +8440,7 @@ class MemoryAdapter {
7861
8440
  set(viewPath, key, data) {
7862
8441
  let view = this.views.get(viewPath);
7863
8442
  if (!view) {
7864
- view = new ViewData$1();
8443
+ view = new ViewData();
7865
8444
  this.views.set(viewPath, view);
7866
8445
  }
7867
8446
  view.set(key, data);
@@ -7901,7 +8480,7 @@ class MemoryAdapter {
7901
8480
  }
7902
8481
  }
7903
8482
 
7904
- function getNestedValue$1(obj, path) {
8483
+ function getNestedValue(obj, path) {
7905
8484
  let current = obj;
7906
8485
  for (const segment of path) {
7907
8486
  if (current === null || current === undefined)
@@ -7912,16 +8491,25 @@ function getNestedValue$1(obj, path) {
7912
8491
  }
7913
8492
  return current;
7914
8493
  }
7915
- function compareSortValues$1(a, b) {
8494
+ function compareSortValues(a, b) {
7916
8495
  if (a === b)
7917
8496
  return 0;
7918
8497
  if (a === undefined || a === null)
7919
8498
  return -1;
7920
8499
  if (b === undefined || b === null)
7921
8500
  return 1;
8501
+ if (typeof a === 'bigint' && typeof b === 'bigint') {
8502
+ return a < b ? -1 : 1;
8503
+ }
7922
8504
  if (typeof a === 'number' && typeof b === 'number') {
7923
8505
  return a - b;
7924
8506
  }
8507
+ if (typeof a === 'bigint' && typeof b === 'number' && Number.isInteger(b)) {
8508
+ return a < BigInt(b) ? -1 : 1;
8509
+ }
8510
+ if (typeof a === 'number' && typeof b === 'bigint' && Number.isInteger(a)) {
8511
+ return BigInt(a) < b ? -1 : 1;
8512
+ }
7925
8513
  if (typeof a === 'string' && typeof b === 'string') {
7926
8514
  return a.localeCompare(b);
7927
8515
  }
@@ -8048,7 +8636,7 @@ class SortedStorageDecorator {
8048
8636
  sortedKeys.splice(insertIdx, 0, key);
8049
8637
  }
8050
8638
  binarySearchInsertPosition(viewPath, sortedKeys, sortConfig, newKey, newValue) {
8051
- const newSortValue = getNestedValue$1(newValue, sortConfig.field);
8639
+ const newSortValue = getNestedValue(newValue, sortConfig.field);
8052
8640
  const isDesc = sortConfig.order === 'desc';
8053
8641
  let low = 0;
8054
8642
  let high = sortedKeys.length;
@@ -8056,8 +8644,8 @@ class SortedStorageDecorator {
8056
8644
  const mid = Math.floor((low + high) / 2);
8057
8645
  const midKey = sortedKeys[mid];
8058
8646
  const midEntity = this.inner.get(viewPath, midKey);
8059
- const midValue = getNestedValue$1(midEntity, sortConfig.field);
8060
- let cmp = compareSortValues$1(newSortValue, midValue);
8647
+ const midValue = getNestedValue(midEntity, sortConfig.field);
8648
+ let cmp = compareSortValues(newSortValue, midValue);
8061
8649
  if (isDesc)
8062
8650
  cmp = -cmp;
8063
8651
  if (cmp === 0) {
@@ -8079,9 +8667,9 @@ class SortedStorageDecorator {
8079
8667
  const isDesc = sortConfig.order === 'desc';
8080
8668
  const entries = allKeys.map(k => [k, this.inner.get(viewPath, k)]);
8081
8669
  entries.sort((a, b) => {
8082
- const aValue = getNestedValue$1(a[1], sortConfig.field);
8083
- const bValue = getNestedValue$1(b[1], sortConfig.field);
8084
- let cmp = compareSortValues$1(aValue, bValue);
8670
+ const aValue = getNestedValue(a[1], sortConfig.field);
8671
+ const bValue = getNestedValue(b[1], sortConfig.field);
8672
+ let cmp = compareSortValues(aValue, bValue);
8085
8673
  if (isDesc)
8086
8674
  cmp = -cmp;
8087
8675
  if (cmp === 0) {
@@ -8411,6 +8999,137 @@ function createTypedViews(stack, storage, subscriptionRegistry) {
8411
8999
  return views;
8412
9000
  }
8413
9001
 
9002
+ class ReadRequestError extends Error {
9003
+ constructor(input) {
9004
+ super(`Read request to '${input.path}' failed (${input.status}): ${input.body}`);
9005
+ this.name = 'ReadRequestError';
9006
+ this.status = input.status;
9007
+ this.path = input.path;
9008
+ this.body = input.body;
9009
+ this.serverErrorCode = input.serverErrorCode;
9010
+ }
9011
+ }
9012
+ function getServerErrorCode(response, body) {
9013
+ const headerCode = response.headers.get('X-Error-Code');
9014
+ if (headerCode) {
9015
+ return headerCode;
9016
+ }
9017
+ try {
9018
+ const parsed = JSON.parse(body);
9019
+ return typeof parsed.code === 'string' ? parsed.code : undefined;
9020
+ }
9021
+ catch {
9022
+ return undefined;
9023
+ }
9024
+ }
9025
+ async function parseReadResponse(response, path) {
9026
+ if (!response.ok) {
9027
+ const body = await response.text();
9028
+ throw new ReadRequestError({
9029
+ status: response.status,
9030
+ path,
9031
+ body,
9032
+ serverErrorCode: getServerErrorCode(response, body),
9033
+ });
9034
+ }
9035
+ return response.json();
9036
+ }
9037
+
9038
+ function joinUrl(baseUrl, path) {
9039
+ return `${baseUrl.replace(/\/$/, '')}${path.startsWith('/') ? path : `/${path}`}`;
9040
+ }
9041
+ function decodeBase64(encoded) {
9042
+ if (typeof atob === 'function') {
9043
+ const binary = atob(encoded);
9044
+ const bytes = new Uint8Array(binary.length);
9045
+ for (let i = 0; i < binary.length; i++) {
9046
+ bytes[i] = binary.charCodeAt(i);
9047
+ }
9048
+ return bytes;
9049
+ }
9050
+ const bufferCtor = globalThis.Buffer;
9051
+ if (bufferCtor) {
9052
+ return new Uint8Array(bufferCtor.from(encoded, 'base64'));
9053
+ }
9054
+ throw new Error('No base64 decoder available in this environment');
9055
+ }
9056
+ function deriveHttpEndpoint(wsUrl) {
9057
+ try {
9058
+ const parsed = new URL(wsUrl);
9059
+ if (parsed.protocol === 'ws:') {
9060
+ parsed.protocol = 'http:';
9061
+ }
9062
+ else if (parsed.protocol === 'wss:') {
9063
+ parsed.protocol = 'https:';
9064
+ }
9065
+ return parsed.toString().replace(/\/$/, '');
9066
+ }
9067
+ catch {
9068
+ return wsUrl.replace(/^wss?:/i, (protocol) => protocol.toLowerCase() === 'wss:' ? 'https:' : 'http:');
9069
+ }
9070
+ }
9071
+ function createChainClient(httpBaseUrl, fetchImpl) {
9072
+ return {
9073
+ async exists(address) {
9074
+ const path = `/chain/exists/${encodeURIComponent(address)}`;
9075
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9076
+ const body = await parseReadResponse(response, path);
9077
+ return body.exists;
9078
+ },
9079
+ async lamports(address) {
9080
+ const path = `/chain/lamports/${encodeURIComponent(address)}`;
9081
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9082
+ const body = await parseReadResponse(response, path);
9083
+ return body.lamports;
9084
+ },
9085
+ async minimumBalanceForRentExemption(space) {
9086
+ const path = `/chain/rent-exemption/${encodeURIComponent(String(space))}`;
9087
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9088
+ const body = await parseReadResponse(response, path);
9089
+ return body.lamports;
9090
+ },
9091
+ async clock() {
9092
+ const path = '/chain/clock';
9093
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9094
+ return parseReadResponse(response, path);
9095
+ },
9096
+ async account(address) {
9097
+ const path = `/chain/accounts/${encodeURIComponent(address)}`;
9098
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9099
+ const body = await parseReadResponse(response, path);
9100
+ if (!body) {
9101
+ return null;
9102
+ }
9103
+ return {
9104
+ address: body.address,
9105
+ ownerProgram: body.ownerProgram,
9106
+ lamports: body.lamports,
9107
+ executable: body.executable,
9108
+ data: decodeBase64(body.data),
9109
+ };
9110
+ },
9111
+ async mint(address) {
9112
+ const path = `/chain/mints/${encodeURIComponent(address)}`;
9113
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9114
+ return parseReadResponse(response, path);
9115
+ },
9116
+ async tokenAccount(address) {
9117
+ const path = `/chain/token-accounts/${encodeURIComponent(address)}`;
9118
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path));
9119
+ return parseReadResponse(response, path);
9120
+ },
9121
+ async balance(input) {
9122
+ const path = '/chain/balances';
9123
+ const response = await fetchImpl(joinUrl(httpBaseUrl, path), {
9124
+ method: 'POST',
9125
+ headers: { 'content-type': 'application/json' },
9126
+ body: JSON.stringify(input),
9127
+ });
9128
+ return parseReadResponse(response, path);
9129
+ },
9130
+ };
9131
+ }
9132
+
8414
9133
  /**
8415
9134
  * PDA (Program Derived Address) derivation utilities.
8416
9135
  *
@@ -8425,7 +9144,10 @@ function decodeBase58(str) {
8425
9144
  if (str.length === 0) {
8426
9145
  return new Uint8Array(0);
8427
9146
  }
8428
- const bytes = [0];
9147
+ // Big-endian byte accumulator (stored little-endian here, reversed at the
9148
+ // end). Must start empty: a leading `[0]` produces a spurious extra byte for
9149
+ // all-zero values such as the System Program ("111...1").
9150
+ const bytes = [];
8429
9151
  for (const char of str) {
8430
9152
  const value = BASE58_ALPHABET.indexOf(char);
8431
9153
  if (value === -1) {
@@ -8457,7 +9179,9 @@ function encodeBase58(bytes) {
8457
9179
  if (bytes.length === 0) {
8458
9180
  return '';
8459
9181
  }
8460
- const digits = [0];
9182
+ // Must start empty for the same reason as `decodeBase58`: a leading `[0]`
9183
+ // yields an extra '1' character when encoding all-zero inputs.
9184
+ const digits = [];
8461
9185
  for (const byte of bytes) {
8462
9186
  let carry = byte;
8463
9187
  for (let i = 0; i < digits.length; i++) {
@@ -8478,25 +9202,125 @@ function encodeBase58(bytes) {
8478
9202
  }
8479
9203
  return digits.reverse().map(d => BASE58_ALPHABET[d]).join('');
8480
9204
  }
9205
+ // SHA-256 round constants (first 32 bits of the fractional parts of the cube
9206
+ // roots of the first 64 primes).
9207
+ const SHA256_K = new Uint32Array([
9208
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
9209
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
9210
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
9211
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
9212
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
9213
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
9214
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
9215
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
9216
+ ]);
9217
+ /**
9218
+ * Dependency-free, synchronous SHA-256.
9219
+ *
9220
+ * Used so PDA derivation works identically in browsers, Node (both CJS and
9221
+ * ESM), and bundlers without relying on `require('crypto')` or async WebCrypto.
9222
+ */
9223
+ function sha256Pure(data) {
9224
+ const h = new Uint32Array([
9225
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
9226
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
9227
+ ]);
9228
+ const bitLen = data.length * 8;
9229
+ // Pad: append 0x80, then zeros, until length ≡ 56 (mod 64), then 8-byte length.
9230
+ const paddedLen = ((data.length + 8) >> 6) * 64 + 64;
9231
+ const msg = new Uint8Array(paddedLen);
9232
+ msg.set(data);
9233
+ msg[data.length] = 0x80;
9234
+ // 64-bit big-endian bit length (high 32 bits assumed 0 for our seed sizes).
9235
+ const dv = new DataView(msg.buffer);
9236
+ dv.setUint32(paddedLen - 4, bitLen >>> 0, false);
9237
+ dv.setUint32(paddedLen - 8, Math.floor(bitLen / 0x100000000), false);
9238
+ const w = new Uint32Array(64);
9239
+ for (let offset = 0; offset < paddedLen; offset += 64) {
9240
+ for (let i = 0; i < 16; i++) {
9241
+ w[i] = dv.getUint32(offset + i * 4, false);
9242
+ }
9243
+ for (let i = 16; i < 64; i++) {
9244
+ const w15 = w[i - 15];
9245
+ const w2 = w[i - 2];
9246
+ const s0 = ((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3);
9247
+ const s1 = ((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10);
9248
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
9249
+ }
9250
+ let a = h[0], b = h[1], c = h[2], d = h[3];
9251
+ let e = h[4], f = h[5], g = h[6], hh = h[7];
9252
+ for (let i = 0; i < 64; i++) {
9253
+ const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
9254
+ const ch = (e & f) ^ (~e & g);
9255
+ const t1 = (hh + S1 + ch + SHA256_K[i] + w[i]) >>> 0;
9256
+ const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
9257
+ const maj = (a & b) ^ (a & c) ^ (b & c);
9258
+ const t2 = (S0 + maj) >>> 0;
9259
+ hh = g;
9260
+ g = f;
9261
+ f = e;
9262
+ e = (d + t1) >>> 0;
9263
+ d = c;
9264
+ c = b;
9265
+ b = a;
9266
+ a = (t1 + t2) >>> 0;
9267
+ }
9268
+ h[0] = (h[0] + a) >>> 0;
9269
+ h[1] = (h[1] + b) >>> 0;
9270
+ h[2] = (h[2] + c) >>> 0;
9271
+ h[3] = (h[3] + d) >>> 0;
9272
+ h[4] = (h[4] + e) >>> 0;
9273
+ h[5] = (h[5] + f) >>> 0;
9274
+ h[6] = (h[6] + g) >>> 0;
9275
+ h[7] = (h[7] + hh) >>> 0;
9276
+ }
9277
+ const out = new Uint8Array(32);
9278
+ const outView = new DataView(out.buffer);
9279
+ for (let i = 0; i < 8; i++) {
9280
+ outView.setUint32(i * 4, h[i], false);
9281
+ }
9282
+ return out;
9283
+ }
8481
9284
  /**
8482
- * SHA-256 hash function (synchronous, Node.js).
9285
+ * SHA-256 hash function (synchronous).
8483
9286
  */
8484
9287
  function sha256Sync(data) {
8485
- // eslint-disable-next-line @typescript-eslint/no-var-requires
8486
- const { createHash } = require('crypto');
8487
- return new Uint8Array(createHash('sha256').update(Buffer.from(data)).digest());
9288
+ return sha256Pure(data);
8488
9289
  }
8489
9290
  /**
8490
- * SHA-256 hash function (async, works in browser and Node.js).
9291
+ * SHA-256 hash function (async). Uses WebCrypto when available for speed,
9292
+ * otherwise falls back to the pure implementation.
8491
9293
  */
8492
9294
  async function sha256Async(data) {
8493
9295
  if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.subtle) {
8494
- // Create a copy of the data to ensure we have an ArrayBuffer
8495
9296
  const copy = new Uint8Array(data);
8496
9297
  const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', copy);
8497
9298
  return new Uint8Array(hashBuffer);
8498
9299
  }
8499
- return sha256Sync(data);
9300
+ return sha256Pure(data);
9301
+ }
9302
+ /**
9303
+ * Check if a 32-byte value is a valid point on the ed25519 curve.
9304
+ *
9305
+ * A valid PDA must be OFF the curve (it must NOT correspond to a real
9306
+ * ed25519 public key, so that no private key can ever sign for it).
9307
+ *
9308
+ * We determine on-curve status by attempting to decompress the candidate
9309
+ * as a compressed Edwards point. If decompression succeeds the value lies
9310
+ * on the curve; if it throws, the value is off-curve and is a valid PDA.
9311
+ * This matches the behaviour of `PublicKey.isOnCurve` in @solana/web3.js.
9312
+ */
9313
+ function isOnCurve(publicKey) {
9314
+ if (publicKey.length !== 32) {
9315
+ return false;
9316
+ }
9317
+ try {
9318
+ Point.fromHex(publicKey);
9319
+ return true;
9320
+ }
9321
+ catch {
9322
+ return false;
9323
+ }
8500
9324
  }
8501
9325
  /**
8502
9326
  * PDA marker bytes appended to seeds before hashing.
@@ -8564,7 +9388,7 @@ async function findProgramAddress(seeds, programId) {
8564
9388
  for (let bump = 255; bump >= 0; bump--) {
8565
9389
  const buffer = buildPdaBuffer(seeds, programIdBytes, bump);
8566
9390
  const hash = await sha256Async(buffer);
8567
- {
9391
+ if (!isOnCurve(hash)) {
8568
9392
  return [encodeBase58(hash), bump];
8569
9393
  }
8570
9394
  }
@@ -8584,7 +9408,7 @@ function findProgramAddressSync(seeds, programId) {
8584
9408
  for (let bump = 255; bump >= 0; bump--) {
8585
9409
  const buffer = buildPdaBuffer(seeds, programIdBytes, bump);
8586
9410
  const hash = sha256Sync(buffer);
8587
- {
9411
+ if (!isOnCurve(hash)) {
8588
9412
  return [encodeBase58(hash), bump];
8589
9413
  }
8590
9414
  }
@@ -8633,6 +9457,134 @@ function createPublicKeySeed(address) {
8633
9457
  return decoded;
8634
9458
  }
8635
9459
 
9460
+ /**
9461
+ * Typed serialization of PDA seed values.
9462
+ *
9463
+ * Shared by the standalone PDA DSL (`pda-dsl.ts`) and instruction account
9464
+ * resolution (`account-resolver.ts`). When a seed carries a declared type
9465
+ * (from the IDL or the `pdas!` registry), encoding is exact: pubkeys are
9466
+ * base58-decoded to 32 bytes, integers are little-endian at the declared
9467
+ * width. Without a type, legacy heuristics apply for backward compatibility.
9468
+ */
9469
+ /**
9470
+ * Normalizes the type-name variants that IDLs and codegen produce
9471
+ * ("Pubkey", "publicKey", "solana_pubkey::Pubkey", "String", ...) to a
9472
+ * canonical seed type. Returns undefined for types that cannot be a seed.
9473
+ */
9474
+ function normalizeSeedType(argType) {
9475
+ if (!argType)
9476
+ return undefined;
9477
+ // Strip any path qualifier (e.g. solana_pubkey::Pubkey).
9478
+ const parts = argType.split('::');
9479
+ const t = (parts[parts.length - 1] ?? argType).trim();
9480
+ if (/^[ui](8|16|32|64|128)$/.test(t)) {
9481
+ return t;
9482
+ }
9483
+ switch (t) {
9484
+ case 'pubkey':
9485
+ case 'Pubkey':
9486
+ case 'publicKey':
9487
+ case 'PublicKey':
9488
+ return 'pubkey';
9489
+ case 'string':
9490
+ case 'String':
9491
+ case 'str':
9492
+ return 'string';
9493
+ default:
9494
+ return undefined;
9495
+ }
9496
+ }
9497
+ /**
9498
+ * Serializes a PDA seed value.
9499
+ *
9500
+ * With a recognized `argType`, encoding is strict and width-exact; an
9501
+ * incompatible value throws rather than deriving a wrong address. Without
9502
+ * one, the legacy heuristics apply: raw bytes pass through, 43/44-character
9503
+ * strings are tried as base58, other strings are utf-8, numbers are 8-byte
9504
+ * little-endian u64.
9505
+ */
9506
+ function serializeSeedValue(value, argType) {
9507
+ if (value instanceof Uint8Array) {
9508
+ return value;
9509
+ }
9510
+ const t = normalizeSeedType(argType);
9511
+ if (t === 'pubkey') {
9512
+ if (typeof value !== 'string') {
9513
+ throw new Error(`Pubkey seed requires a base58 string, got ${typeof value}`);
9514
+ }
9515
+ const decoded = decodeBase58(value);
9516
+ if (decoded.length !== 32) {
9517
+ throw new Error(`Pubkey seed '${value}' decoded to ${decoded.length} bytes, expected 32`);
9518
+ }
9519
+ return decoded;
9520
+ }
9521
+ if (t === 'string') {
9522
+ if (typeof value !== 'string') {
9523
+ throw new Error(`String seed requires a string value, got ${typeof value}`);
9524
+ }
9525
+ return new TextEncoder().encode(value);
9526
+ }
9527
+ if (t !== undefined) {
9528
+ // Numeric type at a declared width.
9529
+ if (typeof value !== 'bigint' && typeof value !== 'number') {
9530
+ throw new Error(`Numeric seed of type ${t} requires a number/bigint, got ${typeof value}`);
9531
+ }
9532
+ const bits = parseInt(t.slice(1), 10);
9533
+ return serializeNumber(value, bits / 8, t.startsWith('i'));
9534
+ }
9535
+ // --- Untyped: legacy heuristics. ---
9536
+ if (typeof value === 'string') {
9537
+ if (value.length === 43 || value.length === 44) {
9538
+ try {
9539
+ return decodeBase58(value);
9540
+ }
9541
+ catch {
9542
+ return new TextEncoder().encode(value);
9543
+ }
9544
+ }
9545
+ return new TextEncoder().encode(value);
9546
+ }
9547
+ if (typeof value === 'bigint' || typeof value === 'number') {
9548
+ return serializeNumber(value, 8, true);
9549
+ }
9550
+ throw new Error(`Cannot serialize value for PDA seed: ${typeof value}`);
9551
+ }
9552
+ /**
9553
+ * Little-endian two's-complement encoding at a fixed byte width, with an
9554
+ * overflow check so out-of-range values fail instead of silently truncating.
9555
+ */
9556
+ function serializeNumber(value, size, signed) {
9557
+ const buffer = new Uint8Array(size);
9558
+ let n = typeof value === 'bigint' ? value : BigInt(value);
9559
+ const original = n;
9560
+ for (let i = 0; i < size; i++) {
9561
+ buffer[i] = Number(n & BigInt(0xff));
9562
+ n >>= BigInt(8);
9563
+ }
9564
+ const fits = signed ? n === BigInt(0) || n === BigInt(-1) : n === BigInt(0);
9565
+ if (!fits) {
9566
+ throw new Error(`Seed value ${original} does not fit in ${size * 8} bits`);
9567
+ }
9568
+ return buffer;
9569
+ }
9570
+
9571
+ function getValueByPath(source, path) {
9572
+ if (!source) {
9573
+ return undefined;
9574
+ }
9575
+ if (Object.prototype.hasOwnProperty.call(source, path)) {
9576
+ return source[path];
9577
+ }
9578
+ let current = source;
9579
+ for (const segment of path.split('.')) {
9580
+ if (current === null || typeof current !== 'object') {
9581
+ return undefined;
9582
+ }
9583
+ current = current[segment];
9584
+ }
9585
+ return current;
9586
+ }
9587
+
8636
9588
  /**
8637
9589
  * Topologically sort accounts so that dependencies (accountRef) are resolved first.
8638
9590
  * Non-PDA accounts come first, then PDAs in dependency order.
@@ -8719,13 +9671,32 @@ function resolveAccounts(accountMetas, args, options) {
8719
9671
  missing.push(meta.name);
8720
9672
  }
8721
9673
  }
8722
- // Return accounts in original order (as defined in accountMetas)
9674
+ // Return accounts in original order (as defined in accountMetas).
9675
+ //
9676
+ // Omitted optional accounts that precede a resolved account cannot simply
9677
+ // be dropped — that would shift every later account into the wrong slot.
9678
+ // Anchor's convention is to pass the program ID as a placeholder; trailing
9679
+ // omitted optionals are dropped as usual.
9680
+ const lastResolvedIndex = accountMetas.reduce((last, meta, index) => (resolvedMap[meta.name] ? index : last), -1);
8723
9681
  const orderedAccounts = [];
8724
- for (const meta of accountMetas) {
9682
+ for (let i = 0; i < accountMetas.length; i++) {
9683
+ const meta = accountMetas[i];
8725
9684
  const resolved = resolvedMap[meta.name];
8726
9685
  if (resolved) {
8727
9686
  orderedAccounts.push(resolved);
8728
9687
  }
9688
+ else if (meta.isOptional && i < lastResolvedIndex) {
9689
+ if (!options.programId) {
9690
+ throw new Error('Omitted optional account "' + meta.name + '" precedes other accounts and needs ' +
9691
+ 'the program ID as a placeholder, but no programId was provided in options.');
9692
+ }
9693
+ orderedAccounts.push({
9694
+ name: meta.name,
9695
+ address: options.programId,
9696
+ isSigner: false,
9697
+ isWritable: false,
9698
+ });
9699
+ }
8729
9700
  }
8730
9701
  return {
8731
9702
  accounts: orderedAccounts,
@@ -8735,24 +9706,25 @@ function resolveAccounts(accountMetas, args, options) {
8735
9706
  function resolveSingleAccount(meta, args, options, resolvedMap) {
8736
9707
  switch (meta.category) {
8737
9708
  case 'signer':
8738
- return resolveSignerAccount(meta, options.wallet);
9709
+ return resolveSignerAccount(meta, options.accounts, options.wallet);
8739
9710
  case 'known':
8740
9711
  return resolveKnownAccount(meta);
8741
9712
  case 'pda':
8742
- return resolvePdaAccount(meta, args, resolvedMap, options.programId);
9713
+ return resolvePdaAccount(meta, args, resolvedMap, options.programId, options.resolve);
8743
9714
  case 'userProvided':
8744
9715
  return resolveUserProvidedAccount(meta, options.accounts);
8745
9716
  default:
8746
9717
  return null;
8747
9718
  }
8748
9719
  }
8749
- function resolveSignerAccount(meta, wallet) {
8750
- if (!wallet) {
9720
+ function resolveSignerAccount(meta, accounts, wallet) {
9721
+ const address = accounts?.[meta.name] ?? wallet?.publicKey;
9722
+ if (!address) {
8751
9723
  return null;
8752
9724
  }
8753
9725
  return {
8754
9726
  name: meta.name,
8755
- address: wallet.publicKey,
9727
+ address,
8756
9728
  isSigner: true,
8757
9729
  isWritable: meta.isWritable,
8758
9730
  };
@@ -8768,7 +9740,7 @@ function resolveKnownAccount(meta) {
8768
9740
  isWritable: meta.isWritable,
8769
9741
  };
8770
9742
  }
8771
- function resolvePdaAccount(meta, args, resolvedMap, programId) {
9743
+ function resolvePdaAccount(meta, args, resolvedMap, programId, resolve) {
8772
9744
  if (!meta.pdaConfig) {
8773
9745
  return null;
8774
9746
  }
@@ -8785,13 +9757,16 @@ function resolvePdaAccount(meta, args, resolvedMap, programId) {
8785
9757
  case 'literal':
8786
9758
  seeds.push(createSeed(seed.value));
8787
9759
  break;
9760
+ case 'bytes':
9761
+ seeds.push(Uint8Array.from(seed.value));
9762
+ break;
8788
9763
  case 'argRef': {
8789
- const argValue = args[seed.argName];
9764
+ const argValue = getValueByPath(args, seed.argName) ?? getValueByPath(resolve, seed.argName);
8790
9765
  if (argValue === undefined) {
8791
9766
  throw new Error('PDA seed references missing argument: ' + seed.argName +
8792
9767
  ' (for account "' + meta.name + '")');
8793
9768
  }
8794
- seeds.push(createSeed(argValue));
9769
+ seeds.push(serializeSeedValue(argValue, seed.argType));
8795
9770
  break;
8796
9771
  }
8797
9772
  case 'accountRef': {
@@ -8859,6 +9834,11 @@ function serializeInstructionData(discriminator, args, schema) {
8859
9834
  const buffers = [Buffer.from(discriminator)];
8860
9835
  for (const field of schema) {
8861
9836
  const value = args[field.name];
9837
+ // Option fields treat undefined as None; everything else must be present
9838
+ // (silently encoding zeros for a missing arg corrupts instruction data).
9839
+ if (value === undefined && !(typeof field.type === 'object' && 'option' in field.type)) {
9840
+ throw new Error(`Missing required argument "${field.name}" (type ${JSON.stringify(field.type)})`);
9841
+ }
8862
9842
  const serialized = serializeValue(value, field.type);
8863
9843
  buffers.push(serialized);
8864
9844
  }
@@ -8877,8 +9857,108 @@ function serializeValue(value, type) {
8877
9857
  if ('array' in type) {
8878
9858
  return serializeArray(value, type.array[0], type.array[1]);
8879
9859
  }
9860
+ if ('hashMap' in type) {
9861
+ return serializeHashMap(value, type.hashMap[0], type.hashMap[1]);
9862
+ }
9863
+ if ('struct' in type) {
9864
+ return serializeStruct(value, type.struct);
9865
+ }
9866
+ if ('enum' in type) {
9867
+ return serializeEnum(value, type.enum);
9868
+ }
8880
9869
  throw new Error(`Unknown type: ${JSON.stringify(type)}`);
8881
9870
  }
9871
+ function serializeStruct(value, fields) {
9872
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
9873
+ throw new Error(`Struct value must be a plain object, got ${typeof value}`);
9874
+ }
9875
+ const obj = value;
9876
+ const buffers = [];
9877
+ for (const field of fields) {
9878
+ const fieldValue = obj[field.name];
9879
+ if (fieldValue === undefined &&
9880
+ !(typeof field.type === 'object' && 'option' in field.type)) {
9881
+ throw new Error(`Missing required struct field "${field.name}"`);
9882
+ }
9883
+ buffers.push(serializeValue(fieldValue, field.type));
9884
+ }
9885
+ return Buffer.concat(buffers);
9886
+ }
9887
+ function serializeHashMap(value, keyType, valueType) {
9888
+ if (keyType !== 'string') {
9889
+ throw new Error(`Instruction hashMap keys must use the 'string' schema, got ${JSON.stringify(keyType)}`);
9890
+ }
9891
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
9892
+ throw new Error(`HashMap value must be a plain object, got ${typeof value}`);
9893
+ }
9894
+ const entries = Object.entries(value).sort(([left], [right]) =>
9895
+ // Rust/Borsh sorts String keys by their UTF-8 bytes before serializing.
9896
+ Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8')));
9897
+ const len = Buffer.alloc(4);
9898
+ len.writeUInt32LE(entries.length, 0);
9899
+ const entryBuffers = [];
9900
+ for (const [key, entryValue] of entries) {
9901
+ entryBuffers.push(serializePrimitive(key, 'string'));
9902
+ entryBuffers.push(serializeValue(entryValue, valueType));
9903
+ }
9904
+ return Buffer.concat([len, ...entryBuffers]);
9905
+ }
9906
+ function variantName(variant) {
9907
+ return typeof variant === 'string' ? variant : variant.name;
9908
+ }
9909
+ function serializeEnum(value, variants) {
9910
+ // Numeric value: a bare variant index (fieldless variants only).
9911
+ if (typeof value === 'number') {
9912
+ if (!Number.isInteger(value) || value < 0 || value >= variants.length) {
9913
+ throw new Error(`Enum variant index ${value} out of range (0..${variants.length - 1})`);
9914
+ }
9915
+ const variant = variants[value];
9916
+ if (typeof variant !== 'string') {
9917
+ throw new Error(`Enum variant "${variantName(variant)}" carries data; pass { ${variantName(variant)}: ... } instead of an index`);
9918
+ }
9919
+ return Buffer.from([value]);
9920
+ }
9921
+ // String value: a fieldless variant by name.
9922
+ if (typeof value === 'string') {
9923
+ const index = variants.findIndex((v) => variantName(v) === value);
9924
+ if (index === -1) {
9925
+ throw new Error(`Unknown enum variant "${value}". Expected one of: ${variants.map(variantName).join(', ')}`);
9926
+ }
9927
+ const variant = variants[index];
9928
+ if (typeof variant !== 'string') {
9929
+ throw new Error(`Enum variant "${value}" carries data; pass { ${value}: ... } instead of a bare name`);
9930
+ }
9931
+ return Buffer.from([index]);
9932
+ }
9933
+ // Object value: { variantName: payload } for data-carrying variants.
9934
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
9935
+ const keys = Object.keys(value);
9936
+ if (keys.length !== 1) {
9937
+ throw new Error(`Enum value must be a single-key object ({ variantName: payload }), got keys [${keys.join(', ')}]`);
9938
+ }
9939
+ const key = keys[0];
9940
+ const payload = value[key];
9941
+ const index = variants.findIndex((v) => variantName(v) === key);
9942
+ if (index === -1) {
9943
+ throw new Error(`Unknown enum variant "${key}". Expected one of: ${variants.map(variantName).join(', ')}`);
9944
+ }
9945
+ const variant = variants[index];
9946
+ if (typeof variant === 'string') {
9947
+ throw new Error(`Enum variant "${key}" is fieldless; pass '${key}' instead of an object`);
9948
+ }
9949
+ const prefix = Buffer.from([index]);
9950
+ if ('fields' in variant) {
9951
+ return Buffer.concat([prefix, serializeStruct(payload, variant.fields)]);
9952
+ }
9953
+ const tuple = payload;
9954
+ if (!Array.isArray(tuple) || tuple.length !== variant.tuple.length) {
9955
+ throw new Error(`Enum variant "${key}" expects a tuple of length ${variant.tuple.length}`);
9956
+ }
9957
+ const elements = variant.tuple.map((elementType, i) => serializeValue(tuple[i], elementType));
9958
+ return Buffer.concat([prefix, ...elements]);
9959
+ }
9960
+ throw new Error(`Cannot serialize enum from value of type ${typeof value}`);
9961
+ }
8882
9962
  function serializePrimitive(value, type) {
8883
9963
  switch (type) {
8884
9964
  case 'u8':
@@ -8919,21 +9999,60 @@ function serializePrimitive(value, type) {
8919
9999
  case 'i128':
8920
10000
  const i128 = Buffer.alloc(16);
8921
10001
  const bigI128 = BigInt(value);
8922
- i128.writeBigInt64LE(bigI128 & BigInt('0xFFFFFFFFFFFFFFFF'), 0);
10002
+ // The masked low limb is always non-negative, so it must be written
10003
+ // unsigned; the arithmetic-shifted high limb carries the sign.
10004
+ i128.writeBigUInt64LE(bigI128 & BigInt('0xFFFFFFFFFFFFFFFF'), 0);
8923
10005
  i128.writeBigInt64LE(bigI128 >> BigInt(64), 8);
8924
10006
  return i128;
10007
+ case 'f32': {
10008
+ const f32 = Buffer.alloc(4);
10009
+ f32.writeFloatLE(value, 0);
10010
+ return f32;
10011
+ }
10012
+ case 'f64': {
10013
+ const f64 = Buffer.alloc(8);
10014
+ f64.writeDoubleLE(value, 0);
10015
+ return f64;
10016
+ }
8925
10017
  case 'bool':
8926
10018
  return Buffer.from([value ? 1 : 0]);
10019
+ case 'bytes': {
10020
+ // Borsh bytes: u32 LE length prefix + raw bytes.
10021
+ const raw = value instanceof Uint8Array
10022
+ ? value
10023
+ : Array.isArray(value)
10024
+ ? Uint8Array.from(value)
10025
+ : null;
10026
+ if (raw === null) {
10027
+ throw new Error(`Cannot serialize bytes from value of type ${typeof value}`);
10028
+ }
10029
+ const lenPrefix = Buffer.alloc(4);
10030
+ lenPrefix.writeUInt32LE(raw.length, 0);
10031
+ return Buffer.concat([lenPrefix, Buffer.from(raw)]);
10032
+ }
8927
10033
  case 'string':
8928
10034
  const str = value;
8929
10035
  const strBytes = Buffer.from(str, 'utf-8');
8930
10036
  const strLen = Buffer.alloc(4);
8931
10037
  strLen.writeUInt32LE(strBytes.length, 0);
8932
10038
  return Buffer.concat([strLen, strBytes]);
8933
- case 'pubkey':
8934
- // Public key is 32 bytes
8935
- // In production, decode base58 to 32 bytes
8936
- return Buffer.alloc(32, 0);
10039
+ case 'pubkey': {
10040
+ // Public key is 32 bytes. Accept base58 strings or raw 32-byte buffers.
10041
+ if (value instanceof Uint8Array) {
10042
+ if (value.length !== 32) {
10043
+ throw new Error(`Invalid pubkey byte length: expected 32, got ${value.length}`);
10044
+ }
10045
+ return Buffer.from(value);
10046
+ }
10047
+ if (typeof value === 'string') {
10048
+ const decoded = decodeBase58(value);
10049
+ if (decoded.length !== 32) {
10050
+ throw new Error(`Invalid pubkey: '${value}' decoded to ${decoded.length} bytes, expected 32`);
10051
+ }
10052
+ return Buffer.from(decoded);
10053
+ }
10054
+ throw new Error(`Cannot serialize pubkey from value of type ${typeof value}`);
10055
+ }
8937
10056
  default:
8938
10057
  throw new Error(`Unknown primitive type: ${type}`);
8939
10058
  }
@@ -8960,59 +10079,7 @@ function serializeArray(values, elementType, length) {
8960
10079
  }
8961
10080
 
8962
10081
  /**
8963
- * Waits for transaction confirmation.
8964
- *
8965
- * @param signature - Transaction signature
8966
- * @param level - Desired confirmation level
8967
- * @param timeout - Maximum wait time in milliseconds
8968
- * @returns Confirmation result
8969
- */
8970
- async function waitForConfirmation(signature, level = 'confirmed', timeout = 60000) {
8971
- const startTime = Date.now();
8972
- while (Date.now() - startTime < timeout) {
8973
- const status = await checkTransactionStatus();
8974
- if (status.err) {
8975
- throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
8976
- }
8977
- if (isConfirmationLevelSufficient(status.confirmations, level)) {
8978
- return {
8979
- level,
8980
- slot: status.slot,
8981
- };
8982
- }
8983
- await sleep(1000);
8984
- }
8985
- throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
8986
- }
8987
- async function checkTransactionStatus(_signature) {
8988
- // In production, query the Solana RPC
8989
- return {
8990
- err: null,
8991
- confirmations: 32,
8992
- slot: 123456789,
8993
- };
8994
- }
8995
- function isConfirmationLevelSufficient(confirmations, level) {
8996
- if (confirmations === null) {
8997
- return false;
8998
- }
8999
- switch (level) {
9000
- case 'processed':
9001
- return confirmations >= 0;
9002
- case 'confirmed':
9003
- return confirmations >= 1;
9004
- case 'finalized':
9005
- return confirmations >= 32;
9006
- default:
9007
- return false;
9008
- }
9009
- }
9010
- function sleep(ms) {
9011
- return new Promise(resolve => setTimeout(resolve, ms));
9012
- }
9013
-
9014
- /**
9015
- * Parses and handles instruction errors.
10082
+ * Parses and handles instruction errors.
9016
10083
  */
9017
10084
  /**
9018
10085
  * Parses an error returned from a Solana transaction.
@@ -9070,103 +10137,369 @@ function extractErrorCode(error) {
9070
10137
  function formatProgramError(error) {
9071
10138
  return `${error.name} (${error.code}): ${error.message}`;
9072
10139
  }
9073
-
9074
10140
  /**
9075
- * Converts resolved account array to a map for the builder.
10141
+ * Error thrown when an instruction fails to send and the underlying failure
10142
+ * could be parsed against the handler's IDL error definitions.
9076
10143
  */
9077
- function toResolvedAccountsMap(accounts) {
9078
- const map = {};
9079
- for (const account of accounts) {
9080
- map[account.name] = account.address;
10144
+ class InstructionError extends Error {
10145
+ constructor(message, programError, cause) {
10146
+ super(message);
10147
+ this.name = 'InstructionError';
10148
+ this.programError = programError;
10149
+ this.cause = cause;
9081
10150
  }
9082
- return map;
10151
+ }
10152
+
10153
+ /**
10154
+ * Creates a data-driven instruction handler.
10155
+ *
10156
+ * The returned handler implements `build()` generically: it serializes args
10157
+ * via the schema-driven serializer and constructs the account key list from
10158
+ * the resolved, ordered accounts. No imperative per-instruction code is
10159
+ * required, which keeps generated SDKs tiny and puts all serialization logic
10160
+ * in one tested place.
10161
+ */
10162
+ function createInstructionHandler(config) {
10163
+ const discriminator = config.discriminator instanceof Uint8Array
10164
+ ? config.discriminator
10165
+ : Uint8Array.from(config.discriminator);
10166
+ const argNames = config.args.map((a) => a.name);
10167
+ const errors = config.errors ?? [];
10168
+ return {
10169
+ programId: config.programId,
10170
+ accounts: config.accounts,
10171
+ errors,
10172
+ argNames,
10173
+ build(args, resolved) {
10174
+ const data = serializeInstructionData(discriminator, args, config.args);
10175
+ return {
10176
+ programId: config.programId,
10177
+ keys: resolved.map((r) => ({
10178
+ pubkey: r.address,
10179
+ isSigner: r.isSigner,
10180
+ isWritable: r.isWritable,
10181
+ })),
10182
+ data,
10183
+ };
10184
+ },
10185
+ };
9083
10186
  }
9084
10187
  /**
9085
- * Executes an instruction handler with the given arguments and options.
10188
+ * Splits a merged params object into serialized args and account overrides.
9086
10189
  *
9087
- * This is the main function for executing Solana instructions. It handles:
9088
- * 1. Account resolution (signer, PDA, user-provided)
9089
- * 2. Calling the generated build() function
9090
- * 3. Transaction signing and sending
9091
- * 4. Confirmation waiting
10190
+ * Keys matching a declared argument name are args; keys matching a declared
10191
+ * account name (with a string value) are account address overrides. This
10192
+ * applies to signer slots too, allowing explicit signer addresses to override
10193
+ * the wallet fallback. Anything else throws — a typo'd key silently dropped
10194
+ * here would otherwise change the built instruction. `options.accounts` on
10195
+ * {@link BuildOptions} remains an unvalidated escape hatch for advanced callers.
10196
+ */
10197
+ function splitParams(handler, params) {
10198
+ const argNameSet = new Set(handler.argNames);
10199
+ const accountNameSet = new Set(handler.accounts.map((a) => a.name));
10200
+ const args = {};
10201
+ const accountOverrides = {};
10202
+ let resolve;
10203
+ for (const [key, value] of Object.entries(params)) {
10204
+ if (argNameSet.has(key)) {
10205
+ args[key] = value;
10206
+ }
10207
+ else if (key === 'resolve' && !accountNameSet.has(key)) {
10208
+ if (value === undefined) {
10209
+ continue;
10210
+ }
10211
+ if (value === null || Array.isArray(value) || typeof value !== 'object') {
10212
+ throw new Error('Parameter "resolve" must be an object when provided');
10213
+ }
10214
+ resolve = value;
10215
+ }
10216
+ else if (accountNameSet.has(key)) {
10217
+ if (typeof value !== 'string') {
10218
+ // Non-string values are not valid account addresses.
10219
+ throw new Error(`Parameter "${key}" is not a known argument and is not a base58 account address`);
10220
+ }
10221
+ accountOverrides[key] = value;
10222
+ }
10223
+ else {
10224
+ throw new Error(`Unknown parameter "${key}". Expected one of args [${[...argNameSet].join(', ')}] ` +
10225
+ `or accounts [${[...accountNameSet].join(', ')}]`);
10226
+ }
10227
+ }
10228
+ return { args, accountOverrides, resolve };
10229
+ }
10230
+ /**
10231
+ * Builds a {@link BuiltInstruction} from a handler and a merged params object.
9092
10232
  *
9093
- * @param handler - Instruction handler from generated SDK
9094
- * @param args - Instruction arguments
9095
- * @param options - Execution options
9096
- * @returns Execution result with signature
10233
+ * This is a pure function: it performs no network access. It is the unit of
10234
+ * composition for batching (`wallet.signAndSend([a, b, c])`).
9097
10235
  */
9098
- async function executeInstruction(handler, args, options = {}) {
9099
- // Step 1: Resolve accounts using handler's account metadata
10236
+ function buildInstruction(handler, params, options = {}) {
10237
+ const { args, accountOverrides, resolve } = splitParams(handler, params);
9100
10238
  const resolutionOptions = {
9101
- accounts: options.accounts,
10239
+ accounts: { ...accountOverrides, ...options.accounts },
10240
+ resolve,
9102
10241
  wallet: options.wallet,
9103
- programId: handler.programId, // Pass programId for PDA derivation
10242
+ programId: handler.programId,
9104
10243
  };
9105
10244
  const resolution = resolveAccounts(handler.accounts, args, resolutionOptions);
9106
10245
  validateAccountResolution(resolution);
9107
- // Step 2: Call generated build() function
9108
- const resolvedAccountsMap = toResolvedAccountsMap(resolution.accounts);
9109
- const instruction = handler.build(args, resolvedAccountsMap);
9110
- // Step 3: Build transaction from the built instruction
9111
- const transaction = buildTransaction(instruction);
9112
- // Step 4: Sign and send
9113
- if (!options.wallet) {
9114
- throw new Error('Wallet required to sign transaction');
10246
+ const instruction = handler.build(args, resolution.accounts);
10247
+ if (options.remainingAccounts?.length) {
10248
+ instruction.keys.push(...options.remainingAccounts);
9115
10249
  }
9116
- const signature = await options.wallet.signAndSend(transaction);
9117
- // Step 5: Wait for confirmation
9118
- const confirmationLevel = options.confirmationLevel ?? 'confirmed';
9119
- const timeout = options.timeout ?? 60000;
9120
- const confirmation = await waitForConfirmation(signature, confirmationLevel, timeout);
9121
- return {
9122
- signature,
9123
- confirmationLevel: confirmation.level,
9124
- slot: confirmation.slot,
9125
- };
10250
+ return instruction;
9126
10251
  }
9127
10252
  /**
9128
- * Creates a transaction object from a built instruction.
10253
+ * Builds, signs, and sends an instruction via the wallet adapter.
9129
10254
  *
9130
- * @param instruction - Built instruction from handler
9131
- * @returns Transaction object ready for signing
10255
+ * The core SDK does not touch RPC: the adapter owns blockhash, compilation,
10256
+ * signing, sending, and confirmation. On failure, program errors are parsed
10257
+ * against the handler's IDL error definitions and surfaced as an
10258
+ * {@link InstructionError}.
9132
10259
  */
9133
- function buildTransaction(instruction) {
9134
- // This returns a framework-agnostic transaction representation.
9135
- // The wallet adapter is responsible for converting this to the
9136
- // appropriate format (@solana/web3.js Transaction, etc.)
9137
- return {
9138
- instructions: [{
9139
- programId: instruction.programId,
9140
- keys: instruction.keys,
9141
- data: Array.from(instruction.data),
9142
- }],
10260
+ async function executeInstruction(handler, params, options = {}) {
10261
+ const instruction = buildInstruction(handler, params, options);
10262
+ if (!options.wallet) {
10263
+ throw new Error('Wallet required to sign and send transaction');
10264
+ }
10265
+ const sendOptions = {
10266
+ ...options.send,
9143
10267
  };
10268
+ if (options.confirmationLevel !== undefined) {
10269
+ sendOptions.confirmationLevel = options.confirmationLevel;
10270
+ }
10271
+ try {
10272
+ const result = await options.wallet.signAndSend([instruction], sendOptions);
10273
+ return { signature: result.signature, slot: result.slot };
10274
+ }
10275
+ catch (err) {
10276
+ const programError = parseInstructionError(err, handler.errors);
10277
+ if (programError) {
10278
+ throw new InstructionError(`${programError.name} (${programError.code}): ${programError.message}`, programError, err);
10279
+ }
10280
+ throw err;
10281
+ }
9144
10282
  }
9145
10283
  /**
9146
10284
  * Creates an instruction executor bound to a specific wallet.
9147
- *
9148
- * @param wallet - Wallet adapter
9149
- * @returns Bound executor function
9150
10285
  */
9151
10286
  function createInstructionExecutor(wallet) {
9152
10287
  return {
9153
- execute: async (handler, args, options) => {
9154
- return executeInstruction(handler, args, {
9155
- ...options,
9156
- wallet,
9157
- });
10288
+ execute: async (handler, params, options) => {
10289
+ return executeInstruction(handler, params, { ...options, wallet });
9158
10290
  },
10291
+ build: (handler, params, options) => {
10292
+ return buildInstruction(handler, params, { ...options, wallet });
10293
+ },
10294
+ };
10295
+ }
10296
+
10297
+ const STACK_RUNTIME_EXTENSIONS = '__areteStackRuntimeExtensions';
10298
+ const PROGRAM_OPERATION_EXTENSIONS = '__areteProgramOperationExtensions';
10299
+ function getProgramRuntimeExtensions(program) {
10300
+ return program[PROGRAM_OPERATION_EXTENSIONS];
10301
+ }
10302
+ function getStackRuntimeExtensions(stack) {
10303
+ return stack[STACK_RUNTIME_EXTENSIONS];
10304
+ }
10305
+ function defineClientField(target, key, value) {
10306
+ if (value === undefined || key in target) {
10307
+ return;
10308
+ }
10309
+ Object.defineProperty(target, key, {
10310
+ value,
10311
+ enumerable: true,
10312
+ configurable: true,
10313
+ writable: false,
10314
+ });
10315
+ }
10316
+ function applyConnectedStackExtensions(client, stack) {
10317
+ const extendedStack = stack;
10318
+ defineClientField(client, 'addresses', extendedStack.addresses);
10319
+ defineClientField(client, 'constants', extendedStack.constants);
10320
+ defineClientField(client, 'defaults', extendedStack.defaults);
10321
+ defineClientField(client, 'math', extendedStack.math);
10322
+ const runtime = getStackRuntimeExtensions(stack);
10323
+ defineClientField(client, 'flows', runtime?.createFlows?.(client));
10324
+ defineClientField(client, 'read', runtime?.createRead?.(client));
10325
+ return client;
10326
+ }
10327
+ function nonEmpty(values, label) {
10328
+ if (values.length === 0) {
10329
+ throw new Error(`${label} must contain at least one item`);
10330
+ }
10331
+ return [...values];
10332
+ }
10333
+ function inferSignerAddress(value) {
10334
+ if (typeof value === 'string' && value.length > 0) {
10335
+ return value;
10336
+ }
10337
+ if (!value || typeof value !== 'object') {
10338
+ return null;
10339
+ }
10340
+ const candidate = value;
10341
+ if (typeof candidate.address === 'string' && candidate.address.length > 0) {
10342
+ return candidate.address;
10343
+ }
10344
+ if (typeof candidate.publicKey === 'string' && candidate.publicKey.length > 0) {
10345
+ return candidate.publicKey;
10346
+ }
10347
+ const publicKey = candidate.publicKey;
10348
+ return typeof publicKey?.toBase58 === 'function' ? publicKey.toBase58() : null;
10349
+ }
10350
+ function validateTransactionSigners(transaction, host, options) {
10351
+ const signerAddresses = (options.signers ?? []).map(inferSignerAddress);
10352
+ const available = new Set(options.availableSignerAddresses ?? []);
10353
+ for (const address of options.signerRegistry?.addresses() ?? []) {
10354
+ available.add(address);
10355
+ }
10356
+ const wallet = options.wallet ?? host.wallet;
10357
+ for (const address of wallet?.signerAddresses ?? []) {
10358
+ available.add(address);
10359
+ }
10360
+ const walletAddress = wallet?.publicKey ?? host.publicKey;
10361
+ if (walletAddress) {
10362
+ available.add(walletAddress);
10363
+ }
10364
+ for (const address of signerAddresses) {
10365
+ if (address) {
10366
+ available.add(address);
10367
+ }
10368
+ }
10369
+ const missing = transaction.requiredSignerAddresses.filter((address) => !available.has(address));
10370
+ if (missing.length > 0) {
10371
+ throw new Error(`Missing signer(s) for ${transaction.name}: ${missing.join(', ')}`);
10372
+ }
10373
+ }
10374
+ class OperationExecutionError extends Error {
10375
+ constructor(input) {
10376
+ super(`Operation '${input.operation.name}' failed at transaction ${input.failedTransactionIndex + 1} (${input.failedTransaction.name})`);
10377
+ this.name = 'OperationExecutionError';
10378
+ this.operation = input.operation;
10379
+ this.failedTransaction = input.failedTransaction;
10380
+ this.failedTransactionIndex = input.failedTransactionIndex;
10381
+ this.completedReceipts = [...input.completedReceipts];
10382
+ this.cause = input.cause;
10383
+ }
10384
+ }
10385
+ async function executePreparedOperation(host, operation, options = {}) {
10386
+ const receipts = [];
10387
+ const signers = [
10388
+ ...new Set([
10389
+ ...(options.signerRegistry?.values() ?? []),
10390
+ ...(options.signers ?? []),
10391
+ ]),
10392
+ ];
10393
+ for (const [transactionIndex, transaction] of operation.plan.transactions.entries()) {
10394
+ try {
10395
+ validateTransactionSigners(transaction, host, options);
10396
+ await options.onTransactionStart?.({ operation, transaction, transactionIndex });
10397
+ const result = await host.transaction(transaction.instructions, {
10398
+ wallet: options.wallet,
10399
+ send: options.send,
10400
+ errors: [...transaction.errors],
10401
+ signers: signers.length > 0 ? signers : undefined,
10402
+ });
10403
+ const receipt = {
10404
+ transactionIndex,
10405
+ transactionName: transaction.name,
10406
+ signature: result.signature,
10407
+ slot: result.slot,
10408
+ };
10409
+ receipts.push(receipt);
10410
+ await options.onTransactionSuccess?.({
10411
+ operation,
10412
+ transaction,
10413
+ transactionIndex,
10414
+ receipt,
10415
+ });
10416
+ }
10417
+ catch (cause) {
10418
+ throw new OperationExecutionError({
10419
+ operation,
10420
+ failedTransaction: transaction,
10421
+ failedTransactionIndex: transactionIndex,
10422
+ completedReceipts: receipts,
10423
+ cause,
10424
+ });
10425
+ }
10426
+ }
10427
+ if (operation.kind === 'flow') {
10428
+ return {
10429
+ kind: 'flow',
10430
+ operationName: operation.name,
10431
+ artifacts: operation.artifacts,
10432
+ signatures: nonEmpty(receipts.map((receipt) => receipt.signature), `Operation '${operation.name}' signatures`),
10433
+ transactions: nonEmpty(receipts, `Operation '${operation.name}' receipts`),
10434
+ };
10435
+ }
10436
+ return {
10437
+ kind: operation.kind,
10438
+ operationName: operation.name,
10439
+ artifacts: operation.artifacts,
10440
+ signatures: [receipts[0].signature],
10441
+ transaction: receipts[0],
9159
10442
  };
9160
10443
  }
9161
10444
 
9162
- class Arete {
9163
- constructor(url, options) {
10445
+ function mergeAttachedPrograms(stack, attachedPrograms) {
10446
+ const merged = { ...(attachedPrograms ?? {}) };
10447
+ for (const [name, definition] of Object.entries(stack.programs ?? {})) {
10448
+ if (name in merged) {
10449
+ console.warn(`Ignoring attached program '${name}' for stack '${stack.name}' because the stack already defines that key`);
10450
+ }
10451
+ merged[name] = definition;
10452
+ }
10453
+ return merged;
10454
+ }
10455
+ function normalizeProgramAccountWireKeys(value) {
10456
+ if (Array.isArray(value)) {
10457
+ return value.map(normalizeProgramAccountWireKeys);
10458
+ }
10459
+ if (!value || typeof value !== 'object') {
10460
+ return value;
10461
+ }
10462
+ return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [
10463
+ key.replace(/[A-Z]/g, (letter, index) => `${index === 0 ? '' : '_'}${letter.toLowerCase()}`),
10464
+ normalizeProgramAccountWireKeys(nestedValue),
10465
+ ]));
10466
+ }
10467
+ function parseProgramAccountValue(definition, value) {
10468
+ const schema = definition.schema;
10469
+ if (!schema) {
10470
+ return value;
10471
+ }
10472
+ const parsed = schema.safeParse(value);
10473
+ if (parsed.success) {
10474
+ return parsed.data;
10475
+ }
10476
+ const normalized = schema.safeParse(normalizeProgramAccountWireKeys(value));
10477
+ if (normalized.success) {
10478
+ return normalized.data;
10479
+ }
10480
+ throw new Error(`Program account read '${definition.account}' failed schema validation`);
10481
+ }
10482
+ function cloneStackWithPrograms(stack, programs) {
10483
+ const cloned = Object.create(Object.getPrototypeOf(stack), Object.getOwnPropertyDescriptors(stack));
10484
+ cloned.programs = programs;
10485
+ return cloned;
10486
+ }
10487
+ function withPrograms(stack, attachedPrograms) {
10488
+ return cloneStackWithPrograms(stack, mergeAttachedPrograms(stack, attachedPrograms));
10489
+ }
10490
+ let Arete$1 = class Arete {
10491
+ constructor(url, httpBaseUrl, options) {
9164
10492
  this.stack = options.stack;
10493
+ this._wallet = options.wallet;
10494
+ this.executionDefaults = options.execution;
10495
+ this.httpBaseUrl = httpBaseUrl;
10496
+ this.fetchImpl = options.fetch ?? this.resolveFetchImpl();
9165
10497
  this.storage = new SortedStorageDecorator(options.storage ?? new MemoryAdapter());
9166
10498
  this.processor = new FrameProcessor(this.storage, {
9167
10499
  maxEntriesPerView: options.maxEntriesPerView,
9168
10500
  flushIntervalMs: options.flushIntervalMs,
9169
- schemas: options.validateFrames ? this.stack.schemas : undefined,
10501
+ schemas: this.stack.schemas,
10502
+ patchSchemas: this.stack.patchSchemas,
9170
10503
  });
9171
10504
  this.connection = new ConnectionManager({
9172
10505
  websocketUrl: url,
@@ -9179,26 +10512,178 @@ class Arete {
9179
10512
  this.processor.handleFrame(frame);
9180
10513
  });
9181
10514
  this._views = createTypedViews(this.stack, this.storage, this.subscriptionRegistry);
9182
- this._instructions = this.buildInstructions();
9183
- }
9184
- buildInstructions() {
9185
- const instructions = {};
9186
- if (this.stack.instructions) {
9187
- for (const [name, handler] of Object.entries(this.stack.instructions)) {
9188
- instructions[name] = (args, options) => {
9189
- return executeInstruction(handler, args, options);
9190
- };
10515
+ this._queries = this.buildQueries();
10516
+ this._chain = createChainClient(this.httpBaseUrl, this.authenticatedFetch.bind(this));
10517
+ this._programs = this.buildPrograms();
10518
+ }
10519
+ resolveFetchImpl() {
10520
+ if (typeof globalThis.fetch !== 'function') {
10521
+ throw new AreteError('A fetch implementation is required for HTTP point reads (provide ConnectOptions.fetch or use an environment with global fetch)', 'INVALID_CONFIG');
10522
+ }
10523
+ return globalThis.fetch.bind(globalThis);
10524
+ }
10525
+ buildQueries() {
10526
+ const queries = {};
10527
+ for (const [name, definition] of Object.entries(this.stack.queries ?? {})) {
10528
+ queries[name] = this.createQueryExecutor(definition);
10529
+ }
10530
+ return queries;
10531
+ }
10532
+ buildPrograms() {
10533
+ const bases = {};
10534
+ for (const [name, definition] of Object.entries(this.stack.programs ?? {})) {
10535
+ const instructions = {};
10536
+ for (const [instructionName, handler] of Object.entries(definition.rawInstructions ?? {})) {
10537
+ instructions[instructionName] = this.createTypedInstruction(handler);
9191
10538
  }
10539
+ const accounts = {};
10540
+ for (const [accountName, accountDefinition] of Object.entries(definition.accounts ?? {})) {
10541
+ accounts[accountName] = this.createAccountReader(accountDefinition);
10542
+ }
10543
+ const queries = {};
10544
+ for (const [queryName, queryDefinition] of Object.entries(definition.queries ?? {})) {
10545
+ queries[queryName] = this.createQueryExecutor(queryDefinition);
10546
+ }
10547
+ bases[name] = {
10548
+ name: definition.name,
10549
+ programId: definition.programId,
10550
+ schemas: definition.schemas,
10551
+ pdas: definition.pdas ?? {},
10552
+ accounts,
10553
+ queries,
10554
+ raw: instructions,
10555
+ addresses: definition.addresses ?? {},
10556
+ constants: definition.constants ?? {},
10557
+ defaults: definition.defaults ?? {},
10558
+ math: definition.math ?? {},
10559
+ };
10560
+ }
10561
+ const programs = {};
10562
+ const client = this;
10563
+ for (const [name, definition] of Object.entries(this.stack.programs ?? {})) {
10564
+ const base = bases[name];
10565
+ const connectedProgram = {
10566
+ ...base,
10567
+ instructions: {},
10568
+ transactions: {},
10569
+ flows: {},
10570
+ };
10571
+ const runtime = getProgramRuntimeExtensions(definition);
10572
+ const operations = runtime?.createOperations({
10573
+ chain: this._chain,
10574
+ get wallet() {
10575
+ return client._wallet;
10576
+ },
10577
+ program: connectedProgram,
10578
+ });
10579
+ connectedProgram.instructions = operations?.instructions ?? {};
10580
+ connectedProgram.transactions = operations?.transactions ?? {};
10581
+ connectedProgram.flows = operations?.flows ?? {};
10582
+ programs[name] = connectedProgram;
9192
10583
  }
9193
- return instructions;
10584
+ return programs;
9194
10585
  }
9195
- static async connect(stack, options) {
9196
- const url = options?.url ?? stack.url;
9197
- if (!url) {
9198
- throw new AreteError('URL is required (provide url option or define url in stack)', 'INVALID_CONFIG');
10586
+ createTypedInstruction(handler) {
10587
+ return {
10588
+ build: (params, options) => buildInstruction(handler, params, this.withWallet(options)),
10589
+ };
10590
+ }
10591
+ createAccountReader(definition) {
10592
+ return {
10593
+ fetch: async (address) => {
10594
+ const result = await this.readJson(`${definition.path}/${encodeURIComponent(address)}`);
10595
+ return result === null ? null : parseProgramAccountValue(definition, result);
10596
+ },
10597
+ fetchMany: async (addresses) => {
10598
+ const result = await this.readJson(definition.path, {
10599
+ method: 'POST',
10600
+ body: { addresses },
10601
+ });
10602
+ return result.map((value) => value === null ? null : parseProgramAccountValue(definition, value));
10603
+ },
10604
+ exists: async (address) => {
10605
+ const result = await this.readJson(`${definition.path}/${encodeURIComponent(address)}/exists`);
10606
+ return result.exists;
10607
+ },
10608
+ };
10609
+ }
10610
+ createQueryExecutor(definition) {
10611
+ return async (params) => {
10612
+ const result = await this.readJson(definition.path, {
10613
+ method: definition.method ?? 'POST',
10614
+ body: params,
10615
+ });
10616
+ if (!definition.schema) {
10617
+ return result;
10618
+ }
10619
+ const parsed = definition.schema.safeParse(result);
10620
+ if (!parsed.success) {
10621
+ throw new Error(`Query '${definition.name}' failed schema validation`);
10622
+ }
10623
+ return parsed.data;
10624
+ };
10625
+ }
10626
+ async readJson(path, options) {
10627
+ const response = await this.authenticatedFetch(this.resolveReadUrl(path), {
10628
+ method: options?.method ?? 'GET',
10629
+ headers: options?.body === undefined ? undefined : { 'content-type': 'application/json' },
10630
+ body: options?.body === undefined ? undefined : JSON.stringify(options.body),
10631
+ });
10632
+ return parseReadResponse(response, path);
10633
+ }
10634
+ async authenticatedFetch(input, init) {
10635
+ const attempt = async (forceRefresh = false) => {
10636
+ const token = await this.connection.getHttpAuthToken(forceRefresh);
10637
+ const headers = new Headers(init?.headers ?? undefined);
10638
+ if (token) {
10639
+ headers.set('authorization', `Bearer ${token}`);
10640
+ }
10641
+ return this.fetchImpl(input, {
10642
+ ...init,
10643
+ headers,
10644
+ });
10645
+ };
10646
+ let response = await attempt(false);
10647
+ if (!response.ok) {
10648
+ const wireErrorCode = response.headers.get('X-Error-Code');
10649
+ const errorCode = wireErrorCode ? parseErrorCode(wireErrorCode) : undefined;
10650
+ if (errorCode && shouldRefreshToken(errorCode)) {
10651
+ this.connection.clearHttpAuthToken();
10652
+ response = await attempt(true);
10653
+ }
9199
10654
  }
10655
+ return response;
10656
+ }
10657
+ resolveReadUrl(path) {
10658
+ return `${this.httpBaseUrl.replace(/\/$/, '')}${path.startsWith('/') ? path : `/${path}`}`;
10659
+ }
10660
+ /** Merge the client's default wallet into call options (call options win). */
10661
+ withWallet(options) {
10662
+ const merged = { ...(options ?? {}) };
10663
+ if (!merged.wallet && this._wallet) {
10664
+ merged.wallet = this._wallet;
10665
+ }
10666
+ return merged;
10667
+ }
10668
+ static async connect(stack, options) {
10669
+ const requestedUrl = options?.url ?? stack.endpoints.ws;
10670
+ const autoReconnect = options?.autoReconnect !== false;
10671
+ const httpOnly = options?.transport === 'http' || (!requestedUrl && !autoReconnect);
10672
+ const url = httpOnly ? null : requestedUrl;
10673
+ const httpUrl = options?.httpUrl
10674
+ ?? stack.endpoints.http
10675
+ ?? (requestedUrl ? deriveHttpEndpoint(requestedUrl) : undefined);
10676
+ if (!httpOnly && !url) {
10677
+ throw new AreteError('WebSocket URL is required (provide url option or define endpoints.ws in stack)', 'INVALID_CONFIG');
10678
+ }
10679
+ if (!httpUrl) {
10680
+ throw new AreteError('HTTP endpoint is required for transport: "http" (provide httpUrl option or define endpoints.http in stack)', 'INVALID_CONFIG');
10681
+ }
10682
+ const attachedPrograms = options?.programs;
10683
+ const effectiveStack = withPrograms(stack, attachedPrograms);
9200
10684
  const internalOptions = {
9201
- stack,
10685
+ stack: effectiveStack,
10686
+ httpUrl,
9202
10687
  storage: options?.storage,
9203
10688
  maxEntriesPerView: options?.maxEntriesPerView,
9204
10689
  flushIntervalMs: options?.flushIntervalMs,
@@ -9207,18 +10692,113 @@ class Arete {
9207
10692
  maxReconnectAttempts: options?.maxReconnectAttempts,
9208
10693
  validateFrames: options?.validateFrames,
9209
10694
  auth: options?.auth,
10695
+ wallet: options?.wallet,
10696
+ fetch: options?.fetch,
10697
+ execution: options?.execution,
9210
10698
  };
9211
- const client = new Arete(url, internalOptions);
9212
- if (options?.autoReconnect !== false) {
10699
+ const client = new Arete(url, httpUrl, internalOptions);
10700
+ if (!httpOnly && autoReconnect) {
9213
10701
  await client.connection.connect();
9214
10702
  }
9215
- return client;
10703
+ return applyConnectedStackExtensions(client, effectiveStack);
9216
10704
  }
9217
10705
  get views() {
9218
10706
  return this._views;
9219
10707
  }
9220
- get instructions() {
9221
- return this._instructions;
10708
+ get queries() {
10709
+ return this._queries;
10710
+ }
10711
+ get programs() {
10712
+ return this._programs;
10713
+ }
10714
+ get chain() {
10715
+ return this._chain;
10716
+ }
10717
+ /** The default wallet adapter, if one was configured. */
10718
+ get wallet() {
10719
+ return this._wallet;
10720
+ }
10721
+ /** The connected wallet address, if a default wallet was configured. */
10722
+ get publicKey() {
10723
+ return this._wallet?.publicKey;
10724
+ }
10725
+ /**
10726
+ * Set (or clear) the default wallet adapter used for instruction execution.
10727
+ * Useful for connecting/disconnecting a wallet after the client is created.
10728
+ */
10729
+ setWallet(wallet) {
10730
+ this._wallet = wallet;
10731
+ }
10732
+ /**
10733
+ * Sign and send a batch of pre-built instructions as a single transaction.
10734
+ *
10735
+ * Build instructions with `client.programs.<program>.raw.<name>.build(params)`
10736
+ * and compose them here. RPC/compilation/confirmation are owned by the adapter.
10737
+ *
10738
+ * On failure, the error is parsed against `options.errors` when given,
10739
+ * otherwise against error metadata aggregated from all the stack's handlers
10740
+ * (deduped by code, first-wins — if the stack bundles programs with
10741
+ * overlapping error codes, pass `options.errors` or use the per-instruction
10742
+ * call path for precise attribution).
10743
+ */
10744
+ async transaction(instructions, options) {
10745
+ const wallet = options?.wallet ?? this._wallet;
10746
+ if (!wallet) {
10747
+ throw new Error('Wallet required to sign and send transaction');
10748
+ }
10749
+ try {
10750
+ const sendOptions = {
10751
+ ...(options?.send ?? {}),
10752
+ };
10753
+ if (options?.signers !== undefined) {
10754
+ sendOptions.signers = options.signers;
10755
+ }
10756
+ const result = await wallet.signAndSend(instructions, sendOptions);
10757
+ return { signature: result.signature, slot: result.slot };
10758
+ }
10759
+ catch (err) {
10760
+ const programError = parseInstructionError(err, options?.errors ?? this.aggregateErrors());
10761
+ if (programError) {
10762
+ throw new InstructionError(`${programError.name} (${programError.code}): ${programError.message}`, programError, err);
10763
+ }
10764
+ throw err;
10765
+ }
10766
+ }
10767
+ execute(prepared, options) {
10768
+ const defaults = this.executionDefaults;
10769
+ return executePreparedOperation(this, prepared, {
10770
+ wallet: options?.wallet ?? defaults?.wallet,
10771
+ send: defaults?.send || options?.send
10772
+ ? { ...(defaults?.send ?? {}), ...(options?.send ?? {}) }
10773
+ : undefined,
10774
+ signers: options?.signers ?? defaults?.signers,
10775
+ signerRegistry: options?.signerRegistry ?? defaults?.signerRegistry,
10776
+ availableSignerAddresses: options?.availableSignerAddresses ?? defaults?.availableSignerAddresses,
10777
+ onTransactionStart: options?.onTransactionStart ?? defaults?.onTransactionStart,
10778
+ onTransactionSuccess: options?.onTransactionSuccess ?? defaults?.onTransactionSuccess,
10779
+ });
10780
+ }
10781
+ /** Error metadata from every handler in the stack, deduped by code. */
10782
+ aggregateErrors() {
10783
+ if (!this._aggregatedErrors) {
10784
+ const all = [];
10785
+ const seen = new Set();
10786
+ const collect = (handler) => {
10787
+ for (const error of handler.errors ?? []) {
10788
+ if (!seen.has(error.code)) {
10789
+ seen.add(error.code);
10790
+ all.push(error);
10791
+ }
10792
+ }
10793
+ };
10794
+ for (const program of Object.values(this.stack.programs ?? {})) {
10795
+ for (const handler of Object.values(program.rawInstructions ?? {})) {
10796
+ collect(handler);
10797
+ }
10798
+ }
10799
+ this._aggregatedErrors = all;
10800
+ }
10801
+ return this._aggregatedErrors;
9222
10802
  }
9223
10803
  get connectionState() {
9224
10804
  return this.connection.getState();
@@ -9260,8 +10840,180 @@ class Arete {
9260
10840
  getSubscriptionRegistry() {
9261
10841
  return this.subscriptionRegistry;
9262
10842
  }
10843
+ };
10844
+
10845
+ function createSignerRegistry(entries = []) {
10846
+ const signers = new Map();
10847
+ for (const [address, signer] of entries) {
10848
+ if (!address) {
10849
+ throw new Error('Signer registry addresses must not be empty');
10850
+ }
10851
+ signers.set(address, signer);
10852
+ }
10853
+ return {
10854
+ register(address, signer) {
10855
+ if (!address) {
10856
+ throw new Error('Signer registry addresses must not be empty');
10857
+ }
10858
+ signers.set(address, signer);
10859
+ },
10860
+ unregister(address) {
10861
+ return signers.delete(address);
10862
+ },
10863
+ get(address) {
10864
+ return signers.get(address);
10865
+ },
10866
+ has(address) {
10867
+ return signers.has(address);
10868
+ },
10869
+ addresses() {
10870
+ return [...signers.keys()];
10871
+ },
10872
+ values() {
10873
+ return [...signers.values()];
10874
+ },
10875
+ entries() {
10876
+ return [...signers.entries()];
10877
+ },
10878
+ clear() {
10879
+ signers.clear();
10880
+ },
10881
+ };
9263
10882
  }
9264
10883
 
10884
+ function resolveMemberConnectOptions(stack, member, options, forceHttpOnly) {
10885
+ const transport = member?.transport ?? options?.transport ?? (forceHttpOnly ? 'http' : 'ws');
10886
+ // Resolution order: per-member override → the stack's own endpoints →
10887
+ // session-wide fallback endpoints.
10888
+ const url = member?.url ?? (stack.endpoints.ws || options?.endpoints?.ws);
10889
+ const httpUrl = member?.httpUrl ?? stack.endpoints.http ?? options?.endpoints?.http;
10890
+ return {
10891
+ url,
10892
+ httpUrl,
10893
+ transport,
10894
+ auth: member?.auth ?? options?.auth,
10895
+ storage: member?.storage,
10896
+ autoReconnect: member?.autoReconnect,
10897
+ wallet: options?.wallet,
10898
+ fetch: options?.fetch,
10899
+ };
10900
+ }
10901
+ function programAsStack(name, program) {
10902
+ return {
10903
+ name,
10904
+ endpoints: { ws: '' },
10905
+ views: {},
10906
+ programs: { [name]: program },
10907
+ };
10908
+ }
10909
+ async function createSession(definition, options) {
10910
+ const stackEntries = Object.entries(definition.stacks ?? {});
10911
+ const programEntries = Object.entries(definition.programs ?? {});
10912
+ if (stackEntries.length === 0 && programEntries.length === 0) {
10913
+ throw new AreteError('createSession requires at least one stack or program member', 'INVALID_CONFIG');
10914
+ }
10915
+ let wallet = options?.wallet;
10916
+ const signerRegistry = options?.signerRegistry ?? createSignerRegistry();
10917
+ const connectedStacks = await Promise.all(stackEntries.map(async ([key, stack]) => {
10918
+ const memberOptions = options?.stacks?.[key];
10919
+ const effectiveStack = withPrograms(stack, memberOptions?.programs);
10920
+ const connectOptions = resolveMemberConnectOptions(effectiveStack, memberOptions, options, false);
10921
+ const client = await Arete$1.connect(effectiveStack, connectOptions);
10922
+ return [key, client];
10923
+ }));
10924
+ const connectedPrograms = await Promise.all(programEntries.map(async ([key, program]) => {
10925
+ const syntheticStack = programAsStack(key, program);
10926
+ const connectOptions = resolveMemberConnectOptions(syntheticStack, options?.programs?.[key], options, true);
10927
+ const client = await Arete$1.connect(syntheticStack, connectOptions);
10928
+ return [key, client];
10929
+ }));
10930
+ const memberClients = [
10931
+ ...connectedStacks.map(([, client]) => client),
10932
+ ...connectedPrograms.map(([, client]) => client),
10933
+ ];
10934
+ const executionHost = memberClients[0];
10935
+ const stacks = Object.fromEntries(connectedStacks);
10936
+ const explicitProgramKeys = new Set(connectedPrograms.map(([key]) => key));
10937
+ const programOwners = new Map();
10938
+ const connectedProgramEntries = connectedPrograms.map(([key, client]) => [
10939
+ key,
10940
+ client.programs[key],
10941
+ ]);
10942
+ const promotedPrograms = Object.fromEntries(connectedProgramEntries);
10943
+ for (const [stackKey, client] of connectedStacks) {
10944
+ for (const [programKey, program] of Object.entries(client.programs)) {
10945
+ if (explicitProgramKeys.has(programKey)) {
10946
+ continue;
10947
+ }
10948
+ const existingOwner = programOwners.get(programKey);
10949
+ if (existingOwner) {
10950
+ console.warn(`Program '${programKey}' is bundled by stacks '${existingOwner.stack}'` +
10951
+ ` (${existingOwner.programId ?? 'unknown program ID'}) and '${stackKey}'` +
10952
+ ` (${program.programId ?? 'unknown program ID'}); session.programs.${programKey}` +
10953
+ ` uses '${existingOwner.stack}' because it was connected first`);
10954
+ continue;
10955
+ }
10956
+ promotedPrograms[programKey] = program;
10957
+ programOwners.set(programKey, { stack: stackKey, programId: program.programId });
10958
+ }
10959
+ }
10960
+ const programs = promotedPrograms;
10961
+ const chain = options?.chain ?? (options?.endpoints?.http !== undefined
10962
+ ? createChainClient(options.endpoints.http, (options?.fetch ?? globalThis.fetch?.bind(globalThis)))
10963
+ : executionHost.chain);
10964
+ const session = {
10965
+ stacks,
10966
+ programs,
10967
+ get wallet() {
10968
+ return wallet;
10969
+ },
10970
+ signerRegistry,
10971
+ chain,
10972
+ transaction(instructions, transactionOptions) {
10973
+ const defaults = options?.execution;
10974
+ const configuredSigners = transactionOptions?.signers ?? defaults?.signers;
10975
+ const signers = [...new Set([...signerRegistry.values(), ...(configuredSigners ?? [])])];
10976
+ return executionHost.transaction(instructions, {
10977
+ wallet: transactionOptions?.wallet ?? defaults?.wallet,
10978
+ send: defaults?.send || transactionOptions?.send
10979
+ ? { ...(defaults?.send ?? {}), ...(transactionOptions?.send ?? {}) }
10980
+ : undefined,
10981
+ errors: transactionOptions?.errors,
10982
+ signers: signers.length > 0 ? signers : undefined,
10983
+ });
10984
+ },
10985
+ execute(prepared, executionOptions) {
10986
+ const defaults = options?.execution;
10987
+ const configuredSigners = executionOptions?.signers ?? defaults?.signers;
10988
+ return executionHost.execute(prepared, {
10989
+ wallet: executionOptions?.wallet ?? defaults?.wallet,
10990
+ send: defaults?.send || executionOptions?.send
10991
+ ? { ...(defaults?.send ?? {}), ...(executionOptions?.send ?? {}) }
10992
+ : undefined,
10993
+ signers: configuredSigners,
10994
+ signerRegistry,
10995
+ availableSignerAddresses: executionOptions?.availableSignerAddresses ?? defaults?.availableSignerAddresses,
10996
+ onTransactionStart: executionOptions?.onTransactionStart ?? defaults?.onTransactionStart,
10997
+ onTransactionSuccess: executionOptions?.onTransactionSuccess ?? defaults?.onTransactionSuccess,
10998
+ });
10999
+ },
11000
+ setWallet(nextWallet) {
11001
+ wallet = nextWallet;
11002
+ for (const client of memberClients) {
11003
+ client.setWallet(nextWallet);
11004
+ }
11005
+ },
11006
+ close() {
11007
+ for (const client of memberClients) {
11008
+ client.disconnect();
11009
+ }
11010
+ },
11011
+ };
11012
+ return session;
11013
+ }
11014
+
11015
+ const Arete = Object.assign(Arete$1, { session: createSession });
11016
+
9265
11017
  const DEFAULT_FLUSH_INTERVAL_MS = 16;
9266
11018
 
9267
11019
  class ZustandAdapter {
@@ -9430,11 +11182,52 @@ class ZustandAdapter {
9430
11182
  }
9431
11183
  }
9432
11184
 
11185
+ function syncClientWallets(entries, wallet) {
11186
+ for (const entry of entries) {
11187
+ entry.client.setWallet(wallet);
11188
+ }
11189
+ }
11190
+ function initializeConnectedClient(client, adapter, wallet) {
11191
+ client.setWallet(wallet);
11192
+ client.onConnectionStateChange((state) => {
11193
+ adapter.setConnectionState(state);
11194
+ });
11195
+ adapter.setConnectionState(client.connectionState);
11196
+ }
11197
+
11198
+ const objectKeys = new WeakMap();
11199
+ let nextObjectKey = 0;
11200
+ function getObjectKey(value, prefix) {
11201
+ const existing = objectKeys.get(value);
11202
+ if (existing) {
11203
+ return existing;
11204
+ }
11205
+ const key = `${prefix}-${++nextObjectKey}`;
11206
+ objectKeys.set(value, key);
11207
+ return key;
11208
+ }
11209
+ function createClientCacheKey(stack, options) {
11210
+ if (!stack) {
11211
+ return null;
11212
+ }
11213
+ return [
11214
+ getObjectKey(stack, 'stack'),
11215
+ options?.transport ?? 'ws',
11216
+ options?.url ?? stack.endpoints.ws,
11217
+ options?.httpUrl ?? stack.endpoints.http ?? '',
11218
+ options?.programs
11219
+ ? getObjectKey(options.programs, 'programs')
11220
+ : 'programs-none',
11221
+ ].join(':');
11222
+ }
11223
+
9433
11224
  const AreteContext = createContext(null);
9434
11225
  function AreteProvider({ children, fallback = null, ...config }) {
9435
11226
  const clientsRef = useRef(new Map());
9436
11227
  const connectingRef = useRef(new Map());
9437
11228
  const clientChangeListenersRef = useRef(new Set());
11229
+ const latestWalletRef = useRef(config.wallet);
11230
+ latestWalletRef.current = config.wallet;
9438
11231
  const notifyClientChange = useCallback(() => {
9439
11232
  clientChangeListenersRef.current.forEach(cb => { cb(); });
9440
11233
  }, []);
@@ -9444,8 +11237,11 @@ function AreteProvider({ children, fallback = null, ...config }) {
9444
11237
  clientChangeListenersRef.current.delete(callback);
9445
11238
  };
9446
11239
  }, []);
9447
- const getOrCreateClient = useCallback(async (stack, urlOverride) => {
9448
- const cacheKey = urlOverride ? `${stack.name}:${urlOverride}` : stack.name;
11240
+ const getOrCreateClient = useCallback(async (stack, options) => {
11241
+ const cacheKey = createClientCacheKey(stack, options);
11242
+ if (!cacheKey) {
11243
+ throw new Error('Stack is required to create an Arete client');
11244
+ }
9449
11245
  const existing = clientsRef.current.get(cacheKey);
9450
11246
  if (existing) {
9451
11247
  return existing.client;
@@ -9456,21 +11252,24 @@ function AreteProvider({ children, fallback = null, ...config }) {
9456
11252
  }
9457
11253
  const adapter = new ZustandAdapter();
9458
11254
  const connectionPromise = Arete.connect(stack, {
9459
- url: urlOverride,
11255
+ url: options?.url,
11256
+ httpUrl: options?.httpUrl,
11257
+ transport: options?.transport,
11258
+ programs: options?.programs,
9460
11259
  storage: adapter,
9461
11260
  autoReconnect: config.autoConnect,
9462
11261
  reconnectIntervals: config.reconnectIntervals,
9463
11262
  maxReconnectAttempts: config.maxReconnectAttempts,
9464
11263
  maxEntriesPerView: config.maxEntriesPerView,
9465
11264
  flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,
11265
+ fetch: config.fetch,
11266
+ validateFrames: config.validateFrames,
9466
11267
  auth: config.auth,
11268
+ wallet: latestWalletRef.current,
9467
11269
  }).then((client) => {
9468
- client.onConnectionStateChange((state, error) => {
9469
- adapter.setConnectionState(state, error);
9470
- });
9471
- adapter.setConnectionState(client.connectionState);
11270
+ initializeConnectedClient(client, adapter, latestWalletRef.current);
9472
11271
  clientsRef.current.set(cacheKey, {
9473
- client,
11272
+ client: client,
9474
11273
  disconnect: () => client.disconnect()
9475
11274
  });
9476
11275
  connectingRef.current.delete(cacheKey);
@@ -9479,8 +11278,8 @@ function AreteProvider({ children, fallback = null, ...config }) {
9479
11278
  });
9480
11279
  connectingRef.current.set(cacheKey, connectionPromise);
9481
11280
  return connectionPromise;
9482
- }, [config.autoConnect, config.reconnectIntervals, config.maxReconnectAttempts, config.maxEntriesPerView, config.flushIntervalMs, config.auth, notifyClientChange]);
9483
- const getClient = useCallback((stack) => {
11281
+ }, [config.autoConnect, config.reconnectIntervals, config.maxReconnectAttempts, config.maxEntriesPerView, config.flushIntervalMs, config.fetch, config.validateFrames, config.auth, notifyClientChange]);
11282
+ const getClient = useCallback((stack, options) => {
9484
11283
  if (!stack) {
9485
11284
  if (clientsRef.current.size === 1) {
9486
11285
  const firstEntry = clientsRef.current.values().next().value;
@@ -9488,9 +11287,17 @@ function AreteProvider({ children, fallback = null, ...config }) {
9488
11287
  }
9489
11288
  return null;
9490
11289
  }
9491
- const entry = clientsRef.current.get(stack.name);
11290
+ const cacheKey = createClientCacheKey(stack, options);
11291
+ if (!cacheKey) {
11292
+ return null;
11293
+ }
11294
+ const entry = clientsRef.current.get(cacheKey);
9492
11295
  return entry ? entry.client : null;
9493
11296
  }, []);
11297
+ useEffect(() => {
11298
+ syncClientWallets(clientsRef.current.values(), config.wallet);
11299
+ notifyClientChange();
11300
+ }, [config.wallet, notifyClientChange]);
9494
11301
  useEffect(() => {
9495
11302
  return () => {
9496
11303
  clientsRef.current.forEach((entry) => {
@@ -9515,10 +11322,10 @@ function useAreteContext() {
9515
11322
  }
9516
11323
  return context;
9517
11324
  }
9518
- function useConnectionState(stack) {
11325
+ function useConnectionState(stack, options) {
9519
11326
  const { getClient, subscribeToClientChanges } = useAreteContext();
9520
11327
  const [state, setState] = React.useState(() => {
9521
- const client = getClient(stack);
11328
+ const client = getClient(stack, options);
9522
11329
  return client?.connectionState ?? 'disconnected';
9523
11330
  });
9524
11331
  const unsubscribeRef = React.useRef(undefined);
@@ -9527,7 +11334,7 @@ function useConnectionState(stack) {
9527
11334
  const setupClientSubscription = () => {
9528
11335
  unsubscribeRef.current?.();
9529
11336
  unsubscribeRef.current = undefined;
9530
- const client = getClient(stack);
11337
+ const client = getClient(stack, options);
9531
11338
  if (client && mounted) {
9532
11339
  setState(client.connectionState);
9533
11340
  unsubscribeRef.current = client.onConnectionStateChange((newState) => {
@@ -9546,12 +11353,12 @@ function useConnectionState(stack) {
9546
11353
  unsubscribeFromClientChanges();
9547
11354
  unsubscribeRef.current?.();
9548
11355
  };
9549
- }, [getClient, subscribeToClientChanges, stack]);
11356
+ }, [getClient, subscribeToClientChanges, stack, options]);
9550
11357
  return state;
9551
11358
  }
9552
- function useView(stack, viewPath) {
11359
+ function useView(stack, viewPath, options) {
9553
11360
  const { getClient } = useAreteContext();
9554
- const client = getClient(stack);
11361
+ const client = getClient(stack, options);
9555
11362
  return useSyncExternalStore((callback) => {
9556
11363
  if (!client)
9557
11364
  return () => { };
@@ -9563,9 +11370,9 @@ function useView(stack, viewPath) {
9563
11370
  return data;
9564
11371
  });
9565
11372
  }
9566
- function useEntity(stack, viewPath, key) {
11373
+ function useEntity(stack, viewPath, key, options) {
9567
11374
  const { getClient } = useAreteContext();
9568
- const client = getClient(stack);
11375
+ const client = getClient(stack, options);
9569
11376
  return useSyncExternalStore((callback) => {
9570
11377
  if (!client)
9571
11378
  return () => { };
@@ -9578,6 +11385,84 @@ function useEntity(stack, viewPath, key) {
9578
11385
  });
9579
11386
  }
9580
11387
 
11388
+ function wrapRawInstruction(instruction, client, createMutationHook) {
11389
+ const execute = async (input, options) => {
11390
+ if (!client) {
11391
+ throw new Error('Arete client is not connected');
11392
+ }
11393
+ return client.transaction([instruction.build(input)], options);
11394
+ };
11395
+ return {
11396
+ execute,
11397
+ build: instruction.build,
11398
+ useMutation: () => createMutationHook(execute),
11399
+ };
11400
+ }
11401
+ function isConnectedOperation(value) {
11402
+ return Boolean(value && typeof value === 'object' && typeof value.prepare === 'function');
11403
+ }
11404
+ function wrapOperation(operation, client, createMutationHook) {
11405
+ const execute = async (input, options) => {
11406
+ if (!client) {
11407
+ throw new Error('Arete client is not connected');
11408
+ }
11409
+ const prepared = await operation.prepare(input);
11410
+ return client.execute(prepared, options);
11411
+ };
11412
+ return {
11413
+ prepare: operation.prepare.bind(operation),
11414
+ execute,
11415
+ useMutation: () => createMutationHook(execute),
11416
+ };
11417
+ }
11418
+ function wrapOperationNamespace(namespace, client, createMutationHook) {
11419
+ const wrapped = {};
11420
+ for (const [name, value] of Object.entries(namespace)) {
11421
+ if (isConnectedOperation(value)) {
11422
+ wrapped[name] = wrapOperation(value, client, createMutationHook);
11423
+ continue;
11424
+ }
11425
+ if (value && typeof value === 'object') {
11426
+ wrapped[name] = wrapOperationNamespace(value, client, createMutationHook);
11427
+ }
11428
+ }
11429
+ return wrapped;
11430
+ }
11431
+ function wrapMaybeOperationNamespace(namespace, client, createMutationHook) {
11432
+ return namespace
11433
+ ? wrapOperationNamespace(namespace, client, createMutationHook)
11434
+ : {};
11435
+ }
11436
+ function buildProgramHookInterfaces(programs, client, createMutationHook) {
11437
+ const wrappedPrograms = {};
11438
+ if (!programs) {
11439
+ return wrappedPrograms;
11440
+ }
11441
+ for (const [name, program] of Object.entries(programs)) {
11442
+ const raw = {};
11443
+ for (const [instructionName, instruction] of Object.entries(program.raw)) {
11444
+ raw[instructionName] = wrapRawInstruction(instruction, client, createMutationHook);
11445
+ }
11446
+ wrappedPrograms[name] = {
11447
+ name: program.name,
11448
+ programId: program.programId,
11449
+ schemas: program.schemas,
11450
+ pdas: program.pdas,
11451
+ accounts: program.accounts,
11452
+ queries: program.queries,
11453
+ addresses: program.addresses,
11454
+ constants: program.constants,
11455
+ defaults: program.defaults,
11456
+ math: program.math,
11457
+ raw: raw,
11458
+ instructions: wrapMaybeOperationNamespace(program.instructions, client, createMutationHook),
11459
+ transactions: wrapMaybeOperationNamespace(program.transactions, client, createMutationHook),
11460
+ flows: wrapMaybeOperationNamespace(program.flows, client, createMutationHook),
11461
+ };
11462
+ }
11463
+ return wrappedPrograms;
11464
+ }
11465
+
9581
11466
  function shallowArrayEqual(a, b) {
9582
11467
  if (a === b)
9583
11468
  return true;
@@ -9591,6 +11476,34 @@ function shallowArrayEqual(a, b) {
9591
11476
  }
9592
11477
  return true;
9593
11478
  }
11479
+ function compareNumericValues(value, condition, op) {
11480
+ if (typeof value === 'bigint' || typeof condition === 'bigint') {
11481
+ const left = typeof value === 'bigint' ? value : BigInt(value);
11482
+ const right = typeof condition === 'bigint' ? condition : BigInt(condition);
11483
+ switch (op) {
11484
+ case 'gte':
11485
+ return left >= right;
11486
+ case 'lte':
11487
+ return left <= right;
11488
+ case 'gt':
11489
+ return left > right;
11490
+ case 'lt':
11491
+ return left < right;
11492
+ }
11493
+ }
11494
+ const left = value;
11495
+ const right = condition;
11496
+ switch (op) {
11497
+ case 'gte':
11498
+ return left >= right;
11499
+ case 'lte':
11500
+ return left <= right;
11501
+ case 'gt':
11502
+ return left > right;
11503
+ case 'lt':
11504
+ return left < right;
11505
+ }
11506
+ }
9594
11507
  function useStateView(viewDef, client, key, options) {
9595
11508
  const [isLoading, setIsLoading] = useState(!options?.initialData && options?.withSnapshot !== false);
9596
11509
  const [error, setError] = useState();
@@ -9675,7 +11588,10 @@ function useStateView(viewDef, client, key, options) {
9675
11588
  ? clientRef.current.store.get(viewDef.view, keyString)
9676
11589
  : clientRef.current.store.getAll(viewDef.view)[0];
9677
11590
  const validated = entity && schema
9678
- ? (schema.safeParse(entity).success ? entity : undefined)
11591
+ ? (() => {
11592
+ const parsed = schema.safeParse(entity);
11593
+ return parsed.success ? parsed.data : undefined;
11594
+ })()
9679
11595
  : entity;
9680
11596
  if (validated !== cachedSnapshotRef.current) {
9681
11597
  cachedSnapshotRef.current = validated;
@@ -9801,20 +11717,23 @@ function useListView(viewDef, client, params, options) {
9801
11717
  if (typeof condition === 'object' && condition !== null) {
9802
11718
  const cond = condition;
9803
11719
  if ('gte' in cond)
9804
- return value >= cond.gte;
11720
+ return compareNumericValues(value, cond.gte, 'gte');
9805
11721
  if ('lte' in cond)
9806
- return value <= cond.lte;
11722
+ return compareNumericValues(value, cond.lte, 'lte');
9807
11723
  if ('gt' in cond)
9808
- return value > cond.gt;
11724
+ return compareNumericValues(value, cond.gt, 'gt');
9809
11725
  if ('lt' in cond)
9810
- return value < cond.lt;
11726
+ return compareNumericValues(value, cond.lt, 'lt');
9811
11727
  }
9812
11728
  return value === condition;
9813
11729
  });
9814
11730
  });
9815
11731
  }
9816
11732
  if (schema) {
9817
- items = items.filter((item) => schema.safeParse(item).success);
11733
+ items = items.flatMap((item) => {
11734
+ const parsed = schema.safeParse(item);
11735
+ return parsed.success ? [parsed.data] : [];
11736
+ });
9818
11737
  }
9819
11738
  if (limit) {
9820
11739
  items = items.slice(0, limit);
@@ -9874,30 +11793,42 @@ function createListViewHook(viewDef, client) {
9874
11793
  function useInstructionMutation(execute) {
9875
11794
  const [status, setStatus] = useState('idle');
9876
11795
  const [error, setError] = useState(null);
11796
+ const [signatures, setSignatures] = useState([]);
9877
11797
  const [signature, setSignature] = useState(null);
9878
11798
  const submit = useCallback(async (args, options) => {
9879
11799
  setStatus('pending');
9880
11800
  setError(null);
11801
+ setSignatures([]);
9881
11802
  setSignature(null);
11803
+ const { onSuccess, onError, ...executionOptions } = options ?? {};
9882
11804
  try {
9883
- const result = await execute(args, options);
11805
+ const result = await execute(args, executionOptions);
11806
+ const resultSignatures = typeof result === 'object' && result !== null && 'signatures' in result
11807
+ && Array.isArray(result.signatures)
11808
+ ? result.signatures.map(String)
11809
+ : typeof result === 'object' && result !== null && 'signature' in result
11810
+ ? [String(result.signature)]
11811
+ : [];
9884
11812
  setStatus('success');
9885
- setSignature(result.signature);
9886
- if (options?.onSuccess) {
9887
- options.onSuccess(result);
11813
+ setSignatures(resultSignatures);
11814
+ setSignature(resultSignatures.length === 1 ? resultSignatures[0] : null);
11815
+ if (onSuccess) {
11816
+ onSuccess(result);
9888
11817
  }
9889
11818
  return result;
9890
11819
  }
9891
11820
  catch (err) {
9892
- const errorMessage = err instanceof Error ? err.message : String(err);
9893
- const programError = parseInstructionError(err, []);
9894
- const displayError = programError
9895
- ? `${programError.name}: ${programError.message}`
9896
- : errorMessage;
11821
+ // The core executor already parses program errors against the handler's
11822
+ // IDL error definitions and throws an InstructionError.
11823
+ const displayError = err instanceof InstructionError && err.programError
11824
+ ? `${err.programError.name}: ${err.programError.message}`
11825
+ : err instanceof Error
11826
+ ? err.message
11827
+ : String(err);
9897
11828
  setStatus('error');
9898
11829
  setError(displayError);
9899
- if (options?.onError && err instanceof Error) {
9900
- options.onError(err);
11830
+ if (onError && err instanceof Error) {
11831
+ onError(err);
9901
11832
  }
9902
11833
  throw err;
9903
11834
  }
@@ -9905,12 +11836,14 @@ function useInstructionMutation(execute) {
9905
11836
  const reset = useCallback(() => {
9906
11837
  setStatus('idle');
9907
11838
  setError(null);
11839
+ setSignatures([]);
9908
11840
  setSignature(null);
9909
11841
  }, []);
9910
11842
  return {
9911
11843
  submit,
9912
11844
  status,
9913
11845
  error,
11846
+ signatures,
9914
11847
  signature,
9915
11848
  isLoading: status === 'pending',
9916
11849
  reset,
@@ -9919,21 +11852,25 @@ function useInstructionMutation(execute) {
9919
11852
 
9920
11853
  function useArete(stack, options) {
9921
11854
  const { getOrCreateClient, getClient } = useAreteContext();
9922
- const urlOverride = options?.url;
9923
- const [client, setClient] = useState(getClient(stack));
11855
+ const url = options?.url;
11856
+ const httpUrl = options?.httpUrl;
11857
+ const transport = options?.transport;
11858
+ const attachedPrograms = options?.programs;
11859
+ const lookupOptions = useMemo(() => ({ url, httpUrl, transport, programs: attachedPrograms }), [url, httpUrl, transport, attachedPrograms]);
11860
+ const [client, setClient] = useState(getClient(stack, lookupOptions));
9924
11861
  const [isLoading, setIsLoading] = useState(!client);
9925
11862
  const [error, setError] = useState(null);
9926
11863
  const [connectionState, setConnectionState] = useState(() => client?.connectionState ?? 'disconnected');
9927
11864
  useEffect(() => {
9928
- const existingClient = getClient(stack);
9929
- if (existingClient && !urlOverride) {
11865
+ const existingClient = getClient(stack, lookupOptions);
11866
+ if (existingClient) {
9930
11867
  setClient(existingClient);
9931
11868
  setIsLoading(false);
9932
11869
  return;
9933
11870
  }
9934
11871
  setIsLoading(true);
9935
11872
  setError(null);
9936
- getOrCreateClient(stack, urlOverride)
11873
+ getOrCreateClient(stack, lookupOptions)
9937
11874
  .then((newClient) => {
9938
11875
  setClient(newClient);
9939
11876
  setIsLoading(false);
@@ -9942,7 +11879,7 @@ function useArete(stack, options) {
9942
11879
  setError(err instanceof Error ? err : new Error(String(err)));
9943
11880
  setIsLoading(false);
9944
11881
  });
9945
- }, [stack, getOrCreateClient, getClient, urlOverride]);
11882
+ }, [stack, getOrCreateClient, getClient, lookupOptions]);
9946
11883
  useEffect(() => {
9947
11884
  if (!client) {
9948
11885
  setConnectionState('disconnected');
@@ -9973,21 +11910,14 @@ function useArete(stack, options) {
9973
11910
  }
9974
11911
  return result;
9975
11912
  }, [stack, client]);
9976
- const instructions = useMemo(() => {
9977
- const result = {};
9978
- if (client?.instructions) {
9979
- for (const [instructionName, executeFn] of Object.entries(client.instructions)) {
9980
- result[instructionName] = {
9981
- execute: executeFn,
9982
- useMutation: () => useInstructionMutation(executeFn)
9983
- };
9984
- }
9985
- }
9986
- return result;
11913
+ const programs = useMemo(() => {
11914
+ return buildProgramHookInterfaces(client?.programs, client, useInstructionMutation);
9987
11915
  }, [client]);
9988
11916
  return {
9989
11917
  views: views,
9990
- instructions: instructions,
11918
+ queries: (client?.queries ?? {}),
11919
+ programs: programs,
11920
+ chain: client?.chain,
9991
11921
  zustandStore: client?.store?.store,
9992
11922
  client: client,
9993
11923
  connectionState,
@@ -9997,5 +11927,5 @@ function useArete(stack, options) {
9997
11927
  };
9998
11928
  }
9999
11929
 
10000
- export { Arete, AreteError, AreteProvider, ConnectionManager, DEFAULT_CONFIG, DEFAULT_MAX_ENTRIES_PER_VIEW, FrameProcessor, MemoryAdapter, SubscriptionRegistry, ZustandAdapter, createInstructionExecutor, createPublicKeySeed, createSeed, findProgramAddress as derivePda, executeInstruction, formatProgramError, isSnapshotFrame, isValidFrame, parseFrame, parseFrameFromBlob, parseInstructionError, resolveAccounts, serializeInstructionData, useArete, useAreteContext, useConnectionState, useEntity, useInstructionMutation, useView, validateAccountResolution, waitForConfirmation };
11930
+ export { Arete, AreteError, AreteProvider, ConnectionManager, DEFAULT_CONFIG, DEFAULT_MAX_ENTRIES_PER_VIEW, FrameProcessor, InstructionError, MemoryAdapter, ReadRequestError, SubscriptionRegistry, ZustandAdapter, buildInstruction, createInstructionExecutor, createInstructionHandler, createPublicKeySeed, createSeed, findProgramAddress as derivePda, executeInstruction, formatProgramError, isSnapshotFrame, isValidFrame, parseFrame, parseFrameFromBlob, parseInstructionError, resolveAccounts, serializeInstructionData, useArete, useAreteContext, useConnectionState, useEntity, useInstructionMutation, useView, validateAccountResolution, withPrograms };
10001
11931
  //# sourceMappingURL=index.esm.js.map