From 2e0344ad9d73f4e7dcf92ed9ae565aa1c482815e Mon Sep 17 00:00:00 2001 From: lightchainaidev Date: Sat, 10 Oct 2026 06:10:23 +0200 Subject: [PATCH] Drop internal references from comments, scripts and the README Comments and the README pointed at the orchestrator's files (scheme docs, manifests, terraform, consumer-api source). npm run openapi now reads the document the API serves, and npm run abi takes the ABI's path. --- README.md | 8 ++++---- package.json | 2 +- scripts/abi.ts | 12 +++++++----- scripts/openapi.ts | 28 ++++++++-------------------- src/abi.ts | 2 +- src/client.ts | 4 ++-- src/networks.ts | 7 +------ test/openapi.test.ts | 4 ++-- test/payment.test.ts | 2 +- test/x402.test.ts | 2 +- 10 files changed, 28 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 100a75f..43ca19e 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ The constructor throws on any other combination, and on an option the mode would | `mainnet` | 9200 | `https://chat-api.mainnet.lightchain.ai` (provisional) | `https://rpc.mainnet.lightchain.ai` | `0xfB15F90298e4CcD7106E76fFB5e520315cC42B0b` | | `testnet` | 8200 | `https://chat-api.testnet.lightchain.ai` | `https://rpc.testnet.lightchain.ai` | `0x531b3A87c5D785441B9cF55b98169F20FD9056a7` | -The mainnet Developer API hostname is not decided yet. `chat-api.mainnet.lightchain.ai` is the production consumer API's name, but today it serves an older consumer API without the key routes and `/v1`: mainnet calls fail there until the Developer API is deployed behind it. +The mainnet Developer API is not live yet: mainnet calls fail until it is, and its URL may change. ## Development @@ -130,14 +130,14 @@ npm install npm test # unit tests against recorded devnet answers (Node >= 22.18) npm run typecheck npm run build # dist/ -npm run abi # regenerate src/abi.ts from pkg/chain/abis (inside the orchestrator's sdk/, after `make bindings`) -npm run openapi # regenerate test/fixtures/openapi.json from consumer-api's source (inside the orchestrator's sdk/) +npm run abi -- IJobRegistry.json # regenerate src/abi.ts from the JobRegistry's ABI, after the contracts change +npm run openapi # refresh test/fixtures/openapi.json from the API testnet serves WALLET_PRIVATE_KEY=0x... npm run acceptance # a fresh wallet: the key alone gets its 402, then account pays it; see scripts/acceptance.ts WALLET_PRIVATE_KEY=0x... LIGHTCHAIN_MODEL=gemma4:e2b npm run acceptance:x402 # keyless x402 mode; see scripts/acceptance-x402.ts FUNDER_PRIVATE_KEY=0x... LIGHTCHAIN_MODEL=gemma4:e2b npm run acceptance:x402:fresh # the same, from a fresh wallet FUNDER_PRIVATE_KEY funds WALLET_PRIVATE_KEY=0x... npm run acceptance:pool # streaming, and two interleaved conversations in one pooled session ``` -The fixtures in `test/fixtures` were recorded from a local devnet (`make devnet-full`, chain 48221) with Foundry's publicly known test account 7. The x402 tests sign the scheme's published test vectors (`test/fixtures/x402-vectors.json`, a copy of the orchestrator's `scripts/x402-vectors/vectors.json`) byte for byte, with Foundry's test account 3. Never use either key on a real network. +The fixtures in `test/fixtures` were recorded from a local devnet with Foundry's publicly known test account 7. The x402 tests sign the scheme's test vectors (`test/fixtures/x402-vectors.json`) byte for byte, with Foundry's test account 3. Never use either key on a real network. CI (`.github/workflows/ci.yml`) typechecks, builds and tests every pull request and every push to `main`. `acceptance.yml` runs `acceptance:pool`, then `acceptance:x402:fresh`, against testnet every night at 03:17 UTC, and on demand from the Actions tab. It pays from the wallet in the `TESTNET_WALLET_PRIVATE_KEY` secret, which needs testnet LCAI. `acceptance:x402:fresh` (`scripts/fresh-wallet.ts`) runs `acceptance:x402` with a wallet made for that run, which the secret's wallet funds and which sends what it has left back: `acceptance:x402` needs a wallet that never authorized a delegate. Each run's log is kept as an artifact. diff --git a/package.json b/package.json index 4dfbe18..2ed74a2 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "typecheck": "tsc --noEmit", "test": "node --test 'test/*.test.ts'", "abi": "node scripts/abi.ts", - "openapi": "../consumer-api/node_modules/.bin/tsx scripts/openapi.ts", + "openapi": "node scripts/openapi.ts", "acceptance": "node scripts/acceptance.ts", "acceptance:x402": "node scripts/acceptance-x402.ts", "acceptance:pool": "node scripts/acceptance-pool.ts", diff --git a/scripts/abi.ts b/scripts/abi.ts index 1ee04c5..249985a 100644 --- a/scripts/abi.ts +++ b/scripts/abi.ts @@ -1,9 +1,11 @@ -// Writes src/abi.ts: the JobRegistry functions the SDK calls, cut from the ABI -// that `make bindings` extracts from the compiled contracts. Run from sdk/ in -// the orchestrator checkout, after `make bindings` if the contracts moved. +// Writes src/abi.ts: the JobRegistry functions the SDK calls, cut from the +// JobRegistry's ABI (a JSON array) when the contracts change. +// +// npm run abi -- path/to/IJobRegistry.json import { readFileSync, writeFileSync } from 'node:fs'; -const SOURCE = '../pkg/chain/abis/IJobRegistry.json'; +const SOURCE = process.argv[2]; +if (!SOURCE) throw new Error('usage: npm run abi -- path/to/IJobRegistry.json'); const FUNCTIONS = ['deposit', 'depositAndAuthorize', 'prepaidBalanceOf', 'isDelegateAuthorized', 'delegateAllowance']; const abi: { type: string; name?: string }[] = JSON.parse(readFileSync(SOURCE, 'utf8')); @@ -15,6 +17,6 @@ const picked = FUNCTIONS.map((name) => { writeFileSync( 'src/abi.ts', - `// Generated by scripts/abi.ts from ${SOURCE.slice(3)}. Do not edit.\n` + + '// Generated by scripts/abi.ts from the JobRegistry ABI. Do not edit.\n' + `export const jobRegistryAbi = ${JSON.stringify(picked, null, 2)} as const;\n`, ); diff --git a/scripts/openapi.ts b/scripts/openapi.ts index cc92d05..d3544a4 100644 --- a/scripts/openapi.ts +++ b/scripts/openapi.ts @@ -1,26 +1,14 @@ // Writes test/fixtures/openapi.json: the /v1/chat/completions part of the -// consumer API's /docs/json, built from the consumer-api submodule's source -// and read by injection, no server listening. Run from sdk/ with consumer-api's -// dependencies installed: `npm run openapi` (it runs under consumer-api's tsx). +// Developer API's OpenAPI document, as the network's API serves it. +// +// LIGHTCHAIN_NETWORK=testnet npm run openapi import { writeFileSync } from 'node:fs'; -import { createRequire } from 'node:module'; +import { networks } from '../src/index.ts'; -const API = new URL('../../consumer-api/', import.meta.url); -// The env schema exits without these; nothing the document says depends on them. -process.env.DATABASE_URL ??= 'postgres://unused/unused'; -process.env.DISPATCHER_INTERNAL_AUTH_SECRET ??= 'unused'; -process.env.DISPATCHER_JWT_PUBLIC_KEY_HEX ??= `02${'00'.repeat(32)}`; -process.env.CHAIN_ID ??= '1'; - -// Loaded from consumer-api, by computed paths, so this package's tsc stays out of its source. -const load = async (path: string) => (await import(new URL(path, API).href)).default; -const Fastify = createRequire(API)('fastify'); -const app = Fastify({ logger: false }); -app.decorate('redis', {}); -await app.register(await load('src/plugins/swagger.plugin.ts')); -await app.register(await load('src/routes/v1/index.ts')); -const { openapi, info, paths } = (await app.inject({ method: 'GET', url: '/docs/json' })).json(); -await app.close(); +const { apiUrl } = networks[(process.env.LIGHTCHAIN_NETWORK ?? 'testnet') as keyof typeof networks]; +const res = await fetch(`${apiUrl}/docs/json`); +if (!res.ok) throw new Error(`${apiUrl}/docs/json: ${res.status}`); +const { openapi, info, paths } = await res.json(); const path = '/v1/chat/completions'; const fixture = { openapi, info, paths: { [path]: paths[path] } }; diff --git a/src/abi.ts b/src/abi.ts index beda19a..ace37e4 100644 --- a/src/abi.ts +++ b/src/abi.ts @@ -1,4 +1,4 @@ -// Generated by scripts/abi.ts from pkg/chain/abis/IJobRegistry.json. Do not edit. +// Generated by scripts/abi.ts from the JobRegistry ABI. Do not edit. export const jobRegistryAbi = [ { "type": "function", diff --git a/src/client.ts b/src/client.ts index 08ec6bf..5209d04 100644 --- a/src/client.ts +++ b/src/client.ts @@ -117,7 +117,7 @@ type X402Accept = { /** A /v1 402 body: OpenAI's error, with the ways to pay in `accepts`. */ type PaymentRequired = { error?: { message?: string; code?: string; accepts?: (DelegateAccept | X402Accept)[] } }; -/** LightChain's x402 scheme (docs/x402/lightchain-scheme.md in the orchestrator): its EIP-712 domain and type. */ +/** LightChain's x402 scheme, prepaid-debit: its EIP-712 domain and type. */ const X402_SCHEME = 'prepaid-debit'; const DEBIT_DOMAIN = { name: 'LightChain JobRegistry', version: '1' } as const; const DEBIT_AUTHORIZATION = { @@ -307,7 +307,7 @@ export class Lightchain { headers.delete('content-length'); return new Response(JSON.stringify(refused), { status: 402, headers }); } - // ponytail: sent again once. A 402 on that retry (the fee rose meanwhile) + // Sent again once. A 402 on that retry (the fee rose meanwhile) // comes back to the caller; loop, with a bound, if that shows up. if (!x402) return this.#fetch(again, init); const paidHeaders = new Headers(headers); diff --git a/src/networks.ts b/src/networks.ts index f84d47d..8f4e449 100644 --- a/src/networks.ts +++ b/src/networks.ts @@ -11,18 +11,13 @@ export type Network = { }; export const networks = { - // JobRegistry from scripts/mainnet/chat/manifest.mainnet.json (verified live 2026-09-09). - // ponytail: the mainnet Developer API hostname is not decided; this is the - // production consumer-api name, which serves an older API without the key - // routes and /v1 today. Change it here once one is chosen. + // The mainnet Developer API is not live yet, and its URL may change. mainnet: { chainId: 9200, apiUrl: 'https://chat-api.mainnet.lightchain.ai', rpcUrl: 'https://rpc.mainnet.lightchain.ai', jobRegistry: '0xfB15F90298e4CcD7106E76fFB5e520315cC42B0b', }, - // JobRegistry from terraform/environments/testnet/terraform.tfvars; API from - // consumer-api/docs/developer-api/quickstart.md. testnet: { chainId: 8200, apiUrl: 'https://chat-api.testnet.lightchain.ai', diff --git a/test/openapi.test.ts b/test/openapi.test.ts index a152d36..b7bdaeb 100644 --- a/test/openapi.test.ts +++ b/test/openapi.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import { test } from 'node:test'; import vectors from './fixtures/x402-vectors.json' with { type: 'json' }; -// The consumer API's published document; `npm run openapi` writes it from ../consumer-api. +// The Developer API's OpenAPI document, as testnet serves it; `npm run openapi` refreshes it. import spec from './fixtures/openapi.json' with { type: 'json' }; import pay from './fixtures/pay-402.json' with { type: 'json' }; @@ -10,7 +10,7 @@ type Schema = { required?: string[]; properties?: Record; items? /** * The fields `schema` requires that `value` lacks, as paths. A oneOf takes * the branch that misses least. - * ponytail: required fields only, no types or $ref; the published schemas are + * Required fields only, no types or $ref; the published schemas are * inline. Use a JSON Schema validator if they grow those. */ function missing(schema: Schema, value: unknown, at = '$'): string[] { diff --git a/test/payment.test.ts b/test/payment.test.ts index 56a9017..5e6b69a 100644 --- a/test/payment.test.ts +++ b/test/payment.test.ts @@ -39,7 +39,7 @@ function withAccepts(accepts: object[]): Exchange { const withOffer = (change: (accept: Accept) => object) => withAccepts([change(offer)]); // The x402 prepaid-debit requirements an API that takes x402 payments lists -// after the delegate entry, shaped as consumer-api's own tests build them. +// after the delegate entry. const prepaidDebit = { scheme: 'prepaid-debit', network: `eip155:${network.chainId}`, diff --git a/test/x402.test.ts b/test/x402.test.ts index 9a0ceae..2d20483 100644 --- a/test/x402.test.ts +++ b/test/x402.test.ts @@ -7,7 +7,7 @@ import vectors from './fixtures/x402-vectors.json' with { type: 'json' }; import pay from './fixtures/pay-402.json' with { type: 'json' }; import { type Exchange, replayHttp, replayRpc } from './replay.ts'; -// The published vectors of the prepaid-debit scheme (docs/x402/lightchain-scheme.md): +// The prepaid-debit scheme's test vectors: // their payer is Foundry's public test account 3, never a key for a real network. type Vector = (typeof vectors.vectors)[number]; const payerKey = vectors.accounts.find((a) => a.role === 'payer')!.privateKey as Hex;