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