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

193 lines (192 loc) • 8.23 kB
/** * Leases — how a lender keeps control of a credential that lives on someone * else's machine. * * In **live** sharing the lender's gate is in the request path, so control is * immediate and total. **Complete** sharing trades that away: the borrower holds * its own credential on the lender's account and calls the upstream directly, so * the lender is not consulted per request. What is left is this — a signed, * time-boxed statement of consent that the borrower enforces on itself and must * keep renewing. * * The design turns on one number: **how long may the borrower run without * hearing from me.** `offlineGraceMs` is that number. Set it to zero and * complete mode collapses into live mode's availability; set it to a day and the * borrower keeps working through a weekend when the lender's laptop is shut, at * the cost of a day's revocation latency. Both are legitimate; neither is free. * * `notAfter` is the backstop that does not depend on the borrower's cooperation * at all — it is baked into the signed payload, so a borrower that simply never * calls home still stops. * * **Signing.** HMAC-SHA256 keyed by a per-grant secret shared with the borrower * at provisioning time. Asymmetric signatures would be tidier, but the key * distribution problem they solve does not exist here — exactly two parties are * involved and they already share a secret — and the package's browser bundle * stubs `node:crypto` down to a subset with no Ed25519 in it. * * @module proxy/shareLease */ import { generateShareSecret, secretsMatch, signSharePayload, } from "./shareSigning.js"; /** A week: long enough to survive a holiday, short enough to be a real bound. */ export const DEFAULT_LEASE_TTL_MS = 604_800_000; /** Fifteen minutes — frequent enough that a pause lands the same session. */ export const DEFAULT_HEARTBEAT_MS = 900_000; /** Twenty-four hours of running unheard-from. The headline trade-off. */ export const DEFAULT_OFFLINE_GRACE_MS = 86_400_000; /** * Narrow a verdict to its refusing half. * * One of the package's build steps compiles without `strictNullChecks`, where * TypeScript will not narrow a boolean discriminant. An explicit predicate holds * in both modes — see the same pattern in `sharePolicy.isShareRefusal`. */ export function isLeaseRefusal(verdict) { return !verdict.usable; } export function generateLeaseSecret() { return generateShareSecret(); } /** * The signed portion of a lease — everything but the signature itself. * * Field order is irrelevant: `signSharePayload` canonicalises before hashing. * The explicit list is still worth keeping, because it says which fields a * borrower is entitled to rely on rather than signing whatever happens to be on * the object. */ function leasePayload(lease) { return { schemaVersion: lease.schemaVersion, grantId: lease.grantId, peerLabel: lease.peerLabel, issuedAt: lease.issuedAt, notAfter: lease.notAfter, heartbeatEveryMs: lease.heartbeatEveryMs, offlineGraceMs: lease.offlineGraceMs, gates: lease.gates, entitlementSnapshot: lease.entitlementSnapshot, }; } function sign(payload, secret) { return signSharePayload(payload, secret); } /** * Issue a lease for a grant. * * The gates are snapshotted rather than referenced: the borrower enforces what * the lender agreed to at issue time, and a tightened policy reaches them at the * next heartbeat rather than silently mid-lease. */ export function issueLease(grant, now = Date.now()) { const policy = grant.leasePolicy; const secret = grant.leaseSecret; if (!secret) { throw new Error(`Grant ${grant.id} has no lease secret — provision it before issuing a lease.`); } const ttl = policy?.ttlMs ?? DEFAULT_LEASE_TTL_MS; // A lease can never outlive the grant's own expiry. const notAfter = Math.min(now + ttl, grant.gates.notAfter ?? Number.POSITIVE_INFINITY); const unsigned = { schemaVersion: 1, grantId: grant.id, peerLabel: grant.peerLabel, issuedAt: now, notAfter, heartbeatEveryMs: policy?.heartbeatEveryMs ?? DEFAULT_HEARTBEAT_MS, offlineGraceMs: policy?.offlineGraceMs ?? DEFAULT_OFFLINE_GRACE_MS, gates: grant.gates, entitlementSnapshot: grant.entitlement.ledger === "coins" ? (grant.entitlement.coins ?? 0) : "unlimited", }; return { ...unsigned, signature: sign(leasePayload(unsigned), secret) }; } /** Does this lease actually come from the lender it claims to? */ export function isLeaseAuthentic(lease, secret) { const { signature, ...unsigned } = lease; return secretsMatch(sign(leasePayload(unsigned), secret), signature); } /** * May the borrower serve from this lease right now? * * Three independent stops, in the order that matters: * * 1. **Unsigned** — someone edited the file. Nothing else is worth checking. * 2. **Expired** — `notAfter` passed. Immune to a borrower that never checks in. * 3. **Grace elapsed** — the lender has been unreachable for longer than it * agreed to be trusted for. This is the one that makes "the lender turned * their laptop off" survivable and "the lender revoked me" eventually * binding. */ export function evaluateLease(args) { const now = args.now ?? Date.now(); if (!isLeaseAuthentic(args.lease, args.secret)) { return { usable: false, reason: "unsigned", detail: "lease signature does not match the lender's secret", }; } if (args.lease.notAfter <= now) { return { usable: false, reason: "expired", detail: "the lease's hard expiry has passed", }; } // The lease's own issue time is the first heartbeat: a freshly provisioned // borrower has not failed to check in, it simply has not had to yet. const lastContact = args.lastHeartbeatAt ?? args.lease.issuedAt; const graceDeadline = lastContact + args.lease.offlineGraceMs; if (graceDeadline <= now) { return { usable: false, reason: "grace_elapsed", detail: "the lender has been unreachable for longer than this lease allows", }; } return { usable: true, nextHeartbeatDueAt: lastContact + args.lease.heartbeatEveryMs, }; } /** Should the borrower check in now? */ export function isHeartbeatDue(lease, lastHeartbeatAt, now = Date.now()) { const lastContact = lastHeartbeatAt ?? lease.issuedAt; return now - lastContact >= lease.heartbeatEveryMs; } /** The gates a resident grant must enforce on itself, from its lease. */ export function leasedGates(lease) { return lease.gates; } /** * Assemble what the borrower collects once the lender has authorized. * * Carries no token, by construction. The borrower already holds the verifier * that turns the enclosed code into tokens, and it exchanges the two on its own * machine — so nothing here is worth intercepting, and the lender never holds a * credential for the account it just authorized. * * `accountLabel` is the lender's *suggestion*, not the key the credential ends * up under. The borrower names the account itself — `<peer>-shared` unless * `--label` says otherwise — and refuses to install over an existing one, * because Anthropic quota snapshots are keyed by the bare label and two * accounts sharing one would merge each other's windows. Derived from both * parties' names so that a lender running `share list` and a borrower running * `auth list` are looking at recognisably the same thing. */ export function buildProvisionClaim(args) { const now = args.now ?? Date.now(); if (!args.grant.leaseSecret) { throw new Error(`Grant ${args.grant.id} has no lease secret — attach lease material first.`); } return { code: args.code, state: args.state, accountLabel: `${args.grant.peerLabel}-via-${args.lenderName}`, leaseSecret: args.grant.leaseSecret, lease: issueLease(args.grant, now), lenderUrl: (args.lenderUrl ?? "").replace(/\/+$/, ""), }; }