@inbrowser/model 0.1.1 → 0.4.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.
Files changed (90) hide show
  1. package/AGENTS.md +44 -18
  2. package/README.md +129 -20
  3. package/dist/contract.d.ts +104 -0
  4. package/dist/contract.d.ts.map +1 -0
  5. package/dist/contract.js +13 -0
  6. package/dist/contract.js.map +1 -0
  7. package/dist/engine-client.d.ts +44 -0
  8. package/dist/engine-client.d.ts.map +1 -0
  9. package/dist/engine-client.js +136 -0
  10. package/dist/engine-client.js.map +1 -0
  11. package/dist/engine.d.ts.map +1 -1
  12. package/dist/engine.js +20 -10
  13. package/dist/engine.js.map +1 -1
  14. package/dist/index.d.ts +25 -8
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +46 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/presets.d.ts +10 -0
  19. package/dist/presets.d.ts.map +1 -1
  20. package/dist/presets.js +21 -0
  21. package/dist/presets.js.map +1 -1
  22. package/dist/providers/anthropic.d.ts +45 -0
  23. package/dist/providers/anthropic.d.ts.map +1 -0
  24. package/dist/providers/anthropic.js +217 -0
  25. package/dist/providers/anthropic.js.map +1 -0
  26. package/dist/providers/claude-cli.d.ts +135 -0
  27. package/dist/providers/claude-cli.d.ts.map +1 -0
  28. package/dist/providers/claude-cli.js +270 -0
  29. package/dist/providers/claude-cli.js.map +1 -0
  30. package/dist/providers/claude-code.d.ts +188 -0
  31. package/dist/providers/claude-code.d.ts.map +1 -0
  32. package/dist/providers/claude-code.js +182 -0
  33. package/dist/providers/claude-code.js.map +1 -0
  34. package/dist/providers/gemini.d.ts +32 -0
  35. package/dist/providers/gemini.d.ts.map +1 -0
  36. package/dist/providers/gemini.js +441 -0
  37. package/dist/providers/gemini.js.map +1 -0
  38. package/dist/providers/llama-server.d.ts +15 -0
  39. package/dist/providers/llama-server.d.ts.map +1 -0
  40. package/dist/providers/llama-server.js +51 -0
  41. package/dist/providers/llama-server.js.map +1 -0
  42. package/dist/providers/oai-compat.d.ts +113 -0
  43. package/dist/providers/oai-compat.d.ts.map +1 -0
  44. package/dist/providers/oai-compat.js +257 -0
  45. package/dist/providers/oai-compat.js.map +1 -0
  46. package/dist/providers/ollama.d.ts +15 -0
  47. package/dist/providers/ollama.d.ts.map +1 -0
  48. package/dist/providers/ollama.js +51 -0
  49. package/dist/providers/ollama.js.map +1 -0
  50. package/dist/providers/openrouter-oauth.d.ts +67 -0
  51. package/dist/providers/openrouter-oauth.d.ts.map +1 -0
  52. package/dist/providers/openrouter-oauth.js +84 -0
  53. package/dist/providers/openrouter-oauth.js.map +1 -0
  54. package/dist/providers/openrouter.d.ts +16 -0
  55. package/dist/providers/openrouter.d.ts.map +1 -0
  56. package/dist/providers/openrouter.js +27 -0
  57. package/dist/providers/openrouter.js.map +1 -0
  58. package/dist/providers/requesty.d.ts +16 -0
  59. package/dist/providers/requesty.d.ts.map +1 -0
  60. package/dist/providers/requesty.js +27 -0
  61. package/dist/providers/requesty.js.map +1 -0
  62. package/dist/providers/types.d.ts +50 -0
  63. package/dist/providers/types.d.ts.map +1 -0
  64. package/dist/providers/types.js +2 -0
  65. package/dist/providers/types.js.map +1 -0
  66. package/dist/sse.d.ts +20 -0
  67. package/dist/sse.d.ts.map +1 -0
  68. package/dist/sse.js +47 -0
  69. package/dist/sse.js.map +1 -0
  70. package/dist/types.d.ts +2 -13
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/usage.d.ts +6 -0
  73. package/dist/usage.d.ts.map +1 -0
  74. package/dist/usage.js +55 -0
  75. package/dist/usage.js.map +1 -0
  76. package/dist/with-retry.d.ts +27 -0
  77. package/dist/with-retry.d.ts.map +1 -0
  78. package/dist/with-retry.js +55 -0
  79. package/dist/with-retry.js.map +1 -0
  80. package/dist/worker.d.ts +1 -1
  81. package/dist/worker.js +1 -1
  82. package/package.json +14 -30
  83. package/dist/adapters/agent.d.ts +0 -19
  84. package/dist/adapters/agent.d.ts.map +0 -1
  85. package/dist/adapters/agent.js +0 -96
  86. package/dist/adapters/agent.js.map +0 -1
  87. package/dist/adapters/relay.d.ts +0 -17
  88. package/dist/adapters/relay.d.ts.map +0 -1
  89. package/dist/adapters/relay.js +0 -90
  90. package/dist/adapters/relay.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ /**
2
+ * OpenRouter OAuth (PKCE) — a browser-first "Connect OpenRouter" flow. Lets a
3
+ * backend-less app obtain a user-controlled, revocable OpenRouter API key
4
+ * without the user pasting a raw key.
5
+ *
6
+ * Two primitives; the app owns the redirect/popup, storage, and routing:
7
+ *
8
+ * 1. `beginOpenRouterOAuth({ callbackUrl })` -> `{ authUrl, codeVerifier }`
9
+ * Persist `codeVerifier` (e.g. sessionStorage), then send the user to
10
+ * `authUrl` (full-page redirect or popup).
11
+ * 2. On return, OpenRouter appends `?code=<code>` to the callback URL. Call
12
+ * `completeOpenRouterOAuth({ code, codeVerifier })` -> `{ key, userId }`.
13
+ * Feed `key` to `openrouterModelClient({ apiKey: key })`.
14
+ *
15
+ * Fully client-side: PKCE means no client secret, and the implementation uses
16
+ * only WebCrypto + `fetch`, so it runs in the browser with no backend (and is
17
+ * import-safe in Node). The key still lives wherever the app stores it — this
18
+ * provisions and exchanges it; it does not persist anything itself.
19
+ *
20
+ * OpenRouter constrains the callback URL to https on port 443 or 3000, or
21
+ * localhost on any port.
22
+ */
23
+ const DEFAULT_BASE_URL = 'https://openrouter.ai';
24
+ /** base64url (RFC 4648, no padding) of a byte array. */
25
+ function base64UrlEncode(bytes) {
26
+ let binary = '';
27
+ for (const b of bytes)
28
+ binary += String.fromCharCode(b);
29
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
30
+ }
31
+ async function sha256(text) {
32
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
33
+ return new Uint8Array(digest);
34
+ }
35
+ /** A cryptographically-random PKCE code verifier (43-char base64url, 256 bits). */
36
+ function randomCodeVerifier() {
37
+ const bytes = new Uint8Array(32);
38
+ crypto.getRandomValues(bytes);
39
+ return base64UrlEncode(bytes);
40
+ }
41
+ const trimSlashes = (url) => url.replace(/\/+$/, '');
42
+ /**
43
+ * Step 1 of the PKCE flow: mint a verifier + S256 challenge and build the
44
+ * OpenRouter authorization URL. Persist the returned `codeVerifier` (it must
45
+ * survive the redirect), then navigate the user to `authUrl`.
46
+ */
47
+ export async function beginOpenRouterOAuth(opts) {
48
+ const baseUrl = trimSlashes(opts.baseUrl ?? DEFAULT_BASE_URL);
49
+ const codeVerifier = randomCodeVerifier();
50
+ const codeChallenge = base64UrlEncode(await sha256(codeVerifier));
51
+ const params = new URLSearchParams({
52
+ callback_url: opts.callbackUrl,
53
+ code_challenge: codeChallenge,
54
+ code_challenge_method: 'S256',
55
+ });
56
+ return { authUrl: `${baseUrl}/auth?${params.toString()}`, codeVerifier };
57
+ }
58
+ /**
59
+ * Step 2 of the PKCE flow: exchange the `code` (from the callback) plus the
60
+ * stored `codeVerifier` for a user-controlled API key. Throws on a non-OK
61
+ * response or a missing key so callers can surface a clear error.
62
+ */
63
+ export async function completeOpenRouterOAuth(opts) {
64
+ const baseUrl = trimSlashes(opts.baseUrl ?? DEFAULT_BASE_URL);
65
+ const res = await fetch(`${baseUrl}/api/v1/auth/keys`, {
66
+ method: 'POST',
67
+ headers: { 'Content-Type': 'application/json' },
68
+ body: JSON.stringify({
69
+ code: opts.code,
70
+ code_verifier: opts.codeVerifier,
71
+ code_challenge_method: 'S256',
72
+ }),
73
+ signal: opts.signal,
74
+ });
75
+ if (!res.ok) {
76
+ const detail = await res.text().catch(() => '');
77
+ throw new Error(`OpenRouter OAuth exchange failed (HTTP ${res.status})${detail ? `: ${detail}` : ''}`);
78
+ }
79
+ const json = (await res.json());
80
+ if (!json.key)
81
+ throw new Error('OpenRouter OAuth exchange returned no key');
82
+ return { key: json.key, userId: json.user_id ?? null };
83
+ }
84
+ //# sourceMappingURL=openrouter-oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter-oauth.js","sourceRoot":"","sources":["../../src/providers/openrouter-oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAsCjD,wDAAwD;AACxD,SAAS,eAAe,CAAC,KAAiB;IACxC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrF,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,mFAAmF;AACnF,SAAS,kBAAkB;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE7D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAA8B;IAE9B,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;IAC1C,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,YAAY,EAAE,IAAI,CAAC,WAAW;QAC9B,cAAc,EAAE,aAAa;QAC7B,qBAAqB,EAAE,MAAM;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,SAAS,MAAM,CAAC,QAAQ,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAiC;IAEjC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,mBAAmB,EAAE;QACrD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,aAAa,EAAE,IAAI,CAAC,YAAY;YAChC,qBAAqB,EAAE,MAAM;SAC9B,CAAC;QACF,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,0CAA0C,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACtF,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA8C,CAAC;IAC7E,IAAI,CAAC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC5E,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ModelClient } from '../contract.js';
2
+ import { type OaiGatewayAttribution, toOaiTools } from './oai-compat.js';
3
+ import type { CloudProviderConfig } from './types.js';
4
+ /** Construction config for the OpenRouter provider. */
5
+ export interface OpenRouterConfig extends CloudProviderConfig {
6
+ appAttribution?: OaiGatewayAttribution;
7
+ }
8
+ export { toOaiTools };
9
+ /**
10
+ * Build an OpenRouter `ModelClient`.
11
+ *
12
+ * OpenRouter speaks the OpenAI chat-completions stream plus gateway extensions
13
+ * for final cost telemetry and streamed reasoning summaries.
14
+ */
15
+ export declare function openrouterModelClient(config: OpenRouterConfig): ModelClient;
16
+ //# sourceMappingURL=openrouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EACL,KAAK,qBAAqB,EAG1B,UAAU,EACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,uDAAuD;AACvD,MAAM,WAAW,gBAAiB,SAAQ,mBAAmB;IAC3D,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW,CAgB3E"}
@@ -0,0 +1,27 @@
1
+ import { makeOaiClient, oaiGatewayAttributionHeaders, toOaiTools, } from './oai-compat.js';
2
+ const ENDPOINT = 'https://openrouter.ai/api/v1/chat/completions';
3
+ export { toOaiTools };
4
+ /**
5
+ * Build an OpenRouter `ModelClient`.
6
+ *
7
+ * OpenRouter speaks the OpenAI chat-completions stream plus gateway extensions
8
+ * for final cost telemetry and streamed reasoning summaries.
9
+ */
10
+ export function openrouterModelClient(config) {
11
+ return makeOaiClient({
12
+ id: `openrouter:${config.model}`,
13
+ endpoint: ENDPOINT,
14
+ model: config.model,
15
+ headers: {
16
+ Authorization: `Bearer ${config.apiKey}`,
17
+ ...oaiGatewayAttributionHeaders(config.appAttribution),
18
+ },
19
+ errorLabel: 'OpenRouter',
20
+ idPrefix: 'or',
21
+ temperatureDefault: config.temperature,
22
+ includeUsage: true,
23
+ reasoningMode: 'openrouter-compatible',
24
+ thinkingDeltaFields: ['reasoning', 'reasoning_content'],
25
+ });
26
+ }
27
+ //# sourceMappingURL=openrouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/providers/openrouter.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,aAAa,EACb,4BAA4B,EAC5B,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,MAAM,QAAQ,GAAG,+CAA+C,CAAC;AAOjE,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwB;IAC5D,OAAO,aAAa,CAAC;QACnB,EAAE,EAAE,cAAc,MAAM,CAAC,KAAK,EAAE;QAChC,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;YACxC,GAAG,4BAA4B,CAAC,MAAM,CAAC,cAAc,CAAC;SACvD;QACD,UAAU,EAAE,YAAY;QACxB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,MAAM,CAAC,WAAW;QACtC,YAAY,EAAE,IAAI;QAClB,aAAa,EAAE,uBAAuB;QACtC,mBAAmB,EAAE,CAAC,WAAW,EAAE,mBAAmB,CAAC;KACxD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { ModelClient } from '../contract.js';
2
+ import { type OaiGatewayAttribution, toOaiTools } from './oai-compat.js';
3
+ import type { CloudProviderConfig } from './types.js';
4
+ /** Construction config for the Requesty provider. */
5
+ export interface RequestyConfig extends CloudProviderConfig {
6
+ appAttribution?: OaiGatewayAttribution;
7
+ }
8
+ export { toOaiTools };
9
+ /**
10
+ * Build a Requesty `ModelClient`.
11
+ *
12
+ * Requesty speaks the OpenAI chat-completions stream plus OpenRouter-compatible
13
+ * gateway extensions for final cost telemetry and streamed reasoning summaries.
14
+ */
15
+ export declare function requestyModelClient(config: RequestyConfig): ModelClient;
16
+ //# sourceMappingURL=requesty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requesty.d.ts","sourceRoot":"","sources":["../../src/providers/requesty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EACL,KAAK,qBAAqB,EAG1B,UAAU,EACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,qDAAqD;AACrD,MAAM,WAAW,cAAe,SAAQ,mBAAmB;IACzD,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACxC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAgBvE"}
@@ -0,0 +1,27 @@
1
+ import { makeOaiClient, oaiGatewayAttributionHeaders, toOaiTools, } from './oai-compat.js';
2
+ const ENDPOINT = 'https://router.requesty.ai/v1/chat/completions';
3
+ export { toOaiTools };
4
+ /**
5
+ * Build a Requesty `ModelClient`.
6
+ *
7
+ * Requesty speaks the OpenAI chat-completions stream plus OpenRouter-compatible
8
+ * gateway extensions for final cost telemetry and streamed reasoning summaries.
9
+ */
10
+ export function requestyModelClient(config) {
11
+ return makeOaiClient({
12
+ id: `requesty:${config.model}`,
13
+ endpoint: ENDPOINT,
14
+ model: config.model,
15
+ headers: {
16
+ Authorization: `Bearer ${config.apiKey}`,
17
+ ...oaiGatewayAttributionHeaders(config.appAttribution),
18
+ },
19
+ errorLabel: 'Requesty',
20
+ idPrefix: 'rq',
21
+ temperatureDefault: config.temperature,
22
+ includeUsage: true,
23
+ reasoningMode: 'openrouter-compatible',
24
+ thinkingDeltaFields: ['reasoning', 'reasoning_content'],
25
+ });
26
+ }
27
+ //# sourceMappingURL=requesty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requesty.js","sourceRoot":"","sources":["../../src/providers/requesty.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,aAAa,EACb,4BAA4B,EAC5B,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,MAAM,QAAQ,GAAG,gDAAgD,CAAC;AAOlE,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,OAAO,aAAa,CAAC;QACnB,EAAE,EAAE,YAAY,MAAM,CAAC,KAAK,EAAE;QAC9B,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;YACxC,GAAG,4BAA4B,CAAC,MAAM,CAAC,cAAc,CAAC;SACvD;QACD,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,MAAM,CAAC,WAAW;QACtC,YAAY,EAAE,IAAI;QAClB,aAAa,EAAE,uBAAuB;QACtC,mBAAmB,EAAE,CAAC,WAAW,EAAE,mBAAmB,CAAC;KACxD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Shared config + factory types for the cloud providers.
3
+ *
4
+ * relay supports BYOK (a per-request API key) plus routing, so a
5
+ * *pre-built* `ModelClient` can't carry a per-request key. Each cloud
6
+ * provider is therefore a FACTORY: construction settings (apiKey / model
7
+ * / baseUrl) come in the config; per-call settings (messages / tools /
8
+ * sampling) come in the `ModelRequest` at `.chat()` time.
9
+ *
10
+ * relay's `providers` map is `Record<string, ModelClientFactory>`; the
11
+ * producer calls `factory({ apiKey: body.apiKey, model: body.model })`
12
+ * per request, then drives `.chat(modelRequest, signal)`.
13
+ */
14
+ import type { ModelClient } from '../contract.js';
15
+ /**
16
+ * Construction config common to every cloud provider.
17
+ * - `apiKey` — BYOK key (Gemini x-goog-api-key,
18
+ * OpenRouter/Anthropic bearer/x-api-key); ignored by
19
+ * claude-cli/claude-code's subscription paths;
20
+ * carries the base URL for Ollama when `baseUrl` is
21
+ * unset.
22
+ * - `model` — the upstream model id.
23
+ * - `baseUrl` — optional override (Ollama's server URL).
24
+ * - `temperature` — optional construction-time default applied when a
25
+ * request omits its own `temperature`. Lets a caller
26
+ * pin a sampling default (e.g. the docs agent's 0.2)
27
+ * without threading it through every `ModelRequest`.
28
+ * A per-request `temperature` always wins. The relay
29
+ * never sets this, so its providers keep "send
30
+ * temperature only when the client did" semantics.
31
+ */
32
+ export interface CloudProviderConfig {
33
+ apiKey?: string;
34
+ model: string;
35
+ baseUrl?: string;
36
+ temperature?: number;
37
+ }
38
+ /**
39
+ * The shape relay's `providers` map holds. relay constructs one
40
+ * `ModelClient` per request from `{ apiKey: body.apiKey, model:
41
+ * body.model }`. Providers may accept a wider config (e.g.
42
+ * `ClaudeCliOptions`), but the relay-facing call only ever supplies
43
+ * `apiKey` + `model` — every provider's config makes those the only
44
+ * required fields.
45
+ */
46
+ export type ModelClientFactory = (config: {
47
+ apiKey?: string;
48
+ model: string;
49
+ }) => ModelClient;
50
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAAK,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
package/dist/sse.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * SSE reader shared by the cloud providers. Gemini, OpenRouter, and
3
+ * Ollama all stream `data:`-prefixed SSE upstream; each provider parses
4
+ * the raw line payloads itself (JSON.parse + a `[DONE]` sentinel). The
5
+ * relay's *outbound* SSE wire helpers (`encodeSseEvent`, `SSE_DONE_LINE`,
6
+ * `SSE_STREAM_OPEN`) are a transport concern and stay in
7
+ * `@inbrowser/relay`.
8
+ */
9
+ /**
10
+ * Stream-line SSE reader. Yields each `data:` line payload as a raw
11
+ * string. Caller decides how to parse (JSON.parse, `[DONE]` sentinel).
12
+ *
13
+ * Splits on `\n` and accumulates a buffer across reads so a chunk
14
+ * boundary mid-line doesn't lose data. SSE event boundaries (blank
15
+ * lines) aren't tracked here because every format this is used against
16
+ * (Gemini's SSE, OpenRouter's SSE, Ollama's OAI-compatible SSE) uses
17
+ * single-line `data:` events.
18
+ */
19
+ export declare function readSseDataLines(body: ReadableStream<Uint8Array> | null): AsyncGenerator<string>;
20
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;GASG;AACH,wBAAuB,gBAAgB,CACrC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,GACtC,cAAc,CAAC,MAAM,CAAC,CAsBxB"}
package/dist/sse.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * SSE reader shared by the cloud providers. Gemini, OpenRouter, and
3
+ * Ollama all stream `data:`-prefixed SSE upstream; each provider parses
4
+ * the raw line payloads itself (JSON.parse + a `[DONE]` sentinel). The
5
+ * relay's *outbound* SSE wire helpers (`encodeSseEvent`, `SSE_DONE_LINE`,
6
+ * `SSE_STREAM_OPEN`) are a transport concern and stay in
7
+ * `@inbrowser/relay`.
8
+ */
9
+ /**
10
+ * Stream-line SSE reader. Yields each `data:` line payload as a raw
11
+ * string. Caller decides how to parse (JSON.parse, `[DONE]` sentinel).
12
+ *
13
+ * Splits on `\n` and accumulates a buffer across reads so a chunk
14
+ * boundary mid-line doesn't lose data. SSE event boundaries (blank
15
+ * lines) aren't tracked here because every format this is used against
16
+ * (Gemini's SSE, OpenRouter's SSE, Ollama's OAI-compatible SSE) uses
17
+ * single-line `data:` events.
18
+ */
19
+ export async function* readSseDataLines(body) {
20
+ if (!body)
21
+ throw new Error('SSE response has no body');
22
+ const reader = body.getReader();
23
+ const decoder = new TextDecoder();
24
+ let buf = '';
25
+ try {
26
+ while (true) {
27
+ const { value, done } = await reader.read();
28
+ if (done)
29
+ break;
30
+ buf += decoder.decode(value, { stream: true });
31
+ let nl;
32
+ while ((nl = buf.indexOf('\n')) !== -1) {
33
+ const line = buf.slice(0, nl).replace(/\r$/, '');
34
+ buf = buf.slice(nl + 1);
35
+ if (!line.startsWith('data: '))
36
+ continue;
37
+ yield line.slice(6);
38
+ }
39
+ }
40
+ if (buf.startsWith('data: '))
41
+ yield buf.slice(6);
42
+ }
43
+ finally {
44
+ reader.releaseLock();
45
+ }
46
+ }
47
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,gBAAgB,CACrC,IAAuC;IAEvC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,IAAI,EAAU,CAAC;YACf,OAAO,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACvC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACjD,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;gBACxB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBACzC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
package/dist/types.d.ts CHANGED
@@ -13,6 +13,7 @@
13
13
  * agent's `ChatEvent` shape. Cloud-only concepts (cost, signatures)
