@contractspec/integration.providers-impls 0.0.0-canary-20260113170453
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/_virtual/rolldown_runtime.js +36 -0
- package/dist/calendar.d.ts +8 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +3 -0
- package/dist/email.d.ts +8 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +3 -0
- package/dist/embedding.d.ts +8 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/embedding.js +3 -0
- package/dist/impls/elevenlabs-voice.d.ts +21 -0
- package/dist/impls/elevenlabs-voice.d.ts.map +1 -0
- package/dist/impls/elevenlabs-voice.js +93 -0
- package/dist/impls/elevenlabs-voice.js.map +1 -0
- package/dist/impls/gcs-storage.d.ts +25 -0
- package/dist/impls/gcs-storage.d.ts.map +1 -0
- package/dist/impls/gcs-storage.js +90 -0
- package/dist/impls/gcs-storage.js.map +1 -0
- package/dist/impls/gmail-inbound.d.ts +27 -0
- package/dist/impls/gmail-inbound.d.ts.map +1 -0
- package/dist/impls/gmail-inbound.js +201 -0
- package/dist/impls/gmail-inbound.js.map +1 -0
- package/dist/impls/gmail-outbound.d.ts +19 -0
- package/dist/impls/gmail-outbound.d.ts.map +1 -0
- package/dist/impls/gmail-outbound.js +106 -0
- package/dist/impls/gmail-outbound.js.map +1 -0
- package/dist/impls/google-calendar.d.ts +24 -0
- package/dist/impls/google-calendar.d.ts.map +1 -0
- package/dist/impls/google-calendar.js +155 -0
- package/dist/impls/google-calendar.js.map +1 -0
- package/dist/impls/index.d.ts +15 -0
- package/dist/impls/index.js +16 -0
- package/dist/impls/mistral-embedding.d.ts +24 -0
- package/dist/impls/mistral-embedding.d.ts.map +1 -0
- package/dist/impls/mistral-embedding.js +42 -0
- package/dist/impls/mistral-embedding.js.map +1 -0
- package/dist/impls/mistral-llm.d.ts +32 -0
- package/dist/impls/mistral-llm.d.ts.map +1 -0
- package/dist/impls/mistral-llm.js +248 -0
- package/dist/impls/mistral-llm.js.map +1 -0
- package/dist/impls/postmark-email.d.ts +20 -0
- package/dist/impls/postmark-email.d.ts.map +1 -0
- package/dist/impls/postmark-email.js +56 -0
- package/dist/impls/postmark-email.js.map +1 -0
- package/dist/impls/powens-client.d.ts +125 -0
- package/dist/impls/powens-client.d.ts.map +1 -0
- package/dist/impls/powens-client.js +172 -0
- package/dist/impls/powens-client.js.map +1 -0
- package/dist/impls/powens-openbanking.d.ts +28 -0
- package/dist/impls/powens-openbanking.d.ts.map +1 -0
- package/dist/impls/powens-openbanking.js +219 -0
- package/dist/impls/powens-openbanking.js.map +1 -0
- package/dist/impls/provider-factory.d.ts +27 -0
- package/dist/impls/provider-factory.d.ts.map +1 -0
- package/dist/impls/provider-factory.js +143 -0
- package/dist/impls/provider-factory.js.map +1 -0
- package/dist/impls/qdrant-vector.d.ts +25 -0
- package/dist/impls/qdrant-vector.d.ts.map +1 -0
- package/dist/impls/qdrant-vector.js +72 -0
- package/dist/impls/qdrant-vector.js.map +1 -0
- package/dist/impls/stripe-payments.d.ts +29 -0
- package/dist/impls/stripe-payments.d.ts.map +1 -0
- package/dist/impls/stripe-payments.js +203 -0
- package/dist/impls/stripe-payments.js.map +1 -0
- package/dist/impls/twilio-sms.d.ts +21 -0
- package/dist/impls/twilio-sms.d.ts.map +1 -0
- package/dist/impls/twilio-sms.js +59 -0
- package/dist/impls/twilio-sms.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +8 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +3 -0
- package/dist/openbanking.d.ts +8 -0
- package/dist/openbanking.d.ts.map +1 -0
- package/dist/openbanking.js +3 -0
- package/dist/payments.d.ts +8 -0
- package/dist/payments.d.ts.map +1 -0
- package/dist/payments.js +3 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +0 -0
- package/dist/secrets/provider.d.ts +2 -0
- package/dist/secrets/provider.js +3 -0
- package/dist/sms.d.ts +8 -0
- package/dist/sms.d.ts.map +1 -0
- package/dist/sms.js +3 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +3 -0
- package/dist/vector-store.d.ts +8 -0
- package/dist/vector-store.d.ts.map +1 -0
- package/dist/vector-store.js +3 -0
- package/dist/voice.d.ts +8 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +3 -0
- package/package.json +125 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { Mistral } from "@mistralai/mistralai";
|
|
2
|
+
|
|
3
|
+
//#region src/impls/mistral-llm.ts
|
|
4
|
+
var MistralLLMProvider = class {
|
|
5
|
+
client;
|
|
6
|
+
defaultModel;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
if (!options.apiKey) throw new Error("MistralLLMProvider requires an apiKey");
|
|
9
|
+
this.client = options.client ?? new Mistral({
|
|
10
|
+
apiKey: options.apiKey,
|
|
11
|
+
serverURL: options.serverURL,
|
|
12
|
+
userAgent: options.userAgentSuffix ? `${options.userAgentSuffix}` : void 0
|
|
13
|
+
});
|
|
14
|
+
this.defaultModel = options.defaultModel ?? "mistral-large-latest";
|
|
15
|
+
}
|
|
16
|
+
async chat(messages, options = {}) {
|
|
17
|
+
const request = this.buildChatRequest(messages, options);
|
|
18
|
+
const response = await this.client.chat.complete(request);
|
|
19
|
+
return this.buildLLMResponse(response);
|
|
20
|
+
}
|
|
21
|
+
async *stream(messages, options = {}) {
|
|
22
|
+
const request = this.buildChatRequest(messages, options);
|
|
23
|
+
request.stream = true;
|
|
24
|
+
const stream = await this.client.chat.stream(request);
|
|
25
|
+
const aggregatedParts = [];
|
|
26
|
+
const aggregatedToolCalls = [];
|
|
27
|
+
let usage;
|
|
28
|
+
let finishReason;
|
|
29
|
+
for await (const event of stream) {
|
|
30
|
+
for (const choice of event.data.choices) {
|
|
31
|
+
const delta = choice.delta;
|
|
32
|
+
if (typeof delta.content === "string") {
|
|
33
|
+
if (delta.content.length > 0) {
|
|
34
|
+
aggregatedParts.push({
|
|
35
|
+
type: "text",
|
|
36
|
+
text: delta.content
|
|
37
|
+
});
|
|
38
|
+
yield {
|
|
39
|
+
type: "message_delta",
|
|
40
|
+
delta: {
|
|
41
|
+
type: "text",
|
|
42
|
+
text: delta.content
|
|
43
|
+
},
|
|
44
|
+
index: choice.index
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
} else if (Array.isArray(delta.content)) {
|
|
48
|
+
for (const chunk of delta.content) if (chunk.type === "text" && "text" in chunk) {
|
|
49
|
+
aggregatedParts.push({
|
|
50
|
+
type: "text",
|
|
51
|
+
text: chunk.text
|
|
52
|
+
});
|
|
53
|
+
yield {
|
|
54
|
+
type: "message_delta",
|
|
55
|
+
delta: {
|
|
56
|
+
type: "text",
|
|
57
|
+
text: chunk.text
|
|
58
|
+
},
|
|
59
|
+
index: choice.index
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (delta.toolCalls) {
|
|
64
|
+
let localIndex = 0;
|
|
65
|
+
for (const call of delta.toolCalls) {
|
|
66
|
+
const toolCall = this.fromMistralToolCall(call, localIndex);
|
|
67
|
+
aggregatedToolCalls.push(toolCall);
|
|
68
|
+
yield {
|
|
69
|
+
type: "tool_call",
|
|
70
|
+
call: toolCall,
|
|
71
|
+
index: choice.index
|
|
72
|
+
};
|
|
73
|
+
localIndex += 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (choice.finishReason && choice.finishReason !== "null") finishReason = choice.finishReason;
|
|
77
|
+
}
|
|
78
|
+
if (event.data.usage) {
|
|
79
|
+
const usageEntry = this.fromUsage(event.data.usage);
|
|
80
|
+
if (usageEntry) {
|
|
81
|
+
usage = usageEntry;
|
|
82
|
+
yield {
|
|
83
|
+
type: "usage",
|
|
84
|
+
usage: usageEntry
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const message = {
|
|
90
|
+
role: "assistant",
|
|
91
|
+
content: aggregatedParts.length ? aggregatedParts : [{
|
|
92
|
+
type: "text",
|
|
93
|
+
text: ""
|
|
94
|
+
}]
|
|
95
|
+
};
|
|
96
|
+
if (aggregatedToolCalls.length > 0) message.content = [...aggregatedToolCalls, ...aggregatedParts.length ? aggregatedParts : []];
|
|
97
|
+
yield {
|
|
98
|
+
type: "end",
|
|
99
|
+
response: {
|
|
100
|
+
message,
|
|
101
|
+
usage,
|
|
102
|
+
finishReason: mapFinishReason(finishReason)
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async countTokens(_messages) {
|
|
107
|
+
throw new Error("Mistral API does not currently support token counting");
|
|
108
|
+
}
|
|
109
|
+
buildChatRequest(messages, options) {
|
|
110
|
+
const request = {
|
|
111
|
+
model: options.model ?? this.defaultModel,
|
|
112
|
+
messages: messages.map((message) => this.toMistralMessage(message))
|
|
113
|
+
};
|
|
114
|
+
if (options.temperature != null) request.temperature = options.temperature;
|
|
115
|
+
if (options.topP != null) request.topP = options.topP;
|
|
116
|
+
if (options.maxOutputTokens != null) request.maxTokens = options.maxOutputTokens;
|
|
117
|
+
if (options.stopSequences?.length) request.stop = options.stopSequences.length === 1 ? options.stopSequences[0] : options.stopSequences;
|
|
118
|
+
if (options.tools?.length) request.tools = options.tools.map((tool) => ({
|
|
119
|
+
type: "function",
|
|
120
|
+
function: {
|
|
121
|
+
name: tool.name,
|
|
122
|
+
description: tool.description,
|
|
123
|
+
parameters: typeof tool.inputSchema === "object" && tool.inputSchema !== null ? tool.inputSchema : {}
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
if (options.responseFormat === "json") request.responseFormat = { type: "json_object" };
|
|
127
|
+
return request;
|
|
128
|
+
}
|
|
129
|
+
buildLLMResponse(response) {
|
|
130
|
+
const firstChoice = response.choices[0];
|
|
131
|
+
if (!firstChoice) return {
|
|
132
|
+
message: {
|
|
133
|
+
role: "assistant",
|
|
134
|
+
content: [{
|
|
135
|
+
type: "text",
|
|
136
|
+
text: ""
|
|
137
|
+
}]
|
|
138
|
+
},
|
|
139
|
+
usage: this.fromUsage(response.usage),
|
|
140
|
+
raw: response
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
message: this.fromAssistantMessage(firstChoice.message),
|
|
144
|
+
usage: this.fromUsage(response.usage),
|
|
145
|
+
finishReason: mapFinishReason(firstChoice.finishReason),
|
|
146
|
+
raw: response
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
fromUsage(usage) {
|
|
150
|
+
if (!usage) return void 0;
|
|
151
|
+
return {
|
|
152
|
+
promptTokens: usage.promptTokens ?? 0,
|
|
153
|
+
completionTokens: usage.completionTokens ?? 0,
|
|
154
|
+
totalTokens: usage.totalTokens ?? 0
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
fromAssistantMessage(message) {
|
|
158
|
+
const parts = [];
|
|
159
|
+
if (typeof message.content === "string") parts.push({
|
|
160
|
+
type: "text",
|
|
161
|
+
text: message.content
|
|
162
|
+
});
|
|
163
|
+
else if (Array.isArray(message.content)) message.content.forEach((chunk) => {
|
|
164
|
+
if (chunk.type === "text" && "text" in chunk) parts.push({
|
|
165
|
+
type: "text",
|
|
166
|
+
text: chunk.text
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
const toolCalls = message.toolCalls?.map((call, index) => this.fromMistralToolCall(call, index)) ?? [];
|
|
170
|
+
if (toolCalls.length > 0) parts.splice(0, 0, ...toolCalls);
|
|
171
|
+
if (parts.length === 0) parts.push({
|
|
172
|
+
type: "text",
|
|
173
|
+
text: ""
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
role: "assistant",
|
|
177
|
+
content: parts
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
fromMistralToolCall(call, index) {
|
|
181
|
+
const args = typeof call.function.arguments === "string" ? call.function.arguments : JSON.stringify(call.function.arguments);
|
|
182
|
+
return {
|
|
183
|
+
type: "tool-call",
|
|
184
|
+
id: call.id ?? `tool-call-${index}`,
|
|
185
|
+
name: call.function.name,
|
|
186
|
+
arguments: args
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
toMistralMessage(message) {
|
|
190
|
+
const textContent = this.extractText(message.content);
|
|
191
|
+
const toolCalls = this.extractToolCalls(message);
|
|
192
|
+
switch (message.role) {
|
|
193
|
+
case "system": return {
|
|
194
|
+
role: "system",
|
|
195
|
+
content: textContent ?? ""
|
|
196
|
+
};
|
|
197
|
+
case "user": return {
|
|
198
|
+
role: "user",
|
|
199
|
+
content: textContent ?? ""
|
|
200
|
+
};
|
|
201
|
+
case "assistant": return {
|
|
202
|
+
role: "assistant",
|
|
203
|
+
content: toolCalls.length > 0 ? null : textContent ?? "",
|
|
204
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
205
|
+
};
|
|
206
|
+
case "tool": return {
|
|
207
|
+
role: "tool",
|
|
208
|
+
content: textContent ?? "",
|
|
209
|
+
toolCallId: message.toolCallId ?? toolCalls[0]?.id
|
|
210
|
+
};
|
|
211
|
+
default: return {
|
|
212
|
+
role: "user",
|
|
213
|
+
content: textContent ?? ""
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
extractText(parts) {
|
|
218
|
+
const textParts = parts.filter((part) => part.type === "text").map((part) => part.text);
|
|
219
|
+
if (textParts.length === 0) return null;
|
|
220
|
+
return textParts.join("");
|
|
221
|
+
}
|
|
222
|
+
extractToolCalls(message) {
|
|
223
|
+
return message.content.filter((part) => part.type === "tool-call").map((call, index) => ({
|
|
224
|
+
id: call.id ?? `call_${index}`,
|
|
225
|
+
type: "function",
|
|
226
|
+
index,
|
|
227
|
+
function: {
|
|
228
|
+
name: call.name,
|
|
229
|
+
arguments: call.arguments
|
|
230
|
+
}
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
function mapFinishReason(reason) {
|
|
235
|
+
if (!reason) return void 0;
|
|
236
|
+
switch (reason.toLowerCase()) {
|
|
237
|
+
case "stop": return "stop";
|
|
238
|
+
case "length": return "length";
|
|
239
|
+
case "tool_call":
|
|
240
|
+
case "tool_calls": return "tool_call";
|
|
241
|
+
case "content_filter": return "content_filter";
|
|
242
|
+
default: return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//#endregion
|
|
247
|
+
export { MistralLLMProvider };
|
|
248
|
+
//# sourceMappingURL=mistral-llm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mistral-llm.js","names":[],"sources":["../../src/impls/mistral-llm.ts"],"sourcesContent":["import { Mistral } from '@mistralai/mistralai';\nimport type * as components from '@mistralai/mistralai/models/components/index.js';\n\nimport type {\n LLMChatOptions,\n LLMContentPart,\n LLMMessage,\n LLMProvider,\n LLMResponse,\n LLMStreamChunk,\n LLMToolCallPart,\n LLMTokenUsage,\n} from '../llm';\n\nexport interface MistralLLMProviderOptions {\n apiKey: string;\n defaultModel?: string;\n serverURL?: string;\n client?: Mistral;\n userAgentSuffix?: string;\n}\n\nexport class MistralLLMProvider implements LLMProvider {\n private readonly client: Mistral;\n private readonly defaultModel: string;\n\n constructor(options: MistralLLMProviderOptions) {\n if (!options.apiKey) {\n throw new Error('MistralLLMProvider requires an apiKey');\n }\n\n this.client =\n options.client ??\n new Mistral({\n apiKey: options.apiKey,\n serverURL: options.serverURL,\n userAgent: options.userAgentSuffix\n ? `${options.userAgentSuffix}`\n : undefined,\n });\n this.defaultModel = options.defaultModel ?? 'mistral-large-latest';\n }\n\n async chat(\n messages: LLMMessage[],\n options: LLMChatOptions = {}\n ): Promise<LLMResponse> {\n const request = this.buildChatRequest(messages, options);\n const response = await this.client.chat.complete(request);\n return this.buildLLMResponse(response);\n }\n\n async *stream(\n messages: LLMMessage[],\n options: LLMChatOptions = {}\n ): AsyncIterable<LLMStreamChunk> {\n const request = this.buildChatRequest(messages, options);\n request.stream = true;\n const stream = await this.client.chat.stream(request);\n\n const aggregatedParts: LLMContentPart[] = [];\n const aggregatedToolCalls: LLMToolCallPart[] = [];\n let usage: LLMTokenUsage | undefined;\n let finishReason: string | undefined;\n\n for await (const event of stream) {\n for (const choice of event.data.choices) {\n const delta = choice.delta;\n if (typeof delta.content === 'string') {\n if (delta.content.length > 0) {\n aggregatedParts.push({ type: 'text', text: delta.content });\n yield {\n type: 'message_delta',\n delta: { type: 'text', text: delta.content },\n index: choice.index,\n };\n }\n } else if (Array.isArray(delta.content)) {\n for (const chunk of delta.content) {\n if (chunk.type === 'text' && 'text' in chunk) {\n aggregatedParts.push({ type: 'text', text: chunk.text });\n yield {\n type: 'message_delta',\n delta: { type: 'text', text: chunk.text },\n index: choice.index,\n };\n }\n }\n }\n\n if (delta.toolCalls) {\n let localIndex = 0;\n for (const call of delta.toolCalls) {\n const toolCall = this.fromMistralToolCall(call, localIndex);\n aggregatedToolCalls.push(toolCall);\n yield {\n type: 'tool_call',\n call: toolCall,\n index: choice.index,\n };\n localIndex += 1;\n }\n }\n\n if (choice.finishReason && choice.finishReason !== 'null') {\n finishReason = choice.finishReason;\n }\n }\n\n if (event.data.usage) {\n const usageEntry = this.fromUsage(event.data.usage);\n if (usageEntry) {\n usage = usageEntry;\n yield { type: 'usage', usage: usageEntry };\n }\n }\n }\n\n const message: LLMMessage = {\n role: 'assistant',\n content: aggregatedParts.length\n ? aggregatedParts\n : [{ type: 'text', text: '' }],\n };\n if (aggregatedToolCalls.length > 0) {\n message.content = [\n ...aggregatedToolCalls,\n ...(aggregatedParts.length ? aggregatedParts : []),\n ];\n }\n\n yield {\n type: 'end',\n response: {\n message,\n usage,\n finishReason: mapFinishReason(finishReason),\n },\n };\n }\n\n async countTokens(\n _messages: LLMMessage[]\n ): Promise<{ promptTokens: number }> {\n throw new Error('Mistral API does not currently support token counting');\n }\n\n private buildChatRequest(\n messages: LLMMessage[],\n options: LLMChatOptions\n ): components.ChatCompletionRequest {\n const model = options.model ?? this.defaultModel;\n const mappedMessages = messages.map((message) =>\n this.toMistralMessage(message)\n );\n\n const request: components.ChatCompletionRequest = {\n model,\n messages: mappedMessages,\n };\n\n if (options.temperature != null) {\n request.temperature = options.temperature;\n }\n if (options.topP != null) {\n request.topP = options.topP;\n }\n if (options.maxOutputTokens != null) {\n request.maxTokens = options.maxOutputTokens;\n }\n if (options.stopSequences?.length) {\n request.stop =\n options.stopSequences.length === 1\n ? options.stopSequences[0]\n : options.stopSequences;\n }\n if (options.tools?.length) {\n request.tools = options.tools.map((tool) => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters:\n typeof tool.inputSchema === 'object' && tool.inputSchema !== null\n ? tool.inputSchema\n : {},\n },\n }));\n }\n if (options.responseFormat === 'json') {\n request.responseFormat = { type: 'json_object' };\n }\n\n return request;\n }\n\n private buildLLMResponse(\n response: components.ChatCompletionResponse\n ): LLMResponse {\n const firstChoice = response.choices[0];\n if (!firstChoice) {\n return {\n message: {\n role: 'assistant',\n content: [{ type: 'text', text: '' }],\n },\n usage: this.fromUsage(response.usage),\n raw: response,\n };\n }\n const message = this.fromAssistantMessage(firstChoice.message);\n return {\n message,\n usage: this.fromUsage(response.usage),\n finishReason: mapFinishReason(firstChoice.finishReason),\n raw: response,\n };\n }\n\n private fromUsage(\n usage: components.UsageInfo | undefined\n ): LLMTokenUsage | undefined {\n if (!usage) return undefined;\n return {\n promptTokens: usage.promptTokens ?? 0,\n completionTokens: usage.completionTokens ?? 0,\n totalTokens: usage.totalTokens ?? 0,\n };\n }\n\n private fromAssistantMessage(\n message: components.AssistantMessage\n ): LLMMessage {\n const parts: LLMContentPart[] = [];\n if (typeof message.content === 'string') {\n parts.push({ type: 'text', text: message.content });\n } else if (Array.isArray(message.content)) {\n message.content.forEach((chunk) => {\n if (chunk.type === 'text' && 'text' in chunk) {\n parts.push({ type: 'text', text: chunk.text });\n }\n });\n }\n\n const toolCalls =\n message.toolCalls?.map((call, index) =>\n this.fromMistralToolCall(call, index)\n ) ?? [];\n\n if (toolCalls.length > 0) {\n parts.splice(0, 0, ...toolCalls);\n }\n\n if (parts.length === 0) {\n parts.push({ type: 'text', text: '' });\n }\n\n return {\n role: 'assistant',\n content: parts,\n };\n }\n\n private fromMistralToolCall(\n call: components.ToolCall,\n index: number\n ): LLMToolCallPart {\n const args =\n typeof call.function.arguments === 'string'\n ? call.function.arguments\n : JSON.stringify(call.function.arguments);\n return {\n type: 'tool-call',\n id: call.id ?? `tool-call-${index}`,\n name: call.function.name,\n arguments: args,\n };\n }\n\n private toMistralMessage(message: LLMMessage): components.Messages {\n const textContent = this.extractText(message.content);\n const toolCalls = this.extractToolCalls(message);\n\n switch (message.role) {\n case 'system':\n return {\n role: 'system',\n content: textContent ?? '',\n };\n case 'user':\n return {\n role: 'user',\n content: textContent ?? '',\n };\n case 'assistant':\n return {\n role: 'assistant',\n content: toolCalls.length > 0 ? null : (textContent ?? ''),\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n };\n case 'tool':\n return {\n role: 'tool',\n content: textContent ?? '',\n toolCallId: message.toolCallId ?? toolCalls[0]?.id,\n };\n default:\n return {\n role: 'user',\n content: textContent ?? '',\n };\n }\n }\n\n private extractText(parts: LLMContentPart[]): string | null {\n const textParts = parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as Extract<LLMContentPart, { type: 'text' }>).text);\n if (textParts.length === 0) return null;\n return textParts.join('');\n }\n\n private extractToolCalls(message: LLMMessage): components.ToolCall[] {\n const toolCallParts = message.content.filter(\n (part): part is LLMToolCallPart => part.type === 'tool-call'\n );\n return toolCallParts.map((call, index) => ({\n id: call.id ?? `call_${index}`,\n type: 'function',\n index,\n function: {\n name: call.name,\n arguments: call.arguments,\n },\n }));\n }\n}\n\nfunction mapFinishReason(\n reason?: string | null\n): LLMResponse['finishReason'] | undefined {\n if (!reason) return undefined;\n const normalized = reason.toLowerCase();\n switch (normalized) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_call':\n case 'tool_calls':\n return 'tool_call';\n case 'content_filter':\n return 'content_filter';\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { email_d_exports } from "../email.js";
|
|
2
|
+
import { ServerClient } from "postmark";
|
|
3
|
+
|
|
4
|
+
//#region src/impls/postmark-email.d.ts
|
|
5
|
+
interface PostmarkEmailProviderOptions {
|
|
6
|
+
serverToken: string;
|
|
7
|
+
defaultFromEmail?: string;
|
|
8
|
+
messageStream?: string;
|
|
9
|
+
client?: ServerClient;
|
|
10
|
+
}
|
|
11
|
+
declare class PostmarkEmailProvider implements email_d_exports.EmailOutboundProvider {
|
|
12
|
+
private readonly client;
|
|
13
|
+
private readonly defaultFromEmail?;
|
|
14
|
+
private readonly messageStream?;
|
|
15
|
+
constructor(options: PostmarkEmailProviderOptions);
|
|
16
|
+
sendEmail(message: email_d_exports.EmailOutboundMessage): Promise<email_d_exports.EmailOutboundResult>;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { PostmarkEmailProvider, PostmarkEmailProviderOptions };
|
|
20
|
+
//# sourceMappingURL=postmark-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postmark-email.d.ts","names":[],"sources":["../../src/impls/postmark-email.ts"],"sourcesContent":[],"mappings":";;;;UAQiB,4BAAA;;EAAA,gBAAA,CAAA,EAAA,MAAA;EAOJ,aAAA,CAAA,EAAA,MAAA;EAKU,MAAA,CAAA,EARZ,YAQY;;AAUmC,cAf7C,qBAAA,YAAiC,eAAA,CAAA,qBAeY,CAAA;EAAR,iBAAA,MAAA;EAfJ,iBAAA,gBAAA;EAAqB,iBAAA,aAAA;uBAK5C;qBAUI,eAAA,CAAA,uBAAuB,QAAQ,eAAA,CAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ServerClient } from "postmark";
|
|
2
|
+
|
|
3
|
+
//#region src/impls/postmark-email.ts
|
|
4
|
+
var PostmarkEmailProvider = class {
|
|
5
|
+
client;
|
|
6
|
+
defaultFromEmail;
|
|
7
|
+
messageStream;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.client = options.client ?? new ServerClient(options.serverToken, { useHttps: true });
|
|
10
|
+
this.defaultFromEmail = options.defaultFromEmail;
|
|
11
|
+
this.messageStream = options.messageStream;
|
|
12
|
+
}
|
|
13
|
+
async sendEmail(message) {
|
|
14
|
+
const request = {
|
|
15
|
+
From: formatAddress(message.from) ?? this.defaultFromEmail,
|
|
16
|
+
To: message.to.map((addr) => formatAddress(addr)).join(", "),
|
|
17
|
+
Cc: message.cc?.map((addr) => formatAddress(addr)).join(", ") || void 0,
|
|
18
|
+
Bcc: message.bcc?.map((addr) => formatAddress(addr)).join(", ") || void 0,
|
|
19
|
+
ReplyTo: message.replyTo ? formatAddress(message.replyTo) : void 0,
|
|
20
|
+
Subject: message.subject,
|
|
21
|
+
TextBody: message.textBody,
|
|
22
|
+
HtmlBody: message.htmlBody,
|
|
23
|
+
Headers: message.headers ? Object.entries(message.headers).map(([name, value]) => ({
|
|
24
|
+
Name: name,
|
|
25
|
+
Value: value
|
|
26
|
+
})) : void 0,
|
|
27
|
+
MessageStream: this.messageStream,
|
|
28
|
+
Attachments: buildAttachments(message)
|
|
29
|
+
};
|
|
30
|
+
const response = await this.client.sendEmail(request);
|
|
31
|
+
return {
|
|
32
|
+
id: response.MessageID,
|
|
33
|
+
providerMessageId: response.MessageID,
|
|
34
|
+
queuedAt: new Date(response.SubmittedAt ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function formatAddress(address) {
|
|
39
|
+
if (address.name) return `"${address.name}" <${address.email}>`;
|
|
40
|
+
return address.email;
|
|
41
|
+
}
|
|
42
|
+
function buildAttachments(message) {
|
|
43
|
+
if (!message.attachments?.length) return void 0;
|
|
44
|
+
return message.attachments.filter((attachment) => attachment.data).map((attachment) => ({
|
|
45
|
+
Name: attachment.filename,
|
|
46
|
+
Content: Buffer.from(attachment.data ?? new Uint8Array()).toString("base64"),
|
|
47
|
+
ContentType: attachment.contentType,
|
|
48
|
+
ContentID: null,
|
|
49
|
+
ContentLength: attachment.sizeBytes,
|
|
50
|
+
Disposition: "attachment"
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { PostmarkEmailProvider };
|
|
56
|
+
//# sourceMappingURL=postmark-email.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postmark-email.js","names":[],"sources":["../../src/impls/postmark-email.ts"],"sourcesContent":["import { ServerClient, type Models as PostmarkModels } from 'postmark';\n\nimport type {\n EmailOutboundMessage,\n EmailOutboundProvider,\n EmailOutboundResult,\n} from '../email';\n\nexport interface PostmarkEmailProviderOptions {\n serverToken: string;\n defaultFromEmail?: string;\n messageStream?: string;\n client?: ServerClient;\n}\n\nexport class PostmarkEmailProvider implements EmailOutboundProvider {\n private readonly client: ServerClient;\n private readonly defaultFromEmail?: string;\n private readonly messageStream?: string;\n\n constructor(options: PostmarkEmailProviderOptions) {\n this.client =\n options.client ??\n new ServerClient(options.serverToken, {\n useHttps: true,\n });\n this.defaultFromEmail = options.defaultFromEmail;\n this.messageStream = options.messageStream;\n }\n\n async sendEmail(message: EmailOutboundMessage): Promise<EmailOutboundResult> {\n const request: PostmarkModels.Message = {\n From: formatAddress(message.from) ?? this.defaultFromEmail,\n To: message.to.map((addr) => formatAddress(addr)).join(', '),\n Cc:\n message.cc?.map((addr) => formatAddress(addr)).join(', ') || undefined,\n Bcc:\n message.bcc?.map((addr) => formatAddress(addr)).join(', ') || undefined,\n ReplyTo: message.replyTo ? formatAddress(message.replyTo) : undefined,\n Subject: message.subject,\n TextBody: message.textBody,\n HtmlBody: message.htmlBody,\n Headers: message.headers\n ? Object.entries(message.headers).map(([name, value]) => ({\n Name: name,\n Value: value,\n }))\n : undefined,\n MessageStream: this.messageStream,\n Attachments: buildAttachments(message),\n };\n\n const response = await this.client.sendEmail(request);\n return {\n id: response.MessageID,\n providerMessageId: response.MessageID,\n queuedAt: new Date(response.SubmittedAt ?? new Date().toISOString()),\n };\n }\n}\n\nfunction formatAddress(address: { email: string; name?: string }): string {\n if (address.name) {\n return `\"${address.name}\" <${address.email}>`;\n }\n return address.email;\n}\n\nfunction buildAttachments(\n message: EmailOutboundMessage\n): PostmarkModels.Attachment[] | undefined {\n if (!message.attachments?.length) return undefined;\n return message.attachments\n .filter((attachment) => attachment.data)\n .map((attachment) => ({\n Name: attachment.filename,\n Content: Buffer.from(attachment.data ?? new Uint8Array()).toString(\n 'base64'\n ),\n ContentType: attachment.contentType,\n ContentID: null,\n ContentLength: attachment.sizeBytes,\n Disposition: 'attachment',\n }));\n}\n"],"mappings":";;;AAeA,IAAa,wBAAb,MAAoE;CAClE,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAuC;AACjD,OAAK,SACH,QAAQ,UACR,IAAI,aAAa,QAAQ,aAAa,EACpC,UAAU,MACX,CAAC;AACJ,OAAK,mBAAmB,QAAQ;AAChC,OAAK,gBAAgB,QAAQ;;CAG/B,MAAM,UAAU,SAA6D;EAC3E,MAAM,UAAkC;GACtC,MAAM,cAAc,QAAQ,KAAK,IAAI,KAAK;GAC1C,IAAI,QAAQ,GAAG,KAAK,SAAS,cAAc,KAAK,CAAC,CAAC,KAAK,KAAK;GAC5D,IACE,QAAQ,IAAI,KAAK,SAAS,cAAc,KAAK,CAAC,CAAC,KAAK,KAAK,IAAI;GAC/D,KACE,QAAQ,KAAK,KAAK,SAAS,cAAc,KAAK,CAAC,CAAC,KAAK,KAAK,IAAI;GAChE,SAAS,QAAQ,UAAU,cAAc,QAAQ,QAAQ,GAAG;GAC5D,SAAS,QAAQ;GACjB,UAAU,QAAQ;GAClB,UAAU,QAAQ;GAClB,SAAS,QAAQ,UACb,OAAO,QAAQ,QAAQ,QAAQ,CAAC,KAAK,CAAC,MAAM,YAAY;IACtD,MAAM;IACN,OAAO;IACR,EAAE,GACH;GACJ,eAAe,KAAK;GACpB,aAAa,iBAAiB,QAAQ;GACvC;EAED,MAAM,WAAW,MAAM,KAAK,OAAO,UAAU,QAAQ;AACrD,SAAO;GACL,IAAI,SAAS;GACb,mBAAmB,SAAS;GAC5B,UAAU,IAAI,KAAK,SAAS,gCAAe,IAAI,MAAM,EAAC,aAAa,CAAC;GACrE;;;AAIL,SAAS,cAAc,SAAmD;AACxE,KAAI,QAAQ,KACV,QAAO,IAAI,QAAQ,KAAK,KAAK,QAAQ,MAAM;AAE7C,QAAO,QAAQ;;AAGjB,SAAS,iBACP,SACyC;AACzC,KAAI,CAAC,QAAQ,aAAa,OAAQ,QAAO;AACzC,QAAO,QAAQ,YACZ,QAAQ,eAAe,WAAW,KAAK,CACvC,KAAK,gBAAgB;EACpB,MAAM,WAAW;EACjB,SAAS,OAAO,KAAK,WAAW,QAAQ,IAAI,YAAY,CAAC,CAAC,SACxD,SACD;EACD,aAAa,WAAW;EACxB,WAAW;EACX,eAAe,WAAW;EAC1B,aAAa;EACd,EAAE"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
//#region src/impls/powens-client.d.ts
|
|
2
|
+
type PowensEnvironment = 'sandbox' | 'production';
|
|
3
|
+
interface PowensClientOptions {
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret: string;
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
environment: PowensEnvironment;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
fetchImpl?: typeof fetch;
|
|
10
|
+
defaultTimeoutMs?: number;
|
|
11
|
+
logger?: {
|
|
12
|
+
debug?: (...args: unknown[]) => void;
|
|
13
|
+
warn?: (...args: unknown[]) => void;
|
|
14
|
+
error?: (...args: unknown[]) => void;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface PowensAccount {
|
|
18
|
+
uuid: string;
|
|
19
|
+
reference: string;
|
|
20
|
+
userUuid: string;
|
|
21
|
+
institution: {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
logoUrl?: string;
|
|
25
|
+
};
|
|
26
|
+
name: string;
|
|
27
|
+
iban?: string;
|
|
28
|
+
bic?: string;
|
|
29
|
+
currency?: string;
|
|
30
|
+
balance?: number;
|
|
31
|
+
availableBalance?: number;
|
|
32
|
+
type?: string;
|
|
33
|
+
status?: string;
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
interface PowensAccountListResponse {
|
|
37
|
+
accounts: PowensAccount[];
|
|
38
|
+
pagination?: {
|
|
39
|
+
nextCursor?: string;
|
|
40
|
+
hasMore?: boolean;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
interface PowensTransaction {
|
|
44
|
+
uuid: string;
|
|
45
|
+
accountUuid: string;
|
|
46
|
+
amount: number;
|
|
47
|
+
currency: string;
|
|
48
|
+
direction: 'credit' | 'debit';
|
|
49
|
+
description?: string;
|
|
50
|
+
category?: string;
|
|
51
|
+
rawLabel?: string;
|
|
52
|
+
bookingDate?: string;
|
|
53
|
+
valueDate?: string;
|
|
54
|
+
status?: string;
|
|
55
|
+
merchantName?: string;
|
|
56
|
+
merchantCategoryCode?: string;
|
|
57
|
+
counterpartyName?: string;
|
|
58
|
+
counterpartyAccount?: string;
|
|
59
|
+
metadata?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
interface PowensTransactionListResponse {
|
|
62
|
+
transactions: PowensTransaction[];
|
|
63
|
+
pagination?: {
|
|
64
|
+
nextCursor?: string;
|
|
65
|
+
hasMore?: boolean;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
interface PowensBalance {
|
|
69
|
+
accountUuid: string;
|
|
70
|
+
type: string;
|
|
71
|
+
amount: number;
|
|
72
|
+
currency: string;
|
|
73
|
+
updatedAt: string;
|
|
74
|
+
metadata?: Record<string, unknown>;
|
|
75
|
+
}
|
|
76
|
+
interface PowensConnectionStatusResponse {
|
|
77
|
+
connectionUuid: string;
|
|
78
|
+
status: 'healthy' | 'error' | 'revoked' | 'pending';
|
|
79
|
+
lastAttemptAt?: string;
|
|
80
|
+
errorCode?: string;
|
|
81
|
+
errorMessage?: string;
|
|
82
|
+
metadata?: Record<string, unknown>;
|
|
83
|
+
}
|
|
84
|
+
declare class PowensClientError extends Error {
|
|
85
|
+
readonly status: number;
|
|
86
|
+
readonly code?: string;
|
|
87
|
+
readonly requestId?: string;
|
|
88
|
+
readonly response?: unknown;
|
|
89
|
+
constructor(message: string, status: number, code?: string, requestId?: string, response?: unknown);
|
|
90
|
+
}
|
|
91
|
+
declare class PowensClient {
|
|
92
|
+
private readonly clientId;
|
|
93
|
+
private readonly clientSecret;
|
|
94
|
+
private readonly apiKey?;
|
|
95
|
+
private readonly fetchImpl;
|
|
96
|
+
private readonly logger?;
|
|
97
|
+
private readonly defaultTimeoutMs;
|
|
98
|
+
private token?;
|
|
99
|
+
private readonly baseUrl;
|
|
100
|
+
constructor(options: PowensClientOptions);
|
|
101
|
+
listAccounts(params: {
|
|
102
|
+
userUuid: string;
|
|
103
|
+
cursor?: string;
|
|
104
|
+
limit?: number;
|
|
105
|
+
includeBalances?: boolean;
|
|
106
|
+
institutionUuid?: string;
|
|
107
|
+
}): Promise<PowensAccountListResponse>;
|
|
108
|
+
getAccount(accountUuid: string): Promise<PowensAccount>;
|
|
109
|
+
listTransactions(params: {
|
|
110
|
+
accountUuid: string;
|
|
111
|
+
cursor?: string;
|
|
112
|
+
limit?: number;
|
|
113
|
+
from?: string;
|
|
114
|
+
to?: string;
|
|
115
|
+
includePending?: boolean;
|
|
116
|
+
}): Promise<PowensTransactionListResponse>;
|
|
117
|
+
getBalances(accountUuid: string): Promise<PowensBalance[]>;
|
|
118
|
+
getConnectionStatus(connectionUuid: string): Promise<PowensConnectionStatusResponse>;
|
|
119
|
+
private request;
|
|
120
|
+
private ensureAccessToken;
|
|
121
|
+
private fetchAccessToken;
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
export { PowensAccount, PowensAccountListResponse, PowensBalance, PowensClient, PowensClientError, PowensClientOptions, PowensConnectionStatusResponse, PowensEnvironment, PowensTransaction, PowensTransactionListResponse };
|
|
125
|
+
//# sourceMappingURL=powens-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"powens-client.d.ts","names":[],"sources":["../../src/impls/powens-client.ts"],"sourcesContent":[],"mappings":";KAEY,iBAAA;AAAA,UAOK,mBAAA,CAPY;EAOZ,QAAA,EAAA,MAAA;EA4BA,YAAA,EAAA,MAAa;EAoBb,MAAA,CAAA,EAAA,MAAA;EAQA,WAAA,EApDF,iBAoDmB;EAmBjB,OAAA,CAAA,EAAA,MAAA;EAQA,SAAA,CAAA,EAAA,OA7EI,KA6ES;EASb,gBAAA,CAAA,EAAA,MAAA;EASJ,MAAA,CAAA,EAAA;IAgCA,KAAA,CAAA,EAAA,CAAA,GAAY,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA;IAUF,IAAA,CAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA;IAmBT,KAAA,CAAA,EAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAAA,IAAA;EAAR,CAAA;;AAgBmC,UAtJxB,aAAA,CAsJwB;EAc3B,IAAA,EAAA,MAAA;EAAR,SAAA,EAAA,MAAA;EAgB4C,QAAA,EAAA,MAAA;EAAR,WAAA,EAAA;IAS7B,EAAA,EAAA,MAAA;IAAR,IAAA,EAAA,MAAA;IAAO,OAAA,CAAA,EAAA,MAAA;;;;;;;;;;aA5KC;;UAGI,yBAAA;YACL;;;;;;UAOK,iBAAA;;;;;;;;;;;;;;;;aAgBJ;;UAGI,6BAAA;gBACD;;;;;;UAOC,aAAA;;;;;;aAMJ;;UAGI,8BAAA;;;;;;aAMJ;;cAGA,iBAAA,SAA0B,KAAA;;;;;;;cAgC1B,YAAA;;;;;;;;;uBAUU;;;;;;;MAmBjB,QAAQ;mCAgB2B,QAAQ;;;;;;;;MAc3C,QAAQ;oCAgB4B,QAAQ;+CAS7C,QAAQ"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { URL } from "node:url";
|
|
2
|
+
|
|
3
|
+
//#region src/impls/powens-client.ts
|
|
4
|
+
const POWENS_BASE_URL = {
|
|
5
|
+
sandbox: "https://api-sandbox.powens.com/v2",
|
|
6
|
+
production: "https://api.powens.com/v2"
|
|
7
|
+
};
|
|
8
|
+
var PowensClientError = class extends Error {
|
|
9
|
+
status;
|
|
10
|
+
code;
|
|
11
|
+
requestId;
|
|
12
|
+
response;
|
|
13
|
+
constructor(message, status, code, requestId, response) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "PowensClientError";
|
|
16
|
+
this.status = status;
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.requestId = requestId;
|
|
19
|
+
this.response = response;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var PowensClient = class {
|
|
23
|
+
clientId;
|
|
24
|
+
clientSecret;
|
|
25
|
+
apiKey;
|
|
26
|
+
fetchImpl;
|
|
27
|
+
logger;
|
|
28
|
+
defaultTimeoutMs;
|
|
29
|
+
token;
|
|
30
|
+
baseUrl;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.clientId = options.clientId;
|
|
33
|
+
this.clientSecret = options.clientSecret;
|
|
34
|
+
this.apiKey = options.apiKey;
|
|
35
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
36
|
+
this.logger = options.logger;
|
|
37
|
+
this.defaultTimeoutMs = options.defaultTimeoutMs ?? 15e3;
|
|
38
|
+
this.baseUrl = options.baseUrl ?? POWENS_BASE_URL[options.environment] ?? POWENS_BASE_URL.production;
|
|
39
|
+
}
|
|
40
|
+
async listAccounts(params) {
|
|
41
|
+
const searchParams = {
|
|
42
|
+
cursor: params.cursor,
|
|
43
|
+
limit: params.limit,
|
|
44
|
+
include_balances: params.includeBalances,
|
|
45
|
+
institution_uuid: params.institutionUuid
|
|
46
|
+
};
|
|
47
|
+
return await this.request({
|
|
48
|
+
method: "GET",
|
|
49
|
+
path: `/users/${encodeURIComponent(params.userUuid)}/accounts`,
|
|
50
|
+
searchParams
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async getAccount(accountUuid) {
|
|
54
|
+
return this.request({
|
|
55
|
+
method: "GET",
|
|
56
|
+
path: `/accounts/${encodeURIComponent(accountUuid)}`
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async listTransactions(params) {
|
|
60
|
+
const searchParams = {
|
|
61
|
+
cursor: params.cursor,
|
|
62
|
+
limit: params.limit,
|
|
63
|
+
from: params.from,
|
|
64
|
+
to: params.to,
|
|
65
|
+
include_pending: params.includePending
|
|
66
|
+
};
|
|
67
|
+
return this.request({
|
|
68
|
+
method: "GET",
|
|
69
|
+
path: `/accounts/${encodeURIComponent(params.accountUuid)}/transactions`,
|
|
70
|
+
searchParams
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async getBalances(accountUuid) {
|
|
74
|
+
return this.request({
|
|
75
|
+
method: "GET",
|
|
76
|
+
path: `/accounts/${encodeURIComponent(accountUuid)}/balances`
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async getConnectionStatus(connectionUuid) {
|
|
80
|
+
return this.request({
|
|
81
|
+
method: "GET",
|
|
82
|
+
path: `/connections/${encodeURIComponent(connectionUuid)}`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async request(options) {
|
|
86
|
+
const url = new URL(options.path, this.baseUrl);
|
|
87
|
+
if (options.searchParams) for (const [key, value] of Object.entries(options.searchParams)) {
|
|
88
|
+
if (value === void 0 || value === null) continue;
|
|
89
|
+
url.searchParams.set(key, String(value));
|
|
90
|
+
}
|
|
91
|
+
const headers = {
|
|
92
|
+
Accept: "application/json",
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
...options.headers
|
|
95
|
+
};
|
|
96
|
+
if (this.apiKey) headers["x-api-key"] = this.apiKey;
|
|
97
|
+
if (!options.skipAuth) headers.Authorization = `Bearer ${await this.ensureAccessToken()}`;
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? this.defaultTimeoutMs);
|
|
100
|
+
try {
|
|
101
|
+
const response = await this.fetchImpl(url, {
|
|
102
|
+
method: options.method,
|
|
103
|
+
headers,
|
|
104
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
105
|
+
signal: controller.signal
|
|
106
|
+
});
|
|
107
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
let errorBody;
|
|
110
|
+
try {
|
|
111
|
+
errorBody = await response.json();
|
|
112
|
+
} catch {}
|
|
113
|
+
const errorObject = typeof errorBody === "object" && errorBody !== null ? errorBody : void 0;
|
|
114
|
+
const message = typeof errorObject?.message === "string" ? errorObject.message : `Powens API request failed with status ${response.status}`;
|
|
115
|
+
const code = typeof errorObject?.code === "string" ? errorObject.code : void 0;
|
|
116
|
+
throw new PowensClientError(message, response.status, code, requestId, errorBody);
|
|
117
|
+
}
|
|
118
|
+
if (response.status === 204) return;
|
|
119
|
+
try {
|
|
120
|
+
return await response.json();
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.logger?.error?.("[PowensClient] Failed to parse JSON response", error);
|
|
123
|
+
throw new PowensClientError("Failed to parse Powens response payload as JSON", response.status, void 0, requestId);
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof PowensClientError) throw error;
|
|
127
|
+
if (error.name === "AbortError") throw new PowensClientError(`Powens API request timed out after ${options.timeoutMs ?? this.defaultTimeoutMs}ms`, 408);
|
|
128
|
+
this.logger?.error?.("[PowensClient] Request failed", error);
|
|
129
|
+
throw new PowensClientError(error.message ?? "Powens API request failed", 500);
|
|
130
|
+
} finally {
|
|
131
|
+
clearTimeout(timeout);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async ensureAccessToken() {
|
|
135
|
+
if (this.token && Date.now() < this.token.expiresAt - 5e3) return this.token.accessToken;
|
|
136
|
+
this.token = await this.fetchAccessToken();
|
|
137
|
+
return this.token.accessToken;
|
|
138
|
+
}
|
|
139
|
+
async fetchAccessToken() {
|
|
140
|
+
const url = new URL("/oauth/token", this.baseUrl);
|
|
141
|
+
const basicAuth = Buffer.from(`${this.clientId}:${this.clientSecret}`, "utf-8").toString("base64");
|
|
142
|
+
const response = await this.fetchImpl(url, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
headers: {
|
|
145
|
+
Authorization: `Basic ${basicAuth}`,
|
|
146
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
147
|
+
Accept: "application/json"
|
|
148
|
+
},
|
|
149
|
+
body: new URLSearchParams({ grant_type: "client_credentials" }).toString()
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
let errorBody;
|
|
153
|
+
try {
|
|
154
|
+
errorBody = await response.json();
|
|
155
|
+
} catch {}
|
|
156
|
+
const errorObject = typeof errorBody === "object" && errorBody !== null ? errorBody : void 0;
|
|
157
|
+
throw new PowensClientError(typeof errorObject?.error_description === "string" ? errorObject.error_description : "Failed to obtain Powens access token", response.status, void 0, void 0, errorBody);
|
|
158
|
+
}
|
|
159
|
+
const payload = await response.json();
|
|
160
|
+
const expiresAt = Date.now() + payload.expires_in * 1e3;
|
|
161
|
+
this.logger?.debug?.("[PowensClient] Received access token", { expiresIn: payload.expires_in });
|
|
162
|
+
return {
|
|
163
|
+
accessToken: payload.access_token,
|
|
164
|
+
expiresAt,
|
|
165
|
+
scope: payload.scope
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
//#endregion
|
|
171
|
+
export { PowensClient, PowensClientError };
|
|
172
|
+
//# sourceMappingURL=powens-client.js.map
|