lightnode-sdk 0.7.16 → 0.7.17

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/add.js CHANGED
@@ -31,57 +31,72 @@ function detectTemplate(cwd) {
31
31
  return "hono";
32
32
  return "node";
33
33
  }
34
- const HOSTING_GUIDE = `# Hosting LightChain AI inference - your options
35
-
36
- A single LightChain mainnet inference takes **60-90 seconds** under normal
37
- load (the workers do the model run, attest the result on-chain, and return
38
- the answer). If your server-side route has a function timeout shorter than
39
- that, every call will fail with a generic timeout error.
40
-
41
- This file is a quick reference for picking a host that actually finishes
42
- the request. If you used \`lightnode add chat-web3\`, ignore everything
43
- below - that path has NO server-side route to worry about.
44
-
45
- ## TL;DR
46
-
47
- | Need | Use |
48
- |---------------------------------------|--------------------------------|
49
- | Zero infra, users pay (Web3 dApp) | \`lightnode add chat-web3\` |
50
- | Cheapest server-side host that works | Railway / Fly.io / Render |
51
- | Already on Vercel and need it to fit | Vercel Pro (60s) + streaming |
52
- | You self-host already (Docker, VPS) | Anywhere - no timeout to fight |
53
-
54
- ## The detailed table
55
-
56
- | Host | Free / Hobby timeout | Paid timeout | Verdict |
57
- |---------------------|----------------------------|-----------------------------|---------|
58
- | Vercel Hobby (free) | **10 seconds** | - | **DOES NOT WORK** for mainnet inference. Every call times out. |
59
- | Vercel Pro ($20/mo) | - | 60s default, up to 800s with \`maxDuration\` config | Works if calls finish under 60s; 70-80s calls cut it close. Stream tokens to keep the connection warm. |
60
- | Cloudflare Workers | 30s CPU | unbounded with Durable Objects | Free tier 30s is too tight; Workers + DO works but is complex. |
61
- | Railway | none | none | **Great fit.** $5/mo for the smallest container, no timeout. Deploy a plain Node server or Next.js. |
62
- | Fly.io | none | none | **Great fit.** Free tier covers small apps, scales to paid. |
63
- | Render | none | none | **Great fit.** $7/mo for the smallest web service. |
64
- | Netlify Functions | 26s sync / 15min background | 26s sync / 15min background | Use background functions for inference; sync functions time out. |
65
- | AWS Lambda | 15 min | 15 min | Works, but WebSocket setup for streaming is involved. |
66
- | Self-host (Docker) | no limit | no limit | **Works anywhere.** ECS, Cloud Run, your own VPS, fine. |
67
-
68
- ## What I recommend
69
-
70
- 1. **Building a Web3 app where users have wallets?** Switch to \`lightnode add
71
- chat-web3\`. Each user signs and pays from their own wallet. You host the
72
- static page (Vercel/Netlify/Cloudflare Pages free tier all work). No timeout
73
- to fight because there is no server-side inference route.
74
-
75
- 2. **Building a SaaS chatbot where users do NOT have wallets?** Deploy your
76
- inference route on Railway or Fly. Both have no function timeout, scale
77
- to traffic, and cost ~$5/mo for small apps. Cheaper than Vercel Pro.
78
-
79
- 3. **Already committed to Vercel?** Upgrade to Pro and add streaming. The
80
- chat template generated by \`lightnode add chat\` already uses streaming
81
- tokens, so the connection stays warm while the model runs.
82
-
83
- 4. **Have a Docker setup already?** Run the inference route in your existing
84
- container. No timeout, no per-call cost beyond your existing infra.
34
+ const HOSTING_GUIDE = `# Hosting your LightChain AI app
35
+
36
+ A single LightChain mainnet inference takes **60-90 seconds** (the workers
37
+ run the model, attest the result on-chain, and return the answer). Anywhere
38
+ that puts a short timeout on your request will fail with a generic timeout
39
+ error. So the question is just: how do you give your route enough time to
40
+ finish?
41
+
42
+ If you used \`lightnode add chat-web3\`, skip this file - that path has NO
43
+ server-side route, the visitor's own browser does the wait.
44
+
45
+ ## The clean answer: run it yourself
46
+
47
+ This template ships with a **Dockerfile + docker-compose.yml** so you can
48
+ run the entire stack on your own machine, your own VPS, or anywhere Docker
49
+ runs. Long-running Node processes have no timeout. The result:
50
+
51
+ \`\`\`bash
52
+ docker compose up --build
53
+ # → http://localhost:3000 ready, no signup, no per-call cost beyond your
54
+ # LCAI fee, no platform vendor lock-in.
55
+ \`\`\`
56
+
57
+ That's the recommended path. You own the box, you own the keys, you own
58
+ the uptime. Costs as much as the VPS does - $5/mo on Hetzner gets you a
59
+ 2-core machine that handles plenty of traffic.
60
+
61
+ ### Where to run that container
62
+
63
+ | Where | Cost | Notes |
64
+ |--------------------------|-----------------------|-------|
65
+ | Your laptop / home server | free | Perfect for dev + small personal projects. Expose via Cloudflare Tunnel or Tailscale Funnel if you want a public URL. |
66
+ | Hetzner CX22 | ~€4/mo | 2 CPU, 4 GB RAM. Generous bandwidth. EU-based. |
67
+ | DigitalOcean droplet | $4/mo | 1 CPU, 512 MB. Bumps to $6 for 1 GB. |
68
+ | OVH VPS | ~€3/mo | Cheap, EU. |
69
+ | AWS Lightsail | $5/mo | 1 CPU, 1 GB. AWS billing if you want it. |
70
+ | Your existing k8s | $0 marginal | Just \`docker push\` and \`kubectl apply\`. |
71
+ | Fly.io | free tier + $0-5/mo | Their Docker-native platform, cleanest UX of the paid options. |
72
+ | Railway | $5/mo | Same idea. No timeout, easy deploys. |
73
+ | Render | $7/mo | Same idea. |
74
+ | Google Cloud Run | pay-per-request | Scales to zero. Watch the 60-minute request limit. |
75
+
76
+ ## When you'd pick a managed platform instead
77
+
78
+ | Platform | Trade-off |
79
+ |---------------------|-----------|
80
+ | Vercel Pro ($20/mo) | If you're already deploying your Next.js app on Vercel and don't want to split infra. The 60s function cap is tight for mainnet (70-80s calls cut it close); rely on streaming to keep the connection warm. **Hobby tier (free) does NOT work** - 10s cap, every call times out. |
81
+ | Netlify | 26s sync function cap is too tight. Use Netlify's "background functions" (15min) and adapt the route to write the result to KV / a webhook. More work. |
82
+ | Cloudflare Workers | 30s on free, unbounded with Durable Objects. The WebSocket relay setup is more involved than a plain Node server. |
83
+
84
+ The free-tier serverless platforms (Vercel Hobby, Netlify free, Cloudflare
85
+ free) **all fail** at the 60-90s mark. There's no way around that on those
86
+ plans short of upgrading. If you're not paying anyway, self-host - it's
87
+ strictly cheaper and faster than a $20/mo plan.
88
+
89
+ ## What I'd actually pick
90
+
91
+ - **First time trying this out**: \`docker compose up\` on your laptop. Free,
92
+ works in 30 seconds, real end-to-end test of your code.
93
+ - **Going to production with users**: same Dockerfile on a $5/mo Hetzner or
94
+ Fly VM. You're done; it'll handle plenty of traffic.
95
+ - **You already have a Next.js app on Vercel**: upgrade to Pro and keep your
96
+ build pipeline. The streaming route works under their 60s cap for most
97
+ mainnet calls.
98
+ - **You're building a Web3 dApp**: re-run \`lightnode add chat-web3\`. No
99
+ backend, no LCAI cost for you - each user pays their own way.
85
100
 
86
101
  ## Why the request is slow at all
87
102
 
@@ -98,7 +113,74 @@ and worker pickup. The protocol's verifiable-AI guarantee comes from doing
98
113
  all of this on-chain instead of just hitting an OpenAI-style API, which is
99
114
  the reason the call takes 60-90s instead of 1-2s. There is no way to
100
115
  shortcut this on the SDK side; the host just has to allow long-running
101
- functions.
116
+ processes - which is exactly what a plain Node server (or Docker container)
117
+ already does for free.
118
+ `;
119
+ /**
120
+ * Dockerfile that builds your Next.js app and runs it as a long-running
121
+ * Node server. There is no function timeout on a plain server, so a 60-90s
122
+ * mainnet inference just works. Multi-stage build keeps the runtime image
123
+ * around 200 MB.
124
+ */
125
+ const NEXTJS_DOCKERFILE = `# Generated by 'lightnode add chat' (or 'add inference' / 'add judge').
126
+ # Build a Next.js production image; run with 'docker compose up --build'.
127
+ FROM node:20-alpine AS deps
128
+ WORKDIR /app
129
+ COPY package.json package-lock.json* ./
130
+ RUN npm ci --omit=optional
131
+
132
+ FROM node:20-alpine AS builder
133
+ WORKDIR /app
134
+ COPY --from=deps /app/node_modules ./node_modules
135
+ COPY . .
136
+ ENV NEXT_TELEMETRY_DISABLED=1
137
+ RUN npm run build
138
+
139
+ FROM node:20-alpine AS runner
140
+ WORKDIR /app
141
+ ENV NODE_ENV=production
142
+ ENV NEXT_TELEMETRY_DISABLED=1
143
+ COPY --from=builder /app/public ./public
144
+ COPY --from=builder /app/.next ./.next
145
+ COPY --from=builder /app/node_modules ./node_modules
146
+ COPY --from=builder /app/package.json ./package.json
147
+ EXPOSE 3000
148
+ # Long-running Node process - no function timeout to fight. Mainnet inference
149
+ # calls (60-90s) complete normally because the process just stays up.
150
+ CMD ["npm", "start"]
151
+ `;
152
+ /**
153
+ * docker-compose.yml. The 'env_file' line wires .env from the project root
154
+ * into the container at runtime, so the same PRIVATE_KEY a 'npm run dev'
155
+ * session uses also flows to the container build.
156
+ */
157
+ const NEXTJS_DOCKER_COMPOSE = `# Generated by 'lightnode add chat' (or 'add inference' / 'add judge').
158
+ # Quick start: docker compose up --build
159
+ # (then visit http://localhost:3000)
160
+ services:
161
+ app:
162
+ build: .
163
+ image: lightnode-app
164
+ container_name: lightnode-app
165
+ ports:
166
+ - "3000:3000"
167
+ # PRIVATE_KEY, NETWORK, MODEL are read from .env at runtime.
168
+ # Make sure .env exists in the same folder as this file (cp .env.example .env).
169
+ env_file:
170
+ - .env
171
+ restart: unless-stopped
172
+ `;
173
+ const DOCKERIGNORE = `# Generated by 'lightnode add chat' (or 'add inference' / 'add judge').
174
+ .git
175
+ .gitignore
176
+ node_modules
177
+ .next
178
+ .env
179
+ .env.local
180
+ .env.*.local
181
+ LIGHTNODE-HOSTING.md
182
+ README.md
183
+ *.log
102
184
  `;
