@providerprotocol/ai 0.0.33 → 0.0.35

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 (133) hide show
  1. package/README.md +542 -3
  2. package/dist/anthropic/index.d.ts +2 -1
  3. package/dist/anthropic/index.js +151 -145
  4. package/dist/anthropic/index.js.map +1 -1
  5. package/dist/cerebras/index.d.ts +392 -0
  6. package/dist/cerebras/index.js +648 -0
  7. package/dist/cerebras/index.js.map +1 -0
  8. package/dist/chunk-3GWM5GR3.js +153 -0
  9. package/dist/chunk-3GWM5GR3.js.map +1 -0
  10. package/dist/chunk-4OGB7JZA.js +157 -0
  11. package/dist/chunk-4OGB7JZA.js.map +1 -0
  12. package/dist/chunk-7DXVRILR.js +49 -0
  13. package/dist/chunk-7DXVRILR.js.map +1 -0
  14. package/dist/{chunk-3C7O2RNO.js → chunk-A2IM7PGT.js} +6 -4
  15. package/dist/{chunk-3C7O2RNO.js.map → chunk-A2IM7PGT.js.map} +1 -1
  16. package/dist/{chunk-3D6XGGVG.js → chunk-ARVM24K2.js} +2 -2
  17. package/dist/{chunk-4J6OFUKX.js → chunk-AY55T37A.js} +70 -162
  18. package/dist/chunk-AY55T37A.js.map +1 -0
  19. package/dist/{chunk-ILR2D5PN.js → chunk-BRP5XJ6Q.js} +2 -86
  20. package/dist/chunk-BRP5XJ6Q.js.map +1 -0
  21. package/dist/chunk-C4JP64VW.js +298 -0
  22. package/dist/chunk-C4JP64VW.js.map +1 -0
  23. package/dist/chunk-COS4ON4G.js +111 -0
  24. package/dist/chunk-COS4ON4G.js.map +1 -0
  25. package/dist/chunk-ETBFOLQN.js +34 -0
  26. package/dist/chunk-ETBFOLQN.js.map +1 -0
  27. package/dist/chunk-HB4ZIH3T.js +31 -0
  28. package/dist/chunk-HB4ZIH3T.js.map +1 -0
  29. package/dist/chunk-I53CI6ZZ.js +142 -0
  30. package/dist/chunk-I53CI6ZZ.js.map +1 -0
  31. package/dist/chunk-IDZOVWP3.js +29 -0
  32. package/dist/chunk-IDZOVWP3.js.map +1 -0
  33. package/dist/chunk-JA3UZALR.js +88 -0
  34. package/dist/chunk-JA3UZALR.js.map +1 -0
  35. package/dist/{chunk-WAKD3OO5.js → chunk-N5DX5JW3.js} +31 -31
  36. package/dist/chunk-N5DX5JW3.js.map +1 -0
  37. package/dist/chunk-OIEWDFQU.js +97 -0
  38. package/dist/chunk-OIEWDFQU.js.map +1 -0
  39. package/dist/{chunk-TOJCZMVU.js → chunk-PMK5LZ5Z.js} +40 -40
  40. package/dist/chunk-PMK5LZ5Z.js.map +1 -0
  41. package/dist/chunk-UFFJDYCE.js +94 -0
  42. package/dist/chunk-UFFJDYCE.js.map +1 -0
  43. package/dist/chunk-VGKZIGVI.js +222 -0
  44. package/dist/chunk-VGKZIGVI.js.map +1 -0
  45. package/dist/chunk-VOEWHQUB.js +31 -0
  46. package/dist/chunk-VOEWHQUB.js.map +1 -0
  47. package/dist/{chunk-KUPF5KHT.js → chunk-Y5H7C5J4.js} +2 -2
  48. package/dist/chunk-ZI67WIQS.js +30 -0
  49. package/dist/chunk-ZI67WIQS.js.map +1 -0
  50. package/dist/{embedding-D2BYIehX.d.ts → embedding-CW6SaOOz.d.ts} +1 -1
  51. package/dist/google/index.d.ts +2 -1
  52. package/dist/google/index.js +202 -199
  53. package/dist/google/index.js.map +1 -1
  54. package/dist/groq/index.d.ts +410 -0
  55. package/dist/groq/index.js +649 -0
  56. package/dist/groq/index.js.map +1 -0
  57. package/dist/http/index.d.ts +3 -2
  58. package/dist/http/index.js +5 -4
  59. package/dist/image-stream-C0ciACM2.d.ts +11 -0
  60. package/dist/index.d.ts +8 -118
  61. package/dist/index.js +518 -767
  62. package/dist/index.js.map +1 -1
  63. package/dist/{llm-BQJZj3cD.d.ts → llm-DwbUK7un.d.ts} +12 -1632
  64. package/dist/middleware/logging/index.d.ts +76 -0
  65. package/dist/middleware/logging/index.js +74 -0
  66. package/dist/middleware/logging/index.js.map +1 -0
  67. package/dist/middleware/parsed-object/index.d.ts +45 -0
  68. package/dist/middleware/parsed-object/index.js +73 -0
  69. package/dist/middleware/parsed-object/index.js.map +1 -0
  70. package/dist/middleware/pubsub/index.d.ts +104 -0
  71. package/dist/middleware/pubsub/index.js +230 -0
  72. package/dist/middleware/pubsub/index.js.map +1 -0
  73. package/dist/middleware/pubsub/server/express/index.d.ts +52 -0
  74. package/dist/middleware/pubsub/server/express/index.js +11 -0
  75. package/dist/middleware/pubsub/server/express/index.js.map +1 -0
  76. package/dist/middleware/pubsub/server/fastify/index.d.ts +53 -0
  77. package/dist/middleware/pubsub/server/fastify/index.js +11 -0
  78. package/dist/middleware/pubsub/server/fastify/index.js.map +1 -0
  79. package/dist/middleware/pubsub/server/h3/index.d.ts +56 -0
  80. package/dist/middleware/pubsub/server/h3/index.js +11 -0
  81. package/dist/middleware/pubsub/server/h3/index.js.map +1 -0
  82. package/dist/middleware/pubsub/server/index.d.ts +78 -0
  83. package/dist/middleware/pubsub/server/index.js +34 -0
  84. package/dist/middleware/pubsub/server/index.js.map +1 -0
  85. package/dist/middleware/pubsub/server/webapi/index.d.ts +53 -0
  86. package/dist/middleware/pubsub/server/webapi/index.js +11 -0
  87. package/dist/middleware/pubsub/server/webapi/index.js.map +1 -0
  88. package/dist/ollama/index.d.ts +2 -1
  89. package/dist/ollama/index.js +48 -45
  90. package/dist/ollama/index.js.map +1 -1
  91. package/dist/openai/index.d.ts +2 -1
  92. package/dist/openai/index.js +319 -313
  93. package/dist/openai/index.js.map +1 -1
  94. package/dist/openrouter/index.d.ts +2 -1
  95. package/dist/openrouter/index.js +379 -383
  96. package/dist/openrouter/index.js.map +1 -1
  97. package/dist/proxy/index.d.ts +10 -914
  98. package/dist/proxy/index.js +275 -1007
  99. package/dist/proxy/index.js.map +1 -1
  100. package/dist/proxy/server/express/index.d.ts +161 -0
  101. package/dist/proxy/server/express/index.js +24 -0
  102. package/dist/proxy/server/express/index.js.map +1 -0
  103. package/dist/proxy/server/fastify/index.d.ts +162 -0
  104. package/dist/proxy/server/fastify/index.js +24 -0
  105. package/dist/proxy/server/fastify/index.js.map +1 -0
  106. package/dist/proxy/server/h3/index.d.ts +189 -0
  107. package/dist/proxy/server/h3/index.js +28 -0
  108. package/dist/proxy/server/h3/index.js.map +1 -0
  109. package/dist/proxy/server/index.d.ts +151 -0
  110. package/dist/proxy/server/index.js +48 -0
  111. package/dist/proxy/server/index.js.map +1 -0
  112. package/dist/proxy/server/webapi/index.d.ts +278 -0
  113. package/dist/proxy/server/webapi/index.js +32 -0
  114. package/dist/proxy/server/webapi/index.js.map +1 -0
  115. package/dist/responses/index.d.ts +650 -0
  116. package/dist/responses/index.js +930 -0
  117. package/dist/responses/index.js.map +1 -0
  118. package/dist/{retry-8Ch-WWgX.d.ts → retry-YayV42GV.d.ts} +1 -1
  119. package/dist/stream-CecfVCPO.d.ts +1632 -0
  120. package/dist/types-C8Gciizr.d.ts +168 -0
  121. package/dist/utils/index.d.ts +53 -0
  122. package/dist/utils/index.js +7 -0
  123. package/dist/utils/index.js.map +1 -0
  124. package/dist/xai/index.d.ts +2 -1
  125. package/dist/xai/index.js +310 -310
  126. package/dist/xai/index.js.map +1 -1
  127. package/package.json +94 -4
  128. package/dist/chunk-4J6OFUKX.js.map +0 -1
  129. package/dist/chunk-ILR2D5PN.js.map +0 -1
  130. package/dist/chunk-TOJCZMVU.js.map +0 -1
  131. package/dist/chunk-WAKD3OO5.js.map +0 -1
  132. /package/dist/{chunk-3D6XGGVG.js.map → chunk-ARVM24K2.js.map} +0 -0
  133. /package/dist/{chunk-KUPF5KHT.js.map → chunk-Y5H7C5J4.js.map} +0 -0
