@flowselections/ai-authenticatie 1.0.2

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 (159) hide show
  1. package/dist-lib/_core-safelist.d.ts +2 -0
  2. package/dist-lib/_core-safelist.d.ts.map +1 -0
  3. package/dist-lib/_core-safelist.js +15 -0
  4. package/dist-lib/components/AiAuthenticatieLogo.d.ts +3 -0
  5. package/dist-lib/components/AiAuthenticatieLogo.d.ts.map +1 -0
  6. package/dist-lib/components/AiAuthenticatieLogo.js +4 -0
  7. package/dist-lib/components/AiAuthenticatiePage.d.ts +4 -0
  8. package/dist-lib/components/AiAuthenticatiePage.d.ts.map +1 -0
  9. package/dist-lib/components/AiAuthenticatiePage.js +145 -0
  10. package/dist-lib/components/AiModuleDetailPage.d.ts +2 -0
  11. package/dist-lib/components/AiModuleDetailPage.d.ts.map +1 -0
  12. package/dist-lib/components/AiModuleDetailPage.js +43 -0
  13. package/dist-lib/components/AiModuleTestPanel.d.ts +4 -0
  14. package/dist-lib/components/AiModuleTestPanel.d.ts.map +1 -0
  15. package/dist-lib/components/AiModuleTestPanel.js +38 -0
  16. package/dist-lib/components/AiPeriodFilter.d.ts +7 -0
  17. package/dist-lib/components/AiPeriodFilter.d.ts.map +1 -0
  18. package/dist-lib/components/AiPeriodFilter.js +14 -0
  19. package/dist-lib/components/AiStatTile.d.ts +6 -0
  20. package/dist-lib/components/AiStatTile.d.ts.map +1 -0
  21. package/dist-lib/components/AiStatTile.js +5 -0
  22. package/dist-lib/components/ModuleAgentsDialog.d.ts +14 -0
  23. package/dist-lib/components/ModuleAgentsDialog.d.ts.map +1 -0
  24. package/dist-lib/components/ModuleAgentsDialog.js +78 -0
  25. package/dist-lib/components/ProviderLogo.d.ts +8 -0
  26. package/dist-lib/components/ProviderLogo.d.ts.map +1 -0
  27. package/dist-lib/components/ProviderLogo.js +24 -0
  28. package/dist-lib/components/ProviderManageDialog.d.ts +11 -0
  29. package/dist-lib/components/ProviderManageDialog.d.ts.map +1 -0
  30. package/dist-lib/components/ProviderManageDialog.js +173 -0
  31. package/dist-lib/components/settings/AiAuthenticatieSettingsCard.d.ts +2 -0
  32. package/dist-lib/components/settings/AiAuthenticatieSettingsCard.d.ts.map +1 -0
  33. package/dist-lib/components/settings/AiAuthenticatieSettingsCard.js +7 -0
  34. package/dist-lib/components/settings/MijnModuleSettingsCard.d.ts +2 -0
  35. package/dist-lib/components/settings/MijnModuleSettingsCard.d.ts.map +1 -0
  36. package/dist-lib/components/settings/MijnModuleSettingsCard.js +42 -0
  37. package/dist-lib/hooks/useAdminCredentials.d.ts +14 -0
  38. package/dist-lib/hooks/useAdminCredentials.d.ts.map +1 -0
  39. package/dist-lib/hooks/useAdminCredentials.js +17 -0
  40. package/dist-lib/hooks/useAiAdmin.d.ts +44 -0
  41. package/dist-lib/hooks/useAiAdmin.d.ts.map +1 -0
  42. package/dist-lib/hooks/useAiAdmin.js +32 -0
  43. package/dist-lib/hooks/useAiCostOverview.d.ts +7 -0
  44. package/dist-lib/hooks/useAiCostOverview.d.ts.map +1 -0
  45. package/dist-lib/hooks/useAiCostOverview.js +28 -0
  46. package/dist-lib/hooks/useAiForGoal.d.ts +21 -0
  47. package/dist-lib/hooks/useAiForGoal.d.ts.map +1 -0
  48. package/dist-lib/hooks/useAiForGoal.js +40 -0
  49. package/dist-lib/hooks/useAiForModule.d.ts +11 -0
  50. package/dist-lib/hooks/useAiForModule.d.ts.map +1 -0
  51. package/dist-lib/hooks/useAiForModule.js +11 -0
  52. package/dist-lib/hooks/useAiGoals.d.ts +8 -0
  53. package/dist-lib/hooks/useAiGoals.d.ts.map +1 -0
  54. package/dist-lib/hooks/useAiGoals.js +22 -0
  55. package/dist-lib/hooks/useAiModules.d.ts +15 -0
  56. package/dist-lib/hooks/useAiModules.d.ts.map +1 -0
  57. package/dist-lib/hooks/useAiModules.js +59 -0
  58. package/dist-lib/hooks/useAiPricing.d.ts +20 -0
  59. package/dist-lib/hooks/useAiPricing.d.ts.map +1 -0
  60. package/dist-lib/hooks/useAiPricing.js +97 -0
  61. package/dist-lib/hooks/useAiUsage.d.ts +12 -0
  62. package/dist-lib/hooks/useAiUsage.d.ts.map +1 -0
  63. package/dist-lib/hooks/useAiUsage.js +90 -0
  64. package/dist-lib/hooks/useAiUsageByModule.d.ts +8 -0
  65. package/dist-lib/hooks/useAiUsageByModule.d.ts.map +1 -0
  66. package/dist-lib/hooks/useAiUsageByModule.js +22 -0
  67. package/dist-lib/hooks/useIsAiAdmin.d.ts +6 -0
  68. package/dist-lib/hooks/useIsAiAdmin.d.ts.map +1 -0
  69. package/dist-lib/hooks/useIsAiAdmin.js +5 -0
  70. package/dist-lib/hooks/useMijnModuleData.d.ts +13 -0
  71. package/dist-lib/hooks/useMijnModuleData.d.ts.map +1 -0
  72. package/dist-lib/hooks/useMijnModuleData.js +49 -0
  73. package/dist-lib/hooks/useModules.d.ts +14 -0
  74. package/dist-lib/hooks/useModules.d.ts.map +1 -0
  75. package/dist-lib/hooks/useModules.js +47 -0
  76. package/dist-lib/index.d.ts +29 -0
  77. package/dist-lib/index.d.ts.map +1 -0
  78. package/dist-lib/index.js +33 -0
  79. package/dist-lib/integrations/supabase/auth-attacher.d.ts +2 -0
  80. package/dist-lib/integrations/supabase/auth-attacher.d.ts.map +1 -0
  81. package/dist-lib/integrations/supabase/auth-attacher.js +12 -0
  82. package/dist-lib/integrations/supabase/auth-middleware.d.ts +15971 -0
  83. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -0
  84. package/dist-lib/integrations/supabase/auth-middleware.js +49 -0
  85. package/dist-lib/integrations/supabase/client.d.ts +15967 -0
  86. package/dist-lib/integrations/supabase/client.d.ts.map +1 -0
  87. package/dist-lib/integrations/supabase/client.js +13 -0
  88. package/dist-lib/integrations/supabase/client.server.d.ts +15967 -0
  89. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -0
  90. package/dist-lib/integrations/supabase/client.server.js +30 -0
  91. package/dist-lib/integrations/supabase/types.d.ts +16477 -0
  92. package/dist-lib/integrations/supabase/types.d.ts.map +1 -0
  93. package/dist-lib/integrations/supabase/types.js +78 -0
  94. package/dist-lib/lib/aiChat.functions.d.ts +31948 -0
  95. package/dist-lib/lib/aiChat.functions.d.ts.map +1 -0
  96. package/dist-lib/lib/aiChat.functions.js +51 -0
  97. package/dist-lib/lib/aiChat.server.d.ts +8 -0
  98. package/dist-lib/lib/aiChat.server.d.ts.map +1 -0
  99. package/dist-lib/lib/aiChat.server.js +347 -0
  100. package/dist-lib/lib/aiChat.stream.d.ts +33 -0
  101. package/dist-lib/lib/aiChat.stream.d.ts.map +1 -0
  102. package/dist-lib/lib/aiChat.stream.js +77 -0
  103. package/dist-lib/lib/aiChat.stream.server.d.ts +38 -0
  104. package/dist-lib/lib/aiChat.stream.server.d.ts.map +1 -0
  105. package/dist-lib/lib/aiChat.stream.server.js +259 -0
  106. package/dist-lib/lib/aiChat.types.d.ts +63 -0
  107. package/dist-lib/lib/aiChat.types.d.ts.map +1 -0
  108. package/dist-lib/lib/aiChat.types.js +1 -0
  109. package/dist-lib/lib/aiCredentialTest.functions.d.ts +31959 -0
  110. package/dist-lib/lib/aiCredentialTest.functions.d.ts.map +1 -0
  111. package/dist-lib/lib/aiCredentialTest.functions.js +714 -0
  112. package/dist-lib/lib/aiGoals.functions.d.ts +12912 -0
  113. package/dist-lib/lib/aiGoals.functions.d.ts.map +1 -0
  114. package/dist-lib/lib/aiGoals.functions.js +14 -0
  115. package/dist-lib/lib/aiModules.functions.d.ts +95851 -0
  116. package/dist-lib/lib/aiModules.functions.d.ts.map +1 -0
  117. package/dist-lib/lib/aiModules.functions.js +41 -0
  118. package/dist-lib/lib/aiModules.server.d.ts +65 -0
  119. package/dist-lib/lib/aiModules.server.d.ts.map +1 -0
  120. package/dist-lib/lib/aiModules.server.js +119 -0
  121. package/dist-lib/lib/aiPeriod.d.ts +11 -0
  122. package/dist-lib/lib/aiPeriod.d.ts.map +1 -0
  123. package/dist-lib/lib/aiPeriod.js +53 -0
  124. package/dist-lib/lib/aiPricing.functions.d.ts +31943 -0
  125. package/dist-lib/lib/aiPricing.functions.d.ts.map +1 -0
  126. package/dist-lib/lib/aiPricing.functions.js +13 -0
  127. package/dist-lib/lib/aiPricing.server.d.ts +19 -0
  128. package/dist-lib/lib/aiPricing.server.d.ts.map +1 -0
  129. package/dist-lib/lib/aiPricing.server.js +97 -0
  130. package/dist-lib/lib/aiUsage.functions.d.ts +5 -0
  131. package/dist-lib/lib/aiUsage.functions.d.ts.map +1 -0
  132. package/dist-lib/lib/aiUsage.functions.js +12 -0
  133. package/dist-lib/lib/aiUsage.server.d.ts +3 -0
  134. package/dist-lib/lib/aiUsage.server.d.ts.map +1 -0
  135. package/dist-lib/lib/aiUsage.server.js +229 -0
  136. package/dist-lib/lib/aiUsage.types.d.ts +21 -0
  137. package/dist-lib/lib/aiUsage.types.d.ts.map +1 -0
  138. package/dist-lib/lib/aiUsage.types.js +1 -0
  139. package/dist-lib/lib/aiUsageByModule.functions.d.ts +31952 -0
  140. package/dist-lib/lib/aiUsageByModule.functions.d.ts.map +1 -0
  141. package/dist-lib/lib/aiUsageByModule.functions.js +37 -0
  142. package/dist-lib/lib/modules.functions.d.ts +47924 -0
  143. package/dist-lib/lib/modules.functions.d.ts.map +1 -0
  144. package/dist-lib/lib/modules.functions.js +21 -0
  145. package/dist-lib/lib/modules.server.d.ts +23 -0
  146. package/dist-lib/lib/modules.server.d.ts.map +1 -0
  147. package/dist-lib/lib/modules.server.js +52 -0
  148. package/dist-lib/lib/utils.d.ts +3 -0
  149. package/dist-lib/lib/utils.d.ts.map +1 -0
  150. package/dist-lib/lib/utils.js +5 -0
  151. package/dist-lib/lib/validationSchemas.d.ts +15 -0
  152. package/dist-lib/lib/validationSchemas.d.ts.map +1 -0
  153. package/dist-lib/lib/validationSchemas.js +25 -0
  154. package/dist-lib/styles.css +1 -0
  155. package/package.json +92 -0
  156. package/public/flowselections-assets/ai-authenticatie/claude.png +0 -0
  157. package/public/flowselections-assets/ai-authenticatie/gemini.png +0 -0
  158. package/public/flowselections-assets/ai-authenticatie/openai.png +0 -0
  159. package/public/logo.png +0 -0
