@zeke-02/tinfoil 0.0.2 → 0.0.4

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.
Files changed (43) hide show
  1. package/dist/ai-sdk-provider.js +8 -3
  2. package/dist/config.d.ts +4 -8
  3. package/dist/config.js +4 -8
  4. package/dist/encrypted-body-fetch.d.ts +3 -2
  5. package/dist/encrypted-body-fetch.js +31 -16
  6. package/dist/esm/{ai-sdk-provider.js → ai-sdk-provider.mjs} +10 -5
  7. package/dist/esm/config.d.ts +4 -8
  8. package/dist/esm/{config.js → config.mjs} +4 -8
  9. package/dist/esm/encrypted-body-fetch.d.ts +3 -2
  10. package/dist/esm/{encrypted-body-fetch.js → encrypted-body-fetch.mjs} +32 -17
  11. package/dist/esm/index.browser.mjs +8 -0
  12. package/dist/esm/index.d.ts +1 -0
  13. package/dist/esm/{index.js → index.mjs} +8 -7
  14. package/dist/esm/router.d.ts +11 -0
  15. package/dist/esm/router.mjs +33 -0
  16. package/dist/esm/secure-client.d.ts +3 -2
  17. package/dist/esm/{secure-client.js → secure-client.mjs} +36 -5
  18. package/dist/esm/{secure-fetch.browser.js → secure-fetch.browser.mjs} +1 -1
  19. package/dist/esm/{secure-fetch.js → secure-fetch.mjs} +3 -3
  20. package/dist/esm/{tinfoilai.js → tinfoilai.mjs} +8 -6
  21. package/dist/esm/unverified-client.d.ts +2 -2
  22. package/dist/esm/unverified-client.mjs +61 -0
  23. package/dist/esm/verifier.d.ts +1 -1
  24. package/dist/esm/{verifier.js → verifier.mjs} +10 -7
  25. package/dist/esm/wasm-exec.mjs +668 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +3 -1
  28. package/dist/router.d.ts +11 -0
  29. package/dist/router.js +36 -0
  30. package/dist/secure-client.d.ts +3 -2
  31. package/dist/secure-client.js +33 -2
  32. package/dist/tinfoilai.js +5 -3
  33. package/dist/unverified-client.d.ts +2 -2
  34. package/dist/unverified-client.js +30 -2
  35. package/dist/verifier.d.ts +1 -1
  36. package/dist/verifier.js +7 -4
  37. package/package.json +22 -16
  38. package/dist/esm/index.browser.js +0 -8
  39. package/dist/esm/unverified-client.js +0 -33
  40. /package/dist/esm/__tests__/{test-utils.js → test-utils.mjs} +0 -0
  41. /package/dist/esm/{env.js → env.mjs} +0 -0
  42. /package/dist/esm/{fetch-adapter.js → fetch-adapter.mjs} +0 -0
  43. /package/dist/esm/{pinned-tls-fetch.js → pinned-tls-fetch.mjs} +0 -0
@@ -5,8 +5,8 @@ const openai_compatible_1 = require("@ai-sdk/openai-compatible");
5
5
  const config_1 = require("./config");
6
6
  const secure_client_1 = require("./secure-client");
