UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

1,080 lines • 44.9 kB
/** * `neurolink proxy share` — the lender's controls. * * Every mutation here lands in the running proxy without a restart: the grant * store re-reads its file when the mtime moves, so `share pause` takes effect on * the borrower's next request rather than at the next deploy. * * @module cli/commands/proxyShare */ import { attachLeaseMaterial, createShareGrant, getNodePublicUrl, setNodePublicUrl, deleteShareGrant, findShareGrantByPeer, initShareGrants, listShareGrants, rotateShareGrantToken, setShareGrantState, updateShareGrant, } from "../../proxy/shareGrants.js"; import { resolveProxyGrantsPath, resolveProxyLedgerPath, resolveProxyPaths, resolveProxyNotesPath, resolveProxyProvisioningPath, resolveProxyReceiptsPath, resolveProxyShareAuditPath, } from "../../proxy/proxyPaths.js"; import { initShareLedger, summarizeGrantUsage, } from "../../proxy/shareLedger.js"; import { clearAuditDrift, getAuditRecord, initShareAudit, } from "../../proxy/shareAudit.js"; const ACTIONS = [ "create", "provision", "url", "list", "status", "pause", "resume", "revoke", "topup", "set", "link", "rotate", "level", "note", "notes", "receipts", "delete", ]; /** Parse `7d`, `12h`, `90m` or a bare number of days into milliseconds. */ export function parseDurationMs(value) { const match = /^(\d+(?:\.\d+)?)\s*([smhdw]?)$/i.exec(value.trim()); if (!match) { return undefined; } const amount = Number(match[1]); const unit = (match[2] || "d").toLowerCase(); const scale = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000, }; const factor = scale[unit]; return factor === undefined ? undefined : amount * factor; } /** * Parse a window-slice expression. * * Accepts `20` (both windows), or `5h=20,7d=15` to set them apart. Both windows * matter: a borrower can be harmless inside any single 5-hour session and still * drain the week. */ export function parseWindowSlice(value) { const trimmed = value.trim(); if (!trimmed) { return undefined; } if (/^\d+(?:\.\d+)?$/.test(trimmed)) { const pct = Number(trimmed); return { session5hPct: pct, weekly7dPct: pct }; } const slice = {}; for (const part of trimmed.split(",")) { const [rawKey, rawValue] = part.split("="); if (!rawKey || !rawValue) { return undefined; } const pct = Number(rawValue.trim()); if (!Number.isFinite(pct)) { return undefined; } const key = rawKey.trim().toLowerCase(); if (key === "5h" || key === "session") { slice.session5hPct = pct; } else if (key === "7d" || key === "weekly" || key === "week") { slice.weekly7dPct = pct; } else { return undefined; } } return Object.keys(slice).length > 0 ? slice : undefined; } /** Parse `12h<60` / `12h<60@25` — window, utilization threshold, slice cap. */ export function parseSpillover(value) { const match = /^(\d+(?:\.\d+)?)h?\s*<\s*(\d+(?:\.\d+)?)(?:@(\d+(?:\.\d+)?))?$/i.exec(value.trim()); if (!match) { return undefined; } return { beforeResetHours: Number(match[1]), whenUtilizationBelowPct: Number(match[2]), ...(match[3] !== undefined ? { maxSlicePct: Number(match[3]) } : {}), }; } /** Parse `21-9` into an hour-of-day admission window. */ export function parseSchedule(value) { const match = /^(\d{1,2})\s*-\s*(\d{1,2})$/.exec(value.trim()); if (!match) { return undefined; } const fromHour = Number(match[1]); const toHour = Number(match[2]); if (fromHour > 23 || toHour > 23) { return undefined; } return { fromHour, toHour }; } /** Parse `100/week` or `50/session` into a refill policy. */ export function parseRefill(value) { const [rawAmount, rawPeriod] = value.split("/"); const amount = Number(rawAmount?.trim()); const period = rawPeriod?.trim().toLowerCase(); if (!Number.isFinite(amount) || amount <= 0) { return undefined; } if (period === "week" || period === "weekly" || period === "7d") { return { amount, per: "week" }; } if (period === "session" || period === "5h") { return { amount, per: "session" }; } return undefined; } /** Parse `20/min` or a bare number into a per-minute request ceiling. */ export function parseRate(value) { const match = /^(\d+)(?:\s*\/\s*min(?:ute)?)?$/i.exec(value.trim()); return match ? Number(match[1]) : undefined; } /** * Presets fill the gate set; they are not a separate concept. * Every field a preset sets can be overridden by an explicit flag, so * `--preset spare --reserve 50` is exactly the preset with a tighter floor. */ const PRESETS = { spare: { gates: { reserveFloor: { session5hPct: 30, weekly7dPct: 30 }, maxSlice: { session5hPct: 20, weekly7dPct: 20 }, }, ledger: "unlimited", }, spillover: { gates: { spillover: { beforeResetHours: 12, whenUtilizationBelowPct: 60, maxSlicePct: 25, }, }, ledger: "unlimited", }, metered: { gates: { maxSlice: { session5hPct: 25 } }, ledger: "coins", }, open: { // The most permissive preset still carries a rate ceiling. "Open" means no // window slice and no ledger, not "hammer the pool as fast as you can" — // and a borrower with a runaway loop is the likeliest way an open share // costs its lender a window. gates: { reserveFloor: { session5hPct: 10 }, rate: { perMinute: 60 }, }, ledger: "unlimited", }, }; function isPresetName(value) { return (value === "spare" || value === "spillover" || value === "metered" || value === "open"); } /** * Build the link a borrower consumes with `peer add --link`. * * The token rides in the fragment because fragments are not transmitted: a link * pasted into anything that resolves the URL leaks the host, never the secret. */ export function buildShareLink(publicUrl, token, receiptSecret) { const trimmed = publicUrl.replace(/\/+$/, ""); const host = trimmed.replace(/^https?:\/\//, ""); // https is the default, so only a plaintext origin needs to say so. Without // this the scheme is lost and a LAN or loopback peer silently becomes an // https URL that nothing is listening on. const insecure = /^http:\/\//i.test(trimmed); // The receipt secret rides in the same fragment as the token: it is no more // sensitive, and a borrower without it cannot check a single charge. A "." // separates them because neither half's alphabet contains one. const fragment = receiptSecret ? `${token}.${receiptSecret}` : token; return `neurolink://share/${host}${insecure ? "?scheme=http" : ""}#${fragment}`; } /** * The gate-only listener port, when the running proxy has one. * * Read from the proxy's own state rather than derived, because the operator may * have moved it with `--share-port` and the answer has to match what is actually * listening. */ async function readSharePort() { try { const { StateFileManager } = await import("../utils/serverUtils.js"); const state = new StateFileManager("proxy-state.json").load(); return state?.sharePort; } catch { return undefined; } } function printToken(token, publicUrl, peerLabel, receiptSecret) { console.info(""); console.info(" Share token (shown once — it is not stored anywhere):"); console.info(` ${token}`); if (publicUrl) { console.info(""); console.info(" Send the peer this link:"); console.info(` ${buildShareLink(publicUrl, token, receiptSecret)}`); console.info(""); console.info(" They add it with:"); console.info(` neurolink proxy peer add --name <your-name> --link "${buildShareLink(publicUrl, token, receiptSecret)}"`); } else { console.info(""); console.info(" Re-run with --public-url <your exposed URL> to get a link the peer can paste."); console.info(" Until then they can add it by hand:"); console.info(` neurolink proxy peer add --name <your-name> --url <your-url> --token ${token}` + (receiptSecret ? ` --receipt-secret ${receiptSecret}` : "")); } void peerLabel; } function formatPct(value) { return value === undefined ? "—" : `${value}%`; } function describeGates(gates) { const lines = []; if (gates.reserveFloor) { lines.push(` reserve floor 5h ${formatPct(gates.reserveFloor.session5hPct)} 7d ${formatPct(gates.reserveFloor.weekly7dPct)}`); } if (gates.maxSlice) { lines.push(` max slice 5h ${formatPct(gates.maxSlice.session5hPct)} 7d ${formatPct(gates.maxSlice.weekly7dPct)} (of the pool)`); } if (gates.maxSlicePerAccount) { lines.push(` per-account cap 5h ${formatPct(gates.maxSlicePerAccount.session5hPct)} 7d ${formatPct(gates.maxSlicePerAccount.weekly7dPct)}`); } if (gates.spillover) { lines.push(` spillover last ${gates.spillover.beforeResetHours}h when under ${gates.spillover.whenUtilizationBelowPct}%` + (gates.spillover.maxSlicePct !== undefined ? ` (cap ${gates.spillover.maxSlicePct}%)` : "")); } if (gates.models?.length) { lines.push(` models ${gates.models.join(", ")}`); } if (gates.accounts?.length) { lines.push(` accounts ${gates.accounts.join(", ")}`); } if (gates.rate) { const parts = []; if (gates.rate.perMinute !== undefined) { parts.push(`${gates.rate.perMinute}/min`); } if (gates.rate.concurrency !== undefined) { parts.push(`${gates.rate.concurrency} concurrent`); } lines.push(` rate ${parts.join(", ")}`); } if (gates.schedule) { lines.push(` schedule ${String(gates.schedule.fromHour).padStart(2, "0")}:00–${String(gates.schedule.toHour).padStart(2, "0")}:00 local`); } if (gates.notAfter !== undefined) { lines.push(` expires ${new Date(gates.notAfter).toISOString()}`); } return lines; } function describeGrant(grant) { const entitlement = grant.entitlement.ledger === "coins" ? `${Math.floor(grant.entitlement.coins ?? 0)} coins` : "unlimited"; const refill = grant.entitlement.refill ? ` (+${grant.entitlement.refill.amount}/${grant.entitlement.refill.per})` : ""; const lines = [ `${grant.peerLabel} [${grant.id}]`, ` level ${grant.level}`, ` state ${grant.state}`, ` entitlement ${entitlement}${refill}`, ...describeGates(grant.gates), ]; if (grant.lastUsedAt) { lines.push(` last used ${new Date(grant.lastUsedAt).toISOString()}`); } return lines.join("\n"); } /** * Collect gate overrides from the flags actually supplied. * Returns `undefined` for anything unset so a `set` never silently clears a * control the operator did not mention. */ function gatesFromArgs(argv) { const gates = {}; const errors = []; if (argv.reserve !== undefined) { const parsed = parseWindowSlice(argv.reserve); if (!parsed) { errors.push(`--reserve: cannot parse "${argv.reserve}" (try 30 or 5h=30,7d=20)`); } else { gates.reserveFloor = parsed; } } if (argv.maxSlicePerAccount !== undefined) { const parsed = parseWindowSlice(argv.maxSlicePerAccount); if (!parsed) { errors.push(`--max-slice-per-account: cannot parse "${argv.maxSlicePerAccount}"`); } else { gates.maxSlicePerAccount = parsed; } } if (argv.maxSlice !== undefined) { const parsed = parseWindowSlice(argv.maxSlice); if (!parsed) { errors.push(`--max-slice: cannot parse "${argv.maxSlice}" (try 20 or 5h=20,7d=15)`); } else { gates.maxSlice = parsed; } } if (argv.spillover !== undefined) { const parsed = parseSpillover(argv.spillover); if (!parsed) { errors.push(`--spillover: cannot parse "${argv.spillover}" (try 12h<60@25)`); } else { gates.spillover = parsed; } } if (argv.models?.length) { gates.models = argv.models; } if (argv.accounts?.length) { gates.accounts = argv.accounts; } if (argv.rate !== undefined || argv.concurrency !== undefined) { const rate = {}; if (argv.rate !== undefined) { const parsed = parseRate(argv.rate); if (parsed === undefined) { errors.push(`--rate: cannot parse "${argv.rate}" (try 20/min)`); } else { rate.perMinute = parsed; } } if (argv.concurrency !== undefined) { rate.concurrency = argv.concurrency; } if (Object.keys(rate).length > 0) { gates.rate = rate; } } if (argv.schedule !== undefined) { const parsed = parseSchedule(argv.schedule); if (!parsed) { errors.push(`--schedule: cannot parse "${argv.schedule}" (try 21-9)`); } else { gates.schedule = parsed; } } if (argv.expires !== undefined) { const ms = parseDurationMs(argv.expires); if (ms === undefined) { errors.push(`--expires: cannot parse "${argv.expires}" (try 7d or 48h)`); } else { gates.notAfter = Date.now() + ms; } } return { gates, errors }; } async function resolvePeerOrFail(peer) { if (!peer) { throw new Error("A peer name or grant id is required for this action."); } const grant = await findShareGrantByPeer(peer); if (!grant) { throw new Error(`No share grant found for "${peer}".`); } return grant; } /** * `share create` — mint a grant and print its one-time token. * * The token is shown here and never again: nothing stores it, so a lost link is * replaced by `share rotate`, not reprinted. */ async function handleShareCreate(argv, publicUrl) { if (!argv.peer) { throw new Error("--peer is required to create a share grant."); } const presetName = argv.preset ?? "spare"; if (!isPresetName(presetName)) { throw new Error(`Unknown preset "${presetName}". Use spare, spillover, metered or open.`); } const preset = PRESETS[presetName]; const { gates: overrides, errors } = gatesFromArgs(argv); if (errors.length > 0) { throw new Error(errors.join("\n")); } const level = argv.level === "complete" ? "complete" : "live"; const ledger = argv.ledger === "coins" || argv.coins !== undefined ? "coins" : argv.ledger === "unlimited" ? "unlimited" : preset.ledger; const entitlement = { ledger }; if (ledger === "coins") { entitlement.coins = argv.coins ?? 0; } if (argv.refill) { const refill = parseRefill(argv.refill); if (!refill) { throw new Error(`--refill: cannot parse "${argv.refill}" (try 100/week or 50/session)`); } entitlement.refill = refill; } const issued = await createShareGrant({ peerLabel: argv.peer, level, entitlement, gates: { ...preset.gates, ...overrides }, ...(argv.note ? { note: argv.note } : {}), }); if (argv.json) { console.info(JSON.stringify({ grant: issued.grant, token: issued.token }, null, 2)); return; } console.info(describeGrant(issued.grant)); printToken(issued.token, publicUrl, issued.grant.peerLabel, issued.grant.receiptSecret); // The gate-only listener comes up on the first active grant, so this is // exactly the moment an operator needs to know which port to expose — // and that their own client keeps using the main one. const sharePort = await readSharePort(); console.info(""); if (sharePort !== undefined) { console.info(` Peers connect on the share listener, port ${sharePort}.`); console.info(" It refuses any request without a token, so expose that port — not the"); console.info(" main one, which still serves your own client untokened."); } else { console.info(" The gate-only share listener starts within a few seconds of this grant,"); console.info(" on your proxy port + 1. Expose that port; `neurolink proxy expose` picks"); console.info(" it automatically."); } console.info(""); console.info(" Note: sharing subscription capacity with other people is likely outside"); console.info(" your provider's consumer terms, and the account carrying the traffic is"); console.info(" the one exposed. Share deliberately."); return; } /** `share status` — spend, reach and audit standing, per grant. */ async function handleShareStatus(argv) { const grants = argv.peer ? [await resolvePeerOrFail(argv.peer)] : await listShareGrants(); const withUsage = await Promise.all(grants.map(async (grant) => ({ grant, usage: await summarizeGrantUsage(grant.id), audit: await getAuditRecord(grant.id), }))); if (argv.json) { console.info(JSON.stringify(withUsage, null, 2)); return; } if (withUsage.length === 0) { console.info("No share grants issued."); return; } for (const { grant, usage, audit } of withUsage) { console.info(describeGrant(grant)); console.info(` spent ${usage.coinsSpent.toFixed(1)} coins over ${usage.requests} request(s)`); if (usage.accounts > 0) { console.info(` drew on ${usage.accounts} account(s)`); } if (grant.level === "complete") { // Spend on a complete share is the borrower's own word. Show what the // account's real usage makes of it so the two are never confused. const verdict = audit?.autoPausedAt ? `auto-paused on usage drift ${new Date(audit.autoPausedAt).toISOString()}` : audit && audit.driftStreak > 0 ? `drifting (${audit.driftStreak} consecutive)` : audit?.lastObservation ? "consistent with the account's own usage" : "no check-in observed yet"; console.info(` audit ${verdict}`); if (audit?.lastDriftDetail && audit.driftStreak > 0) { console.info(` ${audit.lastDriftDetail}`); } } console.info(""); } return; } /** `share note` — mint a bearer coin note against this node. */ async function handleShareNote(argv, paths, publicUrl) { const { initShareNotes, issueShareNote, encodeShareNote } = await import("../../proxy/shareNotes.js"); initShareNotes(resolveProxyNotesPath(paths)); if (argv.coins === undefined || argv.coins <= 0) { throw new Error("--coins is required, and must be positive."); } const ttlMs = argv.ttl ? parseDurationMs(argv.ttl) : undefined; if (argv.ttl && ttlMs === undefined) { throw new Error(`--ttl: cannot parse "${argv.ttl}" (try 30d or 48h)`); } const note = await issueShareNote({ issuer: publicUrl ?? "this node", coins: argv.coins, ...(ttlMs !== undefined ? { ttlMs } : {}), ...(argv.memo ? { memo: argv.memo } : {}), }); const encoded = encodeShareNote(note); if (argv.json) { console.info(JSON.stringify({ note, encoded }, null, 2)); return; } console.info(`Minted a ${argv.coins}-coin note against this node.`); console.info(""); console.info(` ${encoded}`); console.info(""); console.info(` Redeemable once, by whoever holds it, until ${new Date(note.notAfter).toISOString()}.`); console.info(" They need a grant with you to redeem it into:"); console.info(" neurolink proxy peer redeem --name <you> --coin-note <the note>"); console.info(" Anyone holding it can check it without spending it, with --check."); return; } /** `share notes` — what this node has minted, and whether it was redeemed. */ async function handleShareNotes(argv, paths) { const { initShareNotes, listShareNotes } = await import("../../proxy/shareNotes.js"); initShareNotes(resolveProxyNotesPath(paths)); const minted = await listShareNotes(); if (argv.json) { console.info(JSON.stringify(minted, null, 2)); return; } if (minted.length === 0) { console.info("No coin notes minted."); return; } const now = Date.now(); for (const record of minted) { const state = record.redeemedAt ? `redeemed ${new Date(record.redeemedAt).toISOString()}` : record.notAfter <= now ? "expired" : `valid until ${new Date(record.notAfter).toISOString()}`; console.info(`${record.noteId} ${String(record.coins).padStart(6)} coins ${state}${record.memo ? ` — ${record.memo}` : ""}`); } return; } /** * `share provision` — authorize a borrower's own credential. * * Split PKCE: the borrower holds the verifier, so the code relayed through here * is worthless to the lender and to anyone who intercepts it. */ async function handleShareProvision(argv, paths, publicUrl) { const grant = await resolvePeerOrFail(argv.peer); const { generateLeaseSecret } = await import("../../proxy/shareLease.js"); const { authorizeProvisionRequest, getProvisionRequest, initShareProvisioning, } = await import("../../proxy/shareProvisioning.js"); initShareProvisioning(resolveProxyProvisioningPath(paths)); // The borrower goes first. Its verifier is the only thing that can turn // the code this command produces into a credential, so there is nothing // to authorize until it has lodged the matching challenge. const pending = await getProvisionRequest(grant.id); if (!pending) { throw new Error(`${grant.peerLabel} has not asked to be provisioned yet.\n` + " On their machine, with your share token already added:\n" + " neurolink proxy peer request --name <your-name>\n" + " Then run this command again. Their request is valid for 15 minutes."); } const leasePolicy = { ttlMs: parseDurationMs(argv.leaseTtl ?? "7d") ?? 604_800_000, heartbeatEveryMs: parseDurationMs(argv.heartbeat ?? "15m") ?? 900_000, offlineGraceMs: parseDurationMs(argv.offlineGrace ?? "24h") ?? 86_400_000, }; const prepared = await updateShareGrant(grant.id, { level: "complete" }); if (!prepared) { throw new Error(`No share grant found for "${argv.peer}".`); } // Which of the lender's accounts this credential is minted from. The // drift audit compares that account's real utilization against what the // borrower reports, so without it complete mode has reporting but no // verification. const fromAccount = argv.fromAccount ?? prepared.gates.accounts?.[0]; const withLease = await attachLeaseMaterial(prepared.id, prepared.leaseSecret ?? generateLeaseSecret(), leasePolicy, fromAccount); if (!withLease) { throw new Error("Could not prepare the grant for provisioning."); } console.info(`Authorizing an independent credential for ${withLease.peerLabel}.`); console.info(""); console.info(" This runs a SEPARATE authorization on your account — it does not copy"); console.info(" your own tokens. Copying them would put two devices on one rotating"); console.info(" refresh chain, and the loser of that race gets disabled — yours."); console.info(""); console.info(" You will never hold a token for this credential. The borrower keeps"); console.info(" the PKCE verifier; you only relay a code that is worthless without it."); console.info(""); console.info(` Once provisioned, ${withLease.peerLabel} calls the provider directly. You keep`); console.info(` control through the lease: they stop ${argv.offlineGrace ?? "24h"} after you become`); console.info(" unreachable, immediately once a heartbeat reaches them, and at the"); console.info(" lease's hard expiry regardless."); console.info(""); console.info(" Note: a credential on someone else's machine can be extracted by them."); console.info(" Complete sharing is enforced cooperatively and audited after the fact —"); console.info(" use it for people you would trust with the account."); console.info(""); const { buildSubscriptionAuthUrl } = await import("../../auth/anthropicOAuth.js"); const authUrl = buildSubscriptionAuthUrl({ codeChallenge: pending.codeChallenge, state: pending.state, }); console.info(" Open this URL, sign in, and authorize:"); console.info(""); console.info(` ${authUrl}`); console.info(""); console.info(" Anthropic then shows an authorization code. Paste it back:"); console.info(""); console.info(` neurolink proxy share provision --peer ${withLease.peerLabel} --code <code>`); if (!argv.code) { console.info(""); console.info(" Nothing has been authorized yet — re-run with --code to finish."); return; } // Anthropic renders the code as `code#state`. Only the code half is ours // to relay; the state came from the borrower and is already on file. const code = argv.code.trim().split("#")[0]; const authorized = await authorizeProvisionRequest({ grantId: withLease.id, code, ...(fromAccount ? { accountLabel: fromAccount } : {}), }); if (!authorized.ok) { throw new Error(`Could not record that code: ${authorized.reason}`); } console.info(""); console.info(`Authorized. ${withLease.peerLabel} can collect it now:`); console.info(""); console.info(" neurolink proxy peer request --name <your-name> --claim"); console.info(""); console.info(" The code is single-use and expires with their request. If they miss"); console.info(" the window, they ask again and you authorize again."); if (!publicUrl) { console.info(""); console.info(" No public URL is recorded, so the lease will carry no heartbeat"); console.info(" address and they will stop at the offline grace. Set one with:"); console.info(" neurolink proxy share url https://your-proxy"); } return; } /** `share url` — read, set or clear the address links are minted against. */ async function handleShareUrl(argv) { const positional = argv.value?.trim(); if (argv.clear || positional === "clear") { await setNodePublicUrl(undefined); console.info("Public URL cleared. Share links now need an explicit --public-url."); return; } // `get` prints the bare value and nothing else, so it can be captured in // a shell variable without post-processing. Absent means empty output and // a non-zero exit, which is what a script expects. if (positional === "get") { const current = await getNodePublicUrl(); if (!current) { process.exitCode = 1; return; } console.info(current); return; } const target = positional && positional !== "show" ? positional : argv.publicUrl; if (!target) { const current = await getNodePublicUrl(); console.info(current ? `This node is shared at ${current}` : "No public URL recorded. Set one with: neurolink proxy share url https://proxy.example.com"); return; } await setNodePublicUrl(target); console.info(`Share links will be minted against ${target}`); const { probeProxyGate } = await import("./proxyExpose.js"); try { const parsed = new URL(target); const port = Number(parsed.port || (parsed.protocol === "https:" ? 443 : 80)); const probe = await probeProxyGate(parsed.hostname, port, parsed.protocol === "https:" ? "https" : "http"); if (probe.reachable && !probe.gated) { console.info(""); console.info(" ⚠ That address served a request carrying no share token."); console.info(" Anyone who finds it can spend your subscription. Point that address"); console.info(" at the gate-only share listener instead — it refuses every untokened"); console.info(" request, and your own client keeps using the main port:"); const sharePort = await readSharePort(); console.info(sharePort !== undefined ? ` port ${sharePort} on this machine` : " your proxy port + 1, once at least one grant is active"); console.info(""); console.info(" Or gate this port itself, which also refuses your own client:"); console.info(" NEUROLINK_PROXY_REQUIRE_GRANT=1 neurolink proxy start"); } } catch { // A URL we cannot probe is not an error — it may not be up yet. } return; } async function runShareCommand(argv) { const paths = resolveProxyPaths(argv.dev ?? false); initShareGrants(resolveProxyGrantsPath(paths)); initShareLedger(resolveProxyLedgerPath(paths)); initShareAudit(resolveProxyShareAuditPath(paths)); // An explicit flag wins; otherwise use whatever address this node was told it // lives at. Most operators front the proxy with a domain they already own, // and retyping it on every mint is how share links go stale. const publicUrl = argv.publicUrl ?? (await getNodePublicUrl()); switch (argv.action) { case "create": await handleShareCreate(argv, publicUrl); return; case "list": { const grants = await listShareGrants(); if (argv.json) { console.info(JSON.stringify(grants, null, 2)); return; } if (grants.length === 0) { console.info("No share grants issued."); return; } for (const grant of grants) { console.info(describeGrant(grant)); console.info(""); } return; } case "status": await handleShareStatus(argv); return; case "pause": case "resume": { const grant = await resolvePeerOrFail(argv.peer); const nextState = argv.action === "pause" ? "paused" : "active"; const updated = await setShareGrantState(grant.id, nextState); if (nextState === "active") { // A grant the drift audit paused carries a marker that stops it firing // twice. Resuming without clearing it would leave the audit permanently // disarmed for this grant, which is the opposite of what resume means. await clearAuditDrift(grant.id); } console.info(`${updated?.peerLabel ?? grant.peerLabel} is now ${nextState}. ` + "Takes effect on the borrower's next request."); return; } case "revoke": { const grant = await resolvePeerOrFail(argv.peer); await setShareGrantState(grant.id, "revoked"); console.info(`${grant.peerLabel} revoked. The token no longer serves traffic.`); if (grant.level === "complete") { console.info(" This grant is complete-level: the borrower holds a credential on your"); console.info(" account. Revocation stops the lease at their next heartbeat and at"); console.info(" lease expiry — it does not reach out and delete the credential."); } return; } case "note": await handleShareNote(argv, paths, publicUrl); return; case "notes": await handleShareNotes(argv, paths); return; case "receipts": { const { initShareReceipts, listShareReceipts, nettedCoinsFor } = await import("../../proxy/shareReceipts.js"); initShareReceipts(resolveProxyReceiptsPath(paths)); const grant = await resolvePeerOrFail(argv.peer); const issuedReceipts = await listShareReceipts(grant.id); const forgiven = await nettedCoinsFor(grant.id); if (argv.json) { console.info(JSON.stringify({ receipts: issuedReceipts, netted: forgiven }, null, 2)); return; } if (issuedReceipts.length === 0) { console.info(`No receipts issued to ${grant.peerLabel} yet.`); return; } const charged = issuedReceipts.reduce((sum, receipt) => sum + receipt.coins, 0); console.info(`${grant.peerLabel}: ${issuedReceipts.length} receipt(s), ${charged.toFixed(1)} coins charged`); if (forgiven > 0) { console.info(` ${forgiven.toFixed(1)} coins forgiven by reciprocal netting`); } for (const receipt of issuedReceipts.slice(-10)) { console.info(` #${String(receipt.sequence).padStart(4)} ${receipt.coins.toFixed(2).padStart(8)} coins ${receipt.model ?? "unknown model"} ${new Date(receipt.settledAt).toISOString()}`); } return; } case "delete": { const grant = await resolvePeerOrFail(argv.peer); const deleted = await deleteShareGrant(grant.id); // The audit trail is keyed by grant id and would otherwise outlive the // grant it describes, forever. const { clearAuditRecord } = await import("../../proxy/shareAudit.js"); await clearAuditRecord(grant.id); // An outstanding challenge outliving its grant would still be claimable // by whoever holds the now-dead token, so it goes with it. const { clearProvisionRequest, initShareProvisioning } = await import("../../proxy/shareProvisioning.js"); initShareProvisioning(resolveProxyProvisioningPath(paths)); await clearProvisionRequest(grant.id); const { clearShareReceipts, initShareReceipts } = await import("../../proxy/shareReceipts.js"); initShareReceipts(resolveProxyReceiptsPath(paths)); await clearShareReceipts(grant.id); console.info(deleted ? `${grant.peerLabel} deleted.` : `${grant.peerLabel} was already gone.`); return; } case "rotate": { const grant = await resolvePeerOrFail(argv.peer); const issued = await rotateShareGrantToken(grant.id); if (!issued) { throw new Error(`No share grant found for "${argv.peer}".`); } console.info(`${grant.peerLabel} token rotated. The previous token is dead.`); printToken(issued.token, publicUrl, grant.peerLabel, issued.grant.receiptSecret); return; } case "topup": { const grant = await resolvePeerOrFail(argv.peer); if (argv.coins === undefined) { throw new Error("--coins is required for topup."); } // An unlimited grant has no balance to add to, and writing `ledger: // "coins"` here would quietly meter a peer the operator had deliberately // left unmetered. Changing the ledger is `set`'s job, and it says so. if (grant.entitlement.ledger !== "coins") { throw new Error(`${grant.peerLabel} is an unlimited grant — there is no balance to top up.\n` + " To start metering it instead:\n" + ` neurolink proxy share set --peer ${grant.peerLabel} --coins ${argv.coins}`); } const balance = Math.max(0, (grant.entitlement.coins ?? 0) + argv.coins); const updated = await updateShareGrant(grant.id, { entitlement: { ledger: "coins", coins: balance }, }); console.info(`${grant.peerLabel} balance is now ${Math.floor(updated?.entitlement.coins ?? balance)} coins.`); return; } case "set": { const grant = await resolvePeerOrFail(argv.peer); const { gates, errors } = gatesFromArgs(argv); if (errors.length > 0) { throw new Error(errors.join("\n")); } const entitlement = {}; if (argv.ledger === "coins" || argv.ledger === "unlimited") { entitlement.ledger = argv.ledger; } if (argv.coins !== undefined) { entitlement.ledger = "coins"; entitlement.coins = Math.max(0, argv.coins); } if (argv.refill !== undefined) { const refill = parseRefill(argv.refill); if (!refill) { throw new Error(`--refill: cannot parse "${argv.refill}"`); } entitlement.refill = refill; } const updated = await updateShareGrant(grant.id, { ...(Object.keys(gates).length > 0 ? { gates } : {}), ...(Object.keys(entitlement).length > 0 ? { entitlement } : {}), }); console.info(updated ? describeGrant(updated) : "No change."); return; } case "provision": await handleShareProvision(argv, paths, publicUrl); return; case "url": await handleShareUrl(argv); return; case "level": { const grant = await resolvePeerOrFail(argv.peer); const target = argv.to; if (target !== "live" && target !== "complete") { throw new Error("--to must be live or complete."); } const updated = await updateShareGrant(grant.id, { level: target }); if (!updated) { throw new Error(`Could not change the level for "${argv.peer}".`); } console.info(`${grant.peerLabel} is now a ${target} share.`); if (target === "complete") { console.info(" Run `neurolink proxy share provision --peer " + `${grant.peerLabel}\` to mint the borrower's own credential.`); } return; } case "link": { const grant = await resolvePeerOrFail(argv.peer); // Nothing stores the token, by design — so a link genuinely cannot be // reprinted. Rotating is the honest answer, and it also invalidates // whatever copy went missing. console.info(`Tokens are never stored, so a link cannot be reprinted for ${grant.peerLabel}.`); console.info(` neurolink proxy share rotate --peer ${grant.peerLabel}` + (publicUrl ? "" : " --public-url <your-url>")); return; } default: throw new Error(`Unknown share action: ${String(argv.action)}`); } } export const proxyShareCommand = { command: "share <action> [value]", describe: "Lend pool capacity to a peer and control how much they may take", builder: (yargs) => yargs .positional("action", { type: "string", choices: [...ACTIONS], describe: "Share action", }) .positional("value", { type: "string", describe: "Action argument, e.g. the URL for `share url`", }) .option("peer", { type: "string", description: "Peer name or grant id", }) .option("level", { type: "string", choices: ["live", "complete"], description: "live = borrower proxies through you; complete = borrower holds its own credential on your account", }) .option("preset", { type: "string", choices: ["spare", "spillover", "metered", "open"], description: "Starting gate set; individual flags override it", }) .option("ledger", { type: "string", choices: ["coins", "unlimited"], description: "Metered against a coin balance, or uncapped", }) .option("coins", { type: "number", description: "Coin balance to set (create/set) or add (topup)", }) .option("refill", { type: "string", description: "Standing allowance, e.g. 100/week or 50/session", }) .option("max-slice", { type: "string", alias: "maxSlice", description: "Hard ceiling as a share of each window: 20, or 5h=20,7d=15", }) .option("max-slice-per-account", { type: "string", alias: "maxSlicePerAccount", description: "Ceiling applied to each account independently, instead of the pool", }) .option("reserve", { type: "string", description: "Headroom you keep for yourself: 30, or 5h=30,7d=20", }) .option("spillover", { type: "string", description: "Lend only near a reset when little was used: 12h<60@25", }) .option("models", { type: "string", array: true, description: "Model tiers this peer may use, e.g. sonnet haiku", }) .option("accounts", { type: "string", array: true, description: "Which of your accounts are lendable under this grant", }) .option("rate", { type: "string", description: "Request ceiling, e.g. 20/min", }) .option("concurrency", { type: "number", description: "Maximum concurrent borrowed requests", }) .option("schedule", { type: "string", description: "Hours this share is open, e.g. 21-9", }) .option("expires", { type: "string", description: "Grant lifetime, e.g. 7d or 48h", }) .option("note", { type: "string", description: "Free-text note kept with the grant", }) .option("to", { type: "string", choices: ["live", "complete"], description: "Target level for `share level`", }) .option("from-account", { type: "string", alias: "fromAccount", description: "Which of your accounts the complete share draws on (enables drift auditing)", }) .option("clear", { type: "boolean", default: false, description: "With `share url`: forget the recorded public address", }) .option("code", { type: "string", description: "Authorization code from your browser, to finish `share provision`", }) .option("ttl", { type: "string", description: "With `share note`: how long the note stays redeemable", }) .option("memo", { type: "string", description: "With `share note`: a note carried on the coin note", }) .option("offline-grace", { type: "string", alias: "offlineGrace", description: "How long a complete-share borrower may run unheard-from (default 24h)", }) .option("heartbeat", { type: "string", description: "Complete-share check-in interval (default 15m)", }) .option("lease-ttl", { type: "string", alias: "leaseTtl", description: "Complete-share lease lifetime (default 7d)", }) .option("public-url", { type: "string", alias: "publicUrl", description: "Public URL for this node; defaults to the one saved by `share url`", }) .option("json", { type: "boolean", default: false, description: "Emit JSON instead of formatted text", }) .option("dev", { type: "boolean", default: false, description: "Use the isolated dev-mode state directory", }), handler: async (argv) => { try { await runShareCommand(argv); } catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; } }, }; //# sourceMappingURL=proxyShare.js.map