lightnode-sdk 0.4.4 → 0.4.5
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/gateway.d.ts +7 -0
- package/dist/gateway.js +35 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/inference.d.ts +1 -1
- package/dist/inference.js +25 -7
- package/package.json +1 -1
package/dist/gateway.d.ts
CHANGED
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
* fresh-each-call thunk) by whatever means they prefer and hands it here.
|
|
9
9
|
*/
|
|
10
10
|
import type { NetworkConfig } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Default gateway URL for a network. In Node, returns the gateway directly.
|
|
13
|
+
* In browser/WebContainer, returns the lightnode.app proxy (same upstream,
|
|
14
|
+
* but with permissive CORS so third-party origins work).
|
|
15
|
+
*/
|
|
11
16
|
export declare function consumerGatewayUrl(net: "mainnet" | "testnet"): string;
|
|
17
|
+
/** Gateway host without any proxy fallback. For diagnostics / advanced callers. */
|
|
18
|
+
export declare function consumerGatewayHost(net: "mainnet" | "testnet"): string;
|
|
12
19
|
/** Either a fixed token, or a function that produces (or refreshes) one. */
|
|
13
20
|
export type BearerSource = string | (() => string | Promise<string>);
|
|
14
21
|
export declare class GatewayHttpError extends Error {
|
package/dist/gateway.js
CHANGED
|
@@ -11,7 +11,42 @@ const GATEWAY_HOSTS = {
|
|
|
11
11
|
mainnet: "https://chat-api.mainnet.lightchain.ai",
|
|
12
12
|
testnet: "https://chat-api.testnet.lightchain.ai",
|
|
13
13
|
};
|
|
14
|
+
// In browser-like contexts the gateway's CORS policy blocks third-party
|
|
15
|
+
// origins, so the SDK routes through lightnode.app's public proxy instead.
|
|
16
|
+
// The proxy is a thin pass-through (no state, no transformation), open to
|
|
17
|
+
// any origin. In a real Node process this isn't needed - the gateway is
|
|
18
|
+
// reached directly.
|
|
19
|
+
const PROXY_HOSTS = {
|
|
20
|
+
mainnet: "https://lightnode.app/api/gw/mainnet",
|
|
21
|
+
testnet: "https://lightnode.app/api/gw/testnet",
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* True when the current runtime is a browser, or a Node-in-browser shim
|
|
25
|
+
* (StackBlitz WebContainer, Bolt, etc.) where `fetch` enforces browser-style
|
|
26
|
+
* CORS. Used to decide whether to call the gateway direct or via the proxy.
|
|
27
|
+
*/
|
|
28
|
+
function looksLikeBrowserFetch() {
|
|
29
|
+
if (typeof window !== "undefined" && typeof document !== "undefined")
|
|
30
|
+
return true;
|
|
31
|
+
// StackBlitz WebContainer exposes `process.versions.webcontainer`. Other
|
|
32
|
+
// Node-in-browser runtimes (Bolt, RunKit) may not, so we also check for
|
|
33
|
+
// the absence of a real Node TCP module via `process.versions.node` PLUS
|
|
34
|
+
// the presence of a global `WebSocket` (browser-only by spec).
|
|
35
|
+
const wc = globalThis.process?.versions?.webcontainer;
|
|
36
|
+
if (wc)
|
|
37
|
+
return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Default gateway URL for a network. In Node, returns the gateway directly.
|
|
42
|
+
* In browser/WebContainer, returns the lightnode.app proxy (same upstream,
|
|
43
|
+
* but with permissive CORS so third-party origins work).
|
|
44
|
+
*/
|
|
14
45
|
export function consumerGatewayUrl(net) {
|
|
46
|
+
return looksLikeBrowserFetch() ? PROXY_HOSTS[net] : GATEWAY_HOSTS[net];
|
|
47
|
+
}
|
|
48
|
+
/** Gateway host without any proxy fallback. For diagnostics / advanced callers. */
|
|
49
|
+
export function consumerGatewayHost(net) {
|
|
15
50
|
return GATEWAY_HOSTS[net];
|
|
16
51
|
}
|
|
17
52
|
async function resolveBearer(src) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS } from "./networks.js";
|
|
2
2
|
import { fromWei } from "./subgraph.js";
|
|
3
3
|
import { aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv } from "./analytics.js";
|
|
4
|
-
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference, runInferenceWithKey } from "./inference.js";
|
|
4
|
+
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference, runInferenceWithKey } from "./inference.js";
|
|
5
5
|
import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker } from "./errors.js";
|
|
6
6
|
import { GatewayClient, GatewayHttpError } from "./gateway.js";
|
|
7
7
|
import * as crypto from "./crypto.js";
|
|
@@ -60,7 +60,7 @@ export declare class LightNode {
|
|
|
60
60
|
baseUrl?: string;
|
|
61
61
|
}): GatewayClient;
|
|
62
62
|
}
|
|
63
|
-
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, runInferenceWithKey, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, };
|
|
63
|
+
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, runInferenceWithKey, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, };
|
|
64
64
|
export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
|
|
65
65
|
export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs } from "./inference.js";
|
|
66
66
|
export type { NetworkId, NetworkConfig, Worker, Job, ModelInfo, NetworkStats, ModelStat, WorkerStat, NetworkAnalytics };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS } from "./networks.js";
|
|
|
2
2
|
import { fetchWorker, fetchWorkerJobs, fetchRecentJobs, fetchModels, fetchWorkers, summarize, fromWei, } from "./subgraph.js";
|
|
3
3
|
import { isRegistered } from "./onchain.js";
|
|
4
4
|
import { aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, } from "./analytics.js";
|
|
5
|
-
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference, runInferenceWithKey, } from "./inference.js";
|
|
5
|
+
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference, runInferenceWithKey, } from "./inference.js";
|
|
6
6
|
import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, } from "./errors.js";
|
|
7
7
|
import { GatewayClient, GatewayHttpError } from "./gateway.js";
|
|
8
8
|
import * as crypto from "./crypto.js";
|
|
@@ -90,7 +90,7 @@ export class LightNode {
|
|
|
90
90
|
return new GatewayClient({ network: this.network, ...opts });
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl,
|
|
93
|
+
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost,
|
|
94
94
|
// v0.3 inference-submit surface (BETA - see README "Submitting inference").
|
|
95
95
|
GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto,
|
|
96
96
|
// v0.4 high-level orchestrator: one call, full flow.
|
package/dist/inference.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ export declare function submitPrompt(gateway: GatewayClient, sessionKey: Uint8Ar
|
|
|
91
91
|
/** Decrypt a worker response (raw bytes or base64 from the relay) with the session key. */
|
|
92
92
|
export declare function decryptResponse(sessionKey: Uint8Array, ciphertext: Uint8Array | string): Promise<string>;
|
|
93
93
|
/** Re-export so callers don't have to import from a second module just for the URL helper. */
|
|
94
|
-
export { consumerGatewayUrl, GatewayClient } from "./gateway.js";
|
|
94
|
+
export { consumerGatewayUrl, consumerGatewayHost, GatewayClient } from "./gateway.js";
|
|
95
95
|
/** Optional helper: generate the caller's own ECDH keypair if they want one (e.g. acting as the disputer). */
|
|
96
96
|
export { generateEcdhKeyPair };
|
|
97
97
|
interface MinimalWalletClient {
|
package/dist/inference.js
CHANGED
|
@@ -123,7 +123,7 @@ export async function decryptResponse(sessionKey, ciphertext) {
|
|
|
123
123
|
return bytesToUtf8(await decrypt(sessionKey, bytes));
|
|
124
124
|
}
|
|
125
125
|
/** Re-export so callers don't have to import from a second module just for the URL helper. */
|
|
126
|
-
export { consumerGatewayUrl, GatewayClient } from "./gateway.js";
|
|
126
|
+
export { consumerGatewayUrl, consumerGatewayHost, GatewayClient } from "./gateway.js";
|
|
127
127
|
/** Optional helper: generate the caller's own ECDH keypair if they want one (e.g. acting as the disputer). */
|
|
128
128
|
export { generateEcdhKeyPair };
|
|
129
129
|
// ----------------------------------------------------------------------------
|
|
@@ -497,26 +497,44 @@ export async function runInferenceWithKey(args) {
|
|
|
497
497
|
// the caller doesn't need a second import; in browsers + Node it works the
|
|
498
498
|
// same against the consumer-api gateway.
|
|
499
499
|
const gwBase = args.gatewayUrl ?? consumerGatewayUrlFn(networkId);
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
500
|
+
// `fetch failed` with no cause is the worst possible error for a builder
|
|
501
|
+
// running this for the first time - they need to know which host failed and
|
|
502
|
+
// what the underlying cause was. Wrap both SIWE calls so the error names a
|
|
503
|
+
// host (so a network/DNS/CORS problem is obvious) and a hint when the cause
|
|
504
|
+
// looks like a CORS or undici-level reachability error.
|
|
505
|
+
const fetchOrFail = async (url, init, label) => {
|
|
506
|
+
try {
|
|
507
|
+
return await fetch(url, init);
|
|
508
|
+
}
|
|
509
|
+
catch (err) {
|
|
510
|
+
const cause = err.cause;
|
|
511
|
+
const code = cause?.code ?? "";
|
|
512
|
+
const msg = err.message ?? "fetch failed";
|
|
513
|
+
const detail = cause?.message ? ` (${cause.message})` : "";
|
|
514
|
+
const hint = /ENOTFOUND|EAI_AGAIN|ECONNREFUSED|UND_ERR_CONNECT|CERT_/.test(code) || msg.includes("CORS")
|
|
515
|
+
? ` Tip: this host may be unreachable from this runtime (CORS, DNS, or TLS). Pass gatewayUrl: 'https://lightnode.app/api/gw/${networkId}' to route through the public proxy.`
|
|
516
|
+
: "";
|
|
517
|
+
throw new Error(`SIWE ${label ?? "request"} to ${url} failed: ${msg}${detail}${hint}`);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
const chRes = await fetchOrFail(`${gwBase}/api/auth/challenge?address=${account.address}`, { headers: { Accept: "application/json" } }, "challenge");
|
|
503
521
|
if (!chRes.ok)
|
|
504
522
|
throw new GatewayAuthError(chRes.status, await chRes.text());
|
|
505
523
|
const ch = (await chRes.json());
|
|
506
524
|
if (!ch.message)
|
|
507
525
|
throw new GatewayAuthError(chRes.status, "auth challenge returned no message");
|
|
508
526
|
const signature = await wallet.signMessage({ account, message: ch.message });
|
|
509
|
-
const verifyRes = await
|
|
527
|
+
const verifyRes = await fetchOrFail(`${gwBase}/api/auth/verify`, {
|
|
510
528
|
method: "POST",
|
|
511
529
|
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
512
530
|
body: JSON.stringify({ message: ch.message, signature }),
|
|
513
|
-
});
|
|
531
|
+
}, "verify");
|
|
514
532
|
if (!verifyRes.ok)
|
|
515
533
|
throw new GatewayAuthError(verifyRes.status, await verifyRes.text());
|
|
516
534
|
const verify = (await verifyRes.json());
|
|
517
535
|
if (!verify.token)
|
|
518
536
|
throw new GatewayAuthError(verifyRes.status, "auth verify returned no token");
|
|
519
|
-
const gateway = new GatewayClientCtor({ network: networkId, bearer: verify.token, baseUrl: args.gatewayUrl });
|
|
537
|
+
const gateway = new GatewayClientCtor({ network: networkId, bearer: verify.token, baseUrl: args.gatewayUrl ?? gwBase });
|
|
520
538
|
// Pick a WebSocket: the browser global if present, otherwise the caller-
|
|
521
539
|
// supplied ctor. We deliberately do NOT try to dynamic-import "ws" - it
|
|
522
540
|
// isn't a hard dep, and a bundler trying to resolve it would fail noisily.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightnode-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
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",
|