sendpro-flowmailer-mcp 0.1.1
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/.env.example +19 -0
- package/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -0
- package/dist/flowmailer-client.d.ts +40 -0
- package/dist/flowmailer-client.js +191 -0
- package/dist/flowmailer-client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +25 -0
- package/dist/tools.js +377 -0
- package/dist/tools.js.map +1 -0
- package/docs/configuration.md +38 -0
- package/docs/releasing.md +85 -0
- package/docs/repository-health.md +110 -0
- package/docs/tools.md +34 -0
- package/package.json +73 -0
- package/server.json +59 -0
package/.env.example
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
SENDPRO_ACCOUNT_ID=your-account-id
|
|
2
|
+
SENDPRO_CLIENT_ID=your-client-id
|
|
3
|
+
SENDPRO_CLIENT_SECRET=your-client-secret
|
|
4
|
+
|
|
5
|
+
# Safe default is true. Set to false only when you want write tools enabled.
|
|
6
|
+
SENDPRO_READ_ONLY=true
|
|
7
|
+
|
|
8
|
+
# READ_ONLY is also supported for MCP clients that pass generic env names.
|
|
9
|
+
# READ_ONLY=true
|
|
10
|
+
|
|
11
|
+
SENDPRO_API_BASE_URL=https://api.flowmailer.net
|
|
12
|
+
SENDPRO_AUTH_BASE_URL=https://login.flowmailer.net
|
|
13
|
+
SENDPRO_API_MEDIA_TYPE=application/vnd.flowmailer.v1.12+json
|
|
14
|
+
|
|
15
|
+
# Legacy aliases are also supported:
|
|
16
|
+
# FLOWMAILER_ACCOUNT_ID=your-account-id
|
|
17
|
+
# FLOWMAILER_CLIENT_ID=your-client-id
|
|
18
|
+
# FLOWMAILER_CLIENT_SECRET=your-client-secret
|
|
19
|
+
# FLOWMAILER_READ_ONLY=true
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sociuu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# Spotler SendPro / FlowMailer MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Mestika/sendpro-flowmailer-mcp/releases)
|
|
4
|
+
[](https://www.npmjs.com/package/sendpro-flowmailer-mcp)
|
|
5
|
+
[](https://www.npmjs.com/package/sendpro-flowmailer-mcp)
|
|
6
|
+
[](https://github.com/Mestika/sendpro-flowmailer-mcp/actions/workflows/ci.yml)
|
|
7
|
+
[](https://scorecard.dev/viewer/?uri=github.com/Mestika/sendpro-flowmailer-mcp)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](package.json)
|
|
10
|
+
[](tsconfig.json)
|
|
11
|
+
[](https://modelcontextprotocol.io/)
|
|
12
|
+
[](#read-only-mode)
|
|
13
|
+
|
|
14
|
+
Unofficial Model Context Protocol server for the Spotler SendPro API, formerly known as FlowMailer.
|
|
15
|
+
|
|
16
|
+
This project is not affiliated with, endorsed by, or maintained by Spotler. It is a community MCP server for teams that need controlled AI-agent access to SendPro account data and, when explicitly enabled, SendPro message operations.
|
|
17
|
+
|
|
18
|
+
<!-- mcp-name: io.github.mestika/sendpro-flowmailer-mcp -->
|
|
19
|
+
|
|
20
|
+
## What It Does
|
|
21
|
+
|
|
22
|
+
- Connects to SendPro over OAuth2 client credentials.
|
|
23
|
+
- Exposes SendPro operations as MCP tools over stdio.
|
|
24
|
+
- Defaults to read-only mode.
|
|
25
|
+
- Blocks mutating SendPro requests when read-only mode is enabled.
|
|
26
|
+
- Supports current SendPro naming plus legacy FlowMailer environment variables.
|
|
27
|
+
- Includes MCP Registry metadata in [server.json](server.json).
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
From npm:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx -y sendpro-flowmailer-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Directly from GitHub:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y github:Mestika/sendpro-flowmailer-mcp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Local development:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/Mestika/sendpro-flowmailer-mcp.git
|
|
47
|
+
cd sendpro-flowmailer-mcp
|
|
48
|
+
npm install
|
|
49
|
+
npm run build
|
|
50
|
+
node dist/index.js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Set credentials through your MCP client config, shell environment, or a local `.env` file.
|
|
56
|
+
|
|
57
|
+
| Variable | Required | Default | Description |
|
|
58
|
+
| --- | --- | --- | --- |
|
|
59
|
+
| `SENDPRO_ACCOUNT_ID` | Yes | | SendPro account id. |
|
|
60
|
+
| `SENDPRO_CLIENT_ID` | Yes | | OAuth client id. |
|
|
61
|
+
| `SENDPRO_CLIENT_SECRET` | Yes | | OAuth client secret. |
|
|
62
|
+
| `SENDPRO_READ_ONLY` | No | `true` | Safe-mode flag. When true, only SendPro read requests are allowed. |
|
|
63
|
+
| `READ_ONLY` | No | | Generic override for `SENDPRO_READ_ONLY`; useful for shared MCP config conventions. |
|
|
64
|
+
| `SENDPRO_API_BASE_URL` | No | `https://api.flowmailer.net` | SendPro API base URL. |
|
|
65
|
+
| `SENDPRO_AUTH_BASE_URL` | No | `https://login.flowmailer.net` | OAuth base URL. |
|
|
66
|
+
| `SENDPRO_API_MEDIA_TYPE` | No | `application/vnd.flowmailer.v1.12+json` | SendPro vendor media type. |
|
|
67
|
+
|
|
68
|
+
Legacy aliases are supported:
|
|
69
|
+
|
|
70
|
+
| Current | Spotler alias | Legacy FlowMailer alias |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `SENDPRO_ACCOUNT_ID` | `SPOTLER_SENDPRO_ACCOUNT_ID` | `FLOWMAILER_ACCOUNT_ID` |
|
|
73
|
+
| `SENDPRO_CLIENT_ID` | `SPOTLER_SENDPRO_CLIENT_ID` | `FLOWMAILER_CLIENT_ID` |
|
|
74
|
+
| `SENDPRO_CLIENT_SECRET` | `SPOTLER_SENDPRO_CLIENT_SECRET` | `FLOWMAILER_CLIENT_SECRET` |
|
|
75
|
+
| `SENDPRO_READ_ONLY` | `SPOTLER_SENDPRO_READ_ONLY` | `FLOWMAILER_READ_ONLY` |
|
|
76
|
+
|
|
77
|
+
Precedence is: `READ_ONLY`, then `SENDPRO_*`, then `SPOTLER_SENDPRO_*`, then `FLOWMAILER_*`.
|
|
78
|
+
|
|
79
|
+
## Creating SendPro API Credentials
|
|
80
|
+
|
|
81
|
+
SendPro uses OAuth2 client credentials. You need three values:
|
|
82
|
+
|
|
83
|
+
- account id
|
|
84
|
+
- client id
|
|
85
|
+
- client secret
|
|
86
|
+
|
|
87
|
+
The public SendPro API docs state that the API uses OAuth2 client credentials, that the access token endpoint is `https://login.flowmailer.net/oauth/token`, and that the `client_id`, `client_secret`, `grant_type=client_credentials`, and optional `scope=api` form values are used to request a token. The same docs also expose source-system credential endpoints under `/{account_id}/sources/{source_id}/users`, including endpoints to list, create, get, update, and delete source credentials.
|
|
88
|
+
|
|
89
|
+
In the SendPro dashboard, the exact labels can vary by account, but the usual path is:
|
|
90
|
+
|
|
91
|
+
1. Sign in to Spotler SendPro.
|
|
92
|
+
2. Go to Setup.
|
|
93
|
+
3. Open Sources or Source systems.
|
|
94
|
+
4. Select the source system that should be used for API access, or create a dedicated source for MCP/automation usage.
|
|
95
|
+
5. Open the source credentials/users section.
|
|
96
|
+
6. Create new credentials with a clear description such as `MCP read-only`.
|
|
97
|
+
7. Copy the generated client id and client secret, and store them in your MCP client environment.
|
|
98
|
+
8. Use the SendPro account id from your account URL, dashboard context, or API settings as `SENDPRO_ACCOUNT_ID`.
|
|
99
|
+
|
|
100
|
+
For AI-agent usage, prefer credentials that are limited to the minimum access needed. Keep this MCP server in read-only mode unless you explicitly need submit, simulate, or resend operations.
|
|
101
|
+
|
|
102
|
+
Official references:
|
|
103
|
+
|
|
104
|
+
- [SendPro API authentication](https://flowmailer.com/apidoc/sendpro-api.html#_authentication)
|
|
105
|
+
- [POST `/oauth/token`](https://flowmailer.com/apidoc/sendpro-api.html#_post_oauth_token)
|
|
106
|
+
- [Source credential endpoints](https://flowmailer.com/apidoc/sendpro-api.html#_post_account_id_sources_source_id_users)
|
|
107
|
+
- [Spotler SendPro Help Center](https://sendpro.spotler.help/hc/en-gb)
|
|
108
|
+
|
|
109
|
+
## Codex
|
|
110
|
+
|
|
111
|
+
Add this to `~/.codex/config.toml`:
|
|
112
|
+
|
|
113
|
+
```toml
|
|
114
|
+
[mcp_servers.sendpro_flowmailer]
|
|
115
|
+
command = "npx"
|
|
116
|
+
args = ["-y", "sendpro-flowmailer-mcp"]
|
|
117
|
+
startup_timeout_sec = 20.0
|
|
118
|
+
|
|
119
|
+
[mcp_servers.sendpro_flowmailer.env]
|
|
120
|
+
SENDPRO_ACCOUNT_ID = "your-account-id"
|
|
121
|
+
SENDPRO_CLIENT_ID = "your-client-id"
|
|
122
|
+
SENDPRO_CLIENT_SECRET = "your-client-secret"
|
|
123
|
+
SENDPRO_READ_ONLY = "true"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
To run directly from GitHub:
|
|
127
|
+
|
|
128
|
+
```toml
|
|
129
|
+
[mcp_servers.sendpro_flowmailer]
|
|
130
|
+
command = "npx"
|
|
131
|
+
args = ["-y", "github:Mestika/sendpro-flowmailer-mcp"]
|
|
132
|
+
startup_timeout_sec = 20.0
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Claude Desktop
|
|
136
|
+
|
|
137
|
+
Add this to `claude_desktop_config.json`:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"mcpServers": {
|
|
142
|
+
"sendpro-flowmailer": {
|
|
143
|
+
"command": "npx",
|
|
144
|
+
"args": ["-y", "sendpro-flowmailer-mcp"],
|
|
145
|
+
"env": {
|
|
146
|
+
"SENDPRO_ACCOUNT_ID": "your-account-id",
|
|
147
|
+
"SENDPRO_CLIENT_ID": "your-client-id",
|
|
148
|
+
"SENDPRO_CLIENT_SECRET": "your-client-secret",
|
|
149
|
+
"SENDPRO_READ_ONLY": "true"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Read-Only Mode
|
|
157
|
+
|
|
158
|
+
`SENDPRO_READ_ONLY` defaults to `true`.
|
|
159
|
+
|
|
160
|
+
When read-only mode is enabled:
|
|
161
|
+
|
|
162
|
+
- MCP schemas only allow `GET` for the generic request tool.
|
|
163
|
+
- Mutating helper tools are not registered.
|
|
164
|
+
- The low-level client rejects `POST`, `PUT`, `PATCH`, and `DELETE` SendPro API requests before requesting an OAuth token.
|
|
165
|
+
|
|
166
|
+
OAuth itself still uses `POST https://login.flowmailer.net/oauth/token`, because SendPro requires OAuth2 client credentials before any resource can be read. The read-only guard applies to SendPro API resource calls against the configured API base URL.
|
|
167
|
+
|
|
168
|
+
## Tools
|
|
169
|
+
|
|
170
|
+
Read tools:
|
|
171
|
+
|
|
172
|
+
| Tool | Description |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| `flowmailer_request` | Generic relative SendPro API request. In read-only mode, only `GET` is accepted. |
|
|
175
|
+
| `flowmailer_endpoint_catalog` | Lists SendPro endpoints known by this server. |
|
|
176
|
+
| `flowmailer_list_messages` | Lists messages using SendPro reference-range paging. |
|
|
177
|
+
| `flowmailer_get_message` | Gets one message by id. |
|
|
178
|
+
| `flowmailer_get_message_archive` | Gets archived content metadata for a message. |
|
|
179
|
+
| `flowmailer_get_message_error_archive` | Gets archived error content for a message. |
|
|
180
|
+
| `flowmailer_get_recipient` | Gets recipient information. |
|
|
181
|
+
| `flowmailer_list_resource` | Lists common resources such as flows, templates, sender domains, sources, and stats. |
|
|
182
|
+
|
|
183
|
+
Write tools, only when `SENDPRO_READ_ONLY=false`:
|
|
184
|
+
|
|
185
|
+
| Tool | Description |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `flowmailer_submit_message` | Submits an email or SMS message. |
|
|
188
|
+
| `flowmailer_simulate_message` | Simulates an email or SMS message. |
|
|
189
|
+
| `flowmailer_resend_message` | Resends a message by id. |
|
|
190
|
+
|
|
191
|
+
The tool names currently retain the FlowMailer prefix because the public SendPro API and media types still use FlowMailer naming in several places. Package names and documentation use both SendPro and FlowMailer for discoverability.
|
|
192
|
+
|
|
193
|
+
## Examples
|
|
194
|
+
|
|
195
|
+
List messages:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"method": "GET",
|
|
200
|
+
"path": "/{account_id}/messages",
|
|
201
|
+
"matrix": {
|
|
202
|
+
"daterange": "2026-05-01T00:00:00Z,2026-05-20T00:00:00Z"
|
|
203
|
+
},
|
|
204
|
+
"query": {
|
|
205
|
+
"addevents": true,
|
|
206
|
+
"sortfield": "INSERTED",
|
|
207
|
+
"sortorder": "ASC"
|
|
208
|
+
},
|
|
209
|
+
"range": "items=:10"
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
List flows through the convenience tool:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"resource": "flows"
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Submit a message, only with `SENDPRO_READ_ONLY=false`:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"body": {
|
|
226
|
+
"messageType": "EMAIL",
|
|
227
|
+
"headerFromAddress": "sender@example.com",
|
|
228
|
+
"headerToAddress": "recipient@example.com",
|
|
229
|
+
"subject": "Hello",
|
|
230
|
+
"text": "Message body"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npm install
|
|
239
|
+
npm run check
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Useful commands:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
npm run dev
|
|
246
|
+
npm run build
|
|
247
|
+
npm run typecheck
|
|
248
|
+
npm test
|
|
249
|
+
npm run inspect
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
For repository structure, badges, release hygiene, and maintenance settings, see [docs/repository-health.md](docs/repository-health.md).
|
|
253
|
+
|
|
254
|
+
## Publishing
|
|
255
|
+
|
|
256
|
+
This package is published to npm as [sendpro-flowmailer-mcp](https://www.npmjs.com/package/sendpro-flowmailer-mcp), and the repository includes MCP Registry metadata for registry submission.
|
|
257
|
+
|
|
258
|
+
For npm:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
npm publish --access public
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
For the official MCP Registry, publish [server.json](server.json) after the npm package exists. The npm package includes:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"mcpName": "io.github.mestika/sendpro-flowmailer-mcp"
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Releases and Versions
|
|
273
|
+
|
|
274
|
+
This project uses semantic version tags such as `v0.1.0`, `v0.1.1`, and `v1.0.0`.
|
|
275
|
+
|
|
276
|
+
Use:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm run version:patch # bug fixes and small documentation-only release updates
|
|
280
|
+
npm run version:minor # new backwards-compatible tools or features
|
|
281
|
+
npm run version:major # breaking changes
|
|
282
|
+
git push origin main --follow-tags
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Then create a GitHub Release from the new tag. The GitHub Release is the public changelog entry; the Git tag is the exact source snapshot. See [docs/releasing.md](docs/releasing.md) for the full checklist.
|
|
286
|
+
|
|
287
|
+
## Security
|
|
288
|
+
|
|
289
|
+
Never commit real SendPro credentials. Use MCP client environment variables, shell environment variables, or a local `.env` file.
|
|
290
|
+
|
|
291
|
+
See [SECURITY.md](SECURITY.md) for vulnerability reporting and operational notes.
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface FlowMailerConfig {
|
|
2
|
+
accountId: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
readOnly: boolean;
|
|
6
|
+
apiBaseUrl: string;
|
|
7
|
+
authBaseUrl: string;
|
|
8
|
+
apiMediaType: string;
|
|
9
|
+
}
|
|
10
|
+
export type Env = Record<string, string | undefined>;
|
|
11
|
+
export declare function loadConfig(env?: Env): FlowMailerConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const ENV_ALIASES = {
|
|
2
|
+
accountId: ["SENDPRO_ACCOUNT_ID", "SPOTLER_SENDPRO_ACCOUNT_ID", "FLOWMAILER_ACCOUNT_ID"],
|
|
3
|
+
clientId: ["SENDPRO_CLIENT_ID", "SPOTLER_SENDPRO_CLIENT_ID", "FLOWMAILER_CLIENT_ID"],
|
|
4
|
+
clientSecret: ["SENDPRO_CLIENT_SECRET", "SPOTLER_SENDPRO_CLIENT_SECRET", "FLOWMAILER_CLIENT_SECRET"],
|
|
5
|
+
readOnly: ["READ_ONLY", "SENDPRO_READ_ONLY", "SPOTLER_SENDPRO_READ_ONLY", "FLOWMAILER_READ_ONLY"],
|
|
6
|
+
apiBaseUrl: ["SENDPRO_API_BASE_URL", "SPOTLER_SENDPRO_API_BASE_URL", "FLOWMAILER_API_BASE_URL"],
|
|
7
|
+
authBaseUrl: ["SENDPRO_AUTH_BASE_URL", "SPOTLER_SENDPRO_AUTH_BASE_URL", "FLOWMAILER_AUTH_BASE_URL"],
|
|
8
|
+
apiMediaType: ["SENDPRO_API_MEDIA_TYPE", "SPOTLER_SENDPRO_API_MEDIA_TYPE", "FLOWMAILER_API_MEDIA_TYPE"]
|
|
9
|
+
};
|
|
10
|
+
export function loadConfig(env = process.env) {
|
|
11
|
+
const accountId = readFirst(env, ENV_ALIASES.accountId);
|
|
12
|
+
const clientId = readFirst(env, ENV_ALIASES.clientId);
|
|
13
|
+
const clientSecret = readFirst(env, ENV_ALIASES.clientSecret);
|
|
14
|
+
const missing = [
|
|
15
|
+
["account id", ENV_ALIASES.accountId, accountId],
|
|
16
|
+
["client id", ENV_ALIASES.clientId, clientId],
|
|
17
|
+
["client secret", ENV_ALIASES.clientSecret, clientSecret]
|
|
18
|
+
].flatMap(([label, names, value]) => (value ? [] : [`${label}: ${formatAliases(names)}`]));
|
|
19
|
+
if (missing.length > 0) {
|
|
20
|
+
throw new Error(`Missing required SendPro environment variables: ${missing.join("; ")}`);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
accountId: accountId,
|
|
24
|
+
clientId: clientId,
|
|
25
|
+
clientSecret: clientSecret,
|
|
26
|
+
readOnly: parseReadOnly(readFirst(env, ENV_ALIASES.readOnly) ?? "true"),
|
|
27
|
+
apiBaseUrl: stripTrailingSlash(readFirst(env, ENV_ALIASES.apiBaseUrl) ?? "https://api.flowmailer.net"),
|
|
28
|
+
authBaseUrl: stripTrailingSlash(readFirst(env, ENV_ALIASES.authBaseUrl) ?? "https://login.flowmailer.net"),
|
|
29
|
+
apiMediaType: readFirst(env, ENV_ALIASES.apiMediaType) ?? "application/vnd.flowmailer.v1.12+json"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function readFirst(env, names) {
|
|
33
|
+
return names.map((name) => env[name]).find((value) => value !== undefined && value.length > 0);
|
|
34
|
+
}
|
|
35
|
+
function formatAliases(names) {
|
|
36
|
+
const [primary, ...aliases] = names;
|
|
37
|
+
return aliases.length === 0 ? primary : `${primary} (aliases: ${aliases.join(", ")})`;
|
|
38
|
+
}
|
|
39
|
+
function parseReadOnly(value) {
|
|
40
|
+
return !["false", "0", "no", "off"].includes(value.trim().toLowerCase());
|
|
41
|
+
}
|
|
42
|
+
function stripTrailingSlash(value) {
|
|
43
|
+
return value.replace(/\/+$/, "");
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { FlowMailerConfig } from "./config.js";
|
|
2
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
3
|
+
export type ParameterValue = string | number | boolean | null | undefined | Array<string | number | boolean>;
|
|
4
|
+
export interface FlowMailerRequest {
|
|
5
|
+
method: HttpMethod;
|
|
6
|
+
path: string;
|
|
7
|
+
accountId?: string;
|
|
8
|
+
matrix?: Record<string, ParameterValue>;
|
|
9
|
+
query?: Record<string, ParameterValue>;
|
|
10
|
+
body?: unknown;
|
|
11
|
+
range?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FlowMailerResponse<T = unknown> {
|
|
14
|
+
status: number;
|
|
15
|
+
headers: Record<string, string>;
|
|
16
|
+
data: T | undefined;
|
|
17
|
+
}
|
|
18
|
+
export declare class ReadOnlyViolationError extends Error {
|
|
19
|
+
constructor(method: string, path: string);
|
|
20
|
+
}
|
|
21
|
+
export declare class FlowMailerApiError extends Error {
|
|
22
|
+
readonly status: number;
|
|
23
|
+
readonly body: unknown;
|
|
24
|
+
readonly headers: Record<string, string>;
|
|
25
|
+
constructor(status: number, body: unknown, headers: Record<string, string>);
|
|
26
|
+
}
|
|
27
|
+
export declare class FlowMailerClient {
|
|
28
|
+
private readonly config;
|
|
29
|
+
private readonly fetchImpl;
|
|
30
|
+
private token;
|
|
31
|
+
constructor(config: FlowMailerConfig, fetchImpl?: typeof fetch);
|
|
32
|
+
request<T = unknown>(request: FlowMailerRequest): Promise<FlowMailerResponse<T>>;
|
|
33
|
+
private requestWithToken;
|
|
34
|
+
private getAccessToken;
|
|
35
|
+
private buildApiUrl;
|
|
36
|
+
private resolvePath;
|
|
37
|
+
private buildApiHeaders;
|
|
38
|
+
private parseResponse;
|
|
39
|
+
private assertReadOnlyAllows;
|
|
40
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export class ReadOnlyViolationError extends Error {
|
|
2
|
+
constructor(method, path) {
|
|
3
|
+
super(`READ_ONLY is enabled; refusing ${method.toUpperCase()} ${path}`);
|
|
4
|
+
this.name = "ReadOnlyViolationError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class FlowMailerApiError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
body;
|
|
10
|
+
headers;
|
|
11
|
+
constructor(status, body, headers) {
|
|
12
|
+
super(`FlowMailer API request failed with status ${status}`);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.body = body;
|
|
15
|
+
this.headers = headers;
|
|
16
|
+
this.name = "FlowMailerApiError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class FlowMailerClient {
|
|
20
|
+
config;
|
|
21
|
+
fetchImpl;
|
|
22
|
+
token;
|
|
23
|
+
constructor(config, fetchImpl = fetch) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.fetchImpl = fetchImpl;
|
|
26
|
+
}
|
|
27
|
+
async request(request) {
|
|
28
|
+
this.assertReadOnlyAllows(request.method, request.path);
|
|
29
|
+
const url = this.buildApiUrl(request);
|
|
30
|
+
return this.requestWithToken(url, request, true);
|
|
31
|
+
}
|
|
32
|
+
async requestWithToken(url, request, allowTokenRefreshRetry) {
|
|
33
|
+
const token = await this.getAccessToken();
|
|
34
|
+
const response = await this.fetchImpl(url, {
|
|
35
|
+
method: request.method,
|
|
36
|
+
headers: this.buildApiHeaders(token, request),
|
|
37
|
+
body: request.body === undefined ? undefined : JSON.stringify(request.body)
|
|
38
|
+
});
|
|
39
|
+
if (response.status === 401 && allowTokenRefreshRetry) {
|
|
40
|
+
this.token = undefined;
|
|
41
|
+
return this.requestWithToken(url, request, false);
|
|
42
|
+
}
|
|
43
|
+
return this.parseResponse(response);
|
|
44
|
+
}
|
|
45
|
+
async getAccessToken() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (this.token && this.token.expiresAt > now) {
|
|
48
|
+
return this.token.accessToken;
|
|
49
|
+
}
|
|
50
|
+
const body = new URLSearchParams({
|
|
51
|
+
client_id: this.config.clientId,
|
|
52
|
+
client_secret: this.config.clientSecret,
|
|
53
|
+
grant_type: "client_credentials",
|
|
54
|
+
scope: "api"
|
|
55
|
+
});
|
|
56
|
+
const response = await this.fetchImpl(`${this.config.authBaseUrl}/oauth/token`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: {
|
|
59
|
+
accept: this.config.apiMediaType,
|
|
60
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
61
|
+
},
|
|
62
|
+
body
|
|
63
|
+
});
|
|
64
|
+
const parsed = (await readResponseBody(response));
|
|
65
|
+
if (!response.ok || !parsed?.access_token) {
|
|
66
|
+
throw new FlowMailerApiError(response.status, parsed, selectedHeaders(response.headers));
|
|
67
|
+
}
|
|
68
|
+
const expiresInSeconds = typeof parsed.expires_in === "number" ? parsed.expires_in : 60;
|
|
69
|
+
this.token = {
|
|
70
|
+
accessToken: parsed.access_token,
|
|
71
|
+
expiresAt: now + Math.max(1, expiresInSeconds - 5) * 1000
|
|
72
|
+
};
|
|
73
|
+
return this.token.accessToken;
|
|
74
|
+
}
|
|
75
|
+
buildApiUrl(request) {
|
|
76
|
+
const resolvedPath = this.resolvePath(request.path, request.accountId);
|
|
77
|
+
const matrixPath = appendMatrixParams(resolvedPath, request.matrix);
|
|
78
|
+
const url = new URL(matrixPath, `${this.config.apiBaseUrl}/`);
|
|
79
|
+
appendSearchParams(url, request.query);
|
|
80
|
+
return url.toString();
|
|
81
|
+
}
|
|
82
|
+
resolvePath(path, accountId) {
|
|
83
|
+
if (!path.startsWith("/")) {
|
|
84
|
+
throw new Error("FlowMailer API path must be a relative path starting with /");
|
|
85
|
+
}
|
|
86
|
+
if (path.startsWith("//")) {
|
|
87
|
+
throw new Error("FlowMailer API path must not be protocol-relative");
|
|
88
|
+
}
|
|
89
|
+
return path.replaceAll("{account_id}", encodeURIComponent(accountId ?? this.config.accountId));
|
|
90
|
+
}
|
|
91
|
+
buildApiHeaders(token, request) {
|
|
92
|
+
const headers = {
|
|
93
|
+
authorization: `Bearer ${token}`,
|
|
94
|
+
accept: this.config.apiMediaType
|
|
95
|
+
};
|
|
96
|
+
if (request.range) {
|
|
97
|
+
headers.range = request.range;
|
|
98
|
+
}
|
|
99
|
+
if (request.body !== undefined) {
|
|
100
|
+
headers["content-type"] = this.config.apiMediaType;
|
|
101
|
+
}
|
|
102
|
+
return headers;
|
|
103
|
+
}
|
|
104
|
+
async parseResponse(response) {
|
|
105
|
+
const headers = selectedHeaders(response.headers);
|
|
106
|
+
const data = await readResponseBody(response);
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new FlowMailerApiError(response.status, data, headers);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
status: response.status,
|
|
112
|
+
headers,
|
|
113
|
+
data: data
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
assertReadOnlyAllows(method, path) {
|
|
117
|
+
if (this.config.readOnly && method !== "GET") {
|
|
118
|
+
throw new ReadOnlyViolationError(method, path);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function appendMatrixParams(path, matrix) {
|
|
123
|
+
if (!matrix) {
|
|
124
|
+
return path;
|
|
125
|
+
}
|
|
126
|
+
const entries = Object.entries(matrix).flatMap(([key, value]) => {
|
|
127
|
+
const serialized = serializeParameterValue(value);
|
|
128
|
+
return serialized === undefined ? [] : [[key, serialized]];
|
|
129
|
+
});
|
|
130
|
+
if (entries.length === 0) {
|
|
131
|
+
return path;
|
|
132
|
+
}
|
|
133
|
+
const encoded = entries
|
|
134
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
135
|
+
.join(";");
|
|
136
|
+
return `${path};${encoded}`;
|
|
137
|
+
}
|
|
138
|
+
function appendSearchParams(url, query) {
|
|
139
|
+
if (!query) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
for (const [key, value] of Object.entries(query)) {
|
|
143
|
+
const serialized = serializeParameterValue(value);
|
|
144
|
+
if (serialized !== undefined) {
|
|
145
|
+
url.searchParams.set(key, serialized);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function serializeParameterValue(value) {
|
|
150
|
+
if (value === undefined || value === null || value === "") {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
if (Array.isArray(value)) {
|
|
154
|
+
return value.length === 0 ? undefined : value.map(String).join(",");
|
|
155
|
+
}
|
|
156
|
+
return String(value);
|
|
157
|
+
}
|
|
158
|
+
async function readResponseBody(response) {
|
|
159
|
+
if (response.status === 204 || response.status === 205) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
const text = await response.text();
|
|
163
|
+
if (text.length === 0) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
167
|
+
if (contentType.includes("json") || /^[\[{]/.test(text.trim())) {
|
|
168
|
+
try {
|
|
169
|
+
return JSON.parse(text);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return text;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return text;
|
|
176
|
+
}
|
|
177
|
+
function selectedHeaders(headers) {
|
|
178
|
+
const keep = [
|
|
179
|
+
"content-range",
|
|
180
|
+
"content-type",
|
|
181
|
+
"location",
|
|
182
|
+
"next-range",
|
|
183
|
+
"retry-after",
|
|
184
|
+
"www-authenticate"
|
|
185
|
+
];
|
|
186
|
+
return Object.fromEntries(keep.flatMap((name) => {
|
|
187
|
+
const value = headers.get(name);
|
|
188
|
+
return value === null ? [] : [[name, value]];
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=flowmailer-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flowmailer-client.js","sourceRoot":"","sources":["../src/flowmailer-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED