@zyphr-dev/mcp-server 0.1.0 → 0.1.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.
- package/package.json +5 -6
- package/src/client.ts +0 -25
- package/src/config.test.ts +0 -64
- package/src/config.ts +0 -33
- package/src/index.ts +0 -24
- package/src/integration/quickstart/email.ts +0 -646
- package/src/integration/quickstart/inbox.ts +0 -222
- package/src/integration/quickstart/index.ts +0 -45
- package/src/integration/quickstart/push.ts +0 -216
- package/src/integration/quickstart/quickstart.test.ts +0 -108
- package/src/integration/quickstart/sms.ts +0 -205
- package/src/integration/quickstart/webhook.ts +0 -664
- package/src/integration/quickstart-types.ts +0 -31
- package/src/integration/sdk-snippets.test.ts +0 -63
- package/src/integration/sdk-snippets.ts +0 -248
- package/src/result.test.ts +0 -107
- package/src/result.ts +0 -65
- package/src/schemas.ts +0 -231
- package/src/server.ts +0 -26
- package/src/tools/index.ts +0 -7
- package/src/tools/integration.ts +0 -54
- package/src/tools/send.ts +0 -153
- package/src/tools/subscribers.ts +0 -126
- package/src/tools/templates.ts +0 -87
- package/src/tools/webhooks.ts +0 -82
|
@@ -1,646 +0,0 @@
|
|
|
1
|
-
import type { QuickstartChannelMap } from '../quickstart-types.js';
|
|
2
|
-
|
|
3
|
-
const DOCS = 'https://docs.zyphr.dev/channels/email';
|
|
4
|
-
|
|
5
|
-
const ENV: string[] = ['ZYPHR_API_KEY'];
|
|
6
|
-
|
|
7
|
-
const NEXT_STEPS = [
|
|
8
|
-
'Add ZYPHR_API_KEY to your .env file (run get_sdk_install_for_language to confirm the install).',
|
|
9
|
-
'Wire the new service into your app entrypoint.',
|
|
10
|
-
'Verify your sender domain in the Zyphr dashboard before sending to real recipients.',
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
export const emailChannel: QuickstartChannelMap = {
|
|
14
|
-
node: {
|
|
15
|
-
sdk: {
|
|
16
|
-
channel: 'email',
|
|
17
|
-
language: 'node',
|
|
18
|
-
framework: null,
|
|
19
|
-
variant: 'sdk',
|
|
20
|
-
files: [
|
|
21
|
-
{
|
|
22
|
-
path: 'src/lib/zyphr.ts',
|
|
23
|
-
purpose: 'Zyphr SDK client singleton',
|
|
24
|
-
contents:
|
|
25
|
-
"import { Zyphr } from '@zyphr-dev/node-sdk';\n\n" +
|
|
26
|
-
'export const zyphr = new Zyphr({ apiKey: process.env.ZYPHR_API_KEY! });\n',
|
|
27
|
-
overwrite: false,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
path: 'src/services/notify.ts',
|
|
31
|
-
purpose: 'Sends a transactional email through Zyphr',
|
|
32
|
-
contents:
|
|
33
|
-
"import { zyphr } from '../lib/zyphr.js';\n\n" +
|
|
34
|
-
'export async function sendWelcomeEmail(to: string, name: string) {\n' +
|
|
35
|
-
' return await zyphr.emails.sendEmail({\n' +
|
|
36
|
-
' to: [{ email: to, name }],\n' +
|
|
37
|
-
' subject: `Welcome, ${name}!`,\n' +
|
|
38
|
-
" html: `<h1>Welcome aboard, ${name}!</h1><p>Glad you're here.</p>`,\n" +
|
|
39
|
-
' });\n' +
|
|
40
|
-
'}\n',
|
|
41
|
-
overwrite: false,
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
envVarsNeeded: ENV,
|
|
45
|
-
nextSteps: NEXT_STEPS,
|
|
46
|
-
docsUrl: DOCS,
|
|
47
|
-
},
|
|
48
|
-
frameworks: {
|
|
49
|
-
express: {
|
|
50
|
-
channel: 'email',
|
|
51
|
-
language: 'node',
|
|
52
|
-
framework: 'express',
|
|
53
|
-
variant: 'sdk',
|
|
54
|
-
files: [
|
|
55
|
-
{
|
|
56
|
-
path: 'src/lib/zyphr.ts',
|
|
57
|
-
purpose: 'Zyphr SDK client singleton',
|
|
58
|
-
contents:
|
|
59
|
-
"import { Zyphr } from '@zyphr-dev/node-sdk';\n\n" +
|
|
60
|
-
'export const zyphr = new Zyphr({ apiKey: process.env.ZYPHR_API_KEY! });\n',
|
|
61
|
-
overwrite: false,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
path: 'src/routes/notify.ts',
|
|
65
|
-
purpose: 'Express route that sends a welcome email',
|
|
66
|
-
contents:
|
|
67
|
-
"import { Router } from 'express';\n" +
|
|
68
|
-
"import { zyphr } from '../lib/zyphr.js';\n\n" +
|
|
69
|
-
'export const notifyRouter = Router();\n\n' +
|
|
70
|
-
"notifyRouter.post('/notify', async (req, res, next) => {\n" +
|
|
71
|
-
' try {\n' +
|
|
72
|
-
' const { to, name } = req.body as { to: string; name: string };\n' +
|
|
73
|
-
' const result = await zyphr.emails.sendEmail({\n' +
|
|
74
|
-
' to: [{ email: to, name }],\n' +
|
|
75
|
-
' subject: `Welcome, ${name}!`,\n' +
|
|
76
|
-
' html: `<h1>Welcome, ${name}!</h1>`,\n' +
|
|
77
|
-
' });\n' +
|
|
78
|
-
' res.json(result);\n' +
|
|
79
|
-
' } catch (err) {\n' +
|
|
80
|
-
' next(err);\n' +
|
|
81
|
-
' }\n' +
|
|
82
|
-
'});\n',
|
|
83
|
-
overwrite: false,
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
envVarsNeeded: ENV,
|
|
87
|
-
nextSteps: [
|
|
88
|
-
...NEXT_STEPS,
|
|
89
|
-
"Mount the router in app.ts: app.use('/api', notifyRouter)",
|
|
90
|
-
'Test: curl -X POST http://localhost:3000/api/notify -d \'{"to":"you@example.com","name":"You"}\' -H "Content-Type: application/json"',
|
|
91
|
-
],
|
|
92
|
-
docsUrl: DOCS,
|
|
93
|
-
},
|
|
94
|
-
nextjs: {
|
|
95
|
-
channel: 'email',
|
|
96
|
-
language: 'node',
|
|
97
|
-
framework: 'nextjs',
|
|
98
|
-
variant: 'sdk',
|
|
99
|
-
files: [
|
|
100
|
-
{
|
|
101
|
-
path: 'src/lib/zyphr.ts',
|
|
102
|
-
purpose: 'Zyphr SDK client singleton (server-only)',
|
|
103
|
-
contents:
|
|
104
|
-
"import 'server-only';\n" +
|
|
105
|
-
"import { Zyphr } from '@zyphr-dev/node-sdk';\n\n" +
|
|
106
|
-
'export const zyphr = new Zyphr({ apiKey: process.env.ZYPHR_API_KEY! });\n',
|
|
107
|
-
overwrite: false,
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
path: 'src/app/api/notify/route.ts',
|
|
111
|
-
purpose: 'Next.js App Router route handler that sends a welcome email',
|
|
112
|
-
contents:
|
|
113
|
-
"import { NextResponse } from 'next/server';\n" +
|
|
114
|
-
"import { zyphr } from '@/lib/zyphr';\n\n" +
|
|
115
|
-
'export async function POST(req: Request) {\n' +
|
|
116
|
-
' const { to, name } = (await req.json()) as { to: string; name: string };\n' +
|
|
117
|
-
' const result = await zyphr.emails.sendEmail({\n' +
|
|
118
|
-
' to: [{ email: to, name }],\n' +
|
|
119
|
-
' subject: `Welcome, ${name}!`,\n' +
|
|
120
|
-
' html: `<h1>Welcome, ${name}!</h1>`,\n' +
|
|
121
|
-
' });\n' +
|
|
122
|
-
' return NextResponse.json(result);\n' +
|
|
123
|
-
'}\n',
|
|
124
|
-
overwrite: false,
|
|
125
|
-
},
|
|
126
|
-
],
|
|
127
|
-
envVarsNeeded: ENV,
|
|
128
|
-
nextSteps: [
|
|
129
|
-
...NEXT_STEPS,
|
|
130
|
-
'Test: curl -X POST http://localhost:3000/api/notify -d \'{"to":"you@example.com","name":"You"}\' -H "Content-Type: application/json"',
|
|
131
|
-
],
|
|
132
|
-
docsUrl: DOCS,
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
python: {
|
|
137
|
-
sdk: {
|
|
138
|
-
channel: 'email',
|
|
139
|
-
language: 'python',
|
|
140
|
-
framework: null,
|
|
141
|
-
variant: 'sdk',
|
|
142
|
-
files: [
|
|
143
|
-
{
|
|
144
|
-
path: 'app/zyphr_client.py',
|
|
145
|
-
purpose: 'REST helper for the Zyphr API',
|
|
146
|
-
contents:
|
|
147
|
-
'import os\n' +
|
|
148
|
-
'import requests\n\n' +
|
|
149
|
-
'ZYPHR_API_KEY = os.environ["ZYPHR_API_KEY"]\n' +
|
|
150
|
-
'BASE_URL = "https://api.zyphr.dev/v1"\n\n' +
|
|
151
|
-
'headers = {\n' +
|
|
152
|
-
' "X-API-Key": ZYPHR_API_KEY,\n' +
|
|
153
|
-
' "Content-Type": "application/json",\n' +
|
|
154
|
-
'}\n\n' +
|
|
155
|
-
'def zyphr_request(method, path, json=None, params=None):\n' +
|
|
156
|
-
' response = requests.request(\n' +
|
|
157
|
-
' method, f"{BASE_URL}{path}", headers=headers, json=json, params=params,\n' +
|
|
158
|
-
' )\n' +
|
|
159
|
-
' response.raise_for_status()\n' +
|
|
160
|
-
' return response.json()\n',
|
|
161
|
-
overwrite: false,
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
path: 'app/notify.py',
|
|
165
|
-
purpose: 'Send a welcome email through Zyphr',
|
|
166
|
-
contents:
|
|
167
|
-
'from .zyphr_client import zyphr_request\n\n' +
|
|
168
|
-
'def send_welcome_email(to: str, name: str) -> dict:\n' +
|
|
169
|
-
' return zyphr_request("POST", "/emails", json={\n' +
|
|
170
|
-
' "to": [{"email": to, "name": name}],\n' +
|
|
171
|
-
' "subject": f"Welcome, {name}!",\n' +
|
|
172
|
-
' "html": f"<h1>Welcome, {name}!</h1>",\n' +
|
|
173
|
-
' })\n',
|
|
174
|
-
overwrite: false,
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
envVarsNeeded: ENV,
|
|
178
|
-
nextSteps: NEXT_STEPS,
|
|
179
|
-
docsUrl: DOCS,
|
|
180
|
-
},
|
|
181
|
-
frameworks: {
|
|
182
|
-
flask: {
|
|
183
|
-
channel: 'email',
|
|
184
|
-
language: 'python',
|
|
185
|
-
framework: 'flask',
|
|
186
|
-
variant: 'sdk',
|
|
187
|
-
files: [
|
|
188
|
-
{
|
|
189
|
-
path: 'app/zyphr_client.py',
|
|
190
|
-
purpose: 'REST helper for the Zyphr API',
|
|
191
|
-
contents:
|
|
192
|
-
'import os\n' +
|
|
193
|
-
'import requests\n\n' +
|
|
194
|
-
'BASE_URL = "https://api.zyphr.dev/v1"\n\n' +
|
|
195
|
-
'def zyphr_request(method, path, json=None, params=None):\n' +
|
|
196
|
-
' response = requests.request(\n' +
|
|
197
|
-
' method, f"{BASE_URL}{path}",\n' +
|
|
198
|
-
' headers={"X-API-Key": os.environ["ZYPHR_API_KEY"], "Content-Type": "application/json"},\n' +
|
|
199
|
-
' json=json, params=params,\n' +
|
|
200
|
-
' )\n' +
|
|
201
|
-
' response.raise_for_status()\n' +
|
|
202
|
-
' return response.json()\n',
|
|
203
|
-
overwrite: false,
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
path: 'app/routes/notify.py',
|
|
207
|
-
purpose: 'Flask blueprint that sends a welcome email',
|
|
208
|
-
contents:
|
|
209
|
-
'from flask import Blueprint, request, jsonify\n' +
|
|
210
|
-
'from ..zyphr_client import zyphr_request\n\n' +
|
|
211
|
-
'notify_bp = Blueprint("notify", __name__)\n\n' +
|
|
212
|
-
'@notify_bp.route("/notify", methods=["POST"])\n' +
|
|
213
|
-
'def notify():\n' +
|
|
214
|
-
' body = request.get_json() or {}\n' +
|
|
215
|
-
' result = zyphr_request("POST", "/emails", json={\n' +
|
|
216
|
-
' "to": [{"email": body["to"], "name": body.get("name", "")}],\n' +
|
|
217
|
-
' "subject": f"Welcome, {body.get(\'name\', \'friend\')}!",\n' +
|
|
218
|
-
' "html": f"<h1>Welcome!</h1>",\n' +
|
|
219
|
-
' })\n' +
|
|
220
|
-
' return jsonify(result)\n',
|
|
221
|
-
overwrite: false,
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
|
-
envVarsNeeded: ENV,
|
|
225
|
-
nextSteps: [
|
|
226
|
-
...NEXT_STEPS,
|
|
227
|
-
'Register the blueprint: app.register_blueprint(notify_bp, url_prefix="/api")',
|
|
228
|
-
],
|
|
229
|
-
docsUrl: DOCS,
|
|
230
|
-
},
|
|
231
|
-
fastapi: {
|
|
232
|
-
channel: 'email',
|
|
233
|
-
language: 'python',
|
|
234
|
-
framework: 'fastapi',
|
|
235
|
-
variant: 'sdk',
|
|
236
|
-
files: [
|
|
237
|
-
{
|
|
238
|
-
path: 'app/zyphr_client.py',
|
|
239
|
-
purpose: 'REST helper for the Zyphr API',
|
|
240
|
-
contents:
|
|
241
|
-
'import os\n' +
|
|
242
|
-
'import httpx\n\n' +
|
|
243
|
-
'BASE_URL = "https://api.zyphr.dev/v1"\n\n' +
|
|
244
|
-
'async def zyphr_request(method: str, path: str, json: dict | None = None) -> dict:\n' +
|
|
245
|
-
' async with httpx.AsyncClient() as client:\n' +
|
|
246
|
-
' resp = await client.request(\n' +
|
|
247
|
-
' method, f"{BASE_URL}{path}",\n' +
|
|
248
|
-
' headers={"X-API-Key": os.environ["ZYPHR_API_KEY"], "Content-Type": "application/json"},\n' +
|
|
249
|
-
' json=json,\n' +
|
|
250
|
-
' )\n' +
|
|
251
|
-
' resp.raise_for_status()\n' +
|
|
252
|
-
' return resp.json()\n',
|
|
253
|
-
overwrite: false,
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
path: 'app/routers/notify.py',
|
|
257
|
-
purpose: 'FastAPI router that sends a welcome email',
|
|
258
|
-
contents:
|
|
259
|
-
'from fastapi import APIRouter\n' +
|
|
260
|
-
'from pydantic import BaseModel, EmailStr\n' +
|
|
261
|
-
'from ..zyphr_client import zyphr_request\n\n' +
|
|
262
|
-
'router = APIRouter()\n\n' +
|
|
263
|
-
'class NotifyIn(BaseModel):\n' +
|
|
264
|
-
' to: EmailStr\n' +
|
|
265
|
-
' name: str\n\n' +
|
|
266
|
-
'@router.post("/notify")\n' +
|
|
267
|
-
'async def notify(body: NotifyIn):\n' +
|
|
268
|
-
' return await zyphr_request("POST", "/emails", json={\n' +
|
|
269
|
-
' "to": [{"email": body.to, "name": body.name}],\n' +
|
|
270
|
-
' "subject": f"Welcome, {body.name}!",\n' +
|
|
271
|
-
' "html": f"<h1>Welcome, {body.name}!</h1>",\n' +
|
|
272
|
-
' })\n',
|
|
273
|
-
overwrite: false,
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
envVarsNeeded: ENV,
|
|
277
|
-
nextSteps: [
|
|
278
|
-
...NEXT_STEPS,
|
|
279
|
-
'Install httpx: `pip install httpx` (or `poetry add httpx`)',
|
|
280
|
-
'Mount the router: app.include_router(router, prefix="/api")',
|
|
281
|
-
],
|
|
282
|
-
docsUrl: DOCS,
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
ruby: {
|
|
287
|
-
sdk: {
|
|
288
|
-
channel: 'email',
|
|
289
|
-
language: 'ruby',
|
|
290
|
-
framework: null,
|
|
291
|
-
variant: 'sdk',
|
|
292
|
-
files: [
|
|
293
|
-
{
|
|
294
|
-
path: 'config/initializers/zyphr.rb',
|
|
295
|
-
purpose: 'Zyphr SDK configuration',
|
|
296
|
-
contents:
|
|
297
|
-
"require 'zyphr'\n\n" +
|
|
298
|
-
'Zyphr.configure do |config|\n' +
|
|
299
|
-
" config.api_key['X-API-Key'] = ENV.fetch('ZYPHR_API_KEY')\n" +
|
|
300
|
-
'end\n',
|
|
301
|
-
overwrite: false,
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
path: 'app/services/notify_service.rb',
|
|
305
|
-
purpose: 'Service object that sends a welcome email',
|
|
306
|
-
contents:
|
|
307
|
-
'class NotifyService\n' +
|
|
308
|
-
' def self.send_welcome_email(to:, name:)\n' +
|
|
309
|
-
' Zyphr::EmailsApi.new.send_email(\n' +
|
|
310
|
-
' Zyphr::SendEmailRequest.new(\n' +
|
|
311
|
-
' to: [{ email: to, name: name }],\n' +
|
|
312
|
-
" subject: \"Welcome, #{name}!\",\n" +
|
|
313
|
-
" html: \"<h1>Welcome, #{name}!</h1>\"\n" +
|
|
314
|
-
' )\n' +
|
|
315
|
-
' )\n' +
|
|
316
|
-
' end\n' +
|
|
317
|
-
'end\n',
|
|
318
|
-
overwrite: false,
|
|
319
|
-
},
|
|
320
|
-
],
|
|
321
|
-
envVarsNeeded: ENV,
|
|
322
|
-
nextSteps: NEXT_STEPS,
|
|
323
|
-
docsUrl: DOCS,
|
|
324
|
-
},
|
|
325
|
-
frameworks: {
|
|
326
|
-
rails: {
|
|
327
|
-
channel: 'email',
|
|
328
|
-
language: 'ruby',
|
|
329
|
-
framework: 'rails',
|
|
330
|
-
variant: 'sdk',
|
|
331
|
-
files: [
|
|
332
|
-
{
|
|
333
|
-
path: 'config/initializers/zyphr.rb',
|
|
334
|
-
purpose: 'Zyphr SDK configuration',
|
|
335
|
-
contents:
|
|
336
|
-
"require 'zyphr'\n\n" +
|
|
337
|
-
'Zyphr.configure do |config|\n' +
|
|
338
|
-
" config.api_key['X-API-Key'] = ENV.fetch('ZYPHR_API_KEY')\n" +
|
|
339
|
-
'end\n',
|
|
340
|
-
overwrite: false,
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
path: 'app/controllers/notify_controller.rb',
|
|
344
|
-
purpose: 'Rails controller that sends a welcome email',
|
|
345
|
-
contents:
|
|
346
|
-
'class NotifyController < ApplicationController\n' +
|
|
347
|
-
' def create\n' +
|
|
348
|
-
' result = Zyphr::EmailsApi.new.send_email(\n' +
|
|
349
|
-
' Zyphr::SendEmailRequest.new(\n' +
|
|
350
|
-
' to: [{ email: params.require(:to), name: params[:name] }],\n' +
|
|
351
|
-
" subject: \"Welcome, #{params[:name]}!\",\n" +
|
|
352
|
-
" html: \"<h1>Welcome, #{params[:name]}!</h1>\"\n" +
|
|
353
|
-
' )\n' +
|
|
354
|
-
' )\n' +
|
|
355
|
-
' render json: result\n' +
|
|
356
|
-
' end\n' +
|
|
357
|
-
'end\n',
|
|
358
|
-
overwrite: false,
|
|
359
|
-
},
|
|
360
|
-
],
|
|
361
|
-
envVarsNeeded: ENV,
|
|
362
|
-
nextSteps: [
|
|
363
|
-
...NEXT_STEPS,
|
|
364
|
-
"Add a route in config/routes.rb: post '/notify', to: 'notify#create'",
|
|
365
|
-
],
|
|
366
|
-
docsUrl: DOCS,
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
go: {
|
|
371
|
-
sdk: {
|
|
372
|
-
channel: 'email',
|
|
373
|
-
language: 'go',
|
|
374
|
-
framework: null,
|
|
375
|
-
variant: 'sdk',
|
|
376
|
-
files: [
|
|
377
|
-
{
|
|
378
|
-
path: 'internal/zyphr/client.go',
|
|
379
|
-
purpose: 'Thin REST client for the Zyphr API',
|
|
380
|
-
contents:
|
|
381
|
-
'package zyphr\n\n' +
|
|
382
|
-
'import (\n' +
|
|
383
|
-
'\t"bytes"\n' +
|
|
384
|
-
'\t"encoding/json"\n' +
|
|
385
|
-
'\t"fmt"\n' +
|
|
386
|
-
'\t"io"\n' +
|
|
387
|
-
'\t"net/http"\n' +
|
|
388
|
-
'\t"os"\n' +
|
|
389
|
-
')\n\n' +
|
|
390
|
-
'const baseURL = "https://api.zyphr.dev/v1"\n\n' +
|
|
391
|
-
'type Client struct {\n' +
|
|
392
|
-
'\tAPIKey string\n' +
|
|
393
|
-
'\tHTTPClient *http.Client\n' +
|
|
394
|
-
'}\n\n' +
|
|
395
|
-
'func NewClient() *Client {\n' +
|
|
396
|
-
'\treturn &Client{APIKey: os.Getenv("ZYPHR_API_KEY"), HTTPClient: &http.Client{}}\n' +
|
|
397
|
-
'}\n\n' +
|
|
398
|
-
'func (c *Client) Do(method, path string, body any) ([]byte, error) {\n' +
|
|
399
|
-
'\tvar buf io.Reader\n' +
|
|
400
|
-
'\tif body != nil {\n' +
|
|
401
|
-
'\t\tb, err := json.Marshal(body)\n' +
|
|
402
|
-
'\t\tif err != nil { return nil, fmt.Errorf("marshal: %w", err) }\n' +
|
|
403
|
-
'\t\tbuf = bytes.NewReader(b)\n' +
|
|
404
|
-
'\t}\n' +
|
|
405
|
-
'\treq, _ := http.NewRequest(method, baseURL+path, buf)\n' +
|
|
406
|
-
'\treq.Header.Set("X-API-Key", c.APIKey)\n' +
|
|
407
|
-
'\treq.Header.Set("Content-Type", "application/json")\n' +
|
|
408
|
-
'\tresp, err := c.HTTPClient.Do(req)\n' +
|
|
409
|
-
'\tif err != nil { return nil, err }\n' +
|
|
410
|
-
'\tdefer resp.Body.Close()\n' +
|
|
411
|
-
'\tdata, _ := io.ReadAll(resp.Body)\n' +
|
|
412
|
-
'\tif resp.StatusCode >= 400 { return nil, fmt.Errorf("zyphr %d: %s", resp.StatusCode, data) }\n' +
|
|
413
|
-
'\treturn data, nil\n' +
|
|
414
|
-
'}\n',
|
|
415
|
-
overwrite: false,
|
|
416
|
-
},
|
|
417
|
-
{
|
|
418
|
-
path: 'internal/notify/notify.go',
|
|
419
|
-
purpose: 'Send a welcome email through Zyphr',
|
|
420
|
-
contents:
|
|
421
|
-
'package notify\n\n' +
|
|
422
|
-
'import "yourapp/internal/zyphr"\n\n' +
|
|
423
|
-
'func SendWelcomeEmail(client *zyphr.Client, to, name string) ([]byte, error) {\n' +
|
|
424
|
-
'\treturn client.Do("POST", "/emails", map[string]any{\n' +
|
|
425
|
-
'\t\t"to": []map[string]string{{"email": to, "name": name}},\n' +
|
|
426
|
-
'\t\t"subject": "Welcome, " + name + "!",\n' +
|
|
427
|
-
'\t\t"html": "<h1>Welcome, " + name + "!</h1>",\n' +
|
|
428
|
-
'\t})\n' +
|
|
429
|
-
'}\n',
|
|
430
|
-
overwrite: false,
|
|
431
|
-
},
|
|
432
|
-
],
|
|
433
|
-
envVarsNeeded: ENV,
|
|
434
|
-
nextSteps: NEXT_STEPS,
|
|
435
|
-
docsUrl: DOCS,
|
|
436
|
-
},
|
|
437
|
-
},
|
|
438
|
-
php: {
|
|
439
|
-
sdk: {
|
|
440
|
-
channel: 'email',
|
|
441
|
-
language: 'php',
|
|
442
|
-
framework: null,
|
|
443
|
-
variant: 'sdk',
|
|
444
|
-
files: [
|
|
445
|
-
{
|
|
446
|
-
path: 'app/Services/ZyphrClient.php',
|
|
447
|
-
purpose: 'Guzzle-backed Zyphr client',
|
|
448
|
-
contents:
|
|
449
|
-
'<?php\n\n' +
|
|
450
|
-
'namespace App\\Services;\n\n' +
|
|
451
|
-
'use GuzzleHttp\\Client;\n\n' +
|
|
452
|
-
'class ZyphrClient\n' +
|
|
453
|
-
'{\n' +
|
|
454
|
-
' private Client $http;\n\n' +
|
|
455
|
-
' public function __construct()\n' +
|
|
456
|
-
' {\n' +
|
|
457
|
-
' $this->http = new Client([\n' +
|
|
458
|
-
" 'base_uri' => 'https://api.zyphr.dev/v1/',\n" +
|
|
459
|
-
" 'headers' => [\n" +
|
|
460
|
-
" 'X-API-Key' => getenv('ZYPHR_API_KEY'),\n" +
|
|
461
|
-
" 'Content-Type' => 'application/json',\n" +
|
|
462
|
-
' ],\n' +
|
|
463
|
-
' ]);\n' +
|
|
464
|
-
' }\n\n' +
|
|
465
|
-
' public function sendWelcomeEmail(string $to, string $name): array\n' +
|
|
466
|
-
' {\n' +
|
|
467
|
-
" $response = $this->http->post('emails', [\n" +
|
|
468
|
-
" 'json' => [\n" +
|
|
469
|
-
" 'to' => [['email' => $to, 'name' => $name]],\n" +
|
|
470
|
-
" 'subject' => \"Welcome, {$name}!\",\n" +
|
|
471
|
-
" 'html' => \"<h1>Welcome, {$name}!</h1>\",\n" +
|
|
472
|
-
' ],\n' +
|
|
473
|
-
' ]);\n' +
|
|
474
|
-
" return json_decode((string) $response->getBody(), true);\n" +
|
|
475
|
-
' }\n' +
|
|
476
|
-
'}\n',
|
|
477
|
-
overwrite: false,
|
|
478
|
-
},
|
|
479
|
-
],
|
|
480
|
-
envVarsNeeded: ENV,
|
|
481
|
-
nextSteps: NEXT_STEPS,
|
|
482
|
-
docsUrl: DOCS,
|
|
483
|
-
},
|
|
484
|
-
frameworks: {
|
|
485
|
-
laravel: {
|
|
486
|
-
channel: 'email',
|
|
487
|
-
language: 'php',
|
|
488
|
-
framework: 'laravel',
|
|
489
|
-
variant: 'sdk',
|
|
490
|
-
files: [
|
|
491
|
-
{
|
|
492
|
-
path: 'app/Services/ZyphrClient.php',
|
|
493
|
-
purpose: 'Laravel-friendly Zyphr client',
|
|
494
|
-
contents:
|
|
495
|
-
'<?php\n\n' +
|
|
496
|
-
'namespace App\\Services;\n\n' +
|
|
497
|
-
'use Illuminate\\Support\\Facades\\Http;\n\n' +
|
|
498
|
-
'class ZyphrClient\n' +
|
|
499
|
-
'{\n' +
|
|
500
|
-
' public function sendWelcomeEmail(string $to, string $name): array\n' +
|
|
501
|
-
' {\n' +
|
|
502
|
-
' $response = Http::withHeaders([\n' +
|
|
503
|
-
" 'X-API-Key' => config('services.zyphr.api_key'),\n" +
|
|
504
|
-
" 'Content-Type' => 'application/json',\n" +
|
|
505
|
-
" ])->post('https://api.zyphr.dev/v1/emails', [\n" +
|
|
506
|
-
" 'to' => [['email' => $to, 'name' => $name]],\n" +
|
|
507
|
-
" 'subject' => \"Welcome, {$name}!\",\n" +
|
|
508
|
-
" 'html' => \"<h1>Welcome, {$name}!</h1>\",\n" +
|
|
509
|
-
' ]);\n' +
|
|
510
|
-
' $response->throw();\n' +
|
|
511
|
-
" return $response->json();\n" +
|
|
512
|
-
' }\n' +
|
|
513
|
-
'}\n',
|
|
514
|
-
overwrite: false,
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
path: 'config/services.php (snippet)',
|
|
518
|
-
purpose: 'Register the Zyphr API key under services config',
|
|
519
|
-
contents:
|
|
520
|
-
"'zyphr' => [\n" +
|
|
521
|
-
" 'api_key' => env('ZYPHR_API_KEY'),\n" +
|
|
522
|
-
'],\n',
|
|
523
|
-
overwrite: false,
|
|
524
|
-
},
|
|
525
|
-
],
|
|
526
|
-
envVarsNeeded: ENV,
|
|
527
|
-
nextSteps: NEXT_STEPS,
|
|
528
|
-
docsUrl: DOCS,
|
|
529
|
-
},
|
|
530
|
-
},
|
|
531
|
-
},
|
|
532
|
-
csharp: {
|
|
533
|
-
sdk: {
|
|
534
|
-
channel: 'email',
|
|
535
|
-
language: 'csharp',
|
|
536
|
-
framework: null,
|
|
537
|
-
variant: 'sdk',
|
|
538
|
-
files: [
|
|
539
|
-
{
|
|
540
|
-
path: 'Services/ZyphrClient.cs',
|
|
541
|
-
purpose: 'Singleton-style Zyphr client wrapper',
|
|
542
|
-
contents:
|
|
543
|
-
'using ZyphrDev.SDK.Api;\n' +
|
|
544
|
-
'using ZyphrDev.SDK.Client;\n' +
|
|
545
|
-
'using ZyphrDev.SDK.Model;\n\n' +
|
|
546
|
-
'namespace YourApp.Services;\n\n' +
|
|
547
|
-
'public class ZyphrClient\n' +
|
|
548
|
-
'{\n' +
|
|
549
|
-
' private readonly EmailsApi _emails;\n\n' +
|
|
550
|
-
' public ZyphrClient()\n' +
|
|
551
|
-
' {\n' +
|
|
552
|
-
' var config = new Configuration\n' +
|
|
553
|
-
' {\n' +
|
|
554
|
-
' ApiKey = new Dictionary<string, string>\n' +
|
|
555
|
-
' {\n' +
|
|
556
|
-
' { "X-API-Key", Environment.GetEnvironmentVariable("ZYPHR_API_KEY")! }\n' +
|
|
557
|
-
' }\n' +
|
|
558
|
-
' };\n' +
|
|
559
|
-
' _emails = new EmailsApi(config);\n' +
|
|
560
|
-
' }\n\n' +
|
|
561
|
-
' public async Task<SendEmailResponse> SendWelcomeEmailAsync(string to, string name)\n' +
|
|
562
|
-
' {\n' +
|
|
563
|
-
' return await _emails.SendEmailAsync(new SendEmailRequest(\n' +
|
|
564
|
-
' to: new List<EmailAddress> { new() { Email = to, Name = name } },\n' +
|
|
565
|
-
' subject: $"Welcome, {name}!",\n' +
|
|
566
|
-
' html: $"<h1>Welcome, {name}!</h1>"\n' +
|
|
567
|
-
' ));\n' +
|
|
568
|
-
' }\n' +
|
|
569
|
-
'}\n',
|
|
570
|
-
overwrite: false,
|
|
571
|
-
},
|
|
572
|
-
],
|
|
573
|
-
envVarsNeeded: ENV,
|
|
574
|
-
nextSteps: NEXT_STEPS,
|
|
575
|
-
docsUrl: DOCS,
|
|
576
|
-
},
|
|
577
|
-
frameworks: {
|
|
578
|
-
aspnetcore: {
|
|
579
|
-
channel: 'email',
|
|
580
|
-
language: 'csharp',
|
|
581
|
-
framework: 'aspnetcore',
|
|
582
|
-
variant: 'sdk',
|
|
583
|
-
files: [
|
|
584
|
-
{
|
|
585
|
-
path: 'Services/ZyphrClient.cs',
|
|
586
|
-
purpose: 'DI-friendly Zyphr client',
|
|
587
|
-
contents:
|
|
588
|
-
'using ZyphrDev.SDK.Api;\n' +
|
|
589
|
-
'using ZyphrDev.SDK.Client;\n' +
|
|
590
|
-
'using ZyphrDev.SDK.Model;\n\n' +
|
|
591
|
-
'namespace YourApp.Services;\n\n' +
|
|
592
|
-
'public class ZyphrClient\n' +
|
|
593
|
-
'{\n' +
|
|
594
|
-
' public EmailsApi Emails { get; }\n\n' +
|
|
595
|
-
' public ZyphrClient(IConfiguration cfg)\n' +
|
|
596
|
-
' {\n' +
|
|
597
|
-
' var config = new Configuration\n' +
|
|
598
|
-
' {\n' +
|
|
599
|
-
' ApiKey = new Dictionary<string, string>\n' +
|
|
600
|
-
' {\n' +
|
|
601
|
-
' { "X-API-Key", cfg["Zyphr:ApiKey"]! }\n' +
|
|
602
|
-
' }\n' +
|
|
603
|
-
' };\n' +
|
|
604
|
-
' Emails = new EmailsApi(config);\n' +
|
|
605
|
-
' }\n' +
|
|
606
|
-
'}\n',
|
|
607
|
-
overwrite: false,
|
|
608
|
-
},
|
|
609
|
-
{
|
|
610
|
-
path: 'Controllers/NotifyController.cs',
|
|
611
|
-
purpose: 'ASP.NET Core controller that sends a welcome email',
|
|
612
|
-
contents:
|
|
613
|
-
'using Microsoft.AspNetCore.Mvc;\n' +
|
|
614
|
-
'using YourApp.Services;\n' +
|
|
615
|
-
'using ZyphrDev.SDK.Model;\n\n' +
|
|
616
|
-
'[ApiController]\n' +
|
|
617
|
-
'[Route("api/[controller]")]\n' +
|
|
618
|
-
'public class NotifyController : ControllerBase\n' +
|
|
619
|
-
'{\n' +
|
|
620
|
-
' private readonly ZyphrClient _zyphr;\n' +
|
|
621
|
-
' public NotifyController(ZyphrClient zyphr) => _zyphr = zyphr;\n\n' +
|
|
622
|
-
' public record NotifyIn(string To, string Name);\n\n' +
|
|
623
|
-
' [HttpPost]\n' +
|
|
624
|
-
' public async Task<IActionResult> Post([FromBody] NotifyIn body)\n' +
|
|
625
|
-
' {\n' +
|
|
626
|
-
' var result = await _zyphr.Emails.SendEmailAsync(new SendEmailRequest(\n' +
|
|
627
|
-
' to: new List<EmailAddress> { new() { Email = body.To, Name = body.Name } },\n' +
|
|
628
|
-
' subject: $"Welcome, {body.Name}!",\n' +
|
|
629
|
-
' html: $"<h1>Welcome, {body.Name}!</h1>"\n' +
|
|
630
|
-
' ));\n' +
|
|
631
|
-
' return Ok(result);\n' +
|
|
632
|
-
' }\n' +
|
|
633
|
-
'}\n',
|
|
634
|
-
overwrite: false,
|
|
635
|
-
},
|
|
636
|
-
],
|
|
637
|
-
envVarsNeeded: ENV,
|
|
638
|
-
nextSteps: [
|
|
639
|
-
...NEXT_STEPS,
|
|
640
|
-
'Register the client in Program.cs: builder.Services.AddSingleton<ZyphrClient>();',
|
|
641
|
-
],
|
|
642
|
-
docsUrl: DOCS,
|
|
643
|
-
},
|
|
644
|
-
},
|
|
645
|
-
},
|
|
646
|
-
};
|