lightnode-sdk 0.7.8 → 0.7.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.
package/dist/auth.d.ts ADDED
@@ -0,0 +1,106 @@
1
+ /**
2
+ * SIWE sign-in against LightChain's consumer-api. The gateway accepts the
3
+ * JWT minted here as its `Authorization: Bearer <token>` header, so this
4
+ * unlocks every protected gateway endpoint (selectSession, prepareSession,
5
+ * uploadBlob, getSessionToken).
6
+ *
7
+ * Reverse-engineered from lightchain-protocol/lcai-chat-v2 (the official
8
+ * chat reference app). The same two endpoints work on mainnet and testnet
9
+ * - only the host differs (see {@link NetworkConfig.consumerApi}).
10
+ *
11
+ * 1. `GET /api/auth/challenge?address=0x...`
12
+ * -> { nonce: string, message: string }
13
+ * The server pre-builds the SIWE message; clients sign it verbatim.
14
+ *
15
+ * 2. `POST /api/auth/verify` body { message, signature }
16
+ * -> { success, address, token, user }
17
+ * `token` is the JWT bearer for the gateway.
18
+ *
19
+ * Returns a {@link SiweSession} that the SDK's GatewayClient consumes as
20
+ * its `bearer` source. The session also exposes `expiresAt` so consumers
21
+ * can refresh proactively.
22
+ */
23
+ import type { NetworkId, NetworkConfig } from "./types.js";
24
+ /**
25
+ * Minimal subset of viem's `WalletClient` we need to sign the SIWE
26
+ * message. Accepts viem's `WalletClient`, wagmi's `useWalletClient().data`,
27
+ * or any structurally compatible object with `account.address` and
28
+ * `signMessage`.
29
+ */
30
+ export interface SiweWalletClient {
31
+ account?: {
32
+ address?: `0x${string}`;
33
+ };
34
+ signMessage(args: {
35
+ account: `0x${string}` | {
36
+ address: `0x${string}`;
37
+ };
38
+ message: string;
39
+ }): Promise<`0x${string}`>;
40
+ }
41
+ export interface SiweChallenge {
42
+ nonce: string;
43
+ message: string;
44
+ }
45
+ export interface SiweVerifyResult {
46
+ success: boolean;
47
+ address: `0x${string}`;
48
+ token: string;
49
+ user?: {
50
+ id: string;
51
+ username?: string | null;
52
+ walletAddress: `0x${string}`;
53
+ type: string;
54
+ };
55
+ }
56
+ export interface SiweSession {
57
+ /** ES256K JWT bearer accepted by the worker-gateway. */
58
+ token: string;
59
+ /** Wallet that signed the message. */
60
+ address: `0x${string}`;
61
+ /** Network the session is bound to. */
62
+ network: NetworkId;
63
+ /** SIWE message expiry as a unix-ms timestamp (null when not parseable). */
64
+ expiresAt: number | null;
65
+ /**
66
+ * Drop-in `BearerSource` for `new GatewayClient({ bearer })`. Returns
67
+ * the same JWT for every call; refresh by calling {@link siweSignIn}
68
+ * again before {@link expiresAt} elapses.
69
+ */
70
+ bearer: () => string;
71
+ }
72
+ /**
73
+ * Fetch a SIWE challenge for `address` from the network's consumer-api.
74
+ * The returned `message` is the canonical SIWE string the wallet must
75
+ * sign verbatim - do NOT reformat or strip whitespace.
76
+ */
77
+ export declare function siweChallenge(network: NetworkId | NetworkConfig, address: `0x${string}`, opts?: {
78
+ signal?: AbortSignal;
79
+ }): Promise<SiweChallenge>;
80
+ /**
81
+ * Verify a signed SIWE message and mint a JWT bearer.
82
+ */
83
+ export declare function siweVerify(network: NetworkId | NetworkConfig, args: {
84
+ message: string;
85
+ signature: `0x${string}`;
86
+ }, opts?: {
87
+ signal?: AbortSignal;
88
+ }): Promise<SiweVerifyResult>;
89
+ /**
90
+ * End-to-end SIWE sign-in: challenge -> sign -> verify -> JWT.
91
+ *
92
+ * ```ts
93
+ * import { siweSignIn, GatewayClient } from "lightnode-sdk";
94
+ * // browser: walletClient from wagmi's useWalletClient().data
95
+ * const session = await siweSignIn(walletClient, "testnet");
96
+ * const gateway = new GatewayClient({ network: "testnet", bearer: session.bearer });
97
+ * // ... use the gateway normally (runInference, selectSession, etc.)
98
+ * ```
99
+ *
100
+ * Pass `address` explicitly when the wallet client cannot expose its own
101
+ * account (some viem clients are intentionally accountless).
102
+ */
103
+ export declare function siweSignIn(walletClient: SiweWalletClient, network: NetworkId | NetworkConfig, opts?: {
104
+ address?: `0x${string}`;
105
+ signal?: AbortSignal;
106
+ }): Promise<SiweSession>;
package/dist/auth.js ADDED
@@ -0,0 +1,144 @@
1
+ /**
2
+ * SIWE sign-in against LightChain's consumer-api. The gateway accepts the
3
+ * JWT minted here as its `Authorization: Bearer <token>` header, so this
4
+ * unlocks every protected gateway endpoint (selectSession, prepareSession,
5
+ * uploadBlob, getSessionToken).
6
+ *
7
+ * Reverse-engineered from lightchain-protocol/lcai-chat-v2 (the official
8
+ * chat reference app). The same two endpoints work on mainnet and testnet
9
+ * - only the host differs (see {@link NetworkConfig.consumerApi}).
10
+ *
11
+ * 1. `GET /api/auth/challenge?address=0x...`
12
+ * -> { nonce: string, message: string }
13
+ * The server pre-builds the SIWE message; clients sign it verbatim.
14
+ *
15
+ * 2. `POST /api/auth/verify` body { message, signature }
16
+ * -> { success, address, token, user }
17
+ * `token` is the JWT bearer for the gateway.
18
+ *
19
+ * Returns a {@link SiweSession} that the SDK's GatewayClient consumes as
20
+ * its `bearer` source. The session also exposes `expiresAt` so consumers
21
+ * can refresh proactively.
22
+ */
23
+ import { NETWORKS } from "./networks.js";
24
+ const REQUEST_TIMEOUT_MS = 15000;
25
+ function resolveNetwork(network) {
26
+ if (typeof network === "string") {
27
+ const cfg = NETWORKS[network];
28
+ if (!cfg)
29
+ throw new Error(`siweSignIn: unknown network "${network}"`);
30
+ return cfg;
31
+ }
32
+ return network;
33
+ }
34
+ async function httpJson(url, init) {
35
+ const ctrl = new AbortController();
36
+ const onAbort = () => ctrl.abort();
37
+ init.signal?.addEventListener("abort", onAbort);
38
+ const timer = setTimeout(() => ctrl.abort(), REQUEST_TIMEOUT_MS);
39
+ try {
40
+ const res = await fetch(url, {
41
+ method: init.method,
42
+ headers: { Accept: "application/json", ...(init.body ? { "content-type": "application/json" } : {}) },
43
+ body: init.body ? JSON.stringify(init.body) : undefined,
44
+ signal: ctrl.signal,
45
+ });
46
+ const text = await res.text();
47
+ if (!res.ok) {
48
+ // Surface the server-side validation message when present.
49
+ const detail = text.length < 400 ? text : `${text.slice(0, 380)}...`;
50
+ throw new Error(`siwe ${url}: ${res.status} ${detail}`);
51
+ }
52
+ try {
53
+ return JSON.parse(text);
54
+ }
55
+ catch {
56
+ throw new Error(`siwe ${url}: non-JSON response (${text.slice(0, 120)})`);
57
+ }
58
+ }
59
+ finally {
60
+ clearTimeout(timer);
61
+ init.signal?.removeEventListener("abort", onAbort);
62
+ }
63
+ }
64
+ /**
65
+ * Fetch a SIWE challenge for `address` from the network's consumer-api.
66
+ * The returned `message` is the canonical SIWE string the wallet must
67
+ * sign verbatim - do NOT reformat or strip whitespace.
68
+ */
69
+ export async function siweChallenge(network, address, opts = {}) {
70
+ const cfg = resolveNetwork(network);
71
+ if (!cfg.consumerApi) {
72
+ throw new Error(`siweChallenge: network "${cfg.id}" has no consumerApi configured`);
73
+ }
74
+ const url = `${cfg.consumerApi.replace(/\/+$/, "")}/api/auth/challenge?address=${address}`;
75
+ return httpJson(url, { method: "GET", signal: opts.signal });
76
+ }
77
+ /**
78
+ * Verify a signed SIWE message and mint a JWT bearer.
79
+ */
80
+ export async function siweVerify(network, args, opts = {}) {
81
+ const cfg = resolveNetwork(network);
82
+ if (!cfg.consumerApi) {
83
+ throw new Error(`siweVerify: network "${cfg.id}" has no consumerApi configured`);
84
+ }
85
+ const url = `${cfg.consumerApi.replace(/\/+$/, "")}/api/auth/verify`;
86
+ const out = await httpJson(url, {
87
+ method: "POST",
88
+ body: { message: args.message, signature: args.signature },
89
+ signal: opts.signal,
90
+ });
91
+ if (!out.success || !out.token) {
92
+ throw new Error("siweVerify: gateway returned success=false or missing token");
93
+ }
94
+ return out;
95
+ }
96
+ /**
97
+ * Extract a SIWE message's `Expiration Time` (ISO-8601) and convert to a
98
+ * unix-ms timestamp. Best-effort: returns null if the field is absent or
99
+ * unparseable.
100
+ */
101
+ function parseExpiry(message) {
102
+ const m = message.match(/Expiration Time:\s*(\S+)/);
103
+ if (!m)
104
+ return null;
105
+ const t = Date.parse(m[1]);
106
+ return Number.isFinite(t) ? t : null;
107
+ }
108
+ /**
109
+ * End-to-end SIWE sign-in: challenge -> sign -> verify -> JWT.
110
+ *
111
+ * ```ts
112
+ * import { siweSignIn, GatewayClient } from "lightnode-sdk";
113
+ * // browser: walletClient from wagmi's useWalletClient().data
114
+ * const session = await siweSignIn(walletClient, "testnet");
115
+ * const gateway = new GatewayClient({ network: "testnet", bearer: session.bearer });
116
+ * // ... use the gateway normally (runInference, selectSession, etc.)
117
+ * ```
118
+ *
119
+ * Pass `address` explicitly when the wallet client cannot expose its own
120
+ * account (some viem clients are intentionally accountless).
121
+ */
122
+ export async function siweSignIn(walletClient, network, opts = {}) {
123
+ const cfg = resolveNetwork(network);
124
+ const address = opts.address ?? walletClient.account?.address;
125
+ if (!address) {
126
+ throw new Error("siweSignIn: walletClient has no account; pass `address` explicitly");
127
+ }
128
+ const { message } = await siweChallenge(cfg, address, { signal: opts.signal });
129
+ // viem's signMessage requires `account` even when one is set on the
130
+ // client; passing it explicitly works with both wagmi and bare viem.
131
+ const signature = await walletClient.signMessage({
132
+ account: walletClient.account?.address ?? address,
133
+ message,
134
+ });
135
+ const verified = await siweVerify(cfg, { message, signature }, { signal: opts.signal });
136
+ const token = verified.token;
137
+ return {
138
+ token,
139
+ address: verified.address ?? address,
140
+ network: cfg.id,
141
+ expiresAt: parseExpiry(message),
142
+ bearer: () => token,
143
+ };
144
+ }
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ import { DAO, DAO_ADDRESSES, ProposalState, PROPOSAL_STATE_LABEL, VoteSupport, G
12
12
  import { OnchainModelRegistry, AIVM_MODEL_REGISTRY_ABI, BENCHMARK_REGISTRY_ABI, ModelStatus, MODEL_STATUS_LABEL } from "./onchain-models.js";
13
13
  import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker } from "./errors.js";