103
185
  const ENV_EXAMPLE = (net) => `# Funded private key. Testnet works free (faucet at https://lightfaucet.ai).
104
186
  PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000000
@@ -252,6 +334,9 @@ export function addInference(opts = {}) {
252
334
  if (template === "nextjs-api") {
253
335
  written.push(writeFile(path.join(cwd, "app/api/inference/route.ts"), NEXTJS_ROUTE, force));
254
336
  written.push(writeFile(path.join(cwd, "LIGHTNODE-HOSTING.md"), HOSTING_GUIDE, force));
337
+ written.push(writeFile(path.join(cwd, "Dockerfile"), NEXTJS_DOCKERFILE, force));
338
+ written.push(writeFile(path.join(cwd, "docker-compose.yml"), NEXTJS_DOCKER_COMPOSE, force));
339
+ written.push(writeFile(path.join(cwd, ".dockerignore"), DOCKERIGNORE, force));
255
340
  }
256
341
  else if (template === "hono") {
257
342
  written.push(writeFile(path.join(cwd, "lightchain-inference.ts"), HONO_HANDLER, force));
@@ -1284,12 +1369,16 @@ export function addChat(opts = {}) {
1284
1369
  const force = !!opts.force;
1285
1370
  const written = [];
1286
1371
  if (template === "nextjs-api") {
1287
- // 'add chat' is now self-contained: it writes BOTH the chat page AND
1288
- // the streaming inference route. Previously the user had to remember
1289
- // to also run 'add inference' separately, which was easy to miss.
1372
+ // 'add chat' is self-contained: it writes the chat page, the streaming
1373
+ // inference route, the hosting guide, AND the Docker setup so the dev
1374
+ // can run the whole stack locally (or anywhere Docker runs) with one
1375
+ // command. No external host signup, no function-timeout fights.
1290
1376
  written.push(writeFile(path.join(cwd, "app/chat/page.tsx"), NEXTJS_CHAT_PAGE, force));
1291
1377
  written.push(writeFile(path.join(cwd, "app/api/inference/route.ts"), NEXTJS_INFERENCE_STREAM_ROUTE, force));
1292
1378
  written.push(writeFile(path.join(cwd, "LIGHTNODE-HOSTING.md"), HOSTING_GUIDE, force));
1379
+ written.push(writeFile(path.join(cwd, "Dockerfile"), NEXTJS_DOCKERFILE, force));
1380
+ written.push(writeFile(path.join(cwd, "docker-compose.yml"), NEXTJS_DOCKER_COMPOSE, force));
1381
+ written.push(writeFile(path.join(cwd, ".dockerignore"), DOCKERIGNORE, force));
1293
1382
  }
1294
1383
  else {
1295
1384
  written.push(writeFile(path.join(cwd, "chat-repl.ts"), NODE_CHAT_REPL, force));
@@ -1616,6 +1705,9 @@ export function addJudge(opts = {}) {
1616
1705
  if (template === "nextjs-api") {
1617
1706
  written.push(writeFile(path.join(cwd, "app/api/judge/route.ts"), NEXTJS_JUDGE_ROUTE, force));
1618
1707
  written.push(writeFile(path.join(cwd, "LIGHTNODE-HOSTING.md"), HOSTING_GUIDE, force));
1708
+ written.push(writeFile(path.join(cwd, "Dockerfile"), NEXTJS_DOCKERFILE, force));
1709
+ written.push(writeFile(path.join(cwd, "docker-compose.yml"), NEXTJS_DOCKER_COMPOSE, force));
1710
+ written.push(writeFile(path.join(cwd, ".dockerignore"), DOCKERIGNORE, force));
1619
1711
  }
1620
1712
  else {
1621
1713
  written.push(writeFile(path.join(cwd, "judge.ts"), NODE_JUDGE_SCRIPT, force));
package/dist/cli.js CHANGED
@@ -534,14 +534,18 @@ async function main() {
534
534
  console.log(` 3. AGENT_INTERVAL_MS=3600000 npx tsx agent.ts # or run under pm2/systemd`);
