@singularity-layer/grid 0.7.0 → 0.9.0

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/README.md CHANGED
@@ -132,3 +132,37 @@ try {
132
132
  ## License
133
133
 
134
134
  MIT
135
+
136
+ ## Processors
137
+
138
+ Processors are served by `processors.x402compute.cc`, not the grid, so they have their own client.
139
+
140
+ ```ts
141
+ import { ProcessorsClient } from "@singularity-layer/grid";
142
+
143
+ const p = new ProcessorsClient({ apiKey: process.env.SGL_API_KEY });
144
+
145
+ await p.catalogue(); // public, no credential
146
+ await p.list(); // yours (processors:read)
147
+ await p.deploy({ manifest, code }); // returns the invoke token ONCE
148
+ await p.update("my-processor", { code });
149
+ await p.setListing("my-processor", true);
150
+ await p.run("my-processor", { name: "world" }, invokeToken);
151
+ ```
152
+
153
+ > **`processors:write` is full control** of processors owned by that key's wallet — delete and
154
+ > secrets included, the same as a Cloudflare API token. Mint `processors:read` if you want a
155
+ > credential that cannot change anything. Note that compute keys do not expire, there is no audit
156
+ > log, and **delete is permanent**: the code is wiped and the slug is burned forever.
157
+
158
+ `run()` takes the **invoke token** from `deploy()`, not the API key — the run route is the only one
159
+ with both a money path and an anonymous buyer lane, so it does not read a key as an ownership
160
+ claim. Buyers use `runWithPayment()` with an x402 header instead.
161
+
162
+ ### Upgrading from 0.8.x
163
+
164
+ The six processor methods on `GridClient` (`deployProcessor`, `invokeProcessor`,
165
+ `listProcessors`, `getProcessor`, `deleteProcessor`, `getProcessorLogs`) are **removed**. They
166
+ pointed at `/grid/processors`, which has never existed — every call returned 404 — and their types
167
+ described an older design that was never shipped. Use `ProcessorsClient`. Nothing else changed:
168
+ chat, embeddings, jobs, models, capacity, pricing, reserve and the vault are untouched.
package/dist/index.d.mts CHANGED
@@ -178,87 +178,6 @@ interface ReserveResponse {
178
178
  attestation_verified?: boolean;
179
179
  expires_in_ms: number;
180
180
  }
181
- interface DeployProcessorOptions {
182
- name: string;
183
- code: string;
184
- runtime?: "deno" | "wasm";
185
- memory_mb?: number;
186
- timeout_seconds?: number;
187
- tee_type_required?: string;
188
- metadata?: Record<string, unknown>;
189
- }
190
- interface ProcessorInfo {
191
- id: string;
192
- name: string;
193
- owner_wallet: string;
194
- owner_chain: string;
195
- runtime: string;
196
- memory_mb: number;
197
- timeout_seconds: number;
198
- tee_type_required?: string;
199
- invocation_count: number;
200
- last_invoked_at?: string;
201
- status: string;
202
- code_hash?: string;
203
- deployment_stake_sgl: number;
204
- invoke_url: string;
205
- created_at: string;
206
- updated_at?: string;
207
- metadata?: Record<string, unknown>;
208
- }
209
- interface ProcessorDeployResult {
210
- id: string;
211
- name: string;
212
- runtime: string;
213
- memory_mb: number;
214
- timeout_seconds: number;
215
- status: string;
216
- code_hash: string;
217
- invoke_url: string;
218
- tier: string;
219
- sgl_staked: number;
220
- created_at: string;
221
- }
222
- interface ProcessorInvokeResult {
223
- job_id: string;
224
- processor: string;
225
- status: string;
226
- output?: unknown;
227
- duration_ms?: number;
228
- payment?: {
229
- amount_usd: string;
230
- token: string;
231
- discount_pct: number;
232
- };
233
- tee?: {
234
- node_id: string;
235
- tee_type: string;
236
- attestation_verified: boolean;
237
- };
238
- message?: string;
239
- }
240
- interface ProcessorListResponse {
241
- processors: ProcessorInfo[];
242
- total: number;
243
- page: number;
244
- limit: number;
245
- }
246
- interface ProcessorLogEntry {
247
- id: string;
248
- processor_id: string;
249
- job_id: string;
250
- node_id: string;
251
- duration_ms?: number;
252
- status: string;
253
- error_message?: string;
254
- created_at: string;
255
- }
256
- interface ProcessorLogsResponse {
257
- logs: ProcessorLogEntry[];
258
- total: number;
259
- page: number;
260
- limit: number;
261
- }
262
181
  interface WalletAuth {
263
182
  address: string;
264
183
  chain?: string;
@@ -321,27 +240,86 @@ declare class GridClient {
321
240
  * streaming (toggle off), the whole reply is yielded as a single chunk.
322
241
  */
323
242
  chatCompletionStream(request: ChatCompletionRequest): AsyncGenerator<string, void, unknown>;
324
- private requestWithWalletAuth;
325
- private requestWithPayment;
326
- deployProcessor(wallet: WalletAuth, options: DeployProcessorOptions): Promise<ProcessorDeployResult>;
327
- invokeProcessor(processorName: string, input: Record<string, unknown>, options?: {
328
- paymentHeader?: string;
329
- paymentToken?: "USDC" | "SGL";
330
- }): Promise<ProcessorInvokeResult>;
331
- listProcessors(options?: {
332
- owner?: string;
333
- page?: number;
334
- limit?: number;
335
- }): Promise<ProcessorListResponse>;
336
- getProcessor(processorId: string): Promise<ProcessorInfo>;
337
- deleteProcessor(processorId: string, wallet: WalletAuth): Promise<{
338
- deleted: boolean;
339
- id: string;
243
+ }
244
+
245
+ /**
246
+ * Agent Vault zero-knowledge encrypted agent backup/restore.
247
+ *
248
+ * Pure-JS envelope (noble scrypt + AES-256-GCM), byte-compatible with the
249
+ * agentvault CLI, the pod runner, and the Python SDK:
250
+ * `[4-byte BE header length][JSON header][GCM body, tag appended]`, with the
251
+ * snapshot identity bound into the GCM AAD. Runs in Node AND browsers.
252
+ *
253
+ * Scope: this module encrypts/decrypts BYTES and drives the API. Packing a
254
+ * directory into a tarball is filesystem work — use the `agentvault` CLI or
255
+ * the Python SDK for that, or bring your own archive bytes.
256
+ *
257
+ * Auth: a Singularity compute API key (X-API-Key). Passphrases and plaintext
258
+ * never leave this process.
259
+ */
260
+ declare const VAULT_URL = "https://compute.x402layer.cc";
261
+ interface VaultAad {
262
+ userId: string;
263
+ agentId: string;
264
+ backupId: string;
265
+ formatVersion: 1;
266
+ }
267
+ /** Envelope-encrypt arbitrary bytes under a passphrase (scrypt + AES-256-GCM). */
268
+ declare function encryptEnvelope(plaintext: Uint8Array, passphrase: string, aad: VaultAad): Uint8Array;
269
+ /** Reverse of encryptEnvelope. Throws on wrong passphrase or AAD mismatch. */
270
+ declare function decryptEnvelope(blob: Uint8Array, passphrase: string, aad: VaultAad): Uint8Array;
271
+ declare function parseAadFromKey(r2Key: string): VaultAad;
272
+ interface VaultAgent {
273
+ id: string;
274
+ name: string;
275
+ framework: string;
276
+ source: "local" | "pod";
277
+ pod_order_id: string | null;
278
+ }
279
+ interface VaultSnapshot {
280
+ id: string;
281
+ agent_id: string;
282
+ size_bytes: number;
283
+ sha256: string | null;
284
+ created_at: string;
285
+ }
286
+ interface VaultUsage {
287
+ plan: "free" | "pro";
288
+ planRenewsAt: string | null;
289
+ bytesUsed: number;
290
+ bytesReserved: number;
291
+ maxBytes: number;
292
+ proPriceUsd: number;
293
+ }
294
+ interface VaultClientOptions {
295
+ apiKey: string;
296
+ baseUrl?: string;
297
+ fetchImpl?: typeof fetch;
298
+ }
299
+ declare class VaultClient {
300
+ private readonly base;
301
+ private readonly apiKey;
302
+ private readonly fetchImpl;
303
+ constructor(options: VaultClientOptions);
304
+ private static id;
305
+ private call;
306
+ agents(): Promise<VaultAgent[]>;
307
+ createAgent(name: string, framework: string): Promise<VaultAgent>;
308
+ snapshots(agentId?: string): Promise<VaultSnapshot[]>;
309
+ usage(): Promise<VaultUsage>;
310
+ /** Activate Vault Pro ($3/mo from credits). */
311
+ subscribePro(): Promise<{
312
+ ok: boolean;
313
+ already?: boolean;
340
314
  }>;
341
- getProcessorLogs(processorId: string, wallet: WalletAuth, options?: {
342
- page?: number;
343
- limit?: number;
344
- }): Promise<ProcessorLogsResponse>;
315
+ deleteSnapshot(id: string): Promise<void>;
316
+ /**
317
+ * Encrypt + upload arbitrary payload bytes (e.g. a tarball you packed) as a
318
+ * snapshot of `agentId`. Returns the snapshot id.
319
+ */
320
+ backupBytes(agentId: string, payload: Uint8Array, passphrase: string): Promise<string>;
321
+ /** Download + decrypt a snapshot's payload bytes. */
322
+ restoreBytes(snapshotId: string, passphrase: string): Promise<Uint8Array>;
345
323
  }
346
324
 
347
325
  declare class SGLError extends Error {
@@ -362,4 +340,264 @@ declare class SGLConnectionError extends SGLError {
362
340
  constructor(message: string);
363
341
  }
364
342
 
365
- export { type Attestation, type AttestationProof, type CapacityResponse, type ChatChoice, type ChatCompletionRequest, type ChatCompletionResponse, type ChatContentPart, type ChatMessage, DEFAULT_BASE_URL, type DeployProcessorOptions, type EmbeddingDatum, type EmbeddingRequest, type EmbeddingResponse, GridClient, type GridClientOptions, type JobResponse, type JobResult, type JobSubmission, type ModelInfo, type ModelPricing, type PricingInfo, type ProcessorDeployResult, type ProcessorInfo, type ProcessorInvokeResult, type ProcessorListResponse, type ProcessorLogEntry, type ProcessorLogsResponse, type ReserveResponse, SGLAPIError, SGLAuthError, SGLConnectionError, SGLError, SGLNotFoundError, type TeeCapacity, type WalletAuth };
343
+ /**
344
+ * Singularity Processors.
345
+ *
346
+ * A processor is a function we host: deploy one and you get a paid HTTP endpoint, an OpenAPI
347
+ * document and an MCP server. Buyers pay the PUBLISHER directly in USDC over x402 — the platform
348
+ * never holds it and takes no cut. The publisher pays for compute instead.
349
+ *
350
+ * ─── WHY THIS IS A SEPARATE CLIENT ──────────────────────────────────────────
351
+ * Processors live on their own worker at `https://processors.x402compute.cc`, not on the grid.
352
+ * Until 0.9.0 these methods hung off `GridClient` and pointed at `/grid/processors`, which has
353
+ * never existed — every call 404'd. Fixing that by teaching `GridClient` a second base URL would
354
+ * have meant a per-call host override inside the shared request path that chat, embeddings and
355
+ * jobs all use, which is a real risk to working features for no benefit. A separate client with
356
+ * its own base URL touches none of that.
357
+ *
358
+ * ─── AUTH ───────────────────────────────────────────────────────────────────
359
+ * A compute API key (`x402c_…`) with the `processors:write` scope, sent as `X-API-Key`.
360
+ *
361
+ * `processors:write` is FULL CONTROL of processors owned by that key's wallet, delete and secrets
362
+ * included — the same shape as a Cloudflare API token. If you want a credential that cannot change
363
+ * anything, mint `processors:read`. Three things to know before relying on it: compute keys do not
364
+ * expire, there is no audit log of what a key did, and delete is permanent — the code is wiped and
365
+ * the slug is burned forever, so a leaked key can destroy a name you can never reclaim.
366
+ *
367
+ * Two routes never accept a key: `suspend` (moderation) and `auth-session`. Both need a wallet
368
+ * signature, and neither is a publisher action.
369
+ *
370
+ * ─── RUNNING A PROCESSOR IS NOT DONE WITH THE API KEY ────────────────────────
371
+ * `run()` takes the INVOKE TOKEN that `deploy()` returns, because the run route is the only one
372
+ * with both a money path and an anonymous buyer lane and deliberately does not read an API key as
373
+ * an ownership claim. Anonymous buyers pay with x402 instead; see `runWithPayment`.
374
+ */
375
+ declare const PROCESSORS_BASE_URL = "https://processors.x402compute.cc";
376
+ interface ProcessorsClientOptions {
377
+ /** Compute API key (`x402c_…`) holding `processors:read` or `processors:write`. */
378
+ apiKey?: string;
379
+ /** Override the base URL. Defaults to https://processors.x402compute.cc */
380
+ baseUrl?: string;
381
+ /**
382
+ * Send the API key to a `baseUrl` that is neither the official host nor loopback.
383
+ *
384
+ * Off by default on purpose: see `keyAllowedOnHost`. Set it only when you genuinely run your
385
+ * own processors host and mean to hand it your credential.
386
+ */
387
+ allowKeyOnCustomHost?: boolean;
388
+ timeoutMs?: number;
389
+ }
390
+ /** Limits are declared, not discovered: the runtime hold before each run derives from `timeout_ms`. */
391
+ interface ProcessorLimits {
392
+ timeout_ms: number;
393
+ cpu_ms: number;
394
+ /** Must be >= 1. */
395
+ subrequests: number;
396
+ }
397
+ interface ProcessorSecretDeclaration {
398
+ name: string;
399
+ /** Hosts this secret may be injected at. Every one must also appear in `egress.allow`. */
400
+ hosts?: string[];
401
+ /** Header injection. `format` must contain the literal `{value}` placeholder. */
402
+ inject?: {
403
+ header: string;
404
+ format: string;
405
+ };
406
+ /** `env` makes the value readable by your own code — a deliberate downgrade, opt in per secret. */
407
+ mode?: "env";
408
+ }
409
+ /** One `price_usd` is the price on EVERY chain: all three assets are 6-decimal stablecoins. */
410
+ interface ProcessorPayout {
411
+ /** base58 wallet. Defaults to the deploying wallet. */
412
+ solana?: string;
413
+ /** 0x… — USDC on Base. */
414
+ base?: string;
415
+ /** 0x… — USDG on Robinhood Chain. */
416
+ robinhood?: string;
417
+ }
418
+ interface ProcessorManifest {
419
+ manifest_version: 1;
420
+ /** Lowercase, permanent, and NEVER reusable — `pause` exists so nobody burns one to stop traffic. */
421
+ slug: string;
422
+ name: string;
423
+ description: string;
424
+ lane?: "managed" | "self_hosted" | "pod";
425
+ price_usd?: string;
426
+ methods?: Array<"GET" | "POST">;
427
+ input_schema: Record<string, unknown>;
428
+ output_schema: Record<string, unknown>;
429
+ limits: ProcessorLimits;
430
+ egress?: {
431
+ allow: string[];
432
+ };
433
+ secrets?: ProcessorSecretDeclaration[];
434
+ payout?: ProcessorPayout;
435
+ pricing?: Record<string, unknown>;
436
+ inference?: Record<string, unknown>;
437
+ [key: string]: unknown;
438
+ }
439
+ interface DeployProcessorInput {
440
+ manifest: ProcessorManifest;
441
+ /** A single ES module. Use `bundle` instead if you need imports or npm packages. */
442
+ code?: string;
443
+ /** esbuild output, bundled on YOUR machine. We never run `npm install` for you. */
444
+ bundle?: string;
445
+ files?: Record<string, string>;
446
+ }
447
+ interface ProcessorDeployResult {
448
+ id: string;
449
+ slug: string;
450
+ /** Shown EXACTLY ONCE. Store it — there is no way to read it back, only to rotate it. */
451
+ invoke_token: string;
452
+ listing_state: string;
453
+ note?: string;
454
+ }
455
+ interface ProcessorSummary {
456
+ id: string;
457
+ slug: string;
458
+ lane: string;
459
+ price_micro: number;
460
+ status: string;
461
+ listed?: boolean;
462
+ listing_state?: string;
463
+ run_count?: number;
464
+ last_run_at?: string | null;
465
+ created_at: string;
466
+ config_rev?: number;
467
+ code_hash?: string | null;
468
+ manifest?: ProcessorManifest | null;
469
+ paused_at?: string | null;
470
+ }
471
+ interface ProcessorListResponse {
472
+ processors: ProcessorSummary[];
473
+ /** Present on the owner-scoped list; the wallet the credential resolved to. */
474
+ owner?: string;
475
+ }
476
+ interface ProcessorRun {
477
+ id: string;
478
+ status: string;
479
+ error: string | null;
480
+ run_ms: number | null;
481
+ cpu_ms: number | null;
482
+ attempt_count?: number;
483
+ created_at: string;
484
+ finished_at?: string | null;
485
+ output?: unknown;
486
+ }
487
+ interface ProcessorRunsResponse {
488
+ runs: ProcessorRun[];
489
+ /** Publisher-caused failures only. Platform faults are excluded, so it measures YOUR code. */
490
+ failure_rate_30d?: number;
491
+ runs_30d?: number;
492
+ }
493
+ interface ProcessorEarnings {
494
+ sales?: unknown;
495
+ runtime?: unknown;
496
+ [key: string]: unknown;
497
+ }
498
+ interface ProcessorWebhookRegistration {
499
+ url: string;
500
+ /** Returned EXACTLY ONCE on registration. There is no way to read it back. */
501
+ secret?: string;
502
+ active?: boolean;
503
+ [key: string]: unknown;
504
+ }
505
+ declare class ProcessorsClient {
506
+ private readonly baseUrl;
507
+ private readonly headers;
508
+ private readonly timeout;
509
+ constructor(options?: ProcessorsClientOptions);
510
+ private request;
511
+ /**
512
+ * The public catalogue.
513
+ *
514
+ * Sends NO credential, even when the client holds one. `GET /processors` is owner-scoped when a
515
+ * key is presented and public otherwise, so passing the key here would silently return your own
516
+ * processors instead of the catalogue — the opposite of what the name promises. Use `list()`
517
+ * when you want yours.
518
+ */
519
+ catalogue(): Promise<ProcessorListResponse>;
520
+ /** Processors owned by this key's wallet. Needs `processors:read`. */
521
+ list(): Promise<ProcessorListResponse>;
522
+ /** Owner projection when the key owns it, public projection otherwise. */
523
+ get(slug: string): Promise<ProcessorSummary>;
524
+ /**
525
+ * Deploy. The wallet behind the key becomes `owner_wallet`, which is also the x402 `payTo` and
526
+ * the runtime-billing account — so the key must be minted on a SOLANA wallet or this returns
527
+ * `400 solana_wallet_required`.
528
+ *
529
+ * The `invoke_token` in the response is shown once and never again.
530
+ */
531
+ deploy(input: DeployProcessorInput): Promise<ProcessorDeployResult>;
532
+ /** Push new code, a new manifest, or both. Omitting `manifest` keeps the stored one. */
533
+ update(slug: string, input: {
534
+ manifest?: ProcessorManifest;
535
+ code?: string;
536
+ bundle?: string;
537
+ files?: Record<string, string>;
538
+ }): Promise<{
539
+ slug: string;
540
+ config_rev: number;
541
+ config_changed: boolean;
542
+ }>;
543
+ /**
544
+ * Delete. **Irreversible, and the slug is burned forever** — it can never be reused, by you or
545
+ * anyone. In-flight runs finish first; the code is wiped when they drain.
546
+ */
547
+ delete(slug: string): Promise<{
548
+ slug: string;
549
+ status: string;
550
+ note?: string;
551
+ }>;
552
+ /** Stop or restart traffic WITHOUT losing the slug. This is the switch, not `delete`. */
553
+ setPaused(slug: string, paused: boolean): Promise<unknown>;
554
+ /**
555
+ * List or unlist publicly. Instant, no review step.
556
+ *
557
+ * Unlisting is NOT stopping: an unlisted processor keeps answering anyone holding the URL or an
558
+ * invoke token, earning nothing while still drawing compute from your balance. Use `setPaused`.
559
+ */
560
+ setListing(slug: string, listed: boolean): Promise<unknown>;
561
+ /** Set secret VALUES. Each name must already be declared in `manifest.secrets`. */
562
+ setSecrets(slug: string, values: Record<string, string>): Promise<unknown>;
563
+ /** Mint a new invoke token. The old one stops working immediately. */
564
+ rotateToken(slug: string): Promise<{
565
+ invoke_token: string;
566
+ }>;
567
+ runs(slug: string): Promise<ProcessorRunsResponse>;
568
+ run_(slug: string, runId: string): Promise<ProcessorRun>;
569
+ /** Sales (paid straight to your wallet, with the on-chain tx per row) and runtime spend. */
570
+ earnings(slug: string): Promise<ProcessorEarnings>;
571
+ /** The processor's own key/value state. Read-only from out here, by design. */
572
+ kv(slug: string): Promise<unknown>;
573
+ getWebhook(slug: string): Promise<ProcessorWebhookRegistration>;
574
+ /**
575
+ * Register or replace. We immediately POST a signed verification to the URL: it must answer 2xx
576
+ * or the webhook stays registered-but-inactive and delivers nothing. The signing secret comes
577
+ * back EXACTLY ONCE.
578
+ */
579
+ setWebhook(slug: string, url: string): Promise<ProcessorWebhookRegistration>;
580
+ deleteWebhook(slug: string): Promise<unknown>;
581
+ testWebhook(slug: string): Promise<unknown>;
582
+ /**
583
+ * Run YOUR OWN processor with the invoke token from `deploy()`.
584
+ *
585
+ * Not the API key: the run route deliberately does not read a key as an ownership claim, because
586
+ * it is the only route with both a money path and an anonymous buyer lane. You pay for the
587
+ * compute; nobody pays at call time.
588
+ */
589
+ run(slug: string, input: Record<string, unknown>, invokeToken: string): Promise<unknown>;
590
+ /**
591
+ * Run someone else's processor as a buyer, with an x402 payment header.
592
+ *
593
+ * Call once WITHOUT `paymentHeader` to get the 402 and its `accepts` array — one entry per chain
594
+ * that publisher takes. Match on `network`, pay that entry, and retry with the header.
595
+ *
596
+ * Re-sending the SAME header returns the run that payment already bought and does NOT charge
597
+ * again. That is the recovery path for every failure mode, because **there are no refunds**: the
598
+ * money went straight to the publisher and the platform never held it.
599
+ */
600
+ runWithPayment(slug: string, input: Record<string, unknown>, paymentHeader?: string, acceptNetworks?: Array<"solana" | "base" | "robinhood">): Promise<unknown>;
601
+ }
602
+
603
+ export { type Attestation, type AttestationProof, type CapacityResponse, type ChatChoice, type ChatCompletionRequest, type ChatCompletionResponse, type ChatContentPart, type ChatMessage, DEFAULT_BASE_URL, type DeployProcessorInput, type EmbeddingDatum, type EmbeddingRequest, type EmbeddingResponse, GridClient, type GridClientOptions, type JobResponse, type JobResult, type JobSubmission, type ModelInfo, type ModelPricing, PROCESSORS_BASE_URL, type PricingInfo, type ProcessorDeployResult, type ProcessorEarnings, type ProcessorLimits, type ProcessorListResponse, type ProcessorManifest, type ProcessorPayout, type ProcessorRun, type ProcessorRunsResponse, type ProcessorSecretDeclaration, type ProcessorSummary, type ProcessorWebhookRegistration, ProcessorsClient, type ProcessorsClientOptions, type ReserveResponse, SGLAPIError, SGLAuthError, SGLConnectionError, SGLError, SGLNotFoundError, type TeeCapacity, VAULT_URL, type VaultAad, type VaultAgent, VaultClient, type VaultClientOptions, type VaultSnapshot, type VaultUsage, type WalletAuth, decryptEnvelope, encryptEnvelope, parseAadFromKey };