14
14
  * are deliberately absent here.
15
15
  */
16
+ import type { ToolSpec } from './contract.js';
16
17
  /**
17
18
  * HF Hub repo id + optional revision. Pin a revision for
18
19
  * reproducibility — `main` drifts.
@@ -184,19 +185,7 @@ export interface GenerateOpts {
184
185
  */
185
186
  enableThinking?: boolean;
186
187
  }
187
- /**
188
- * Tool declaration shape. Matches the OAI function-calling format
189
- * that most modern chat templates (Qwen 2/3, DeepSeek R1, Llama 3.2+,
190
- * Mistral v0.3+) accept directly.
191
- */
192
- export interface ToolSpec {
193
- type: 'function';
194
- function: {
195
- name: string;
196
- description: string;
197
- parameters: unknown;
198
- };
199
- }
188
+ export type { ToolSpec };
200
189
  /**
201
190
  * Engine's narrow event vocabulary. Adapters translate to the wider
202
191
  * shapes consumers expect (`InferenceEvent`, `ChatEvent`). No cost,
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ModelUsage } from './contract.js';
2
+ export type ModelUsageInput = Partial<ModelUsage> | null | undefined;
3
+ export declare function emptyModelUsage(): ModelUsage;
4
+ export declare function normalizeModelUsage(input: ModelUsageInput): ModelUsage;
5
+ export declare function sumModelUsage(usages: Iterable<ModelUsageInput>): ModelUsage;
6
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAErE,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CAatE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,UAAU,CAmC3E"}
package/dist/usage.js ADDED
@@ -0,0 +1,55 @@
1
+ export function emptyModelUsage() {
2
+ return { promptTokens: 0, outputTokens: 0 };
3
+ }
4
+ export function normalizeModelUsage(input) {
5
+ const promptTokens = nonNegative(input?.promptTokens) ?? 0;
6
+ const outputTokens = nonNegative(input?.outputTokens) ?? 0;
7
+ const cachedTokens = nonNegative(input?.cachedTokens);
8
+ const reasoningTokens = nonNegative(input?.reasoningTokens);
9
+ const costUsd = nonNegative(input?.costUsd);
10
+ return {
11
+ promptTokens,
12
+ outputTokens,
13
+ ...(cachedTokens !== undefined ? { cachedTokens } : {}),
14
+ ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
15
+ ...(costUsd !== undefined ? { costUsd } : {}),
16
+ };
17
+ }
18
+ export function sumModelUsage(usages) {
19
+ let promptTokens = 0;
20
+ let outputTokens = 0;
21
+ let cachedTokens = 0;
22
+ let reasoningTokens = 0;
23
+ let costUsd = 0;
24
+ let hasCachedTokens = false;
25
+ let hasReasoningTokens = false;
26
+ let hasCostUsd = false;
27
+ for (const raw of usages) {
28
+ const usage = normalizeModelUsage(raw);
29
+ promptTokens += usage.promptTokens;
30
+ outputTokens += usage.outputTokens;
31
+ if (usage.cachedTokens !== undefined) {
32
+ cachedTokens += usage.cachedTokens;
33
+ hasCachedTokens = true;
34
+ }
35
+ if (usage.reasoningTokens !== undefined) {
36
+ reasoningTokens += usage.reasoningTokens;
37
+ hasReasoningTokens = true;
38
+ }
39
+ if (usage.costUsd !== undefined) {
40
+ costUsd += usage.costUsd;
41
+ hasCostUsd = true;
42
+ }
43
+ }
44
+ return {
45
+ promptTokens,
46
+ outputTokens,
47
+ ...(hasCachedTokens ? { cachedTokens } : {}),
48
+ ...(hasReasoningTokens ? { reasoningTokens } : {}),
49
+ ...(hasCostUsd ? { costUsd } : {}),
50
+ };
51
+ }
52
+ function nonNegative(value) {
53
+ return typeof value === 'number' && Number.isFinite(value) ? Math.max(0, value) : undefined;
54
+ }
55
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `withRetry` — a reusable `ModelClient` decorator that retries
3
+ * transient upstream failures, but only while nothing has been emitted
4
+ * yet for the current turn (so streamed output is never duplicated).
5
+ *
6
+ * This is the docs agent's old `relayModelClient` retry, lifted out of
7
+ * the site bridge into a shared, provider-agnostic decorator. A wrapped
8
+ * client guarantees a terminal `usage` event before its iterable
9
+ * returns (the contract's terminal is the return itself); the inner
10
+ * client's `usage` is forwarded once.
11
+ */
12
+ import type { ModelClient } from './contract.js';
13
+ export interface WithRetryOpts {
14
+ /** Total attempts before giving up. Default 3. */
15
+ maxAttempts?: number;
16
+ /** Predicate over a `{kind:'error'}` message that decides retryability. */
17
+ isTransient?: (message: string) => boolean;
18
+ }
19
+ /**
20
+ * Wrap a `ModelClient` so transient errors are retried with exponential
21
+ * backoff. Only retries while nothing has streamed this turn; once any
22
+ * text / thinking / tool_call has been yielded, an error passes straight
23
+ * through (we never duplicate partial output). A terminal `usage` event
24
+ * is always emitted before the iterable returns.
25
+ */
26
+ export declare function withRetry(client: ModelClient, opts?: WithRetryOpts): ModelClient;
27
+ //# sourceMappingURL=with-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-retry.d.ts","sourceRoot":"","sources":["../src/with-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAwC,MAAM,eAAe,CAAC;AAWvF,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,GAAE,aAAkB,GAAG,WAAW,CA2CpF"}
@@ -0,0 +1,55 @@
1
+ /** Default transient-failure matcher (overload / rate limit / 5xx). */
2
+ function defaultIsTransient(message) {
3
+ return /\b(429|500|502|503|504)\b|overloaded|unavailable|rate.?limit|resource_exhausted|timeout|temporarily/i.test(message);
4
+ }
5
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
6
+ /**
7
+ * Wrap a `ModelClient` so transient errors are retried with exponential
8
+ * backoff. Only retries while nothing has streamed this turn; once any
9
+ * text / thinking / tool_call has been yielded, an error passes straight
10
+ * through (we never duplicate partial output). A terminal `usage` event
11
+ * is always emitted before the iterable returns.
12
+ */
13
+ export function withRetry(client, opts = {}) {
14
+ const maxAttempts = opts.maxAttempts ?? 3;
15
+ const isTransient = opts.isTransient ?? defaultIsTransient;
16
+ return {
17
+ id: client.id,
18
+ supportsTools: client.supportsTools,
19
+ async *chat(req, signal) {
20
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
21
+ let usage;
22
+ let emitted = false;
23
+ let retryErr = null;
24
+ for await (const e of client.chat(req, signal)) {
25
+ if (e.kind === 'usage') {
26
+ // Hold the final accounting; emit it once before returning.
27
+ usage = e.usage;
28
+ }
29
+ else if (e.kind === 'error') {
30
+ if (!emitted && !signal.aborted && attempt < maxAttempts && isTransient(e.message)) {
31
+ retryErr = e.message;
32
+ break;
33
+ }
34
+ yield e;
35
+ return;
36
+ }
37
+ else {
38
+ // text / thinking / tool_call pass straight through.
39
+ emitted = true;
40
+ yield e;
41
+ }
42
+ }
43
+ if (retryErr) {
44
+ await sleep(400 * 2 ** (attempt - 1));
45
+ continue;
46
+ }
47
+ // Final accounting before the iterable returns (the contract's
48
+ // terminal is the return itself).
49
+ yield { kind: 'usage', usage: usage ?? { promptTokens: 0, outputTokens: 0 } };
50
+ return;
51
+ }
52
+ },
53
+ };
54
+ }
55
+ //# sourceMappingURL=with-retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-retry.js","sourceRoot":"","sources":["../src/with-retry.ts"],"names":[],"mappings":"AAaA,uEAAuE;AACvE,SAAS,kBAAkB,CAAC,OAAe;IACzC,OAAO,sGAAsG,CAAC,IAAI,CAChH,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAS1E;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,MAAmB,EAAE,OAAsB,EAAE;IACrE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAE3D,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAiB,EAAE,MAAmB;YAChD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;gBACxD,IAAI,KAA6B,CAAC;gBAClC,IAAI,OAAO,GAAG,KAAK,CAAC;gBACpB,IAAI,QAAQ,GAAkB,IAAI,CAAC;gBAEnC,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;oBAC/C,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBACvB,4DAA4D;wBAC5D,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;oBAClB,CAAC;yBAAM,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBAC9B,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,GAAG,WAAW,IAAI,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;4BACnF,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC;4BACrB,MAAM;wBACR,CAAC;wBACD,MAAM,CAAC,CAAC;wBACR,OAAO;oBACT,CAAC;yBAAM,CAAC;wBACN,qDAAqD;wBACrD,OAAO,GAAG,IAAI,CAAC;wBACf,MAAM,CAAC,CAAC;oBACV,CAAC;gBACH,CAAC;gBAED,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBACtC,SAAS;gBACX,CAAC;gBAED,+DAA+D;gBAC/D,kCAAkC;gBAClC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC9E,OAAO;YACT,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/worker.d.ts CHANGED
@@ -44,7 +44,7 @@ export interface HostEngineInWorkerOpts {
44
44
  /**
45
45
  * Install the worker-side RPC. Call from inside your worker entry:
46
46
  *
47
- * import { hostEngineInWorker } from '@inbrowser/model/worker';
47
+ * import { hostEngineInWorker } from '@inbrowser/model';
48
48
  * hostEngineInWorker(self);
49
49
  */
50
50
  export declare function hostEngineInWorker(workerScope: DedicatedWorkerGlobalScope, opts?: HostEngineInWorkerOpts): WorkerHostHandle;
package/dist/worker.js CHANGED
@@ -33,7 +33,7 @@ import { createEngine as defaultCreateEngine } from './engine.js';
33
33
  /**
34
34
  * Install the worker-side RPC. Call from inside your worker entry:
35
35
  *
36
- * import { hostEngineInWorker } from '@inbrowser/model/worker';
36
+ * import { hostEngineInWorker } from '@inbrowser/model';
37
37
  * hostEngineInWorker(self);
38
38
  */
39
39
  export function hostEngineInWorker(workerScope, opts) {