535
535
  }
536
536
  else if (sub === "chat" && result.template === "nextjs-api") {
537
- console.log(` 3. npm run dev, open /chat`);
538
- console.log(` (the chat page + /api/inference streaming route are both already wired up)`);
537
+ console.log(` 3. Pick one:`);
538
+ console.log(` a) docker compose up --build # run the whole stack yourself, no timeout`);
539
+ console.log(` b) npm run dev # local dev only`);
540
+ console.log(` Open http://localhost:3000/chat`);
539
541
  }
540
542
  else if (sub === "chat") {
541
543
  console.log(` 3. npx tsx chat-repl.ts (interactive terminal chat)`);
542
544
  }
543
545
  else if (sub === "judge" && result.template === "nextjs-api") {
544
- console.log(` 3. npm run dev`);
546
+ console.log(` 3. Pick one:`);
547
+ console.log(` a) docker compose up --build # run the whole stack yourself, no timeout`);
548
+ console.log(` b) npm run dev # local dev only`);
545
549
  console.log(` 4. curl -X POST localhost:3000/api/judge -H 'content-type: application/json' \\\\`);
546
550
  console.log(` -d '{"criteria":"Run a mile under 8 minutes","evidence":{"time_minutes":7.4,"distance_km":1.61}}'`);
547
551
  }
