@openkeyai/sdk 0.1.0 → 0.3.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/dist/index.d.cts CHANGED
@@ -9,6 +9,19 @@
9
9
  */
10
10
  /** Scopes a tool may request and a JWT may carry. */
11
11
  type ToolJwtScope = "keys.read" | "user.read" | "billing.read";
12
+ /**
13
+ * Issuance mode (Phase 13.4 / Phase 19).
14
+ *
15
+ * production — normal user launches an approved tool through the catalog
16
+ * owner_test — the tool's owner launching their own pre-approval scaffold
17
+ * to dogfood the build. Subscription gate waived; only the
18
+ * owner can mint these
19
+ *
20
+ * Tools that want to render a TEST MODE banner read this claim and check
21
+ * for `'owner_test'`. Backwards-compatible: tokens minted before Phase 13.4
22
+ * default to `'production'` on verify.
23
+ */
24
+ type ToolJwtMode = "production" | "owner_test";
12
25
  /** Decoded + verified claim payload. */
13
26
  type ToolJwtClaims = {
14
27
  /** Always exactly "https://openkeyai.com". */
@@ -21,6 +34,11 @@ type ToolJwtClaims = {
21
34
  scopes: ToolJwtScope[];
22
35
  /** Whether the user has an active subscription at issuance time. */
23
36
  subscription_active: boolean;
37
+ /** Mode the JWT was issued under (Phase 13.4). Defaults to 'production'. */
38
+ mode: ToolJwtMode;
39
+ /** Optional display name of the subject (Phase 22). Tools use this to
40
+ * render the real user name in their HubHeader instead of "User <last8>". */
41
+ name?: string;
24
42
  /** Unix seconds. */
25
43
  iat: number;
26
44
  /** Unix seconds. Tokens default to iat + 900 (15 min). */
@@ -49,6 +67,33 @@ type HubCallOptions = {
49
67
  */
50
68
  signal?: AbortSignal;
51
69
  };
70
+ /**
71
+ * Generic proxy call options. The proxy is the Phase 19 endpoint that
72
+ * forwards arbitrary requests to upstream providers with the user's key
73
+ * injected by the hub — the tool never sees the plaintext key.
74
+ */
75
+ type ProxyCallOptions = HubCallOptions & {
76
+ /** Provider slug — matches the hub's provider registry. */
77
+ provider: ProviderSlug;
78
+ /** HTTP method to use against the upstream. */
79
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
80
+ /**
81
+ * Path portion of the upstream URL. Must start with `/`. The hub appends
82
+ * this to the provider's baseUrl. Example: `/v1/chat/completions`.
83
+ */
84
+ path: string;
85
+ /**
86
+ * Request body. If an object, sent as JSON. If a string / Blob /
87
+ * FormData / ReadableStream / ArrayBuffer, sent as-is. Omit for
88
+ * GET / DELETE.
89
+ */
90
+ body?: Record<string, unknown> | unknown[] | string | Blob | FormData | ArrayBuffer | ReadableStream<Uint8Array> | null;
91
+ /**
92
+ * Extra headers to forward upstream. The hub will strip a few it
93
+ * controls (authorization, host, cookie); the rest pass through.
94
+ */
95
+ headers?: Record<string, string>;
96
+ };
52
97
 
53
98
  /**
54
99
  * `session.verify(jwt, opts?)`
@@ -163,6 +208,422 @@ declare class SecureKey {
163
208
  */
164
209
  declare function get(jwt: string, provider: ProviderSlug, opts?: HubCallOptions): Promise<SecureKey>;
165
210
 
211
+ /**
212
+ * Generic proxy call — JSON in, JSON out. Most tools want this.
213
+ *
214
+ * const completion = await proxy.call<ChatCompletionResponse>(token, {
215
+ * provider: "openai",
216
+ * method: "POST",
217
+ * path: "/v1/chat/completions",
218
+ * body: { model: "gpt-4o-mini", messages: [{ role: "user", content: "hi" }] },
219
+ * });
220
+ *
221
+ * Throws typed HubSdkError subclasses for hub-side failures (missing
222
+ * scope, rate limited, etc.) and `ProviderError` for upstream non-2xx
223
+ * (wrong key, model gone, provider 5xx, etc.).
224
+ */
225
+ declare function call<T = unknown>(token: string, opts: ProxyCallOptions): Promise<T>;
226
+ /**
227
+ * Raw-response proxy call. Used when the upstream returns non-JSON —
228
+ * binary audio (TTS), image bytes (DALL-E with response_format=url is
229
+ * JSON, but other endpoints may stream binary), multipart, etc.
230
+ *
231
+ * const response = await proxy.callRaw(token, {
232
+ * provider: "openai",
233
+ * method: "POST",
234
+ * path: "/v1/audio/speech",
235
+ * body: { model: "tts-1", input: "Hello", voice: "alloy" },
236
+ * });
237
+ * const audio = await response.arrayBuffer();
238
+ *
239
+ * Returns the upstream Response with status / headers intact — the tool
240
+ * decides how to consume the body. Throws on hub-side errors before the
241
+ * Response is returned.
242
+ */
243
+ declare function callRaw(token: string, opts: ProxyCallOptions): Promise<Response>;
244
+ /**
245
+ * Streaming proxy call — returns a ReadableStream of the upstream
246
+ * response body. Used for SSE (chat completion streaming), chunked
247
+ * downloads, large response bodies you want to process as they arrive.
248
+ *
249
+ * const stream = await proxy.callStream(token, {
250
+ * provider: "openai",
251
+ * method: "POST",
252
+ * path: "/v1/chat/completions",
253
+ * body: { model: "gpt-4o", messages: [...], stream: true },
254
+ * });
255
+ * const reader = stream.getReader();
256
+ * while (true) {
257
+ * const { value, done } = await reader.read();
258
+ * if (done) break;
259
+ * // parse SSE chunks here — typed SSE iterator comes in M1.5
260
+ * }
261
+ *
262
+ * Hub-side errors (auth, rate-limit) still throw before the stream is
263
+ * returned. Upstream errors are surfaced via the stream itself — the
264
+ * caller should check `response.status` before reading if a provider 4xx
265
+ * matters; in M1.5 we'll wrap this in `ProviderError` if the upstream
266
+ * status is non-2xx before any chunks are read.
267
+ */
268
+ declare function callStream(token: string, opts: ProxyCallOptions): Promise<ReadableStream<Uint8Array>>;
269
+
270
+ /**
271
+ * Typed convenience wrappers for OpenAI's most-used endpoints. Thin
272
+ * wrappers around `proxy.call(token, opts)` — same gates, same errors,
273
+ * just better DX for the common cases.
274
+ *
275
+ * Tools that need an endpoint not covered here can drop to the generic
276
+ * `proxy.call(token, { provider: "openai", method, path, body })`. The
277
+ * proxy supports every OpenAI endpoint without us shipping wrappers for
278
+ * each one.
279
+ *
280
+ * Types here are pragmatic, not exhaustive — we hit the fields the YT
281
+ * thumbnail tool and other early reference tools need. As more tools land
282
+ * we'll grow these. The escape hatch (`proxy.call`) means tools never wait
283
+ * on the SDK to update types when a new model ships.
284
+ */
285
+ type OpenaiImageModel = "gpt-image-1" | "dall-e-3" | "dall-e-2" | (string & {});
286
+ type OpenaiImageSize = "1024x1024" | "1024x1536" | "1536x1024" | "1792x1024" | "1024x1792" | "256x256" | "512x512" | "auto" | (string & {});
287
+ type OpenaiImageQuality = "high" | "medium" | "low" | "auto" | "hd" | "standard" | (string & {});
288
+ type OpenaiImageStyle = "vivid" | "natural" | (string & {});
289
+ type OpenaiImageGenerateParams = {
290
+ model?: OpenaiImageModel;
291
+ prompt: string;
292
+ n?: number;
293
+ size?: OpenaiImageSize;
294
+ quality?: OpenaiImageQuality;
295
+ style?: OpenaiImageStyle;
296
+ /**
297
+ * `b64_json` returns base64-encoded image bytes inline in the response.
298
+ * `url` returns a hosted URL the client can fetch. gpt-image-1 always
299
+ * returns b64.
300
+ */
301
+ response_format?: "url" | "b64_json";
302
+ user?: string;
303
+ background?: "transparent" | "opaque" | "auto" | (string & {});
304
+ moderation?: "low" | "auto" | (string & {});
305
+ output_compression?: number;
306
+ output_format?: "png" | "jpeg" | "webp" | (string & {});
307
+ };
308
+ type OpenaiImageData = {
309
+ url?: string;
310
+ b64_json?: string;
311
+ revised_prompt?: string;
312
+ };
313
+ type OpenaiImageGenerateResponse = {
314
+ created: number;
315
+ data: OpenaiImageData[];
316
+ usage?: {
317
+ total_tokens?: number;
318
+ input_tokens?: number;
319
+ output_tokens?: number;
320
+ input_tokens_details?: {
321
+ text_tokens?: number;
322
+ image_tokens?: number;
323
+ };
324
+ };
325
+ };
326
+ type OpenaiChatRole = "system" | "user" | "assistant" | "tool";
327
+ type OpenaiChatMessageContentPart = {
328
+ type: "text";
329
+ text: string;
330
+ } | {
331
+ type: "image_url";
332
+ image_url: {
333
+ url: string;
334
+ detail?: "low" | "high" | "auto";
335
+ };
336
+ };
337
+ type OpenaiChatMessage = {
338
+ role: OpenaiChatRole;
339
+ content: string | OpenaiChatMessageContentPart[];
340
+ name?: string;
341
+ tool_call_id?: string;
342
+ };
343
+ type OpenaiChatCompletionParams = {
344
+ model: string;
345
+ messages: OpenaiChatMessage[];
346
+ temperature?: number;
347
+ top_p?: number;
348
+ n?: number;
349
+ max_tokens?: number;
350
+ max_completion_tokens?: number;
351
+ stream?: boolean;
352
+ stop?: string | string[];
353
+ presence_penalty?: number;
354
+ frequency_penalty?: number;
355
+ seed?: number;
356
+ response_format?: {
357
+ type: "text" | "json_object" | "json_schema";
358
+ };
359
+ tools?: Array<{
360
+ type: "function";
361
+ function: {
362
+ name: string;
363
+ description?: string;
364
+ parameters?: unknown;
365
+ };
366
+ }>;
367
+ tool_choice?: "none" | "auto" | "required" | {
368
+ type: "function";
369
+ function: {
370
+ name: string;
371
+ };
372
+ };
373
+ user?: string;
374
+ };
375
+ type OpenaiChatCompletionResponse = {
376
+ id: string;
377
+ object: "chat.completion";
378
+ created: number;
379
+ model: string;
380
+ choices: Array<{
381
+ index: number;
382
+ message: {
383
+ role: "assistant";
384
+ content: string | null;
385
+ tool_calls?: unknown[];
386
+ };
387
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | string;
388
+ }>;
389
+ usage?: {
390
+ prompt_tokens: number;
391
+ completion_tokens: number;
392
+ total_tokens: number;
393
+ };
394
+ };
395
+ type OpenaiEmbeddingsParams = {
396
+ model: string;
397
+ input: string | string[];
398
+ dimensions?: number;
399
+ encoding_format?: "float" | "base64";
400
+ user?: string;
401
+ };
402
+ type OpenaiEmbeddingsResponse = {
403
+ object: "list";
404
+ data: Array<{
405
+ object: "embedding";
406
+ index: number;
407
+ embedding: number[];
408
+ }>;
409
+ model: string;
410
+ usage: {
411
+ prompt_tokens: number;
412
+ total_tokens: number;
413
+ };
414
+ };
415
+ type OpenaiTranscriptionParams = {
416
+ file: Blob;
417
+ model: string;
418
+ language?: string;
419
+ prompt?: string;
420
+ response_format?: "json" | "text" | "srt" | "verbose_json" | "vtt";
421
+ temperature?: number;
422
+ /** Filename to attach to the multipart upload. Defaults to "audio.webm". */
423
+ filename?: string;
424
+ };
425
+ type OpenaiTranscriptionResponse = {
426
+ text: string;
427
+ language?: string;
428
+ duration?: number;
429
+ segments?: Array<{
430
+ id: number;
431
+ start: number;
432
+ end: number;
433
+ text: string;
434
+ }>;
435
+ };
436
+ type OpenaiSpeechParams = {
437
+ model: string;
438
+ input: string;
439
+ voice: "alloy" | "echo" | "fable" | "onyx" | "nova" | "shimmer" | (string & {});
440
+ response_format?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm";
441
+ speed?: number;
442
+ instructions?: string;
443
+ };
444
+ /**
445
+ * The OpenAI typed convenience surface. Wraps `proxy.call` / `callRaw` /
446
+ * `callStream` with provider="openai" pre-set and per-endpoint typings.
447
+ *
448
+ * const result = await openai.images.generate(token, {
449
+ * model: "gpt-image-1",
450
+ * prompt: "...",
451
+ * n: 4,
452
+ * });
453
+ */
454
+ declare const openai: {
455
+ readonly images: {
456
+ readonly generate: (token: string, params: OpenaiImageGenerateParams, opts?: HubCallOptions) => Promise<OpenaiImageGenerateResponse>;
457
+ };
458
+ readonly chat: {
459
+ readonly completions: {
460
+ readonly create: (token: string, params: OpenaiChatCompletionParams, opts?: HubCallOptions) => Promise<OpenaiChatCompletionResponse>;
461
+ readonly stream: (token: string, params: Omit<OpenaiChatCompletionParams, "stream">, opts?: HubCallOptions) => Promise<ReadableStream<Uint8Array>>;
462
+ };
463
+ };
464
+ readonly embeddings: {
465
+ readonly create: (token: string, params: OpenaiEmbeddingsParams, opts?: HubCallOptions) => Promise<OpenaiEmbeddingsResponse>;
466
+ };
467
+ readonly audio: {
468
+ readonly transcriptions: {
469
+ readonly create: (token: string, params: OpenaiTranscriptionParams, opts?: HubCallOptions) => Promise<OpenaiTranscriptionResponse>;
470
+ };
471
+ readonly speech: {
472
+ readonly create: (token: string, params: OpenaiSpeechParams, opts?: HubCallOptions) => Promise<Response>;
473
+ };
474
+ };
475
+ };
476
+
477
+ /**
478
+ * Typed convenience wrappers for Anthropic's Messages API.
479
+ *
480
+ * Hub-side handles the per-provider auth quirk (Anthropic uses `x-api-key`
481
+ * not `Authorization: Bearer`) and injects the required
482
+ * `anthropic-version: 2023-06-01` header automatically — see
483
+ * `src/lib/proxy/providers.ts` on the hub for the config.
484
+ */
485
+ type AnthropicTextBlock = {
486
+ type: "text";
487
+ text: string;
488
+ };
489
+ type AnthropicImageBlock = {
490
+ type: "image";
491
+ source: {
492
+ type: "base64";
493
+ media_type: string;
494
+ data: string;
495
+ } | {
496
+ type: "url";
497
+ url: string;
498
+ };
499
+ };
500
+ type AnthropicToolUseBlock = {
501
+ type: "tool_use";
502
+ id: string;
503
+ name: string;
504
+ input: Record<string, unknown>;
505
+ };
506
+ type AnthropicToolResultBlock = {
507
+ type: "tool_result";
508
+ tool_use_id: string;
509
+ content: string | AnthropicTextBlock[];
510
+ is_error?: boolean;
511
+ };
512
+ type AnthropicContentBlock = AnthropicTextBlock | AnthropicImageBlock | AnthropicToolUseBlock | AnthropicToolResultBlock;
513
+ type AnthropicMessage = {
514
+ role: "user" | "assistant";
515
+ content: string | AnthropicContentBlock[];
516
+ };
517
+ type AnthropicMessagesParams = {
518
+ model: string;
519
+ messages: AnthropicMessage[];
520
+ max_tokens: number;
521
+ system?: string | AnthropicTextBlock[];
522
+ temperature?: number;
523
+ top_p?: number;
524
+ top_k?: number;
525
+ stop_sequences?: string[];
526
+ stream?: boolean;
527
+ tools?: Array<{
528
+ name: string;
529
+ description?: string;
530
+ input_schema: Record<string, unknown>;
531
+ }>;
532
+ tool_choice?: {
533
+ type: "auto";
534
+ } | {
535
+ type: "any";
536
+ } | {
537
+ type: "tool";
538
+ name: string;
539
+ };
540
+ metadata?: {
541
+ user_id?: string;
542
+ };
543
+ };
544
+ type AnthropicMessagesResponse = {
545
+ id: string;
546
+ type: "message";
547
+ role: "assistant";
548
+ model: string;
549
+ content: AnthropicContentBlock[];
550
+ stop_reason: "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | string;
551
+ stop_sequence: string | null;
552
+ usage: {
553
+ input_tokens: number;
554
+ output_tokens: number;
555
+ cache_creation_input_tokens?: number;
556
+ cache_read_input_tokens?: number;
557
+ };
558
+ };
559
+ declare const anthropic: {
560
+ readonly messages: {
561
+ readonly create: (token: string, params: AnthropicMessagesParams, opts?: HubCallOptions) => Promise<AnthropicMessagesResponse>;
562
+ readonly stream: (token: string, params: Omit<AnthropicMessagesParams, "stream">, opts?: HubCallOptions) => Promise<ReadableStream<Uint8Array>>;
563
+ };
564
+ };
565
+
566
+ /**
567
+ * Typed convenience wrappers for Replicate's Predictions API.
568
+ *
569
+ * Replicate uses an async lifecycle: POST to create a prediction, GET to
570
+ * poll its status, optionally cancel. We surface all three plus a small
571
+ * `predictions.run()` helper that polls until the prediction is final.
572
+ *
573
+ * For per-model deployments (Replicate's hosted models with stable URLs),
574
+ * use `proxy.call(token, { provider: "replicate", path: "/v1/models/.../predictions", ... })`
575
+ * directly — the generic passthrough handles every Replicate endpoint we
576
+ * haven't typed here yet.
577
+ */
578
+ type ReplicatePredictionStatus = "starting" | "processing" | "succeeded" | "failed" | "canceled";
579
+ type ReplicatePrediction<TOutput = unknown> = {
580
+ id: string;
581
+ version: string;
582
+ status: ReplicatePredictionStatus;
583
+ input: Record<string, unknown>;
584
+ output: TOutput | null;
585
+ error: string | null;
586
+ logs: string;
587
+ created_at: string;
588
+ started_at: string | null;
589
+ completed_at: string | null;
590
+ urls: {
591
+ get: string;
592
+ cancel: string;
593
+ stream?: string;
594
+ };
595
+ metrics?: {
596
+ predict_time?: number;
597
+ };
598
+ };
599
+ type ReplicateCreatePredictionParams = {
600
+ /** Model version hash. Mutually exclusive with the model-deployment URL form. */
601
+ version: string;
602
+ input: Record<string, unknown>;
603
+ webhook?: string;
604
+ webhook_events_filter?: Array<"start" | "output" | "logs" | "completed">;
605
+ stream?: boolean;
606
+ };
607
+ declare const replicate: {
608
+ readonly predictions: {
609
+ readonly create: <TOutput = unknown>(token: string, params: ReplicateCreatePredictionParams, opts?: HubCallOptions) => Promise<ReplicatePrediction<TOutput>>;
610
+ readonly get: <TOutput = unknown>(token: string, predictionId: string, opts?: HubCallOptions) => Promise<ReplicatePrediction<TOutput>>;
611
+ readonly cancel: <TOutput = unknown>(token: string, predictionId: string, opts?: HubCallOptions) => Promise<ReplicatePrediction<TOutput>>;
612
+ /**
613
+ * Convenience: create + poll until the prediction reaches a terminal
614
+ * status. Polls every `pollIntervalMs` (default 1000ms) with the
615
+ * provided AbortSignal honoured.
616
+ *
617
+ * For long-running predictions consider using webhooks via
618
+ * `create({ webhook, webhook_events_filter })` instead so you're not
619
+ * holding open a long fetch.
620
+ */
621
+ readonly run: <TOutput = unknown>(token: string, params: ReplicateCreatePredictionParams, opts?: HubCallOptions & {
622
+ pollIntervalMs?: number;
623
+ }) => Promise<ReplicatePrediction<TOutput>>;
624
+ };
625
+ };
626
+
166
627
  /**
167
628
  * Typed errors.
168
629
  *
@@ -183,7 +644,7 @@ declare function get(jwt: string, provider: ProviderSlug, opts?: HubCallOptions)
183
644
  * else throw e;
184
645
  * }
185
646
  */
186
- type HubSdkErrorCode = "missing_token" | "bad_token" | "missing_scope" | "subscription_inactive" | "tool_not_found" | "not_subscribed" | "provider_not_granted" | "rate_limited" | "key_not_found" | "internal" | "network" | "secure_key_consumed";
647
+ type HubSdkErrorCode = "missing_token" | "bad_token" | "missing_scope" | "subscription_inactive" | "tool_not_found" | "not_subscribed" | "provider_not_granted" | "rate_limited" | "key_not_found" | "internal" | "network" | "secure_key_consumed" | "provider_error" | "provider_not_configured";
187
648
  /** Base class for every typed error in the SDK. */
188
649
  declare class HubSdkError extends Error {
189
650
  readonly code: HubSdkErrorCode;
@@ -228,28 +689,75 @@ declare class NetworkError extends HubSdkError {
228
689
  declare class SecureKeyConsumedError extends HubSdkError {
229
690
  constructor();
230
691
  }
692
+ /**
693
+ * The proxy was asked to forward to a provider the hub doesn't have
694
+ * configured. Distinct from `provider_not_granted` (which means the tool
695
+ * isn't permitted to use a known provider). Fix: add the provider to
696
+ * `src/lib/proxy/providers.ts` on the hub, or use a registered slug.
697
+ */
698
+ declare class ProviderNotConfiguredError extends HubSdkError {
699
+ constructor(provider: string);
700
+ }
701
+ /**
702
+ * The upstream provider (OpenAI / Anthropic / etc.) returned a non-2xx
703
+ * response. The hub relays it unchanged — `body` holds the parsed JSON
704
+ * body if the response was JSON, or the raw text otherwise, so the tool
705
+ * can inspect the provider's native error shape.
706
+ *
707
+ * This is the catch-all for "the platform did its job correctly; the
708
+ * upstream rejected the request" — wrong key (relayed 401), model not
709
+ * available (provider 400), upstream rate limit (provider 429), etc.
710
+ *
711
+ * Distinguish from `RateLimitedError` (hub-side rate limit) by checking
712
+ * `instanceof` first; the typed hub errors take precedence.
713
+ */
714
+ declare class ProviderError extends HubSdkError {
715
+ /** The provider slug we tried to call. */
716
+ readonly provider: string;
717
+ /** The path on the provider that returned non-2xx. */
718
+ readonly path: string;
719
+ /**
720
+ * The upstream response body. Parsed as JSON when the upstream's
721
+ * content-type was JSON; raw text otherwise.
722
+ */
723
+ readonly body: unknown;
724
+ /** The upstream response status code (relayed unchanged). */
725
+ readonly upstreamStatus: number;
726
+ constructor(provider: string, path: string, upstreamStatus: number, body: unknown);
727
+ }
231
728
 
232
729
  /**
233
730
  * `@openkeyai/sdk` — public entry.
234
731
  *
235
732
  * Tools install this and import only from the package root:
236
733
  *
237
- * import { session, keys, SecureKey, SubscriptionInactiveError } from "@openkeyai/sdk";
734
+ * import { session, openai, anthropic, proxy, ProviderError } from "@openkeyai/sdk";
238
735
  *
239
- * The five-module surface (session / keys / user / billing / webhooks) is
240
- * defined in
736
+ * The seven-module surface (session / keys / proxy / openai / anthropic /
737
+ * replicate / webhooks) is defined in
241
738
  * https://github.com/Scott-Builds-AI/hub/blob/main/docs/TOOL_SDK.md
242
739
  *
243
- * Status by module in 0.1.0:
740
+ * Status by module in 0.2.0:
244
741
  * - session.verify ✓
245
- * - keys.get → SecureKey ✓
246
- * - user — deferred until the hub ships /api/me (issue TBD)
742
+ * - keys.get → SecureKey ✓ (kept for endpoints the proxy doesn't typeset yet)
743
+ * - proxy.call / .callRaw / .callStream ✓ ← Phase 19 universal passthrough
744
+ * - openai.{images,chat,embeddings,audio} ✓ ← typed convenience
745
+ * - anthropic.messages ✓ ← typed convenience
746
+ * - replicate.predictions ✓ ← typed convenience
747
+ * - user — deferred until the hub ships /api/me
247
748
  * - billing — deferred until the hub ships /api/billing/status
248
- * - webhooks — deferred until Phase 16 (the hub's webhook delivery layer)
749
+ * - webhooks — deferred until Phase 16 (hub's webhook delivery layer)
249
750
  *
250
751
  * Internal helpers live under `_internal/`. They are NOT part of the
251
752
  * public API and may change without notice — the tool-manifest scanner
252
753
  * (Phase 9) treats `@openkeyai/sdk/_internal` imports as a CI failure.
754
+ *
755
+ * Migration note (Phase 19):
756
+ * The `keys.get(jwt, provider).use(callback)` SecureKey pattern still
757
+ * works and is the only path for endpoints we haven't typed in the
758
+ * proxy yet. For canonical model calls (images.generate, chat,
759
+ * embeddings, etc.) prefer the proxy — the plaintext key never enters
760
+ * your Worker process.
253
761
  */
254
762
 
255
763
  /** session module — JWT verification + (future) refresh. */
@@ -260,8 +768,18 @@ declare const session: {
260
768
  declare const keys: {
261
769
  readonly get: typeof get;
262
770
  };
771
+ /**
772
+ * proxy module — Phase 19 zero-trust universal forwarder. Plaintext keys
773
+ * never leave the hub. Supports any HTTP method, any path on any
774
+ * registered provider, any body shape, streaming and binary responses.
775
+ */
776
+ declare const proxy: {
777
+ readonly call: typeof call;
778
+ readonly callRaw: typeof callRaw;
779
+ readonly callStream: typeof callStream;
780
+ };
263
781
 
264
782
  /** Bumped on each release. Tools log this on boot. */
265
- declare const SDK_VERSION = "0.1.0";
783
+ declare const SDK_VERSION = "0.2.0";
266
784
 
267
- export { BadTokenError, type HubCallOptions, HubSdkError, type HubSdkErrorCode, InternalError, KeyNotFoundError, MissingScopeError, MissingTokenError, NetworkError, NotSubscribedError, ProviderNotGrantedError, type ProviderSlug, RateLimitedError, SDK_VERSION, SecureKey, SecureKeyConsumedError, SubscriptionInactiveError, type ToolJwtClaims, type ToolJwtScope, ToolNotFoundError, keys, session };
785
+ export { type AnthropicContentBlock, type AnthropicImageBlock, type AnthropicMessage, type AnthropicMessagesParams, type AnthropicMessagesResponse, type AnthropicTextBlock, type AnthropicToolResultBlock, type AnthropicToolUseBlock, BadTokenError, type HubCallOptions, HubSdkError, type HubSdkErrorCode, InternalError, KeyNotFoundError, MissingScopeError, MissingTokenError, NetworkError, NotSubscribedError, type OpenaiChatCompletionParams, type OpenaiChatCompletionResponse, type OpenaiChatMessage, type OpenaiChatMessageContentPart, type OpenaiChatRole, type OpenaiEmbeddingsParams, type OpenaiEmbeddingsResponse, type OpenaiImageData, type OpenaiImageGenerateParams, type OpenaiImageGenerateResponse, type OpenaiImageModel, type OpenaiImageQuality, type OpenaiImageSize, type OpenaiImageStyle, type OpenaiSpeechParams, type OpenaiTranscriptionParams, type OpenaiTranscriptionResponse, ProviderError, ProviderNotConfiguredError, ProviderNotGrantedError, type ProviderSlug, type ProxyCallOptions, RateLimitedError, type ReplicateCreatePredictionParams, type ReplicatePrediction, type ReplicatePredictionStatus, SDK_VERSION, SecureKey, SecureKeyConsumedError, SubscriptionInactiveError, type ToolJwtClaims, type ToolJwtMode, type ToolJwtScope, ToolNotFoundError, anthropic, keys, openai, proxy, replicate, session };