starknet 10.4.0 → 10.5.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [10.5.1](https://github.com/starknet-io/starknet.js/compare/v10.5.0...v10.5.1) (2026-07-21)
2
+
3
+ ### Bug Fixes
4
+
5
+ - ws bound reconnection of a flapping connection ([#1650](https://github.com/starknet-io/starknet.js/issues/1650)) ([241c6c1](https://github.com/starknet-io/starknet.js/commit/241c6c11301a29a22e09a4b8873c236e39326d29))
6
+
7
+ # [10.5.0](https://github.com/starknet-io/starknet.js/compare/v10.4.0...v10.5.0) (2026-07-06)
8
+
9
+ ### Features
10
+
11
+ - add Contract.compile() to build calldata from the abi ([0cdcaf9](https://github.com/starknet-io/starknet.js/commit/0cdcaf927a75b4537ccc071794ae354f058c320c))
12
+
1
13
  # [10.4.0](https://github.com/starknet-io/starknet.js/compare/v10.3.3...v10.4.0) (2026-07-01)
2
14
 
3
15
  ### Features
package/README.md CHANGED
@@ -29,9 +29,6 @@
29
29
  <a href="https://starkware.co/">
30
30
  <img src="https://img.shields.io/badge/powered_by-StarkWare-navy">
31
31
  </a>
32
- <a href="https://twitter.com/starknetjs">
33
- <img src="https://img.shields.io/badge/follow_us-Twitter-blue">
34
- </a>
35
32
  <a href="https://www.drips.network/app/projects/github/starknet-io/starknet.js" target="_blank">
36
33
  <img src="https://www.drips.network/api/embed/project/https%3A%2F%2Fgithub.com%2Fstarknet-io%2Fstarknet.js/support.png?background=light&style=github&text=project&stat=none" alt="Support starknet.js on drips.network" height="20">
37
34
  </a>
@@ -58,6 +55,22 @@ How to [Guides](https://starknet-io.github.io/starknet.js/docs/guides/intro) :bo
58
55
 
59
56
  Play with [Code Examples](https://github.com/PhilippeR26/starknet.js-workshop-typescript) :video_game:
60
57
 
58
+ ## 🤖 Using AI
59
+
60
+ AI training data about starknet.js is often outdated. To give your AI coding agent accurate, up-to-date guidance, install the official starknet.js skill ([`skills/starknet-js/`](./skills/starknet-js/)). It works with Claude Code, Codex, Cursor, Gemini CLI, and any other agent supporting the open [Agent Skills](https://agentskills.io/) standard.
61
+
62
+ ```bash
63
+ npx skills add starknet-io/starknet.js
64
+ ```
65
+
66
+ or copy the skill files directly:
67
+
68
+ ```bash
69
+ mkdir -p ~/.claude/skills/starknet-js && curl -s --output-dir ~/.claude/skills/starknet-js --remote-name-all "https://raw.githubusercontent.com/starknet-io/starknet.js/develop/skills/starknet-js/{SKILL.md,calldata.md,interacting.md}"
70
+ ```
71
+
72
+ > This command installs into Claude Code's skills folder — adapt the target directory for other agents.
73
+
61
74
  ## ✏️ Contributing
62
75
 
63
76
  If you consider to contribute to this project please read [CONTRIBUTING.md](https://github.com/starknet-io/starknet.js/blob/main/CONTRIBUTING.md) first.
package/dist/index.d.ts CHANGED
@@ -5006,6 +5006,14 @@ type ReconnectOptions = {
5006
5006
  * @default true
5007
5007
  */
5008
5008
  exponential?: number | boolean;
5009
+ /**
5010
+ * The minimum time in milliseconds a reconnected connection must stay open before
5011
+ * it is considered stable and the retry counter is reset. This prevents a gateway
5012
+ * that accepts the connection then immediately drops it (a "flapping" connection)
5013
+ * from resetting the counter on every cycle and reconnecting forever.
5014
+ * @default 5000
5015
+ */
5016
+ stableConnectionThreshold?: number;
5009
5017
  };
5010
5018
  /**
5011
5019
  * The type of the WebSocket implementation.
@@ -5098,6 +5106,7 @@ declare class WebSocketChannel {
5098
5106
  private reconnectAttempts;
5099
5107
  private userInitiatedClose;
5100
5108
  private reconnectTimeoutId;
5109
+ private reconnectStabilityTimeoutId;
5101
5110
  private requestQueue;
5102
5111
  private events;
5103
5112
  private openListener;
@@ -5192,6 +5201,13 @@ declare class WebSocketChannel {
5192
5201
  reconnect(): void;
5193
5202
  private _processRequestQueue;
5194
5203
  private _restoreSubscriptions;
5204
+ /**
5205
+ * Reset the reconnection attempt counter, but only once the current connection has
5206
+ * stayed open for `stableConnectionThreshold` ms. A connection that opens and then
5207
+ * immediately drops (a flapping gateway) never reaches this point, so its attempts
5208
+ * keep accumulating toward the retry cap instead of resetting every cycle.
5209
+ */
5210
+ private scheduleReconnectAttemptsReset;
5195
5211
  private _startReconnect;
5196
5212
  private onCloseProxy;
5197
5213
  private onMessageProxy;
@@ -6278,6 +6294,27 @@ declare abstract class ContractInterface {
6278
6294
  * ```
6279
6295
  */
6280
6296
  abstract populate(method: string, args?: ArgsOrCalldata): Invocation;
6297
+ /**
6298
+ * Compile the calldata for a contract method, using the contract abi.
6299
+ *
6300
+ * Unlike {@link populate}, this returns only the compiled `Calldata` array, without wrapping it
6301
+ * in an `Invocation` object (no `contractAddress` nor `entrypoint`). It is the contract-bound
6302
+ * equivalent of `myCallData.compile(method, args)`.
6303
+ *
6304
+ * If `args` is already a compiled `Calldata`, it is returned as-is without recompilation.
6305
+ *
6306
+ * @param method - Name of the contract method, as defined in the abi
6307
+ * @param args - Method arguments as array (in abi order) or object (free order), or an already
6308
+ * compiled calldata
6309
+ * @returns The compiled calldata
6310
+ * @example
6311
+ * ```typescript
6312
+ * // 'amount' is a u256: the abi splits it into 2 felts automatically
6313
+ * const calldata = contract.compile('transfer', { recipient: '0x123', amount: 100n });
6314
+ * // calldata = ['0x123', '100', '0']
6315
+ * ```
6316
+ */
6317
+ abstract compile(method: string, args?: ArgsOrCalldata): Calldata;
6281
6318
  /**
6282
6319
  * Parse events from a transaction receipt using the contract's ABI
6283
6320
  *
@@ -6404,6 +6441,7 @@ declare class Contract implements ContractInterface {
6404
6441
  }): Promise<InvokeFunctionResponse>;
6405
6442
  invoke(method: string, args?: ArgsOrCalldata, options?: ExecuteOptions): Promise<InvokeFunctionResponse>;
6406
6443
  estimate(method: string, args?: ArgsOrCalldata, estimateDetails?: ExecuteOptions): Promise<EstimateFeeResponseOverhead | PaymasterFeeEstimate>;
6444
+ compile(method: string, args?: RawArgs): Calldata;
6407
6445
  populate(method: string, args?: RawArgs): Call;
6408
6446
  parseEvents(receipt: GetTransactionReceiptResponse): ParsedEvents;
6409
6447
  isCairo1(): boolean;
@@ -12608,9 +12608,15 @@ ${indent}}` : "}";
12608
12608
  reconnectAttempts = 0;
12609
12609
  userInitiatedClose = false;
12610
12610
  reconnectTimeoutId = null;
12611
+ // Fires once a (re)connection has stayed open long enough to be considered stable,
12612
+ // resetting the reconnection attempt counter.
12613
+ reconnectStabilityTimeoutId = null;
12611
12614
  requestQueue = [];
12612
12615
  events = new EventEmitter();
12613
- openListener = (ev) => this.events.emit("open", ev);
12616
+ openListener = (ev) => {
12617
+ this.scheduleReconnectAttemptsReset();
12618
+ this.events.emit("open", ev);
12619
+ };
12614
12620
  closeListener = this.onCloseProxy.bind(this);
12615
12621
  messageListener = this.onMessageProxy.bind(this);
12616
12622
  errorListener = (ev) => this.events.emit("error", ev);
@@ -12630,7 +12636,8 @@ ${indent}}` : "}";
12630
12636
  this.reconnectOptions = {
12631
12637
  retries: options.reconnectOptions?.retries ?? 5,
12632
12638
  delay: options.reconnectOptions?.delay ?? 2e3,
12633
- exponential: options.reconnectOptions?.exponential ?? true
12639
+ exponential: options.reconnectOptions?.exponential ?? true,
12640
+ stableConnectionThreshold: options.reconnectOptions?.stableConnectionThreshold ?? 5e3
12634
12641
  };
12635
12642
  this.requestTimeout = options.requestTimeout ?? 6e4;
12636
12643
  this.WsImplementation = options.websocket || config.get("websocket") || ws_default;
@@ -12777,8 +12784,12 @@ ${indent}}` : "}";
12777
12784
  clearTimeout(this.reconnectTimeoutId);
12778
12785
  this.reconnectTimeoutId = null;
12779
12786
  }
12780
- this.websocket.close(code, reason);
12787
+ if (this.reconnectStabilityTimeoutId) {
12788
+ clearTimeout(this.reconnectStabilityTimeoutId);
12789
+ this.reconnectStabilityTimeoutId = null;
12790
+ }
12781
12791
  this.userInitiatedClose = true;
12792
+ this.websocket.close(code, reason);
12782
12793
  }
12783
12794
  /**
12784
12795
  * Returns a Promise that resolves when the WebSocket connection is closed.
@@ -12865,12 +12876,30 @@ ${indent}}` : "}";
12865
12876
  });
12866
12877
  await Promise.all(restorePromises);
12867
12878
  }
12879
+ /**
12880
+ * Reset the reconnection attempt counter, but only once the current connection has
12881
+ * stayed open for `stableConnectionThreshold` ms. A connection that opens and then
12882
+ * immediately drops (a flapping gateway) never reaches this point, so its attempts
12883
+ * keep accumulating toward the retry cap instead of resetting every cycle.
12884
+ */
12885
+ scheduleReconnectAttemptsReset() {
12886
+ if (this.reconnectStabilityTimeoutId) {
12887
+ clearTimeout(this.reconnectStabilityTimeoutId);
12888
+ }
12889
+ this.reconnectStabilityTimeoutId = setTimeout(() => {
12890
+ this.reconnectAttempts = 0;
12891
+ this.reconnectStabilityTimeoutId = null;
12892
+ }, this.reconnectOptions.stableConnectionThreshold);
12893
+ }
12868
12894
  _startReconnect() {
12869
12895
  if (this.isReconnecting || !this.autoReconnect) {
12870
12896
  return;
12871
12897
  }
12898
+ if (this.reconnectStabilityTimeoutId) {
12899
+ clearTimeout(this.reconnectStabilityTimeoutId);
12900
+ this.reconnectStabilityTimeoutId = null;
12901
+ }
12872
12902
  this.isReconnecting = true;
12873
- this.reconnectAttempts = 0;
12874
12903
  const tryReconnect = () => {
12875
12904
  if (this.reconnectAttempts >= this.reconnectOptions.retries) {
12876
12905
  logger.error("WebSocket: Maximum reconnection retries reached. Giving up.");
@@ -12885,7 +12914,6 @@ ${indent}}` : "}";
12885
12914
  this.websocket.onopen = async () => {
12886
12915
  logger.info("WebSocket: Reconnection successful.");
12887
12916
  this.isReconnecting = false;
12888
- this.reconnectAttempts = 0;
12889
12917
  await this._restoreSubscriptions();
12890
12918
  this._processRequestQueue();
12891
12919
  this.events.emit("open", new Event("open"));
@@ -18548,12 +18576,14 @@ ${indent}}` : "}";
18548
18576
  }
18549
18577
  throw Error("Contract must be connected to the account contract to estimate");
18550
18578
  }
18579
+ compile(method, args = []) {
18580
+ return getCompiledCalldata(args, () => this.callData.compile(method, args));
18581
+ }
18551
18582
  populate(method, args = []) {
18552
- const calldata = getCompiledCalldata(args, () => this.callData.compile(method, args));
18553
18583
  return {
18554
18584
  contractAddress: this.address,
18555
18585
  entrypoint: method,
18556
- calldata
18586
+ calldata: this.compile(method, args)
18557
18587
  };
18558
18588
  }
18559
18589
  parseEvents(receipt) {