@@ -553,7 +557,10 @@ async function main() {
553
557
  console.log(` 4. npm run dev, open /nft-mint`);
554
558
  }
555
559
  else if (result.template === "nextjs-api") {
556
- console.log(` 3. npm run dev (then POST /api/inference)`);
560
+ console.log(` 3. Pick one:`);
561
+ console.log(` a) docker compose up --build # run the whole stack yourself, no timeout`);
562
+ console.log(` b) npm run dev # local dev only`);
563
+ console.log(` POST http://localhost:3000/api/inference {"prompt":"hello"}`);
557
564
  }
558
565
  else if (result.template === "hono") {
559
566
  console.log(` 3. wire inferenceHandler into your Hono app, then start it`);
@@ -574,12 +581,16 @@ async function main() {
574
581
  console.log(` 2. npx tsx lightnode-analytics.ts`);
575
582
  }
576
583
  }
577
- // Hosting warning for server-side commands that ship LIGHTNODE-HOSTING.md.
584
+ // Hosting note: the Docker setup we shipped is the recommended path.
585
+ // The managed platforms (Vercel etc.) are the fallback if a builder is
586
+ // already committed to one.
578
587
  if (result.template === "nextjs-api"
579
588
  && (sub === "inference" || sub === "chat" || sub === "judge")) {
580
- console.log(`\n Hosting: a mainnet inference takes 60-90s. Vercel Hobby (free) times`);
581
- console.log(` out at 10s; Vercel Pro at 60s. See LIGHTNODE-HOSTING.md (in this folder)`);
582
- console.log(` for hosts that work - Railway / Fly / Render handle long calls fine.`);
589
+ console.log(`\n Hosting: a mainnet inference takes 60-90s. The Dockerfile + docker-compose.yml`);
590
+ console.log(` we just dropped run a long-running Node server with no timeout - that's the`);
591
+ console.log(` recommended path (your laptop, a $5/mo VPS, anywhere Docker runs).`);
592
+ console.log(` Don't use Vercel Hobby (10s cap, every call times out). Vercel Pro works at`);
593
+ console.log(` 60s if you'd rather stay on Vercel. See LIGHTNODE-HOSTING.md for the full table.`);
583
594
  }