@@ -0,0 +1,142 @@
1
+ // src/utils/partial-json.ts
2
+ function cleanupTrailingIncomplete(json) {
3
+ let result = json.trim();
4
+ let changed = true;
5
+ while (changed) {
6
+ changed = false;
7
+ const trimmed = result.trim();
8
+ if (trimmed.endsWith(",")) {
9
+ result = trimmed.slice(0, -1);
10
+ changed = true;
11
+ continue;
12
+ }
13
+ if (trimmed.endsWith(":")) {
14
+ const colonIndex = trimmed.length - 1;
15
+ let keyStart = colonIndex - 1;
16
+ while (keyStart >= 0 && /\s/.test(trimmed[keyStart])) {
17
+ keyStart--;
18
+ }
19
+ if (keyStart >= 0 && trimmed[keyStart] === '"') {
20
+ keyStart--;
21
+ while (keyStart >= 0 && trimmed[keyStart] !== '"') {
22
+ keyStart--;
23
+ }
24
+ keyStart--;
25
+ while (keyStart >= 0 && /\s/.test(trimmed[keyStart])) {
26
+ keyStart--;
27
+ }
28
+ if (keyStart >= 0 && trimmed[keyStart] === ",") {
29
+ result = trimmed.slice(0, keyStart);
30
+ } else {
31
+ result = trimmed.slice(0, keyStart + 1);
32
+ }
33
+ changed = true;
34
+ continue;
35
+ }
36
+ }
37
+ const literalMatch = trimmed.match(/(,?\s*)(t(?:r(?:ue?)?)?|f(?:a(?:l(?:se?)?)?)?|n(?:u(?:ll?)?)?)$/i);
38
+ if (literalMatch && literalMatch[2]) {
39
+ const partial = literalMatch[2].toLowerCase();
40
+ const literals = ["true", "false", "null"];
41
+ const match = literals.find((lit) => lit.startsWith(partial) && partial !== lit);
42
+ if (match) {
43
+ result = trimmed.slice(0, -literalMatch[2].length) + match;
44
+ changed = true;
45
+ continue;
46
+ }
47
+ }
48
+ const numberMatch = trimmed.match(/(,?\s*)(-?(?:\d+\.|\d*\.?\d+[eE][+-]?|\d+[eE]|-))$/);
49
+ if (numberMatch && numberMatch[2]) {
50
+ const partial = numberMatch[2];
51
+ if (/[.eE+-]$/.test(partial)) {
52
+ if (partial === "-") {
53
+ result = trimmed.slice(0, -(numberMatch[0]?.length ?? 0)).trimEnd();
54
+ } else {
55
+ result = trimmed.slice(0, -1);
56
+ }
57
+ changed = true;
58
+ continue;
59
+ }
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ function repairJson(json) {
65
+ let result = json;
66
+ const stack = [];
67
+ let inString = false;
68
+ let escape = false;
69
+ for (let i = 0; i < result.length; i++) {
70
+ const char = result[i];
71
+ if (escape) {
72
+ escape = false;
73
+ continue;
74
+ }
75
+ if (char === "\\" && inString) {
76
+ escape = true;
77
+ continue;
78
+ }
79
+ if (char === '"' && !escape) {
80
+ inString = !inString;
81
+ }
82
+ if (!inString) {
83
+ if (char === "{") {
84
+ stack.push("{");
85
+ } else if (char === "[") {
86
+ stack.push("[");
87
+ } else if (char === "}") {
88
+ if (stack.length > 0 && stack[stack.length - 1] === "{") {
89
+ stack.pop();
90
+ }
91
+ } else if (char === "]") {
92
+ if (stack.length > 0 && stack[stack.length - 1] === "[") {
93
+ stack.pop();
94
+ }
95
+ }
96
+ }
97
+ }
98
+ if (inString) {
99
+ const unicodeMatch = result.match(/\\u[0-9a-fA-F]{0,3}$/);
100
+ if (unicodeMatch) {
101
+ result = result.slice(0, -unicodeMatch[0].length);
102
+ }
103
+ if (result.endsWith("\\")) {
104
+ result = result.slice(0, -1);
105
+ }
106
+ result += '"';
107
+ inString = false;
108
+ }
109
+ result = cleanupTrailingIncomplete(result);
110
+ while (stack.length > 0) {
111
+ const open = stack.pop();
112
+ if (open === "{") {
113
+ result += "}";
114
+ } else {
115
+ result += "]";
116
+ }
117
+ }
118
+ return result;
119
+ }
120
+ function parsePartialJson(json) {
121
+ const trimmed = json.trim();
122
+ if (trimmed === "") {
123
+ return { value: void 0, isComplete: false };
124
+ }
125
+ try {
126
+ const value = JSON.parse(trimmed);
127
+ return { value, isComplete: true };
128
+ } catch {
129
+ }
130
+ try {
131
+ const repaired = repairJson(trimmed);
132
+ const value = JSON.parse(repaired);
133
+ return { value, isComplete: false };
134
+ } catch {
135
+ return { value: void 0, isComplete: false };
136
+ }
137
+ }
138
+
139
+ export {
140
+ parsePartialJson
141
+ };
142
+ //# sourceMappingURL=chunk-I53CI6ZZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/partial-json.ts"],"sourcesContent":["/**\n * @fileoverview Partial JSON parser for streaming LLM responses.\n *\n * Enables incremental parsing of JSON data as it streams from LLM providers,\n * allowing consumers to access usable partial objects during streaming rather\n * than waiting for complete JSON.\n *\n * @module utils/partial-json\n */\n\n/**\n * Result of parsing partial JSON.\n *\n * @typeParam T - The expected type of the parsed value\n */\nexport interface PartialParseResult<T = unknown> {\n /** The parsed value, or undefined if parsing failed */\n value: T | undefined;\n /** Whether the JSON was complete and valid */\n isComplete: boolean;\n}\n\n/**\n * Cleans up trailing incomplete elements from JSON.\n * Iteratively handles chained incomplete elements (e.g., trailing colon followed by comma).\n */\nfunction cleanupTrailingIncomplete(json: string): string {\n let result = json.trim();\n let changed = true;\n\n // Keep cleaning until no more changes\n while (changed) {\n changed = false;\n const trimmed = result.trim();\n\n // Handle trailing comma - remove it\n if (trimmed.endsWith(',')) {\n result = trimmed.slice(0, -1);\n changed = true;\n continue;\n }\n\n // Handle trailing colon - remove the incomplete key-value pair\n if (trimmed.endsWith(':')) {\n // Find the start of the key (the opening quote before the colon)\n const colonIndex = trimmed.length - 1;\n let keyStart = colonIndex - 1;\n while (keyStart >= 0 && /\\s/.test(trimmed[keyStart]!)) {\n keyStart--;\n }\n // Should now be at closing quote of key\n if (keyStart >= 0 && trimmed[keyStart] === '\"') {\n // Find opening quote of key\n keyStart--;\n while (keyStart >= 0 && trimmed[keyStart] !== '\"') {\n keyStart--;\n }\n // Now find what's before the key (comma or opening brace)\n keyStart--;\n while (keyStart >= 0 && /\\s/.test(trimmed[keyStart]!)) {\n keyStart--;\n }\n if (keyStart >= 0 && trimmed[keyStart] === ',') {\n result = trimmed.slice(0, keyStart);\n } else {\n result = trimmed.slice(0, keyStart + 1);\n }\n changed = true;\n continue;\n }\n }\n\n // Handle incomplete literals (true, false, null)\n const literalMatch = trimmed.match(/(,?\\s*)(t(?:r(?:ue?)?)?|f(?:a(?:l(?:se?)?)?)?|n(?:u(?:ll?)?)?)$/i);\n if (literalMatch && literalMatch[2]) {\n const partial = literalMatch[2].toLowerCase();\n const literals = ['true', 'false', 'null'];\n const match = literals.find((lit) => lit.startsWith(partial) && partial !== lit);\n if (match) {\n result = trimmed.slice(0, -literalMatch[2].length) + match;\n changed = true;\n continue;\n }\n }\n\n // Handle incomplete numbers at end (e.g., \"123.\" or \"1e\" or \"1e+\" or \"-\")\n const numberMatch = trimmed.match(/(,?\\s*)(-?(?:\\d+\\.|\\d*\\.?\\d+[eE][+-]?|\\d+[eE]|-))$/);\n if (numberMatch && numberMatch[2]) {\n const partial = numberMatch[2];\n if (/[.eE+-]$/.test(partial)) {\n if (partial === '-') {\n // Just a minus sign - remove it and any preceding whitespace/comma\n result = trimmed.slice(0, -(numberMatch[0]?.length ?? 0)).trimEnd();\n // If we now end with a colon, the loop will clean that up next iteration\n } else {\n result = trimmed.slice(0, -1);\n }\n changed = true;\n continue;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Attempts to repair incomplete JSON by completing open structures.\n *\n * @param json - The incomplete JSON string\n * @returns A potentially valid JSON string\n */\nfunction repairJson(json: string): string {\n let result = json;\n\n // Track open structures as we scan\n const stack: Array<'{' | '['> = [];\n let inString = false;\n let escape = false;\n\n for (let i = 0; i < result.length; i++) {\n const char = result[i]!;\n\n if (escape) {\n escape = false;\n continue;\n }\n\n if (char === '\\\\' && inString) {\n escape = true;\n continue;\n }\n\n if (char === '\"' && !escape) {\n inString = !inString;\n }\n\n if (!inString) {\n if (char === '{') {\n stack.push('{');\n } else if (char === '[') {\n stack.push('[');\n } else if (char === '}') {\n if (stack.length > 0 && stack[stack.length - 1] === '{') {\n stack.pop();\n }\n } else if (char === ']') {\n if (stack.length > 0 && stack[stack.length - 1] === '[') {\n stack.pop();\n }\n }\n }\n }\n\n // If we ended inside a string, close it\n if (inString) {\n // Check if the string ends with incomplete unicode escape\n const unicodeMatch = result.match(/\\\\u[0-9a-fA-F]{0,3}$/);\n if (unicodeMatch) {\n // Remove incomplete unicode escape\n result = result.slice(0, -unicodeMatch[0].length);\n }\n // Check if string ends with incomplete escape sequence\n if (result.endsWith('\\\\')) {\n result = result.slice(0, -1);\n }\n result += '\"';\n inString = false;\n }\n\n // Handle trailing incomplete structures\n result = cleanupTrailingIncomplete(result);\n\n // Close any open structures\n while (stack.length > 0) {\n const open = stack.pop();\n if (open === '{') {\n result += '}';\n } else {\n result += ']';\n }\n }\n\n return result;\n}\n\n/**\n * Parses potentially incomplete JSON, returning as much as can be extracted.\n *\n * Handles common incomplete states during streaming:\n * - Incomplete strings: `{\"name\":\"Jo` → `{name: \"Jo\"}`\n * - Incomplete objects: `{\"a\":1,\"b\":` → `{a: 1}`\n * - Incomplete arrays: `[1,2,` → `[1, 2]`\n * - Incomplete numbers, booleans, null literals\n * - Nested structures with partial completion\n * - Unicode escape sequences\n *\n * @typeParam T - The expected type of the parsed value\n * @param json - The potentially incomplete JSON string\n * @returns A PartialParseResult with the parsed value and completion status\n *\n * @example\n * ```typescript\n * // Complete JSON\n * parsePartialJson('{\"name\":\"John\"}');\n * // => { value: { name: \"John\" }, isComplete: true }\n *\n * // Incomplete object\n * parsePartialJson('{\"user\":{\"firstName\":\"Jo');\n * // => { value: { user: { firstName: \"Jo\" } }, isComplete: false }\n *\n * // Incomplete array\n * parsePartialJson('[1, 2, 3');\n * // => { value: [1, 2, 3], isComplete: false }\n * ```\n */\nexport function parsePartialJson<T = unknown>(json: string): PartialParseResult<T> {\n const trimmed = json.trim();\n\n if (trimmed === '') {\n return { value: undefined, isComplete: false };\n }\n\n // Try parsing as complete JSON first\n try {\n const value = JSON.parse(trimmed) as T;\n return { value, isComplete: true };\n } catch {\n // Continue with partial parsing\n }\n\n // Attempt to repair and parse the incomplete JSON\n try {\n const repaired = repairJson(trimmed);\n const value = JSON.parse(repaired) as T;\n return { value, isComplete: false };\n } catch {\n return { value: undefined, isComplete: false };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ import {
2
+ fastify
3
+ } from "./chunk-UFFJDYCE.js";
4
+ import {
5
+ webapi
6
+ } from "./chunk-VGKZIGVI.js";
7
+ import {
8
+ express
9
+ } from "./chunk-OIEWDFQU.js";
10
+ import {
11
+ h3
12
+ } from "./chunk-4OGB7JZA.js";
13
+
14
+ // src/providers/proxy/server/index.ts
15
+ var server = {
16
+ /** Web API adapter (Bun, Deno, Next.js, Workers) */
17
+ webapi,
18
+ /** Express/Connect adapter */
19
+ express,
20
+ /** Fastify adapter */
21
+ fastify,
22
+ /** H3/Nitro/Nuxt adapter */
23
+ h3
24
+ };
25
+
26
+ export {
27
+ server
28
+ };
29
+ //# sourceMappingURL=chunk-IDZOVWP3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/proxy/server/index.ts"],"sourcesContent":["/**\n * @fileoverview Framework adapters for proxy server utilities.\n *\n * Provides framework-specific adapters for using PP proxy with various\n * server frameworks. The base Web API utilities (toJSON, toSSE) work with\n * modern frameworks like Bun, Deno, and Next.js App Router. These adapters\n * provide native integration for Express, Fastify, and H3/Nuxt.\n *\n * @module providers/proxy/server\n */\n\nimport { express } from './express.ts';\nimport { fastify } from './fastify.ts';\nimport { h3 } from './h3.ts';\nimport {\n webapi,\n parseBody,\n parseEmbeddingBody,\n parseImageBody,\n toJSON,\n toEmbeddingJSON,\n toImageJSON,\n toSSE,\n toImageSSE,\n toError,\n bindTools,\n} from './webapi.ts';\n\nexport { express, fastify, h3, webapi };\nexport {\n parseBody,\n parseEmbeddingBody,\n parseImageBody,\n toJSON,\n toEmbeddingJSON,\n toImageJSON,\n toSSE,\n toImageSSE,\n toError,\n bindTools,\n};\nexport type { ParsedRequest, ParsedEmbeddingRequest, ParsedImageRequest } from './webapi.ts';\n\nexport type {\n ParsedBody,\n ProxyHandler,\n RequestMeta,\n AdapterOptions,\n} from './types.ts';\n\n/**\n * Server adapters namespace.\n *\n * Contains framework-specific adapters for Web API, Express, Fastify, and H3.\n *\n * @example Express\n * ```typescript\n * import { express } from '@providerprotocol/ai/proxy/server';\n *\n * app.post('/api/ai', async (req, res) => {\n * const { messages } = parseBody(req.body);\n * if (req.headers.accept?.includes('text/event-stream')) {\n * express.streamSSE(instance.stream(messages), res);\n * } else {\n * express.sendJSON(await instance.generate(messages), res);\n * }\n * });\n * ```\n *\n * @example Fastify\n * ```typescript\n * import { fastify } from '@providerprotocol/ai/proxy/server';\n *\n * app.post('/api/ai', async (request, reply) => {\n * const { messages } = parseBody(request.body);\n * if (request.headers.accept?.includes('text/event-stream')) {\n * return fastify.streamSSE(instance.stream(messages), reply);\n * }\n * return fastify.sendJSON(await instance.generate(messages), reply);\n * });\n * ```\n *\n * @example H3/Nuxt\n * ```typescript\n * import { h3 } from '@providerprotocol/ai/proxy/server';\n *\n * export default defineEventHandler(async (event) => {\n * const { messages } = parseBody(await readBody(event));\n * if (getHeader(event, 'accept')?.includes('text/event-stream')) {\n * return h3.streamSSE(instance.stream(messages), event);\n * }\n * return h3.sendJSON(await instance.generate(messages), event);\n * });\n * ```\n */\nexport const server = {\n /** Web API adapter (Bun, Deno, Next.js, Workers) */\n webapi,\n /** Express/Connect adapter */\n express,\n /** Fastify adapter */\n fastify,\n /** H3/Nitro/Nuxt adapter */\n h3,\n};\n"],"mappings":";;;;;;;;;;;;;;AA+FO,IAAM,SAAS;AAAA;AAAA,EAEpB;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF;","names":[]}
@@ -0,0 +1,88 @@
1
+ // src/core/provider-handlers.ts
2
+ function isHandlerResolver(value) {
3
+ return value !== void 0 && "handlers" in value && "getMode" in value;
4
+ }
5
+ var providerHandlers = /* @__PURE__ */ new WeakMap();
6
+ function registerProviderHandlers(provider, handlers) {
7
+ providerHandlers.set(provider, handlers);
8
+ }
9
+ function getProviderHandlers(provider) {
10
+ return providerHandlers.get(provider);
11
+ }
12
+ function resolveLLMHandler(provider, options) {
13
+ const handlers = getProviderHandlers(provider);
14
+ const resolver = handlers?.llmResolver;
15
+ if (resolver) {
16
+ const mode = resolver.getMode(options);
17
+ return resolver.handlers[mode] ?? handlers?.llm;
18
+ }
19
+ return handlers?.llm;
20
+ }
21
+ function resolveEmbeddingHandler(provider) {
22
+ const handlers = getProviderHandlers(provider);
23
+ return handlers?.embedding;
24
+ }
25
+ function resolveImageHandler(provider) {
26
+ const handlers = getProviderHandlers(provider);
27
+ return handlers?.image;
28
+ }
29
+
30
+ // src/core/provider.ts
31
+ function createProvider(options) {
32
+ const llmInput = options.handlers.llm;
33
+ const hasResolver = isHandlerResolver(llmInput);
34
+ const defaultLLMHandler = hasResolver ? llmInput.handlers[llmInput.defaultMode] : llmInput;
35
+ if (hasResolver && !defaultLLMHandler) {
36
+ throw new Error(
37
+ `Provider '${options.name}' LLM resolver defaultMode '${llmInput.defaultMode}' has no handler`
38
+ );
39
+ }
40
+ let provider;
41
+ const fn = function(modelId, modelOptions) {
42
+ if (options.createModelReference) {
43
+ return options.createModelReference(modelId, modelOptions, provider);
44
+ }
45
+ return { modelId, provider, options: modelOptions };
46
+ };
47
+ Object.defineProperties(fn, {
48
+ name: {
49
+ value: options.name,
50
+ writable: false,
51
+ configurable: true
52
+ },
53
+ version: {
54
+ value: options.version,
55
+ writable: false,
56
+ configurable: true
57
+ }
58
+ });
59
+ provider = fn;
60
+ if (hasResolver) {
61
+ for (const handler of Object.values(llmInput.handlers)) {
62
+ handler._setProvider?.(provider);
63
+ }
64
+ } else if (defaultLLMHandler?._setProvider) {
65
+ defaultLLMHandler._setProvider(provider);
66
+ }
67
+ if (options.handlers.embedding?._setProvider) {
68
+ options.handlers.embedding._setProvider(provider);
69
+ }
70
+ if (options.handlers.image?._setProvider) {
71
+ options.handlers.image._setProvider(provider);
72
+ }
73
+ registerProviderHandlers(provider, {
74
+ llm: defaultLLMHandler,
75
+ embedding: options.handlers.embedding,
76
+ image: options.handlers.image,
77
+ ...hasResolver ? { llmResolver: llmInput } : {}
78
+ });
79
+ return provider;
80
+ }
81
+
82
+ export {
83
+ resolveLLMHandler,
84
+ resolveEmbeddingHandler,
85
+ resolveImageHandler,
86
+ createProvider
87
+ };
88
+ //# sourceMappingURL=chunk-JA3UZALR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/provider-handlers.ts","../src/core/provider.ts"],"sourcesContent":["/**\n * @fileoverview Internal handler registry and resolver utilities.\n *\n * @module core/provider-handlers\n */\n\nimport type {\n ProviderIdentity,\n LLMHandler,\n EmbeddingHandler,\n ImageHandler,\n} from '../types/provider.ts';\n\n/**\n * Resolver for dynamically selecting LLM handlers based on model options.\n *\n * Used by providers that support multiple API modes (e.g., OpenAI with responses/completions).\n * The resolver eliminates shared mutable state by storing the mode on the ModelReference\n * and resolving the correct handler at request time.\n *\n * @typeParam TOptions - Provider-specific options type\n */\nexport interface LLMHandlerResolver<TOptions = unknown> {\n /** Map of mode identifiers to their corresponding LLM handlers */\n handlers: Record<string, LLMHandler>;\n /** The default mode when options don't specify one */\n defaultMode: string;\n /** Function to extract the mode from provider options */\n getMode: (options: TOptions | undefined) => string;\n}\n\n/**\n * Type guard to check if a value is an LLMHandlerResolver.\n */\nexport function isHandlerResolver<TOptions>(\n value: LLMHandler | LLMHandlerResolver<TOptions> | undefined\n): value is LLMHandlerResolver<TOptions> {\n return value !== undefined && 'handlers' in value && 'getMode' in value;\n}\n\ntype ProviderHandlers<TOptions = unknown> = {\n llm?: LLMHandler;\n embedding?: EmbeddingHandler;\n image?: ImageHandler;\n llmResolver?: LLMHandlerResolver<TOptions>;\n};\n\nconst providerHandlers = new WeakMap<object, ProviderHandlers<unknown>>();\n\n/**\n * Registers handler implementations for a provider.\n */\nexport function registerProviderHandlers<TOptions>(\n provider: ProviderIdentity,\n handlers: ProviderHandlers<TOptions>\n): void {\n providerHandlers.set(provider as object, handlers as ProviderHandlers<unknown>);\n}\n\nfunction getProviderHandlers<TOptions>(\n provider: ProviderIdentity\n): ProviderHandlers<TOptions> | undefined {\n return providerHandlers.get(provider as object) as ProviderHandlers<TOptions> | undefined;\n}\n\n/**\n * Resolves the correct LLM handler based on model reference options.\n *\n * For providers with multiple LLM handlers (e.g., OpenAI with responses/completions APIs),\n * this function determines which handler to use based on the options stored on the\n * ModelReference. This eliminates race conditions from shared mutable state.\n *\n * For providers with a single LLM handler, this simply returns that handler.\n *\n * @typeParam TOptions - Provider-specific options type\n * @param provider - The provider to resolve the handler from\n * @param options - The options from the ModelReference\n * @returns The resolved LLM handler, or undefined if LLM is not supported\n *\n * @internal\n */\nexport function resolveLLMHandler<TOptions = unknown>(\n provider: ProviderIdentity,\n options: TOptions | undefined\n): LLMHandler | undefined {\n const handlers = getProviderHandlers(provider);\n const resolver = handlers?.llmResolver;\n\n if (resolver) {\n const mode = resolver.getMode(options);\n return resolver.handlers[mode] ?? handlers?.llm;\n }\n\n return handlers?.llm;\n}\n\n/**\n * Resolves the embedding handler for a provider, if supported.\n *\n * @internal\n */\nexport function resolveEmbeddingHandler<TParams = unknown>(\n provider: ProviderIdentity\n): EmbeddingHandler<TParams> | undefined {\n const handlers = getProviderHandlers(provider);\n return handlers?.embedding as EmbeddingHandler<TParams> | undefined;\n}\n\n/**\n * Resolves the image handler for a provider, if supported.\n *\n * @internal\n */\nexport function resolveImageHandler<TParams = unknown>(\n provider: ProviderIdentity\n): ImageHandler<TParams> | undefined {\n const handlers = getProviderHandlers(provider);\n return handlers?.image as ImageHandler<TParams> | undefined;\n}\n","/**\n * @fileoverview Base provider interface and factory for the Universal Provider Protocol.\n *\n * This module provides the foundation for creating AI providers that conform to the\n * UPP specification. Providers are callable functions that create model references\n * and register internal handlers for LLM, embedding, and image modalities.\n *\n * @module core/provider\n */\n\nimport type {\n Provider,\n ModelReference,\n LLMHandler,\n EmbeddingHandler,\n ImageHandler,\n LLMProvider,\n EmbeddingProvider,\n ImageProvider,\n} from '../types/provider.ts';\nimport type { LLMHandlerResolver } from './provider-handlers.ts';\nimport { isHandlerResolver, registerProviderHandlers } from './provider-handlers.ts';\n\n\n/**\n * Configuration options for creating a new provider.\n *\n * @typeParam TOptions - Provider-specific options type\n *\n * @example\n * ```typescript\n * // Simple provider with single handler\n * const options: CreateProviderOptions = {\n * name: 'my-provider',\n * version: '1.0.0',\n * handlers: {\n * llm: createLLMHandler(),\n * embedding: createEmbeddingHandler(),\n * },\n * };\n *\n * // Provider with multiple LLM handlers (API modes)\n * const options: CreateProviderOptions<OpenAIOptions> = {\n * name: 'openai',\n * version: '1.0.0',\n * handlers: {\n * llm: {\n * handlers: { responses: handler1, completions: handler2 },\n * defaultMode: 'responses',\n * getMode: (opts) => opts?.api ?? 'responses',\n * },\n * },\n * };\n * ```\n */\nexport interface CreateProviderOptions<TOptions = unknown> {\n /** Unique identifier for the provider */\n name: string;\n /** Semantic version string for the provider implementation */\n version: string;\n /** Handlers for supported modalities (LLM, embedding, image generation) */\n handlers: {\n /** Handler for language model completions, or resolver for multi-handler providers */\n llm?: LLMHandler | LLMHandlerResolver<TOptions>;\n /** Handler for text embeddings */\n embedding?: EmbeddingHandler;\n /** Handler for image generation */\n image?: ImageHandler;\n };\n /**\n * Custom function to create model references from options.\n * Use this to map provider options to providerConfig (e.g., betas to headers).\n */\n createModelReference?: (\n modelId: string,\n options: TOptions | undefined,\n provider: Provider<TOptions>\n ) => ModelReference<TOptions>;\n}\n\n\n/**\n * Creates a provider factory function with registered modality handlers.\n *\n * The returned provider is a callable function that creates model references\n * when invoked with a model ID. It exposes `name` and `version` metadata.\n *\n * @typeParam TOptions - Provider-specific options type (defaults to unknown)\n * @param options - Provider configuration including name, version, and handlers\n * @returns A callable Provider with handlers registered internally\n *\n * @example\n * ```typescript\n * // Create a basic provider\n * const anthropic = createProvider({\n * name: 'anthropic',\n * version: '1.0.0',\n * handlers: { llm: createLLMHandler() },\n * });\n *\n * // Use the provider to create a model reference\n * const model = anthropic('claude-sonnet-4-20250514');\n *\n * // Provider with custom options type\n * interface MyOptions { apiVersion?: 'v1' | 'v2' }\n * const myProvider = createProvider<MyOptions>({\n * name: 'my-provider',\n * version: '1.0.0',\n * handlers: { llm: handler },\n * });\n *\n * // Provider with multiple LLM handlers (API modes)\n * const openai = createProvider<OpenAIOptions>({\n * name: 'openai',\n * version: '1.0.0',\n * handlers: {\n * llm: {\n * handlers: { responses: responsesHandler, completions: completionsHandler },\n * defaultMode: 'responses',\n * getMode: (opts) => opts?.api ?? 'responses',\n * },\n * },\n * });\n * ```\n */\nexport function createProvider<TOptions = unknown>(\n options: CreateProviderOptions<TOptions>\n): Provider<TOptions> {\n // Resolve the default LLM handler for capabilities/bind\n const llmInput = options.handlers.llm;\n const hasResolver = isHandlerResolver<TOptions>(llmInput);\n const defaultLLMHandler = hasResolver ? llmInput.handlers[llmInput.defaultMode] : llmInput;\n\n if (hasResolver && !defaultLLMHandler) {\n throw new Error(\n `Provider '${options.name}' LLM resolver defaultMode '${llmInput.defaultMode}' has no handler`\n );\n }\n\n // Declare provider first so closure can capture it\n let provider: Provider<TOptions>;\n\n // Create the factory function\n const fn = function (modelId: string, modelOptions?: TOptions): ModelReference<TOptions> {\n if (options.createModelReference) {\n return options.createModelReference(modelId, modelOptions, provider);\n }\n // Default: store options on the reference for handler resolution\n return { modelId, provider, options: modelOptions };\n };\n\n Object.defineProperties(fn, {\n name: {\n value: options.name,\n writable: false,\n configurable: true,\n },\n version: {\n value: options.version,\n writable: false,\n configurable: true,\n },\n });\n\n provider = fn as Provider<TOptions>;\n\n // If there's a resolver, set provider on all handlers\n if (hasResolver) {\n for (const handler of Object.values(llmInput.handlers)) {\n handler._setProvider?.(provider as unknown as LLMProvider);\n }\n } else if (defaultLLMHandler?._setProvider) {\n defaultLLMHandler._setProvider(provider as unknown as LLMProvider);\n }\n\n if (options.handlers.embedding?._setProvider) {\n options.handlers.embedding._setProvider(provider as unknown as EmbeddingProvider);\n }\n if (options.handlers.image?._setProvider) {\n options.handlers.image._setProvider(provider as unknown as ImageProvider);\n }\n\n registerProviderHandlers(provider, {\n llm: defaultLLMHandler,\n embedding: options.handlers.embedding,\n image: options.handlers.image,\n ...(hasResolver ? { llmResolver: llmInput } : {}),\n });\n\n return provider;\n}\n"],"mappings":";AAkCO,SAAS,kBACd,OACuC;AACvC,SAAO,UAAU,UAAa,cAAc,SAAS,aAAa;AACpE;AASA,IAAM,mBAAmB,oBAAI,QAA2C;AAKjE,SAAS,yBACd,UACA,UACM;AACN,mBAAiB,IAAI,UAAoB,QAAqC;AAChF;AAEA,SAAS,oBACP,UACwC;AACxC,SAAO,iBAAiB,IAAI,QAAkB;AAChD;AAkBO,SAAS,kBACd,UACA,SACwB;AACxB,QAAM,WAAW,oBAAoB,QAAQ;AAC7C,QAAM,WAAW,UAAU;AAE3B,MAAI,UAAU;AACZ,UAAM,OAAO,SAAS,QAAQ,OAAO;AACrC,WAAO,SAAS,SAAS,IAAI,KAAK,UAAU;AAAA,EAC9C;AAEA,SAAO,UAAU;AACnB;AAOO,SAAS,wBACd,UACuC;AACvC,QAAM,WAAW,oBAAoB,QAAQ;AAC7C,SAAO,UAAU;AACnB;AAOO,SAAS,oBACd,UACmC;AACnC,QAAM,WAAW,oBAAoB,QAAQ;AAC7C,SAAO,UAAU;AACnB;;;ACOO,SAAS,eACd,SACoB;AAEpB,QAAM,WAAW,QAAQ,SAAS;AAClC,QAAM,cAAc,kBAA4B,QAAQ;AACxD,QAAM,oBAAoB,cAAc,SAAS,SAAS,SAAS,WAAW,IAAI;AAElF,MAAI,eAAe,CAAC,mBAAmB;AACrC,UAAM,IAAI;AAAA,MACR,aAAa,QAAQ,IAAI,+BAA+B,SAAS,WAAW;AAAA,IAC9E;AAAA,EACF;AAGA,MAAI;AAGJ,QAAM,KAAK,SAAU,SAAiB,cAAmD;AACvF,QAAI,QAAQ,sBAAsB;AAChC,aAAO,QAAQ,qBAAqB,SAAS,cAAc,QAAQ;AAAA,IACrE;AAEA,WAAO,EAAE,SAAS,UAAU,SAAS,aAAa;AAAA,EACpD;AAEA,SAAO,iBAAiB,IAAI;AAAA,IAC1B,MAAM;AAAA,MACJ,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,SAAS;AAAA,MACP,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,EACF,CAAC;AAED,aAAW;AAGX,MAAI,aAAa;AACf,eAAW,WAAW,OAAO,OAAO,SAAS,QAAQ,GAAG;AACtD,cAAQ,eAAe,QAAkC;AAAA,IAC3D;AAAA,EACF,WAAW,mBAAmB,cAAc;AAC1C,sBAAkB,aAAa,QAAkC;AAAA,EACnE;AAEA,MAAI,QAAQ,SAAS,WAAW,cAAc;AAC5C,YAAQ,SAAS,UAAU,aAAa,QAAwC;AAAA,EAClF;AACA,MAAI,QAAQ,SAAS,OAAO,cAAc;AACxC,YAAQ,SAAS,MAAM,aAAa,QAAoC;AAAA,EAC1E;AAEA,2BAAyB,UAAU;AAAA,IACjC,KAAK;AAAA,IACL,WAAW,QAAQ,SAAS;AAAA,IAC5B,OAAO,QAAQ,SAAS;AAAA,IACxB,GAAI,cAAc,EAAE,aAAa,SAAS,IAAI,CAAC;AAAA,EACjD,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -1,4 +1,34 @@
1
1
  // src/core/media/Image.ts
2
+ function detectMimeType(path) {
3
+ const ext = path.split(".").pop()?.toLowerCase();
4
+ switch (ext) {
5
+ case "jpg":
6
+ case "jpeg":
7
+ return "image/jpeg";
8
+ case "png":
9
+ return "image/png";
10
+ case "gif":
11
+ return "image/gif";
12
+ case "webp":
13
+ return "image/webp";
14
+ case "svg":
15
+ return "image/svg+xml";
16
+ case "bmp":
17
+ return "image/bmp";
18
+ case "ico":
19
+ return "image/x-icon";
20
+ default:
21
+ return "application/octet-stream";
22
+ }
23
+ }
24
+ function detectMimeTypeFromUrl(url) {
25
+ try {
26
+ const pathname = new URL(url).pathname;
27
+ return detectMimeType(pathname);
28
+ } catch {
29
+ return "application/octet-stream";
30
+ }
31
+ }
2
32
  var Image = class _Image {
3
33
  /** The underlying image source (bytes, base64, or URL) */
4
34
  source;
@@ -187,38 +217,8 @@ var Image = class _Image {
187
217
  );
188
218
  }
189
219
  };
190
- function detectMimeType(path) {
191
- const ext = path.split(".").pop()?.toLowerCase();
192
- switch (ext) {
193
- case "jpg":
194
- case "jpeg":
195
- return "image/jpeg";
196
- case "png":
197
- return "image/png";
198
- case "gif":
199
- return "image/gif";
200
- case "webp":
201
- return "image/webp";
202
- case "svg":
203
- return "image/svg+xml";
204
- case "bmp":
205
- return "image/bmp";
206
- case "ico":
207
- return "image/x-icon";
208
- default:
209
- return "application/octet-stream";
210
- }
211
- }
212
- function detectMimeTypeFromUrl(url) {
213
- try {
214
- const pathname = new URL(url).pathname;
215
- return detectMimeType(pathname);
216
- } catch {
217
- return "application/octet-stream";
218
- }
219
- }
220
220
 
221
221
  export {
222
222
  Image
223
223
  };
224
- //# sourceMappingURL=chunk-WAKD3OO5.js.map
224
+ //# sourceMappingURL=chunk-N5DX5JW3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/media/Image.ts"],"sourcesContent":["/**\n * @fileoverview Image content handling for the Universal Provider Protocol.\n *\n * Provides a unified Image class for working with images across different sources\n * (file paths, URLs, raw bytes, base64). Supports conversion between formats and\n * integration with UPP message content blocks.\n *\n * @module core/media/Image\n */\n\nimport type { ImageSource, ImageBlock } from '../../types/content.ts';\n\n/**\n * Detects the MIME type of an image based on its file extension.\n *\n * Supports common web image formats: JPEG, PNG, GIF, WebP, SVG, BMP, ICO.\n * Returns 'application/octet-stream' for unknown extensions.\n *\n * @param path - File path or filename with extension\n * @returns The detected MIME type string\n */\nfunction detectMimeType(path: string): string {\n const ext = path.split('.').pop()?.toLowerCase();\n\n switch (ext) {\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'png':\n return 'image/png';\n case 'gif':\n return 'image/gif';\n case 'webp':\n return 'image/webp';\n case 'svg':\n return 'image/svg+xml';\n case 'bmp':\n return 'image/bmp';\n case 'ico':\n return 'image/x-icon';\n default:\n return 'application/octet-stream';\n }\n}\n\n/**\n * Detects the MIME type of an image from its URL.\n *\n * Extracts the pathname from the URL and delegates to `detectMimeType`.\n * Returns 'application/octet-stream' if the URL cannot be parsed.\n *\n * @param url - Full URL pointing to an image\n * @returns The detected MIME type string\n */\nfunction detectMimeTypeFromUrl(url: string): string {\n try {\n const pathname = new URL(url).pathname;\n return detectMimeType(pathname);\n } catch {\n return 'application/octet-stream';\n }\n}\n\n/**\n * Represents an image that can be used in UPP messages.\n *\n * Images can be created from various sources (files, URLs, bytes, base64) and\n * converted to different formats as needed by providers. The class provides\n * a unified interface regardless of the underlying source type.\n *\n * @example\n * ```typescript\n * // Load from file\n * const fileImage = await Image.fromPath('./photo.jpg');\n *\n * // Reference by URL\n * const urlImage = Image.fromUrl('https://example.com/image.png');\n *\n * // From raw bytes\n * const bytesImage = Image.fromBytes(uint8Array, 'image/png');\n *\n * // Use in a message\n * const message = new UserMessage([image.toBlock()]);\n * ```\n */\nexport class Image {\n /** The underlying image source (bytes, base64, or URL) */\n readonly source: ImageSource;\n /** MIME type of the image (e.g., 'image/jpeg', 'image/png') */\n readonly mimeType: string;\n /** Image width in pixels, if known */\n readonly width?: number;\n /** Image height in pixels, if known */\n readonly height?: number;\n\n private constructor(\n source: ImageSource,\n mimeType: string,\n width?: number,\n height?: number\n ) {\n this.source = source;\n this.mimeType = mimeType;\n this.width = width;\n this.height = height;\n }\n\n /**\n * Whether this image has data loaded in memory.\n *\n * Returns `false` for URL-sourced images that reference external resources.\n * These must be fetched before their data can be accessed.\n */\n get hasData(): boolean {\n return this.source.type !== 'url';\n }\n\n /**\n * Converts the image to a base64-encoded string.\n *\n * @returns The image data as a base64 string\n * @throws {Error} When the source is a URL (data must be fetched first)\n */\n toBase64(): string {\n if (this.source.type === 'base64') {\n return this.source.data;\n }\n\n if (this.source.type === 'bytes') {\n return btoa(\n Array.from(this.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n }\n\n throw new Error('Cannot convert URL image to base64. Fetch the image first.');\n }\n\n /**\n * Converts the image to a data URL suitable for embedding in HTML or CSS.\n *\n * @returns A data URL in the format `data:{mimeType};base64,{data}`\n * @throws {Error} When the source is a URL (data must be fetched first)\n */\n toDataUrl(): string {\n const base64 = this.toBase64();\n return `data:${this.mimeType};base64,${base64}`;\n }\n\n /**\n * Gets the image data as raw bytes.\n *\n * @returns The image data as a Uint8Array\n * @throws {Error} When the source is a URL (data must be fetched first)\n */\n toBytes(): Uint8Array {\n if (this.source.type === 'bytes') {\n return this.source.data;\n }\n\n if (this.source.type === 'base64') {\n const binaryString = atob(this.source.data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n }\n\n throw new Error('Cannot get bytes from URL image. Fetch the image first.');\n }\n\n /**\n * Gets the URL for URL-sourced images.\n *\n * @returns The image URL\n * @throws {Error} When the source is not a URL\n */\n toUrl(): string {\n if (this.source.type === 'url') {\n return this.source.url;\n }\n\n throw new Error('This image does not have a URL source.');\n }\n\n /**\n * Converts this Image to an ImageBlock for use in UPP messages.\n *\n * @returns An ImageBlock that can be included in message content arrays\n */\n toBlock(): ImageBlock {\n return {\n type: 'image',\n source: this.source,\n mimeType: this.mimeType,\n width: this.width,\n height: this.height,\n };\n }\n\n /**\n * Creates an Image by reading a file from disk.\n *\n * The file is read into memory as bytes. MIME type is automatically\n * detected from the file extension.\n *\n * @param path - Path to the image file\n * @returns Promise resolving to an Image with the file contents\n *\n * @example\n * ```typescript\n * const image = await Image.fromPath('./photos/vacation.jpg');\n * ```\n */\n static async fromPath(path: string): Promise<Image> {\n // Dynamic import to avoid bundling fs in browser builds\n const { readFile } = await import('node:fs/promises');\n const data = await readFile(path);\n const mimeType = detectMimeType(path);\n\n return new Image(\n { type: 'bytes', data: new Uint8Array(data) },\n mimeType\n );\n }\n\n /**\n * Creates an Image from a URL reference.\n *\n * The URL is stored as a reference and not fetched. Providers will handle\n * URL-to-data conversion if needed. MIME type is detected from the URL\n * path if not provided.\n *\n * @param url - URL pointing to the image\n * @param mimeType - Optional MIME type override\n * @returns An Image referencing the URL\n *\n * @example\n * ```typescript\n * const image = Image.fromUrl('https://example.com/logo.png');\n * ```\n */\n static fromUrl(url: string, mimeType?: string): Image {\n const detected = mimeType || detectMimeTypeFromUrl(url);\n return new Image({ type: 'url', url }, detected);\n }\n\n /**\n * Creates an Image from raw byte data.\n *\n * @param data - The image data as a Uint8Array\n * @param mimeType - The MIME type of the image\n * @returns An Image containing the byte data\n *\n * @example\n * ```typescript\n * const image = Image.fromBytes(pngData, 'image/png');\n * ```\n */\n static fromBytes(data: Uint8Array, mimeType: string): Image {\n return new Image({ type: 'bytes', data }, mimeType);\n }\n\n /**\n * Creates an Image from a base64-encoded string.\n *\n * @param base64 - The base64-encoded image data (without data URL prefix)\n * @param mimeType - The MIME type of the image\n * @returns An Image containing the base64 data\n *\n * @example\n * ```typescript\n * const image = Image.fromBase64(base64String, 'image/jpeg');\n * ```\n */\n static fromBase64(base64: string, mimeType: string): Image {\n return new Image({ type: 'base64', data: base64 }, mimeType);\n }\n\n /**\n * Creates an Image from an existing ImageBlock.\n *\n * Useful for converting content blocks received from providers back\n * into Image instances for further processing.\n *\n * @param block - An ImageBlock from message content\n * @returns An Image with the block's source and metadata\n */\n static fromBlock(block: ImageBlock): Image {\n return new Image(\n block.source,\n block.mimeType,\n block.width,\n block.height\n );\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,97 @@
1
+ import {
2
+ resolveImageResult,
3
+ serializeImageResult,
4
+ serializeImageStreamEvent,
5
+ serializeStreamEvent,
6
+ serializeTurn
7
+ } from "./chunk-C4JP64VW.js";
8
+
9
+ // src/providers/proxy/server/express.ts
10
+ function sendJSON(turn, res) {
11
+ res.setHeader("Content-Type", "application/json");
12
+ res.json(serializeTurn(turn));
13
+ }
14
+ function sendEmbeddingJSON(result, res) {
15
+ res.setHeader("Content-Type", "application/json");
16
+ res.json(result);
17
+ }
18
+ function sendImageJSON(result, res) {
19
+ res.setHeader("Content-Type", "application/json");
20
+ res.json(serializeImageResult(result));
21
+ }
22
+ function streamSSE(stream, res) {
23
+ res.setHeader("Content-Type", "text/event-stream");
24
+ res.setHeader("Cache-Control", "no-cache");
25
+ res.setHeader("Connection", "keep-alive");
26
+ (async () => {
27
+ try {
28
+ for await (const event of stream) {
29
+ const serialized = serializeStreamEvent(event);
30
+ res.write(`data: ${JSON.stringify(serialized)}
31
+
32
+ `);
33
+ }
34
+ const turn = await stream.turn;
35
+ res.write(`data: ${JSON.stringify(serializeTurn(turn))}
36
+
37
+ `);
38
+ res.write("data: [DONE]\n\n");
39
+ } catch (error) {
40
+ const message = error instanceof Error ? error.message : String(error);
41
+ res.write(`data: ${JSON.stringify({ error: message })}
42
+
43
+ `);
44
+ } finally {
45
+ res.end();
46
+ }
47
+ })();
48
+ }
49
+ function streamImageSSE(stream, res) {
50
+ res.setHeader("Content-Type", "text/event-stream");
51
+ res.setHeader("Cache-Control", "no-cache");
52
+ res.setHeader("Connection", "keep-alive");
53
+ (async () => {
54
+ try {
55
+ for await (const event of stream) {
56
+ const serialized = serializeImageStreamEvent(event);
57
+ res.write(`data: ${JSON.stringify(serialized)}
58
+
59
+ `);
60
+ }
61
+ const result = await resolveImageResult(stream);
62
+ res.write(`data: ${JSON.stringify(serializeImageResult(result))}
63
+
64
+ `);
65
+ res.write("data: [DONE]\n\n");
66
+ } catch (error) {
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ res.write(`data: ${JSON.stringify({ error: message })}
69
+
70
+ `);
71
+ } finally {
72
+ res.end();
73
+ }
74
+ })();
75
+ }
76
+ function sendError(message, status, res) {
77
+ res.status(status).json({ error: message });
78
+ }
79
+ var express = {
80
+ sendJSON,
81
+ sendEmbeddingJSON,
82
+ sendImageJSON,
83
+ streamSSE,
84
+ streamImageSSE,
85
+ sendError
86
+ };
87
+
88
+ export {
89
+ sendJSON,
90
+ sendEmbeddingJSON,
91
+ sendImageJSON,
92
+ streamSSE,
93
+ streamImageSSE,
94
+ sendError,
95
+ express
96
+ };
97
+ //# sourceMappingURL=chunk-OIEWDFQU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/proxy/server/express.ts"],"sourcesContent":["/**\n * @fileoverview Express/Connect adapter for proxy server.\n *\n * Provides utilities for using PP proxy with Express.js or Connect-based servers.\n * These adapters convert PP types to Express-compatible responses.\n *\n * @module providers/proxy/server/express\n */\n\nimport type { Turn } from '../../../types/turn.ts';\nimport type { StreamResult } from '../../../types/stream.ts';\nimport type { EmbeddingResult } from '../../../types/embedding.ts';\nimport type { ImageResult } from '../../../types/image.ts';\nimport { serializeTurn, serializeStreamEvent } from '../serialization.ts';\nimport { serializeImageResult, serializeImageStreamEvent } from '../serialization.media.ts';\nimport { resolveImageResult, type ImageStreamLike } from './image-stream.ts';\n\n/**\n * Express Response interface (minimal type to avoid dependency).\n */\ninterface ExpressResponse {\n setHeader(name: string, value: string): void;\n status(code: number): ExpressResponse;\n write(chunk: string): boolean;\n end(): void;\n json(body: unknown): void;\n}\n\n/**\n * Send a Turn as JSON response.\n *\n * @param turn - The completed inference turn\n * @param res - Express response object\n *\n * @example\n * ```typescript\n * const turn = await instance.generate(messages);\n * expressAdapter.sendJSON(turn, res);\n * ```\n */\nexport function sendJSON(turn: Turn, res: ExpressResponse): void {\n res.setHeader('Content-Type', 'application/json');\n res.json(serializeTurn(turn));\n}\n\n/**\n * Send an EmbeddingResult as JSON response.\n *\n * @param result - The embedding result\n * @param res - Express response object\n */\nexport function sendEmbeddingJSON(result: EmbeddingResult, res: ExpressResponse): void {\n res.setHeader('Content-Type', 'application/json');\n res.json(result);\n}\n\n/**\n * Send an ImageResult as JSON response.\n *\n * @param result - The image result\n * @param res - Express response object\n */\nexport function sendImageJSON(result: ImageResult, res: ExpressResponse): void {\n res.setHeader('Content-Type', 'application/json');\n res.json(serializeImageResult(result));\n}\n\n/**\n * Stream a StreamResult as Server-Sent Events.\n *\n * @param stream - The StreamResult from instance.stream()\n * @param res - Express response object\n *\n * @example\n * ```typescript\n * const stream = instance.stream(messages);\n * expressAdapter.streamSSE(stream, res);\n * ```\n */\nexport function streamSSE(stream: StreamResult, res: ExpressResponse): void {\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n (async () => {\n try {\n for await (const event of stream) {\n const serialized = serializeStreamEvent(event);\n res.write(`data: ${JSON.stringify(serialized)}\\n\\n`);\n }\n\n const turn = await stream.turn;\n res.write(`data: ${JSON.stringify(serializeTurn(turn))}\\n\\n`);\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n res.write(`data: ${JSON.stringify({ error: message })}\\n\\n`);\n } finally {\n res.end();\n }\n })();\n}\n\n/**\n * Stream an ImageStreamResult as Server-Sent Events.\n *\n * @param stream - The ImageStreamResult or ImageProviderStreamResult from image().stream()\n * @param res - Express response object\n */\nexport function streamImageSSE(stream: ImageStreamLike, res: ExpressResponse): void {\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n\n (async () => {\n try {\n for await (const event of stream) {\n const serialized = serializeImageStreamEvent(event);\n res.write(`data: ${JSON.stringify(serialized)}\\n\\n`);\n }\n\n const result = await resolveImageResult(stream);\n res.write(`data: ${JSON.stringify(serializeImageResult(result))}\\n\\n`);\n res.write('data: [DONE]\\n\\n');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n res.write(`data: ${JSON.stringify({ error: message })}\\n\\n`);\n } finally {\n res.end();\n }\n })();\n}\n\n/**\n * Send an error response.\n *\n * @param message - Error message\n * @param status - HTTP status code\n * @param res - Express response object\n */\nexport function sendError(message: string, status: number, res: ExpressResponse): void {\n res.status(status).json({ error: message });\n}\n\n/**\n * Express adapter utilities.\n *\n * @example Basic usage\n * ```typescript\n * import express from 'express';\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { parseBody } from '@providerprotocol/ai/proxy';\n * import { express as expressAdapter } from '@providerprotocol/ai/proxy/server';\n *\n * const app = express();\n * app.use(express.json());\n *\n * app.post('/api/ai', async (req, res) => {\n * const { messages, system, params } = parseBody(req.body);\n * const instance = llm({ model: anthropic('claude-sonnet-4-20250514'), system });\n *\n * if (req.headers.accept?.includes('text/event-stream')) {\n * expressAdapter.streamSSE(instance.stream(messages), res);\n * } else {\n * const turn = await instance.generate(messages);\n * expressAdapter.sendJSON(turn, res);\n * }\n * });\n * ```\n *\n * @example API Gateway with authentication\n * ```typescript\n * import express from 'express';\n * import { llm } from '@providerprotocol/ai';\n * import { anthropic } from '@providerprotocol/ai/anthropic';\n * import { ExponentialBackoff, RoundRobinKeys } from '@providerprotocol/ai/http';\n * import { parseBody } from '@providerprotocol/ai/proxy';\n * import { express as expressAdapter } from '@providerprotocol/ai/proxy/server';\n *\n * const app = express();\n * app.use(express.json());\n *\n * // Your platform's auth middleware\n * async function authMiddleware(req, res, next) {\n * const token = req.headers.authorization?.replace('Bearer ', '');\n * const user = await validatePlatformToken(token);\n * if (!user) return res.status(401).json({ error: 'Unauthorized' });\n * req.user = user;\n * next();\n * }\n *\n * // Server manages AI provider keys - users never see them\n * const claude = llm({\n * model: anthropic('claude-sonnet-4-20250514'),\n * config: {\n * apiKey: new RoundRobinKeys([process.env.ANTHROPIC_KEY_1!, process.env.ANTHROPIC_KEY_2!]),\n * retryStrategy: new ExponentialBackoff({ maxAttempts: 3 }),\n * },\n * });\n *\n * app.post('/api/ai', authMiddleware, async (req, res) => {\n * // Track usage per user\n * // await trackUsage(req.user.id);\n *\n * const { messages, system, params } = parseBody(req.body);\n *\n * if (params?.stream) {\n * expressAdapter.streamSSE(claude.stream(messages, { system }), res);\n * } else {\n * const turn = await claude.generate(messages, { system });\n * expressAdapter.sendJSON(turn, res);\n * }\n * });\n * ```\n */\nexport const express = {\n sendJSON,\n sendEmbeddingJSON,\n sendImageJSON,\n streamSSE,\n streamImageSSE,\n sendError,\n};\n"],"mappings":";;;;;;;;;AAwCO,SAAS,SAAS,MAAY,KAA4B;AAC/D,MAAI,UAAU,gBAAgB,kBAAkB;AAChD,MAAI,KAAK,cAAc,IAAI,CAAC;AAC9B;AAQO,SAAS,kBAAkB,QAAyB,KAA4B;AACrF,MAAI,UAAU,gBAAgB,kBAAkB;AAChD,MAAI,KAAK,MAAM;AACjB;AAQO,SAAS,cAAc,QAAqB,KAA4B;AAC7E,MAAI,UAAU,gBAAgB,kBAAkB;AAChD,MAAI,KAAK,qBAAqB,MAAM,CAAC;AACvC;AAcO,SAAS,UAAU,QAAsB,KAA4B;AAC1E,MAAI,UAAU,gBAAgB,mBAAmB;AACjD,MAAI,UAAU,iBAAiB,UAAU;AACzC,MAAI,UAAU,cAAc,YAAY;AAExC,GAAC,YAAY;AACX,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,cAAM,aAAa,qBAAqB,KAAK;AAC7C,YAAI,MAAM,SAAS,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA,CAAM;AAAA,MACrD;AAEA,YAAM,OAAO,MAAM,OAAO;AAC1B,UAAI,MAAM,SAAS,KAAK,UAAU,cAAc,IAAI,CAAC,CAAC;AAAA;AAAA,CAAM;AAC5D,UAAI,MAAM,kBAAkB;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,CAAC;AAAA;AAAA,CAAM;AAAA,IAC7D,UAAE;AACA,UAAI,IAAI;AAAA,IACV;AAAA,EACF,GAAG;AACL;AAQO,SAAS,eAAe,QAAyB,KAA4B;AAClF,MAAI,UAAU,gBAAgB,mBAAmB;AACjD,MAAI,UAAU,iBAAiB,UAAU;AACzC,MAAI,UAAU,cAAc,YAAY;AAExC,GAAC,YAAY;AACX,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,cAAM,aAAa,0BAA0B,KAAK;AAClD,YAAI,MAAM,SAAS,KAAK,UAAU,UAAU,CAAC;AAAA;AAAA,CAAM;AAAA,MACrD;AAEA,YAAM,SAAS,MAAM,mBAAmB,MAAM;AAC9C,UAAI,MAAM,SAAS,KAAK,UAAU,qBAAqB,MAAM,CAAC,CAAC;AAAA;AAAA,CAAM;AACrE,UAAI,MAAM,kBAAkB;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAI,MAAM,SAAS,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,CAAC;AAAA;AAAA,CAAM;AAAA,IAC7D,UAAE;AACA,UAAI,IAAI;AAAA,IACV;AAAA,EACF,GAAG;AACL;AASO,SAAS,UAAU,SAAiB,QAAgB,KAA4B;AACrF,MAAI,OAAO,MAAM,EAAE,KAAK,EAAE,OAAO,QAAQ,CAAC;AAC5C;AA0EO,IAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
@@ -1,4 +1,43 @@
1
1
  // src/http/sse.ts
2
+ function parseSSEEvent(eventText) {
3
+ const lines = eventText.split("\n");
4
+ let data = "";
5
+ let eventType = "";
6
+ for (const line of lines) {
7
+ const normalizedLine = line.endsWith("\r") ? line.slice(0, -1) : line;
8
+ if (normalizedLine.startsWith("event:")) {
9
+ let value = normalizedLine.slice(6);
10
+ if (value.startsWith(" ")) value = value.slice(1);
11
+ eventType = value;
12
+ } else if (normalizedLine.startsWith("data:")) {
13
+ let value = normalizedLine.slice(5);
14
+ if (value.startsWith(" ")) value = value.slice(1);
15
+ data += (data ? "\n" : "") + value;
16
+ } else if (normalizedLine.startsWith(":")) {
17
+ continue;
18
+ } else {
19
+ const trimmedStart = normalizedLine.trimStart();
20
+ if (trimmedStart.startsWith("{") || trimmedStart.startsWith("[")) {
21
+ data += (data ? "\n" : "") + trimmedStart;
22
+ }
23
+ }
24
+ }
25
+ if (!data) {
26
+ return null;
27
+ }
28
+ if (data === "[DONE]") {
29
+ return "DONE";
30
+ }
31
+ try {
32
+ const parsed = JSON.parse(data);
33
+ if (eventType) {
34
+ return { _eventType: eventType, ...parsed };
35
+ }
36
+ return parsed;
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
2
41
  async function* parseSSEStream(body) {
3
42
  const reader = body.getReader();
4
43
  const decoder = new TextDecoder();
@@ -40,45 +79,6 @@ async function* parseSSEStream(body) {
40
79
  reader.releaseLock();
41
80
  }
42
81
  }
43
- function parseSSEEvent(eventText) {
44
- const lines = eventText.split("\n");
45
- let data = "";
46
- let eventType = "";
47
- for (const line of lines) {
48
- const normalizedLine = line.endsWith("\r") ? line.slice(0, -1) : line;
49
- if (normalizedLine.startsWith("event:")) {
50
- let value = normalizedLine.slice(6);
51
- if (value.startsWith(" ")) value = value.slice(1);
52
- eventType = value;
53
- } else if (normalizedLine.startsWith("data:")) {
54
- let value = normalizedLine.slice(5);
55
- if (value.startsWith(" ")) value = value.slice(1);
56
- data += (data ? "\n" : "") + value;
57
- } else if (normalizedLine.startsWith(":")) {
58
- continue;
59
- } else {
60
- const trimmedStart = normalizedLine.trimStart();
61
- if (trimmedStart.startsWith("{") || trimmedStart.startsWith("[")) {
62
- data += (data ? "\n" : "") + trimmedStart;
63
- }
64
- }
65
- }
66
- if (!data) {
67
- return null;
68
- }
69
- if (data === "[DONE]") {
70
- return "DONE";
71
- }
72
- try {
73
- const parsed = JSON.parse(data);
74
- if (eventType) {
75
- return { _eventType: eventType, ...parsed };
76
- }
77
- return parsed;
78
- } catch {
79
- return null;
80
- }
81
- }
82
82
  async function* parseSimpleTextStream(body) {
83
83
  const reader = body.getReader();
84
84
  const decoder = new TextDecoder();
@@ -104,4 +104,4 @@ export {
104
104
  parseSSEStream,
105
105
  parseSimpleTextStream
106
106
  };
107
- //# sourceMappingURL=chunk-TOJCZMVU.js.map
107
+ //# sourceMappingURL=chunk-PMK5LZ5Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http/sse.ts"],"sourcesContent":["/**\n * Server-Sent Events (SSE) stream parsing utilities.\n * @module http/sse\n */\n\n/**\n * Parses a single SSE event block into a JSON object.\n *\n * Handles the following line prefixes:\n * - \"data:\" - Event data (multiple data lines are concatenated)\n * - \"event:\" - Event type (added to result as _eventType)\n * - \":\" - Comment (ignored, often used for keep-alive)\n * - Raw JSON starting with { or [ (provider-specific fallback)\n *\n * @param eventText - Raw text of a single SSE event block\n * @returns Parsed JSON object, 'DONE' for termination signal, or null for invalid/empty events\n */\nfunction parseSSEEvent(eventText: string): unknown | 'DONE' | null {\n const lines = eventText.split('\\n');\n let data = '';\n let eventType = '';\n\n for (const line of lines) {\n const normalizedLine = line.endsWith('\\r') ? line.slice(0, -1) : line;\n if (normalizedLine.startsWith('event:')) {\n let value = normalizedLine.slice(6);\n if (value.startsWith(' ')) value = value.slice(1);\n eventType = value;\n } else if (normalizedLine.startsWith('data:')) {\n let value = normalizedLine.slice(5);\n if (value.startsWith(' ')) value = value.slice(1);\n data += (data ? '\\n' : '') + value;\n } else if (normalizedLine.startsWith(':')) {\n continue;\n } else {\n const trimmedStart = normalizedLine.trimStart();\n if (trimmedStart.startsWith('{') || trimmedStart.startsWith('[')) {\n data += (data ? '\\n' : '') + trimmedStart;\n }\n }\n }\n\n if (!data) {\n return null;\n }\n\n if (data === '[DONE]') {\n return 'DONE';\n }\n\n try {\n const parsed = JSON.parse(data);\n\n if (eventType) {\n return { _eventType: eventType, ...parsed };\n }\n\n return parsed;\n } catch {\n return null;\n }\n}\n\n/**\n * Parses a Server-Sent Events stream into JSON objects.\n *\n * This async generator handles the standard SSE wire format:\n * - Lines prefixed with \"data:\" contain event data\n * - Lines prefixed with \"event:\" specify event types\n * - Lines prefixed with \":\" are comments (used for keep-alive)\n * - Events are separated by double newlines\n * - Stream terminates on \"[DONE]\" message (OpenAI convention)\n *\n * Also handles non-standard formats used by some providers:\n * - Raw JSON without \"data:\" prefix (Google)\n * - Multi-line data fields\n *\n * @param body - ReadableStream from fetch response body\n * @yields Parsed JSON objects from each SSE event\n *\n * @example\n * ```typescript\n * const response = await doStreamFetch(url, init, config, 'openai', 'llm');\n *\n * for await (const event of parseSSEStream(response.body!)) {\n * // event is parsed JSON from each SSE data field\n * const chunk = event as OpenAIStreamChunk;\n * const delta = chunk.choices[0]?.delta?.content;\n * if (delta) {\n * process.stdout.write(delta);\n * }\n * }\n * ```\n */\nexport async function* parseSSEStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<unknown, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n const tail = decoder.decode();\n if (tail) {\n buffer += tail;\n }\n // Process any remaining data in buffer\n if (buffer.trim()) {\n const event = parseSSEEvent(buffer);\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n break;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n if (chunk) {\n buffer += chunk;\n }\n\n // Process complete events (separated by double newlines or \\r\\n\\r\\n)\n const events = buffer.split(/\\r?\\n\\r?\\n/);\n\n // Keep the last partial event in the buffer\n buffer = events.pop() ?? '';\n\n for (const eventText of events) {\n if (!eventText.trim()) continue;\n\n const event = parseSSEEvent(eventText);\n if (event === 'DONE') {\n return;\n }\n if (event !== null && event !== undefined) {\n yield event;\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Parses a simple text stream without SSE formatting.\n *\n * This is a simpler alternative to {@link parseSSEStream} for providers\n * that stream raw text deltas without SSE event wrappers. Each chunk\n * from the response body is decoded and yielded as-is.\n *\n * Use this for:\n * - Plain text streaming responses\n * - Providers with custom streaming formats\n * - Testing and debugging stream handling\n *\n * @param body - ReadableStream from fetch response body\n * @yields Decoded text strings from each stream chunk\n *\n * @example\n * ```typescript\n * const response = await doStreamFetch(url, init, config, 'custom', 'llm');\n *\n * for await (const text of parseSimpleTextStream(response.body!)) {\n * process.stdout.write(text);\n * }\n * ```\n */\nexport async function* parseSimpleTextStream(\n body: ReadableStream<Uint8Array>\n): AsyncGenerator<string, void, unknown> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) break;\n\n const text = decoder.decode(value, { stream: true });\n if (text) {\n yield text;\n }\n }\n const remaining = decoder.decode();\n if (remaining) {\n yield remaining;\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"mappings":";AAiBA,SAAS,cAAc,WAA4C;AACjE,QAAM,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,OAAO;AACX,MAAI,YAAY;AAEhB,aAAW,QAAQ,OAAO;AACxB,UAAM,iBAAiB,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACjE,QAAI,eAAe,WAAW,QAAQ,GAAG;AACvC,UAAI,QAAQ,eAAe,MAAM,CAAC;AAClC,UAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAChD,kBAAY;AAAA,IACd,WAAW,eAAe,WAAW,OAAO,GAAG;AAC7C,UAAI,QAAQ,eAAe,MAAM,CAAC;AAClC,UAAI,MAAM,WAAW,GAAG,EAAG,SAAQ,MAAM,MAAM,CAAC;AAChD,eAAS,OAAO,OAAO,MAAM;AAAA,IAC/B,WAAW,eAAe,WAAW,GAAG,GAAG;AACzC;AAAA,IACF,OAAO;AACL,YAAM,eAAe,eAAe,UAAU;AAC9C,UAAI,aAAa,WAAW,GAAG,KAAK,aAAa,WAAW,GAAG,GAAG;AAChE,iBAAS,OAAO,OAAO,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAE9B,QAAI,WAAW;AACb,aAAO,EAAE,YAAY,WAAW,GAAG,OAAO;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAiCA,gBAAuB,eACrB,MACwC;AACxC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,MAAM;AACR,cAAM,OAAO,QAAQ,OAAO;AAC5B,YAAI,MAAM;AACR,oBAAU;AAAA,QACZ;AAEA,YAAI,OAAO,KAAK,GAAG;AACjB,gBAAM,QAAQ,cAAc,MAAM;AAClC,cAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,kBAAM;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAEA,YAAM,QAAQ,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACpD,UAAI,OAAO;AACT,kBAAU;AAAA,MACZ;AAGA,YAAM,SAAS,OAAO,MAAM,YAAY;AAGxC,eAAS,OAAO,IAAI,KAAK;AAEzB,iBAAW,aAAa,QAAQ;AAC9B,YAAI,CAAC,UAAU,KAAK,EAAG;AAEvB,cAAM,QAAQ,cAAc,SAAS;AACrC,YAAI,UAAU,QAAQ;AACpB;AAAA,QACF;AACA,YAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AA0BA,gBAAuB,sBACrB,MACuC;AACvC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI;AACF,WAAO,MAAM;AACX,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,UAAI,KAAM;AAEV,YAAM,OAAO,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACnD,UAAI,MAAM;AACR,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,YAAY,QAAQ,OAAO;AACjC,QAAI,WAAW;AACb,YAAM;AAAA,IACR;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;","names":[]}