14
14
  import { GatewayClient, GatewayHttpError } from "./gateway.js";
15
+ import { siweSignIn, siweChallenge, siweVerify } from "./auth.js";
15
16
  import * as crypto from "./crypto.js";
16
17
  import type { NetworkId, NetworkConfig, Worker, Job, JobTransactions, ModelInfo, WorkerModel, ServedModel, NetworkStats, ModelStat, WorkerStat, NetworkAnalytics } from "./types.js";
17
18
  /**
@@ -133,8 +134,8 @@ export declare class LightNode {
133
134
  * (especially in registry-proxy environments like StackBlitz where lockfiles
134
135
  * may pin an older minor than the local install command suggests).
135
136
  */
136
- export declare const SDK_VERSION = "0.7.8";
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, };
137
+ export declare const SDK_VERSION = "0.7.10";
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, };
138
139
  export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
139
140
  export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult } from "./inference.js";
140
141
  export type { ChatRole, ChatMessage, ConversationOptions, ConversationSendResult } from "./chat.js";
@@ -146,3 +147,4 @@ export type { DaoChain, DaoAddresses, ProposalSummary, ProposalRow, DaoConfig }
146
147
  export type { BaseModel, ModelVariant, AccessTier, AccessPolicy, Benchmark, OnchainModelRegistryOptions } from "./onchain-models.js";