584
595
  if (result.network === "testnet") {
585
596
  console.log(`\nNo wallet yet? Make one: npx lightnode wallet new then fund it free below.`);
package/dist/index.d.ts CHANGED
@@ -134,7 +134,7 @@ export declare class LightNode {
134
134
  * (especially in registry-proxy environments like StackBlitz where lockfiles
135
135
  * may pin an older minor than the local install command suggests).
136
136
  */
137
- export declare const SDK_VERSION = "0.7.16";
137
+ export declare const SDK_VERSION = "0.7.17";
138
138
  export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, resolveJobTransactions, siweSignIn, siweChallenge, siweVerify, 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, };
139
139
  export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
140
140
  export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult } from "./inference.js";
package/dist/index.js CHANGED
@@ -213,7 +213,7 @@ export class LightNode {
213
213
  * (especially in registry-proxy environments like StackBlitz where lockfiles
214
214
  * may pin an older minor than the local install command suggests).
215
215
  */
216
- export const SDK_VERSION = "0.7.16";
216
+ export const SDK_VERSION = "0.7.17";
217
217
  export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei,
218
218
  // v0.7.3 per-job transaction-hash resolver (lifts the upstream
219
219
  // subgraph's "block-only" Job entity to a deep-linkable Job + tx pair).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightnode-sdk",
3
- "version": "0.7.16",
3
+ "version": "0.7.17",
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",