lightnode-sdk 0.7.8 → 0.7.9

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.d.ts CHANGED
@@ -133,7 +133,7 @@ export declare class LightNode {
133
133
  * (especially in registry-proxy environments like StackBlitz where lockfiles
134
134
  * may pin an older minor than the local install command suggests).
135
135
  */
136
- export declare const SDK_VERSION = "0.7.8";
136
+ export declare const SDK_VERSION = "0.7.9";
137
137
  export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, resolveJobTransactions, fetchWorkerModels, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, runInferenceWithKey, runInferenceStream, Conversation, chat, runInferenceBatch, Agent, parseAgentOutput, workerPreflight, workerWatch, Bridge, BRIDGE_ROUTE, HYPERLANE_ROUTER_ABI, ERC20_ABI, addressToBytes32, quoteBridgeFee, bridgeableBalance, bridgeAllowance, approveBridge, bridgeTransfer, DAO, DAO_ADDRESSES, ProposalState, PROPOSAL_STATE_LABEL, VoteSupport, GOVERNOR_ABI, VOTES_ABI, OnchainModelRegistry, AIVM_MODEL_REGISTRY_ABI, BENCHMARK_REGISTRY_ABI, ModelStatus, MODEL_STATUS_LABEL, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, WorkerOperator, WORKER_REGISTRY_ABI, JOB_REGISTRY_OPERATOR_ABI, AI_CONFIG_ABI, JOB_STATE, decodeWorkerError, WorkerOpError, isWorkerOpError, };
138
138
  export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
139
139
  export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult } from "./inference.js";
package/dist/index.js CHANGED
@@ -212,7 +212,7 @@ export class LightNode {
212
212
  * (especially in registry-proxy environments like StackBlitz where lockfiles
213
213
  * may pin an older minor than the local install command suggests).
214
214
  */
215
- export const SDK_VERSION = "0.7.8";
215
+ export const SDK_VERSION = "0.7.9";
216
216
  export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei,
217
217
  // v0.7.3 per-job transaction-hash resolver (lifts the upstream
218
218
  // subgraph's "block-only" Job entity to a deep-linkable Job + tx pair).
package/dist/inference.js CHANGED
@@ -78,25 +78,35 @@ export async function prepareSession(gateway, modelTag) {
78
78
  // The gateway returns 409 selection_mismatch when a NEWER selectSession()
79
79
  // for the same wallet supersedes ours between the select and the prepare.
80
80
  // The error message is literally "re-run POST /api/sessions/select", so we
81
- // do exactly that: rebuild from a fresh selection. The cap stops a busy
82
- // pool of callers from looping forever - 4 attempts at 250ms / 750ms /
83
- // 1500ms covers every churn pattern we have seen.
84
- const MAX_ATTEMPTS = 4;
85
- const BACKOFFS_MS = [0, 250, 750, 1500];
81
+ // do exactly that: rebuild from a fresh selection. Backoff spans several
82
+ // seconds because the gateway's selection TTL can be in that range - quick
83
+ // retries inside that window just hit the same stuck state. Random jitter
84
+ // keeps two concurrent callers from synchronising on identical schedules.
85
+ const MAX_ATTEMPTS = 6;
86
+ const BACKOFFS_MS = [0, 500, 1500, 4000, 9000, 18000];
87
+ const jitter = (ms) => ms + Math.floor(Math.random() * 250);
86
88
  let lastErr = null;
89
+ const isSelectionMismatch = (e) => {
90
+ const msg = e instanceof Error ? e.message : String(e);
91
+ return /selection_mismatch|selection was superseded|409/.test(msg);
92
+ };
87
93
  for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
88
94
  if (attempt > 0)
89
- await new Promise((r) => setTimeout(r, BACKOFFS_MS[attempt]));
90
- const selected = await gateway.selectSession(id);
91
- const sessionKey = await generateSessionKey();
92
- // Workers' pubkeys arrive as base64; disputer's as hex - decodePublicKey
93
- // accepts either.
94
- const workerPub = await importPublicKey(decodePublicKey(selected.workerEncryptionKey));
95
- const encWorker = await encryptSessionKey(sessionKey, workerPub);
96
- const encDisputer = selected.disputerEncryptionKey
97
- ? await encryptSessionKey(sessionKey, await importPublicKey(decodePublicKey(selected.disputerEncryptionKey)))
98
- : new Uint8Array(0);
95
+ await new Promise((r) => setTimeout(r, jitter(BACKOFFS_MS[attempt])));
99
96
  try {
97
+ // Wrap BOTH gateway calls. selectSession itself can 409 if a newer
98
+ // call has already superseded ours by the time the gateway processes
99
+ // it. prepareSession 409s when the same happens between select and
100
+ // prepare. The whole select -> prepare flow is one atomic unit.
101
+ const selected = await gateway.selectSession(id);
102
+ const sessionKey = await generateSessionKey();
103
+ // Workers' pubkeys arrive as base64; disputer's as hex - decodePublicKey
104
+ // accepts either.
105
+ const workerPub = await importPublicKey(decodePublicKey(selected.workerEncryptionKey));
106
+ const encWorker = await encryptSessionKey(sessionKey, workerPub);
107
+ const encDisputer = selected.disputerEncryptionKey
108
+ ? await encryptSessionKey(sessionKey, await importPublicKey(decodePublicKey(selected.disputerEncryptionKey)))
109
+ : new Uint8Array(0);
100
110
  const prepared = await gateway.prepareSession({
101
111
  modelId: id,
102
112
  encWorkerKey: bytesToBase64(encWorker),
@@ -117,8 +127,7 @@ export async function prepareSession(gateway, modelTag) {
117
127
  }
118
128
  catch (e) {
119
129
  lastErr = e;
120
- const msg = e instanceof Error ? e.message : String(e);
121
- if (!/selection_mismatch|selection was superseded|409/.test(msg))
130
+ if (!isSelectionMismatch(e))
122
131
  throw e;
123
132
  // else loop: a newer select stole this session, try again from select.
124
133
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightnode-sdk",
3
- "version": "0.7.8",
3
+ "version": "0.7.9",
4
4
  "description": "Read-only TypeScript client for LightChain AI: workers, jobs, models, on-chain registration, and per-model network analytics. Independent, community-built (not an official LightChain package).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",