@@ -0,0 +1,259 @@
1
+ import { supabaseAdmin } from '../integrations/supabase/client.server';
2
+ export async function* streamAiChatForRequest(input) {
3
+ const started = Date.now();
4
+ const { data: moduleRow } = await supabaseAdmin.from('ai_modules').select('module_key, ai_enabled').eq('module_key', input.consumerModuleId).maybeSingle();
5
+ if (!moduleRow || moduleRow.ai_enabled !== true) {
6
+ yield { type: 'error', code: 'no_binding', status: 404, message: `Module "${input.consumerModuleId}" heeft geen AI ingeschakeld.` };
7
+ return;
8
+ }
9
+ const { data: bindingRows } = await supabaseAdmin.from('ai_module_bindings').select('id, model_id, credential_id, is_default').eq('consumer_module_id', input.consumerModuleId).order('is_default', { ascending: false });
10
+ const binding = Array.isArray(bindingRows) ? bindingRows[0] : null;
11
+ if (!binding) {
12
+ yield { type: 'error', code: 'no_binding', status: 404, message: `Geen AI-agent gekoppeld aan "${input.consumerModuleId}".` };
13
+ return;
14
+ }
15
+ const [{ data: model }, { data: cred }] = await Promise.all([
16
+ supabaseAdmin.from('ai_models').select('id, slug, display_name, provider_id, active').eq('id', binding.model_id).maybeSingle(),
17
+ supabaseAdmin.from('ai_credentials').select('id, api_key, active, provider_id').eq('id', binding.credential_id).maybeSingle(),
18
+ ]);
19
+ if (!model || !cred || !cred.active || model.active === false) {
20
+ yield { type: 'error', code: 'not_configured', status: 403, message: 'Gekoppelde configuratie is niet actief.' };
21
+ return;
22
+ }
23
+ const { data: provider } = await supabaseAdmin.from('ai_providers').select('id, slug, name, base_url, active').eq('id', model.provider_id).maybeSingle();
24
+ if (!provider || provider.active === false) {
25
+ yield { type: 'error', code: 'not_configured', status: 403, message: 'Provider niet actief.' };
26
+ return;
27
+ }
28
+ yield {
29
+ type: 'meta',
30
+ provider: { slug: provider.slug, name: provider.name },
31
+ model: { slug: model.slug, displayName: model.display_name },
32
+ };
33
+ const slug = provider.slug.toLowerCase();
34
+ let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
35
+ let errored = null;
36
+ let fullText = '';
37
+ const emitToken = (delta) => { if (delta)
38
+ fullText += delta; };
39
+ try {
40
+ if (slug.includes('openai') || slug.includes('gpt')) {
41
+ for await (const ev of streamOpenAI(cred.api_key, provider.base_url, model.slug, input.messages, input.options ?? {})) {
42
+ if (ev.type === 'token') {
43
+ emitToken(ev.delta);
44
+ yield ev;
45
+ }
46
+ else if (ev.type === 'usage') {
47
+ usage = ev.usage;
48
+ }
49
+ }
50
+ }
51
+ else if (slug.includes('anthropic') || slug.includes('claude')) {
52
+ for await (const ev of streamAnthropic(cred.api_key, provider.base_url, model.slug, input.messages, input.options ?? {})) {
53
+ if (ev.type === 'token') {
54
+ emitToken(ev.delta);
55
+ yield ev;
56
+ }
57
+ else if (ev.type === 'usage') {
58
+ usage = ev.usage;
59
+ }
60
+ }
61
+ }
62
+ else if (slug.includes('gemini') || slug.includes('google')) {
63
+ for await (const ev of streamGemini(cred.api_key, provider.base_url, model.slug, input.messages, input.options ?? {})) {
64
+ if (ev.type === 'token') {
65
+ emitToken(ev.delta);
66
+ yield ev;
67
+ }
68
+ else if (ev.type === 'usage') {
69
+ usage = ev.usage;
70
+ }
71
+ }
72
+ }
73
+ else {
74
+ errored = { ok: false, status: 400, code: 'unsupported_provider', message: `Provider "${provider.name}" ondersteunt geen streaming.` };
75
+ }
76
+ }
77
+ catch (e) {
78
+ errored = { ok: false, status: 0, code: 'network', message: e instanceof Error ? e.message : 'Streamfout' };
79
+ }
80
+ if (errored) {
81
+ yield { type: 'error', code: errored.code, message: errored.message, status: errored.status };
82
+ }
83
+ // pricing
84
+ const { data: pricing } = await supabaseAdmin.from('ai_model_pricing').select('input_per_mtok, output_per_mtok').eq('provider_slug', provider.slug).eq('model_slug', model.slug).maybeSingle();
85
+ const costUsd = pricing
86
+ ? ((usage.inputTokens / 1e6) * (pricing.input_per_mtok ?? 0) + (usage.outputTokens / 1e6) * (pricing.output_per_mtok ?? 0)) || null
87
+ : null;
88
+ yield { type: 'usage', usage, costUsd };
89
+ // logging
90
+ try {
91
+ await supabaseAdmin.rpc('log_ai_call', {
92
+ _consumer_module_id: input.consumerModuleId,
93
+ _provider_slug: provider.slug,
94
+ _model_slug: model.slug,
95
+ _status: errored ? errored.code : 'ok',
96
+ _input_tokens: usage.inputTokens,
97
+ _output_tokens: usage.outputTokens,
98
+ _total_tokens: usage.totalTokens,
99
+ _cost_usd: costUsd,
100
+ _duration_ms: Date.now() - started,
101
+ _error_code: errored?.code ?? null,
102
+ _error_message: errored?.message ?? null,
103
+ });
104
+ }
105
+ catch { /* noop */ }
106
+ void fullText;
107
+ void input.bearerUserId;
108
+ yield { type: 'done' };
109
+ }
110
+ // ─── Provider stream adapters ──────────────────────────────────────
111
+ async function* parseSSE(res) {
112
+ const reader = res.body?.getReader();
113
+ if (!reader)
114
+ return;
115
+ const decoder = new TextDecoder();
116
+ let buffer = '';
117
+ while (true) {
118
+ const { value, done } = await reader.read();
119
+ if (done)
120
+ break;
121
+ buffer += decoder.decode(value, { stream: true });
122
+ const parts = buffer.split(/\r?\n\r?\n/);
123
+ buffer = parts.pop() ?? '';
124
+ for (const chunk of parts) {
125
+ let event = 'message';
126
+ const lines = chunk.split(/\r?\n/);
127
+ const dataLines = [];
128
+ for (const l of lines) {
129
+ if (l.startsWith('event:'))
130
+ event = l.slice(6).trim();
131
+ else if (l.startsWith('data:'))
132
+ dataLines.push(l.slice(5).trimStart());
133
+ }
134
+ if (dataLines.length)
135
+ yield { event, data: dataLines.join('\n') };
136
+ }
137
+ }
138
+ }
139
+ async function* streamOpenAI(apiKey, baseUrl, model, messages, opts) {
140
+ const base = (baseUrl || 'https://api.openai.com/v1').replace(/\/+$/, '');
141
+ const res = await fetch(`${base}/chat/completions`, {
142
+ method: 'POST',
143
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
144
+ body: JSON.stringify({
145
+ model, messages, stream: true, stream_options: { include_usage: true },
146
+ ...(opts.temperature != null ? { temperature: opts.temperature } : {}),
147
+ ...(opts.maxTokens != null ? { max_tokens: opts.maxTokens } : {}),
148
+ ...(opts.topP != null ? { top_p: opts.topP } : {}),
149
+ }),
150
+ });
151
+ if (!res.ok)
152
+ throw new Error(`OpenAI ${res.status}: ${(await res.text()).slice(0, 300)}`);
153
+ for await (const { data } of parseSSE(res)) {
154
+ if (data === '[DONE]')
155
+ return;
156
+ try {
157
+ const j = JSON.parse(data);
158
+ const delta = j.choices?.[0]?.delta?.content;
159
+ if (typeof delta === 'string' && delta)
160
+ yield { type: 'token', delta };
161
+ if (j.usage)
162
+ yield {
163
+ type: 'usage',
164
+ usage: {
165
+ inputTokens: j.usage.prompt_tokens ?? 0,
166
+ outputTokens: j.usage.completion_tokens ?? 0,
167
+ totalTokens: j.usage.total_tokens ?? 0,
168
+ },
169
+ };
170
+ }
171
+ catch { /* skip */ }
172
+ }
173
+ }
174
+ async function* streamAnthropic(apiKey, baseUrl, model, messages, opts) {
175
+ const base = (baseUrl || 'https://api.anthropic.com').replace(/\/+$/, '');
176
+ const systemParts = messages.filter(m => m.role === 'system').map(m => m.content);
177
+ const rest = messages.filter(m => m.role !== 'system').map(m => ({ role: m.role, content: m.content }));
178
+ const res = await fetch(`${base}/v1/messages`, {
179
+ method: 'POST',
180
+ headers: { 'content-type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
181
+ body: JSON.stringify({
182
+ model, messages: rest, stream: true,
183
+ max_tokens: opts.maxTokens ?? 1024,
184
+ ...(systemParts.length ? { system: systemParts.join('\n\n') } : {}),
185
+ ...(opts.temperature != null ? { temperature: opts.temperature } : {}),
186
+ ...(opts.topP != null ? { top_p: opts.topP } : {}),
187
+ }),
188
+ });
189
+ if (!res.ok)
190
+ throw new Error(`Anthropic ${res.status}: ${(await res.text()).slice(0, 300)}`);
191
+ let inTok = 0, outTok = 0;
192
+ for await (const { event, data } of parseSSE(res)) {
193
+ if (!data)
194
+ continue;
195
+ try {
196
+ const j = JSON.parse(data);
197
+ if (event === 'content_block_delta' && j.delta?.type === 'text_delta') {
198
+ yield { type: 'token', delta: j.delta.text ?? '' };
199
+ }
200
+ else if (event === 'message_start' && j.message?.usage) {
201
+ inTok = j.message.usage.input_tokens ?? 0;
202
+ }
203
+ else if (event === 'message_delta' && j.usage) {
204
+ outTok = j.usage.output_tokens ?? outTok;
205
+ }
206
+ }
207
+ catch { /* skip */ }
208
+ }
209
+ yield { type: 'usage', usage: { inputTokens: inTok, outputTokens: outTok, totalTokens: inTok + outTok } };
210
+ }
211
+ async function* streamGemini(apiKey, baseUrl, model, messages, opts) {
212
+ const raw = (baseUrl || 'https://generativelanguage.googleapis.com/v1beta').replace(/\/+$/, '');
213
+ let base = raw;
214
+ try {
215
+ const u = new URL(raw);
216
+ const parts = u.pathname.split('/').filter(Boolean);
217
+ const vi = parts.findIndex(p => /^v\d+(alpha|beta)?$/i.test(p));
218
+ u.pathname = `/${vi >= 0 ? parts[vi] : 'v1beta'}`;
219
+ u.search = '';
220
+ base = u.toString().replace(/\/+$/, '');
221
+ }
222
+ catch { /* keep */ }
223
+ const modelPath = model.startsWith('models/') ? model : `models/${model}`;
224
+ const systemParts = messages.filter(m => m.role === 'system').map(m => m.content);
225
+ const contents = messages.filter(m => m.role !== 'system').map(m => ({ role: m.role === 'assistant' ? 'model' : 'user', parts: [{ text: m.content }] }));
226
+ const body = {
227
+ contents,
228
+ generationConfig: {
229
+ ...(opts.temperature != null ? { temperature: opts.temperature } : {}),
230
+ ...(opts.maxTokens != null ? { maxOutputTokens: opts.maxTokens } : {}),
231
+ ...(opts.topP != null ? { topP: opts.topP } : {}),
232
+ },
233
+ };
234
+ if (systemParts.length)
235
+ body.systemInstruction = { role: 'system', parts: [{ text: systemParts.join('\n\n') }] };
236
+ const url = `${base}/${modelPath}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;
237
+ const res = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
238
+ if (!res.ok)
239
+ throw new Error(`Gemini ${res.status}: ${(await res.text()).slice(0, 300)}`);
240
+ let inTok = 0, outTok = 0, tot = 0;
241
+ for await (const { data } of parseSSE(res)) {
242
+ if (!data)
243
+ continue;
244
+ try {
245
+ const j = JSON.parse(data);
246
+ const parts = j.candidates?.[0]?.content?.parts ?? [];
247
+ const text = parts.map((p) => p.text ?? '').join('');
248
+ if (text)
249
+ yield { type: 'token', delta: text };
250
+ if (j.usageMetadata) {
251
+ inTok = j.usageMetadata.promptTokenCount ?? inTok;
252
+ outTok = j.usageMetadata.candidatesTokenCount ?? outTok;
253
+ tot = j.usageMetadata.totalTokenCount ?? (inTok + outTok);
254
+ }
255
+ }
256
+ catch { /* skip */ }
257
+ }
258
+ yield { type: 'usage', usage: { inputTokens: inTok, outputTokens: outTok, totalTokens: tot || inTok + outTok } };
259
+ }
@@ -0,0 +1,63 @@
1
+ export type AiChatRole = 'system' | 'user' | 'assistant';
2
+ export type AiChatMessage = {
3
+ role: AiChatRole;
4
+ content: string;
5
+ };
6
+ export type AiChatOptions = {
7
+ temperature?: number;
8
+ maxTokens?: number;
9
+ topP?: number;
10
+ };
11
+ export type AiChatUsage = {
12
+ inputTokens: number;
13
+ outputTokens: number;
14
+ totalTokens: number;
15
+ };
16
+ export type AiChatSuccess = {
17
+ ok: true;
18
+ content: string;
19
+ provider: {
20
+ slug: string;
21
+ name: string;
22
+ };
23
+ model: {
24
+ slug: string;
25
+ displayName: string;
26
+ };
27
+ usage: AiChatUsage;
28
+ costUsd: number | null;
29
+ finishReason?: string | null;
30
+ };
31
+ export type AiChatError = {
32
+ ok: false;
33
+ status: number;
34
+ /**
35
+ * Uniforme foutcode:
36
+ * - `no_binding` — geen model/credential gekoppeld voor dit doel
37
+ * - `not_configured` — provider of credential ontbreekt
38
+ * - `unauthorized` — 401 van provider (ongeldige key)
39
+ * - `rate_limited` — 429
40
+ * - `quota_exceeded` — creditlimiet bereikt
41
+ * - `bad_request` — 400 van provider
42
+ * - `provider_error` — overige providerfouten
43
+ * - `network` — netwerk/timeout
44
+ * - `unsupported_provider` — providerslug niet herkend
45
+ * - `forbidden` — 403
46
+ */
47
+ code: 'no_binding' | 'not_configured' | 'unauthorized' | 'rate_limited' | 'quota_exceeded' | 'bad_request' | 'provider_error' | 'network' | 'unsupported_provider' | 'forbidden';
48
+ message: string;
49
+ };
50
+ export type AiChatResult = AiChatSuccess | AiChatError;
51
+ export type AiChatBindingInfo = {
52
+ ready: boolean;
53
+ provider: {
54
+ slug: string;
55
+ name: string;
56
+ } | null;
57
+ model: {
58
+ slug: string;
59
+ displayName: string;
60
+ } | null;
61
+ reason?: string;
62
+ };
63
+ //# sourceMappingURL=aiChat.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiChat.types.d.ts","sourceRoot":"","sources":["../../src/lib/aiChat.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;OAYG;IACH,IAAI,EACA,YAAY,GACZ,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,aAAa,GACb,gBAAgB,GAChB,SAAS,GACT,sBAAsB,GACtB,WAAW,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,WAAW,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChD,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};