147
148
  export type { MinimalWalletClient, MinimalPublicClient, WorkerOperatorOpts, WorkerProtocolConfig, WorkerStatus, DeregisterReadiness, StuckJob, EarningsBreakdown, OnchainJob, JobState, DecodedWorkerError, } from "./worker-operator.js";
148
149
  export type { NetworkId, NetworkConfig, Worker, Job, JobTransactions, ModelInfo, WorkerModel, ServedModel, NetworkStats, ModelStat, WorkerStat, NetworkAnalytics };
150
+ export type { SiweWalletClient, SiweChallenge, SiweVerifyResult, SiweSession } from "./auth.js";
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import { DAO, DAO_ADDRESSES, ProposalState, PROPOSAL_STATE_LABEL, VoteSupport, G
13
13
  import { OnchainModelRegistry, AIVM_MODEL_REGISTRY_ABI, BENCHMARK_REGISTRY_ABI, ModelStatus, MODEL_STATUS_LABEL, } from "./onchain-models.js";
14
14
  import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, } from "./errors.js";
15
15
  import { GatewayClient, GatewayHttpError } from "./gateway.js";
16
+ import { siweSignIn, siweChallenge, siweVerify } from "./auth.js";
16
17
  import * as crypto from "./crypto.js";
17
18
  /**
18
19
  * Read-only client for a LightChain AI network. Pure reads from the public indexer
@@ -212,11 +213,15 @@ export class LightNode {
212
213
  * (especially in registry-proxy environments like StackBlitz where lockfiles
213
214
  * may pin an older minor than the local install command suggests).
214
215
  */
