lightnode-sdk 0.8.9 → 0.8.10

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.
Files changed (2) hide show
  1. package/dist/inference.js +32 -17
  2. package/package.json +1 -1
package/dist/inference.js CHANGED
@@ -293,6 +293,8 @@ async function runOneAttempt(args, attempt) {
293
293
  setTimeout(() => reject(new Error("relay WebSocket open timeout")), 20000);
294
294
  });
295
295
  const chunks = [];
296
+ let streamDone = false;
297
+ let streamDoneAt = null;
296
298
  const handleMessage = async (rawData) => {
297
299
  const raw = typeof rawData === "string"
298
300
  ? rawData
@@ -308,20 +310,26 @@ async function runOneAttempt(args, attempt) {
308
310
  catch {
309
311
  return;
310
312
  }
311
- if (!frame?.payload)
312
- return;
313
- if (frame.type === "chunk") {
314
- try {
315
- const piece = await decryptResponse(prepared.sessionKey, frame.payload);
316
- chunks.push(piece);
317
- if (onChunk)
318
- onChunk(piece, chunks.join(""));
319
- }
320
- catch {
321
- /* control frame */
313
+ // "complete" marks end-of-stream (it may or may not carry a payload).
314
+ // Record it so the JobCompleted wait can stop promptly instead of polling
315
+ // the full grace window after the answer is already in hand.
316
+ if (frame.type === "complete") {
317
+ streamDone = true;
318
+ streamDoneAt = Date.now();
319
+ if (chunks.length === 0 && frame.payload) {
320
+ try {
321
+ const piece = await decryptResponse(prepared.sessionKey, frame.payload);
322
+ chunks.push(piece);
323
+ if (onChunk)
324
+ onChunk(piece, chunks.join(""));
325
+ }
326
+ catch {
327
+ /* ignore */
328
+ }
322
329
  }
330
+ return;
323
331
  }
324
- else if (frame.type === "complete" && chunks.length === 0) {
332
+ if (frame.type === "chunk" && frame.payload) {
325
333
  try {
326
334
  const piece = await decryptResponse(prepared.sessionKey, frame.payload);
327
335
  chunks.push(piece);
@@ -329,7 +337,7 @@ async function runOneAttempt(args, attempt) {
329
337
  onChunk(piece, chunks.join(""));
330
338
  }
331
339
  catch {
332
- /* ignore */
340
+ /* control frame */
333
341
  }
334
342
  }
335
343
  };
@@ -376,7 +384,8 @@ async function runOneAttempt(args, attempt) {
376
384
  // answer with txs.jobCompleted=null (the answer is still session-key
377
385
  // authentic; the on-chain proof can be polled for separately by callers).
378
386
  const deadline = Date.now() + jobCompletedTimeoutMs;
379
- const POST_CHUNKS_GRACE_MS = 45000;
387
+ const POST_CHUNKS_GRACE_MS = 45000; // fallback if the relay never sends a 'complete' frame
388
+ const POST_DONE_GRACE_MS = 8000; // once the answer is fully in, the worker commits JobCompleted within ~seconds
380
389
  const waitStart = Date.now();
381
390
  let firstChunkAt = chunks.length > 0 ? waitStart : null;
382
391
  const jobIdTopic = (`0x${jobId.toString(16).padStart(64, "0")}`);
@@ -385,9 +394,14 @@ async function runOneAttempt(args, attempt) {
385
394
  const now = Date.now();
386
395
  if (now >= deadline)
387
396
  break;
397
+ // Answer fully received (relay sent 'complete'): wait only briefly for the
398
+ // on-chain proof, then return. The answer is already session-key authentic;
399
+ // callers get txs.jobCompleted=null and can poll the proof later if needed.
400
+ if (streamDone && now - (streamDoneAt ?? now) >= POST_DONE_GRACE_MS)
401
+ break;
388
402
  if (firstChunkAt != null && now - firstChunkAt >= POST_CHUNKS_GRACE_MS)
389
403
  break;
390
- await new Promise((res) => setTimeout(res, 3000));
404
+ await new Promise((res) => setTimeout(res, 1500));
391
405
  if (firstChunkAt == null && chunks.length > 0)
392
406
  firstChunkAt = Date.now();
393
407
  const logs = await publicClient.getLogs({
@@ -414,8 +428,9 @@ async function runOneAttempt(args, attempt) {
414
428
  feeLcai: fee,
415
429
  });
416
430
  }
417
- // 7. grace period for the last relay frame, then close
418
- await new Promise((res) => setTimeout(res, 4000));
431
+ // 7. grace period for the last relay frame, then close. If the stream already
432
+ // signaled 'complete', no more frames are coming - skip the wait.
433
+ await new Promise((res) => setTimeout(res, streamDone ? 300 : 4000));
419
434
  try {
420
435
  ws.close();
421
436
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightnode-sdk",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
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",