7
7
  async function createTinfoilAI(apiKey, options = {}) {
8
- const baseURL = options.baseURL || config_1.TINFOIL_CONFIG.INFERENCE_BASE_URL;
9
- const enclaveURL = options.enclaveURL || config_1.TINFOIL_CONFIG.ENCLAVE_URL;
8
+ const baseURL = options.baseURL;
9
+ const enclaveURL = options.enclaveURL;
10
10
  const configRepo = options.configRepo || config_1.TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
11
11
  const secureClient = new secure_client_1.SecureClient({
12
12
  baseURL,
@@ -14,9 +14,14 @@ async function createTinfoilAI(apiKey, options = {}) {
14
14
  configRepo,
15
15
  });
16
16
  await secureClient.ready();
17
+ // Get the baseURL from SecureClient after initialization
18
+ const finalBaseURL = baseURL || secureClient.getBaseURL();
19
+ if (!finalBaseURL) {
20
+ throw new Error("Unable to determine baseURL for AI SDK provider");
21
+ }
17
22
  return (0, openai_compatible_1.createOpenAICompatible)({
18
23
  name: "tinfoil",
19
- baseURL: baseURL.replace(/\/$/, ""),
24
+ baseURL: finalBaseURL,
20
25
  apiKey: apiKey,
21
26
  fetch: secureClient.fetch,
22
27
  });
package/dist/config.d.ts CHANGED
@@ -2,16 +2,12 @@
2
2
  * Configuration constants for the Tinfoil Node SDK
3
3
  */
4
4
  export declare const TINFOIL_CONFIG: {
5
- /**
6
- * The base URL for the Tinfoil router API
7
- */
8
- readonly INFERENCE_BASE_URL: "https://router.inf6.tinfoil.sh/v1/";
9
- /**
10
- * The URL for enclave key discovery and attestation endpoints
11
- */
12
- readonly ENCLAVE_URL: "https://router.inf6.tinfoil.sh";
13
5
  /**
14
6
  * The GitHub repository for code attestation verification
15
7
  */
16
8
  readonly INFERENCE_PROXY_REPO: "tinfoilsh/confidential-model-router";
9
+ /**
10
+ * The ATC (Attestation and Trust Center) API URL for fetching available routers
11
+ */
12
+ readonly ATC_API_URL: "https://atc.tinfoil.sh/routers";
17
13
  };
package/dist/config.js CHANGED
@@ -5,16 +5,12 @@ exports.TINFOIL_CONFIG = void 0;
5
5
  * Configuration constants for the Tinfoil Node SDK
6
6
  */
7
7
  exports.TINFOIL_CONFIG = {
8
- /**
9
- * The base URL for the Tinfoil router API
10
- */
11
- INFERENCE_BASE_URL: "https://router.inf6.tinfoil.sh/v1/",
12
- /**
13
- * The URL for enclave key discovery and attestation endpoints
14
- */
15
- ENCLAVE_URL: "https://router.inf6.tinfoil.sh",
16
8
  /**
17
9
  * The GitHub repository for code attestation verification
18
10
  */
19
11
  INFERENCE_PROXY_REPO: "tinfoilsh/confidential-model-router",
12
+ /**
13
+ * The ATC (Attestation and Trust Center) API URL for fetching available routers
14
+ */
15
+ ATC_API_URL: "https://atc.tinfoil.sh/routers",
20
16
  };
@@ -1,8 +1,9 @@
1
+ import type { Transport as EhbpTransport } from "@zeke-02/ehbp";
1
2
  export declare function getHPKEKey(enclaveURL: string): Promise<CryptoKey>;
2
3
  export declare function normalizeEncryptedBodyRequestArgs(input: RequestInfo | URL, init?: RequestInit): {
3
4
  url: string;
4
5
  init?: RequestInit;
5
6
  };
6
- export declare function encryptedBodyRequest(input: RequestInfo | URL, hpkePublicKey?: string, init?: RequestInit, enclaveURL?: string): Promise<Response>;
7
+ export declare function encryptedBodyRequest(input: RequestInfo | URL, hpkePublicKey?: string, init?: RequestInit, enclaveURL?: string, transportInstance?: EhbpTransport): Promise<Response>;
7
8
  export declare function createEncryptedBodyFetch(baseURL: string, hpkePublicKey?: string, enclaveURL?: string): typeof fetch;
8
- export declare function resetTransport(): void;
9
+ export declare function getTransportForOrigin(origin: string, keyOrigin: string): Promise<EhbpTransport>;
@@ -4,12 +4,12 @@ exports.getHPKEKey = getHPKEKey;
4
4
  exports.normalizeEncryptedBodyRequestArgs = normalizeEncryptedBodyRequestArgs;
5
5
  exports.encryptedBodyRequest = encryptedBodyRequest;
6
6
  exports.createEncryptedBodyFetch = createEncryptedBodyFetch;
7
- exports.resetTransport = resetTransport;
7
+ exports.getTransportForOrigin = getTransportForOrigin;
8
8
  const ehbp_1 = require("@zeke-02/ehbp");
9
9
  const fetch_adapter_1 = require("./fetch-adapter");
10
- let transport = null;
11
10
  // Public API
12
11
  async function getHPKEKey(enclaveURL) {
12
+ const url = new URL(enclaveURL);
13
13
  const keysURL = new URL(ehbp_1.PROTOCOL.KEYS_PATH, enclaveURL);
14
14
  if (keysURL.protocol !== "https:") {
15
15
  throw new Error(`HTTPS is required for remote key retrieval. Invalid protocol: ${keysURL.protocol}`);
@@ -47,34 +47,49 @@ function normalizeEncryptedBodyRequestArgs(input, init) {
47
47
  init: { ...derivedInit, ...init },
48
48
  };
49
49
  }
50
- async function encryptedBodyRequest(input, hpkePublicKey, init, enclaveURL) {
50
+ async function encryptedBodyRequest(input, hpkePublicKey, init, enclaveURL, transportInstance) {
51
51
  const { url: requestUrl, init: requestInit } = normalizeEncryptedBodyRequestArgs(input, init);
52
- const u = new URL(requestUrl);
53
- const { origin } = u;
54
- const keyOrigin = enclaveURL ? new URL(enclaveURL).origin : origin;
55
- if (!transport) {
56
- transport = getTransportForOrigin(origin, keyOrigin);
52
+ let actualTransport;
53
+ if (transportInstance) {
54
+ // Use provided transport instance
55
+ actualTransport = transportInstance;
56
+ }
57
+ else {
58
+ // Create a new transport for this request
59
+ const u = new URL(requestUrl);
60
+ const { origin } = u;
61
+ const keyOrigin = enclaveURL ? new URL(enclaveURL).origin : origin;
62
+ actualTransport = await getTransportForOrigin(origin, keyOrigin);
57
63
  }
58
- const transportInstance = await transport;
59
64
  if (hpkePublicKey) {
60
- const transportKeyHash = await transportInstance.getServerPublicKeyHex();
65
+ const transportKeyHash = await actualTransport.getServerPublicKeyHex();
61
66
  if (transportKeyHash !== hpkePublicKey) {
62
- transport = null;
63
67
  throw new Error(`HPKE public key mismatch. Expected: ${hpkePublicKey}, Got: ${transportKeyHash}`);
64
68
  }
65
69
  }
66
- return transportInstance.request(requestUrl, requestInit);
70
+ return actualTransport.request(requestUrl, requestInit);
67
71
  }
68
72
  function createEncryptedBodyFetch(baseURL, hpkePublicKey, enclaveURL) {
73
+ // Create a dedicated transport instance for this fetch function
74
+ let transportPromise = null;
75
+ const getOrCreateTransport = async () => {
76
+ if (!transportPromise) {
77
+ const baseUrl = new URL(baseURL);
78
+ const keyOrigin = enclaveURL
79
+ ? new URL(enclaveURL).origin
80
+ : baseUrl.origin;
81
+ transportPromise = getTransportForOrigin(baseUrl.origin, keyOrigin);
82
+ }
83
+ return transportPromise;
84
+ };
69
85
  return (async (input, init) => {
70
86
  const normalized = normalizeEncryptedBodyRequestArgs(input, init);
71
87
  const targetUrl = new URL(normalized.url, baseURL);
72
- return encryptedBodyRequest(targetUrl.toString(), hpkePublicKey, normalized.init, enclaveURL);
88
+ // Get the dedicated transport instance for this fetch function
89
+ const transportInstance = await getOrCreateTransport();
90
+ return encryptedBodyRequest(targetUrl.toString(), hpkePublicKey, normalized.init, enclaveURL, transportInstance);
73
91
  });
74
92
  }
75
- function resetTransport() {
76
- transport = null;
77
- }
78
93
  async function getTransportForOrigin(origin, keyOrigin) {
79
94
  if (typeof globalThis !== "undefined") {
80
95
  const isSecure = globalThis.isSecureContext !== false;
@@ -1,9 +1,9 @@
1
1
  import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
2
- import { TINFOIL_CONFIG } from "./config";
3
- import { SecureClient } from "./secure-client";
2
+ import { TINFOIL_CONFIG } from "./config.mjs";
3
+ import { SecureClient } from "./secure-client.mjs";
4
4
  export async function createTinfoilAI(apiKey, options = {}) {
5
- const baseURL = options.baseURL || TINFOIL_CONFIG.INFERENCE_BASE_URL;
6
- const enclaveURL = options.enclaveURL || TINFOIL_CONFIG.ENCLAVE_URL;
5
+ const baseURL = options.baseURL;
6
+ const enclaveURL = options.enclaveURL;
7
7
  const configRepo = options.configRepo || TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
8
8
  const secureClient = new SecureClient({
9
9
  baseURL,
@@ -11,9 +11,14 @@ export async function createTinfoilAI(apiKey, options = {}) {
11
11
  configRepo,
12
12
  });
13
13
  await secureClient.ready();
14
+ // Get the baseURL from SecureClient after initialization
15
+ const finalBaseURL = baseURL || secureClient.getBaseURL();
16
+ if (!finalBaseURL) {
17
+ throw new Error("Unable to determine baseURL for AI SDK provider");
18
+ }
14
19
  return createOpenAICompatible({
15
20
  name: "tinfoil",
16
- baseURL: baseURL.replace(/\/$/, ""),
21
+ baseURL: finalBaseURL,
17
22
  apiKey: apiKey,
18
23
  fetch: secureClient.fetch,
19
24
  });
@@ -2,16 +2,12 @@
2
2
  * Configuration constants for the Tinfoil Node SDK
3
3
  */
4
4
  export declare const TINFOIL_CONFIG: {
5
- /**
6
- * The base URL for the Tinfoil router API
7
- */
8
- readonly INFERENCE_BASE_URL: "https://router.inf6.tinfoil.sh/v1/";
9
- /**
10
- * The URL for enclave key discovery and attestation endpoints
11
- */
12
- readonly ENCLAVE_URL: "https://router.inf6.tinfoil.sh";
13
5
  /**
14
6
  * The GitHub repository for code attestation verification
15
7
  */
16
8
  readonly INFERENCE_PROXY_REPO: "tinfoilsh/confidential-model-router";
9
+ /**
10
+ * The ATC (Attestation and Trust Center) API URL for fetching available routers
11
+ */
12
+ readonly ATC_API_URL: "https://atc.tinfoil.sh/routers";
17
13
  };
@@ -2,16 +2,12 @@
2
2
  * Configuration constants for the Tinfoil Node SDK
3
3
  */
4
4
  export const TINFOIL_CONFIG = {
5
- /**
6
- * The base URL for the Tinfoil router API
7
- */
8
- INFERENCE_BASE_URL: "https://router.inf6.tinfoil.sh/v1/",
9
- /**
10
- * The URL for enclave key discovery and attestation endpoints
11
- */
12
- ENCLAVE_URL: "https://router.inf6.tinfoil.sh",
13
5
  /**
14
6
  * The GitHub repository for code attestation verification
15
7
  */
16
8
  INFERENCE_PROXY_REPO: "tinfoilsh/confidential-model-router",
9
+ /**
10
+ * The ATC (Attestation and Trust Center) API URL for fetching available routers
11
+ */
12
+ ATC_API_URL: "https://atc.tinfoil.sh/routers",
17
13
  };
@@ -1,8 +1,9 @@
1
+ import type { Transport as EhbpTransport } from "@zeke-02/ehbp";
1
2
  export declare function getHPKEKey(enclaveURL: string): Promise<CryptoKey>;
2
3
  export declare function normalizeEncryptedBodyRequestArgs(input: RequestInfo | URL, init?: RequestInit): {
3
4
  url: string;
4
5
  init?: RequestInit;
5
6
  };
6
- export declare function encryptedBodyRequest(input: RequestInfo | URL, hpkePublicKey?: string, init?: RequestInit, enclaveURL?: string): Promise<Response>;
7
+ export declare function encryptedBodyRequest(input: RequestInfo | URL, hpkePublicKey?: string, init?: RequestInit, enclaveURL?: string, transportInstance?: EhbpTransport): Promise<Response>;
7
8
  export declare function createEncryptedBodyFetch(baseURL: string, hpkePublicKey?: string, enclaveURL?: string): typeof fetch;
8
- export declare function resetTransport(): void;
9
+ export declare function getTransportForOrigin(origin: string, keyOrigin: string): Promise<EhbpTransport>;
@@ -1,8 +1,8 @@
1
1
  import { Identity, Transport, PROTOCOL } from "@zeke-02/ehbp";
2
- import { getFetch } from "./fetch-adapter";
3
- let transport = null;
2
+ import { getFetch } from "./fetch-adapter.mjs";
4
3
  // Public API
5
4
  export async function getHPKEKey(enclaveURL) {
5
+ const url = new URL(enclaveURL);
6
6
  const keysURL = new URL(PROTOCOL.KEYS_PATH, enclaveURL);
7
7
  if (keysURL.protocol !== "https:") {
8
8
  throw new Error(`HTTPS is required for remote key retrieval. Invalid protocol: ${keysURL.protocol}`);
@@ -40,35 +40,50 @@ export function normalizeEncryptedBodyRequestArgs(input, init) {
40
40
  init: { ...derivedInit, ...init },
41
41
  };
42
42
  }
43
- export async function encryptedBodyRequest(input, hpkePublicKey, init, enclaveURL) {
43
+ export async function encryptedBodyRequest(input, hpkePublicKey, init, enclaveURL, transportInstance) {
44
44
  const { url: requestUrl, init: requestInit } = normalizeEncryptedBodyRequestArgs(input, init);
45
- const u = new URL(requestUrl);
46
- const { origin } = u;
47
- const keyOrigin = enclaveURL ? new URL(enclaveURL).origin : origin;
48
- if (!transport) {
49
- transport = getTransportForOrigin(origin, keyOrigin);
45
+ let actualTransport;
46
+ if (transportInstance) {
47
+ // Use provided transport instance
48
+ actualTransport = transportInstance;
49
+ }
50
+ else {
51
+ // Create a new transport for this request
52
+ const u = new URL(requestUrl);
53
+ const { origin } = u;
54
+ const keyOrigin = enclaveURL ? new URL(enclaveURL).origin : origin;
55
+ actualTransport = await getTransportForOrigin(origin, keyOrigin);
50
56
  }
51
- const transportInstance = await transport;
52
57
  if (hpkePublicKey) {
53
- const transportKeyHash = await transportInstance.getServerPublicKeyHex();
58
+ const transportKeyHash = await actualTransport.getServerPublicKeyHex();
54
59
  if (transportKeyHash !== hpkePublicKey) {
55
- transport = null;
56
60
  throw new Error(`HPKE public key mismatch. Expected: ${hpkePublicKey}, Got: ${transportKeyHash}`);
57
61
  }
58
62
  }
59
- return transportInstance.request(requestUrl, requestInit);
63
+ return actualTransport.request(requestUrl, requestInit);
60
64
  }
61
65
  export function createEncryptedBodyFetch(baseURL, hpkePublicKey, enclaveURL) {
66
+ // Create a dedicated transport instance for this fetch function
67
+ let transportPromise = null;
68
+ const getOrCreateTransport = async () => {
69
+ if (!transportPromise) {
70
+ const baseUrl = new URL(baseURL);
71
+ const keyOrigin = enclaveURL
72
+ ? new URL(enclaveURL).origin
73
+ : baseUrl.origin;
74
+ transportPromise = getTransportForOrigin(baseUrl.origin, keyOrigin);
75
+ }
76
+ return transportPromise;
77
+ };
62
78
  return (async (input, init) => {
63
79
  const normalized = normalizeEncryptedBodyRequestArgs(input, init);
64
80
  const targetUrl = new URL(normalized.url, baseURL);
65
- return encryptedBodyRequest(targetUrl.toString(), hpkePublicKey, normalized.init, enclaveURL);
81
+ // Get the dedicated transport instance for this fetch function
82
+ const transportInstance = await getOrCreateTransport();
83
+ return encryptedBodyRequest(targetUrl.toString(), hpkePublicKey, normalized.init, enclaveURL, transportInstance);
66
84
  });
67
85
  }
68
- export function resetTransport() {
69
- transport = null;
70
- }
71
- async function getTransportForOrigin(origin, keyOrigin) {
86
+ export async function getTransportForOrigin(origin, keyOrigin) {
72
87
  if (typeof globalThis !== "undefined") {
73
88
  const isSecure = globalThis.isSecureContext !== false;
74
89
  const hasSubtle = !!(globalThis.crypto && globalThis.crypto.subtle);
@@ -0,0 +1,8 @@
1
+ // Browser-safe entry point: avoids Node built-ins
2
+ export { TinfoilAI } from "./tinfoilai.mjs";
3
+ export { TinfoilAI as default } from "./tinfoilai.mjs";
4
+ export * from "./verifier.mjs";
5
+ export * from "./ai-sdk-provider.mjs";
6
+ export * from "./config.mjs";
7
+ export { SecureClient } from "./secure-client.mjs";
8
+ export { UnverifiedClient } from "./unverified-client.mjs";
@@ -5,4 +5,5 @@ export * from "./ai-sdk-provider";
5
5
  export * from "./config";
6
6
  export { SecureClient } from "./secure-client";
7
7
  export { UnverifiedClient } from "./unverified-client";
8
+ export { fetchRouter } from "./router";
8
9
  export { type Uploadable, toFile, APIPromise, PagePromise, OpenAIError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError, } from "openai";
@@ -1,12 +1,13 @@
1
1
  // Re-export the TinfoilAI class
2
- export { TinfoilAI } from "./tinfoilai";
3
- export { TinfoilAI as default } from "./tinfoilai";
2
+ export { TinfoilAI } from "./tinfoilai.mjs";
3
+ export { TinfoilAI as default } from "./tinfoilai.mjs";
4
4
  // Export verifier
5
- export * from "./verifier";
6
- export * from "./ai-sdk-provider";
7
- export * from "./config";
8
- export { SecureClient } from "./secure-client";
9
- export { UnverifiedClient } from "./unverified-client";
5
+ export * from "./verifier.mjs";
6
+ export * from "./ai-sdk-provider.mjs";
7
+ export * from "./config.mjs";
8
+ export { SecureClient } from "./secure-client.mjs";
9
+ export { UnverifiedClient } from "./unverified-client.mjs";
10
+ export { fetchRouter } from "./router.mjs";
10
11
  // Re-export OpenAI utility types and classes that users might need
11
12
  // Using public exports from the main OpenAI package instead of deep imports
12
13
  export { toFile, APIPromise, PagePromise, OpenAIError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError, } from "openai";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Router utilities for fetching available Tinfoil routers
3
+ */
4
+ /**
5
+ * Fetches the list of available routers from the ATC API
6
+ * and returns a randomly selected address.
7
+ *
8
+ * @returns Promise<string> A randomly selected router address
9
+ * @throws Error if no routers are found or if the request fails
10
+ */
11
+ export declare function fetchRouter(): Promise<string>;
@@ -0,0 +1,33 @@
1
+ import { TINFOIL_CONFIG } from "./config.mjs";
2
+ /**
3
+ * Router utilities for fetching available Tinfoil routers
4
+ */
5
+ /**
6
+ * Fetches the list of available routers from the ATC API
7
+ * and returns a randomly selected address.
8
+ *
9
+ * @returns Promise<string> A randomly selected router address
10
+ * @throws Error if no routers are found or if the request fails
11
+ */
12
+ export async function fetchRouter() {
13
+ const routersUrl = TINFOIL_CONFIG.ATC_API_URL;
14
+ try {
15
+ const response = await fetch(routersUrl);
16
+ if (!response.ok) {
17
+ throw new Error(`Failed to fetch routers: ${response.status} ${response.statusText}`);
18
+ }
19
+ const routers = await response.json();
20
+ if (!Array.isArray(routers) || routers.length === 0) {
21
+ throw new Error("No routers found in the response");
22
+ }
23
+ // Return a randomly selected router
24
+ const randomIndex = Math.floor(Math.random() * routers.length);
25
+ return routers[randomIndex];
26
+ }
27
+ catch (error) {
28
+ if (error instanceof Error) {
29
+ throw new Error(`Failed to fetch router: ${error.message}`);
30
+ }
31
+ throw new Error("Failed to fetch router: Unknown error");
32
+ }
33
+ }
@@ -8,13 +8,14 @@ export declare class SecureClient {
8
8
  private initPromise;
9
9
  private verificationDocument;
10
10
  private _fetch;
11
- private readonly baseURL?;
12
- private readonly enclaveURL?;
11
+ private baseURL?;
12
+ private enclaveURL?;
13
13
  private readonly configRepo?;
14
14
  constructor(options?: SecureClientOptions);
15
15
  ready(): Promise<void>;
16
16
  private initSecureClient;
17
17
  getVerificationDocument(): Promise<VerificationDocument>;
18
+ getBaseURL(): string | undefined;
18
19
  get fetch(): typeof fetch;
19
20
  }
20
21
  export {};
@@ -1,13 +1,14 @@
1
- import { Verifier } from "./verifier";
2
- import { TINFOIL_CONFIG } from "./config";
3
- import { createSecureFetch } from "./secure-fetch";
1
+ import { Verifier } from "./verifier.mjs";
2
+ import { TINFOIL_CONFIG } from "./config.mjs";
3
+ import { createSecureFetch } from "./secure-fetch.mjs";
4
+ import { fetchRouter } from "./router.mjs";
4
5
  export class SecureClient {
5
6
  constructor(options = {}) {
6
7
  this.initPromise = null;
7
8
  this.verificationDocument = null;
8
9
  this._fetch = null;
9
- this.baseURL = options.baseURL || TINFOIL_CONFIG.INFERENCE_BASE_URL;
10
- this.enclaveURL = options.enclaveURL || TINFOIL_CONFIG.ENCLAVE_URL;
10
+ this.baseURL = options.baseURL;
11
+ this.enclaveURL = options.enclaveURL;
11
12
  this.configRepo = options.configRepo || TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
12
13
  }
13
14
  async ready() {
@@ -17,6 +18,33 @@ export class SecureClient {
17
18
  return this.initPromise;
18
19
  }
19
20
  async initSecureClient() {
21
+ // Only fetch router if neither baseURL nor enclaveURL is provided
22
+ if (!this.baseURL && !this.enclaveURL) {
23
+ const routerAddress = await fetchRouter();
24
+ this.enclaveURL = `https://${routerAddress}`;
25
+ this.baseURL = `https://${routerAddress}/v1/`;
26
+ }
27
+ // Ensure both baseURL and enclaveURL are initialized
28
+ if (!this.baseURL) {
29
+ if (this.enclaveURL) {
30
+ // If enclaveURL is provided but baseURL is not, derive baseURL from enclaveURL
31
+ const enclaveUrl = new URL(this.enclaveURL);
32
+ this.baseURL = `${enclaveUrl.origin}/v1/`;
33
+ }
34
+ else {
35
+ throw new Error("Unable to determine baseURL: neither baseURL nor enclaveURL provided");
36
+ }
37
+ }
38
+ if (!this.enclaveURL) {
39
+ if (this.baseURL) {
40
+ // If baseURL is provided but enclaveURL is not, derive enclaveURL from baseURL
41
+ const baseUrl = new URL(this.baseURL);
42
+ this.enclaveURL = baseUrl.origin;
43
+ }
44
+ else {
45
+ throw new Error("Unable to determine enclaveURL: neither baseURL nor enclaveURL provided");
46
+ }
47
+ }
20
48
  const verifier = new Verifier({
21
49
  serverURL: this.enclaveURL,
22
50
  configRepo: this.configRepo,
@@ -77,6 +105,9 @@ export class SecureClient {
77
105
  }
78
106
  return this.verificationDocument;
79
107
  }
108
+ getBaseURL() {
109
+ return this.baseURL;
110
+ }
80
111
  get fetch() {
81
112
  return async (input, init) => {
82
113
  await this.ready();
@@ -1,4 +1,4 @@
1
- import { createEncryptedBodyFetch } from "./encrypted-body-fetch";
1
+ import { createEncryptedBodyFetch } from "./encrypted-body-fetch.mjs";
2
2
  export function createSecureFetch(baseURL, enclaveURL, hpkePublicKey, tlsPublicKeyFingerprint) {
3
3
  if (hpkePublicKey) {
4
4
  return createEncryptedBodyFetch(baseURL, hpkePublicKey, enclaveURL);
@@ -1,6 +1,6 @@
1
- import { createEncryptedBodyFetch } from "./encrypted-body-fetch";
2
- import { createPinnedTlsFetch } from "./pinned-tls-fetch";
3
- import { isRealBrowser } from "./env";
1
+ import { createEncryptedBodyFetch } from "./encrypted-body-fetch.mjs";
2
+ import { createPinnedTlsFetch } from "./pinned-tls-fetch.mjs";
3
+ import { isRealBrowser } from "./env.mjs";
4
4
  export function createSecureFetch(baseURL, enclaveURL, hpkePublicKey, tlsPublicKeyFingerprint) {
5
5
  let fetchFunction;
6
6
  if (hpkePublicKey) {
@@ -1,7 +1,7 @@
1
1
  import OpenAI from "openai";
2
- import { SecureClient } from "./secure-client";
3
- import { TINFOIL_CONFIG } from "./config";
4
- import { isRealBrowser } from "./env";
2
+ import { SecureClient } from "./secure-client.mjs";
3
+ import { TINFOIL_CONFIG } from "./config.mjs";
4
+ import { isRealBrowser } from "./env.mjs";
5
5
  function createAsyncProxy(promise) {
6
6
  return new Proxy({}, {
7
7
  get(target, prop) {
@@ -36,8 +36,8 @@ export class TinfoilAI {
36
36
  openAIOptions.apiKey = process.env.TINFOIL_API_KEY;
37
37
  }
38
38
  this.apiKey = openAIOptions.apiKey;
39
- this.baseURL = options.baseURL || TINFOIL_CONFIG.INFERENCE_BASE_URL;
40
- this.enclaveURL = options.enclaveURL || TINFOIL_CONFIG.ENCLAVE_URL;
39
+ this.baseURL = options.baseURL;
40
+ this.enclaveURL = options.enclaveURL;
41
41
  this.configRepo = options.configRepo || TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
42
42
  this.secureClient = new SecureClient({
43
43
  baseURL: this.baseURL,
@@ -63,9 +63,11 @@ export class TinfoilAI {
63
63
  if (!this.verificationDocument) {
64
64
  throw new Error("Verification document not available after successful verification");
65
65
  }
66
+ // Use the provided baseURL, or get it from SecureClient after initialization
67
+ const baseURL = this.baseURL || this.secureClient.getBaseURL();
66
68
  const clientOptions = {
67
69
  ...options,
68
- baseURL: this.baseURL,
70
+ baseURL: baseURL,
69
71
  fetch: this.secureClient.fetch,
70
72
  };
71
73
  if (isRealBrowser() || options.dangerouslyAllowBrowser === true) {
@@ -6,8 +6,8 @@ interface UnverifiedClientOptions {
6
6
  export declare class UnverifiedClient {
7
7
  private initPromise;
8
8
  private _fetch;
9
- private readonly baseURL;
10
- private readonly enclaveURL;
9
+ private baseURL?;
10
+ private enclaveURL?;
11
11
  private readonly configRepo;
12
12
  constructor(options?: UnverifiedClientOptions);
13
13
  ready(): Promise<void>;
@@ -0,0 +1,61 @@
1
+ import { TINFOIL_CONFIG } from "./config.mjs";
2
+ import { createEncryptedBodyFetch } from "./encrypted-body-fetch.mjs";
3
+ import { fetchRouter } from "./router.mjs";
4
+ export class UnverifiedClient {
5
+ constructor(options = {}) {
6
+ this.initPromise = null;
7
+ this._fetch = null;
8
+ this.baseURL = options.baseURL;
9
+ this.enclaveURL = options.enclaveURL;
10
+ this.configRepo = options.configRepo || TINFOIL_CONFIG.INFERENCE_PROXY_REPO;
11
+ }
12
+ async ready() {
13
+ if (!this.initPromise) {
14
+ this.initPromise = this.initUnverifiedClient();
15
+ }
16
+ return this.initPromise;
17
+ }
18
+ async initUnverifiedClient() {
19
+ // Only fetch router if neither baseURL nor enclaveURL is provided
20
+ if (!this.baseURL && !this.enclaveURL) {
21
+ const routerAddress = await fetchRouter();
22
+ this.enclaveURL = `https://${routerAddress}`;
23
+ this.baseURL = `https://${routerAddress}/v1/`;
24
+ }
25
+ // Ensure both baseURL and enclaveURL are initialized
26
+ if (!this.baseURL) {
27
+ if (this.enclaveURL) {
28
+ // If enclaveURL is provided but baseURL is not, derive baseURL from enclaveURL
29
+ const enclaveUrl = new URL(this.enclaveURL);
30
+ this.baseURL = `${enclaveUrl.origin}/v1/`;
31
+ }
32
+ else {
33
+ throw new Error("Unable to determine baseURL: neither baseURL nor enclaveURL provided");
34
+ }
35
+ }
36
+ if (!this.enclaveURL) {
37
+ if (this.baseURL) {
38
+ // If baseURL is provided but enclaveURL is not, derive enclaveURL from baseURL
39
+ const baseUrl = new URL(this.baseURL);
40
+ this.enclaveURL = baseUrl.origin;
41
+ }
42
+ else {
43
+ throw new Error("Unable to determine enclaveURL: neither baseURL nor enclaveURL provided");
44
+ }
45
+ }
46
+ this._fetch = createEncryptedBodyFetch(this.baseURL, undefined, this.enclaveURL);
47
+ }
48
+ async getVerificationDocument() {
49
+ if (!this.initPromise) {
50
+ await this.ready();
51
+ }
52
+ await this.initPromise;
53
+ throw new Error("Verification document unavailable: this version of the client is unverified");
54
+ }
55
+ get fetch() {
56
+ return async (input, init) => {
57
+ await this.ready();
58
+ return this._fetch(input, init);
59
+ };
60
+ }
61
+ }
@@ -87,7 +87,7 @@ export declare class Verifier {
87
87
  private static executeWithWasm;
88
88
  /**
89
89
  * Fetch the latest release digest from GitHub
90
- * @param configRepo - Repository name (e.g., "tinfoilsh/confidential-inference-proxy")
90
+ * @param configRepo - Repository name (e.g., "tinfoilsh/confidential-model-router")
91
91
  * @returns The digest hash
92
92
  */
93
93
  fetchLatestDigest(configRepo?: string): Promise<string>;