215
- export const SDK_VERSION = "0.7.8";
216
+ export const SDK_VERSION = "0.7.10";
216
217
  export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei,
217
218
  // v0.7.3 per-job transaction-hash resolver (lifts the upstream
218
219
  // subgraph's "block-only" Job entity to a deep-linkable Job + tx pair).
219
220
  resolveJobTransactions,
221
+ // v0.7.10 SIWE sign-in against the consumer-api: returns a JWT bearer
222
+ // the worker-gateway accepts. End-to-end wallet-signed inference with
223
+ // no shared demo-wallet state.
224
+ siweSignIn, siweChallenge, siweVerify,
220
225
  // v0.7.4 per-worker model-registration list (the authoritative "what is
221
226
  // this worker offering to serve" signal, not derived from past jobs).
222
227
  fetchWorkerModels, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost,
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/dist/networks.js CHANGED
@@ -12,6 +12,7 @@ export const NETWORKS = {
12
12
  rpc: "https://rpc.mainnet.lightchain.ai",
13
13
  explorer: "https://mainnet.lightscan.app",
14
14
  workerGateway: "https://worker-gateway.mainnet.lightchain.ai",
15
+ consumerApi: "https://chat-api.mainnet.lightchain.ai",
15
16
  subgraph: "https://workers-api.mainnet.lightchain.ai/graphql",
16
17
  workerRegistry: "0x0000000000000000000000000000000000001002",
17
18
  aiConfig: "0x24D11533C354092ed6E18b964257819cE78Ce77D",
@@ -31,6 +32,7 @@ export const NETWORKS = {
31
32
  rpc: "https://rpc.testnet.lightchain.ai",
32
33
  explorer: "https://testnet.lightscan.app",
33
34
  workerGateway: "https://worker-gateway.testnet.lightchain.ai",
35
+ consumerApi: "https://chat-api.testnet.lightchain.ai",
34
36
  subgraph: "https://workers-api.testnet.lightchain.ai/graphql",
35
37
  workerRegistry: "0x0000000000000000000000000000000000001002",
36
38
  aiConfig: "0xeCF4Ca5Ba6D97ae586993e170764a1E92231b67e",
package/dist/types.d.ts CHANGED
@@ -6,6 +6,16 @@ export interface NetworkConfig {
6
6
  rpc: string;
7
7
  explorer: string;
8
8
  workerGateway: string;
9
+ /**
10
+ * LightChain consumer-api host (SIWE sign-in + JWT issuance). The worker
11
+ * gateway accepts the JWT minted here as its Authorization Bearer.
12
+ *
13
+ * - `GET {consumerApi}/api/auth/challenge?address=0x...` -> { nonce, message }
14
+ * - `POST {consumerApi}/api/auth/verify` body { message, signature } -> { token, ... }
15
+ *
16
+ * Wrapped end-to-end by {@link siweSignIn}.
17
+ */
18
+ consumerApi: string;
9
19
  subgraph: string;
10
20
  /** Genesis predeploy, same address on both networks. */
11
21
  workerRegistry: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightnode-sdk",
3
- "version": "0.7.8",
3
+ "version": "0.7.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",