@christian-ek/sweego 0.1.0
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/README.md +357 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +3 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +282 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +265 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/webhook.d.ts +42 -0
- package/dist/client/webhook.d.ts.map +1 -0
- package/dist/client/webhook.js +89 -0
- package/dist/client/webhook.js.map +1 -0
- package/dist/component/_generated/api.d.ts +43 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +226 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +10 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/lib.d.ts +319 -0
- package/dist/component/lib.d.ts.map +1 -0
- package/dist/component/lib.js +725 -0
- package/dist/component/lib.js.map +1 -0
- package/dist/component/schema.d.ts +259 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +99 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/shared.d.ts +280 -0
- package/dist/component/shared.d.ts.map +1 -0
- package/dist/component/shared.js +213 -0
- package/dist/component/shared.js.map +1 -0
- package/dist/component/sweego.d.ts +95 -0
- package/dist/component/sweego.d.ts.map +1 -0
- package/dist/component/sweego.js +210 -0
- package/dist/component/sweego.js.map +1 -0
- package/dist/component/utils.d.ts +16 -0
- package/dist/component/utils.d.ts.map +1 -0
- package/dist/component/utils.js +29 -0
- package/dist/component/utils.js.map +1 -0
- package/package.json +100 -0
- package/src/client/_generated/_ignore.ts +1 -0
- package/src/client/index.ts +490 -0
- package/src/client/webhook.test.ts +146 -0
- package/src/client/webhook.ts +130 -0
- package/src/component/_generated/api.ts +59 -0
- package/src/component/_generated/component.ts +244 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +12 -0
- package/src/component/lib.test.ts +189 -0
- package/src/component/lib.ts +835 -0
- package/src/component/schema.ts +117 -0
- package/src/component/shared.test.ts +64 -0
- package/src/component/shared.ts +315 -0
- package/src/component/sweego.test.ts +141 -0
- package/src/component/sweego.ts +310 -0
- package/src/component/utils.ts +35 -0
- package/src/test.ts +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
# Sweego Convex Component
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@christian-ek/sweego)
|
|
4
|
+
|
|
5
|
+
A [Convex component](https://www.convex.dev/components) for sending
|
|
6
|
+
**transactional email and SMS** through [Sweego](https://www.sweego.io), with
|
|
7
|
+
durable delivery and webhook-based delivery tracking.
|
|
8
|
+
|
|
9
|
+
Features:
|
|
10
|
+
|
|
11
|
+
- **Email + SMS** through Sweego's unified `/send` API, plus personalized
|
|
12
|
+
**bulk email** (`/send/bulk/email`).
|
|
13
|
+
- **Durable execution** — sends run in a [workpool](https://www.convex.dev/components/workpool)
|
|
14
|
+
and are retried automatically through transient failures (429s, 5xx, network
|
|
15
|
+
blips). Permanent failures (4xx) are recorded without futile retries.
|
|
16
|
+
- **Delivery tracking** — verifies Sweego's HMAC-SHA256 webhook signatures and
|
|
17
|
+
maintains per-recipient delivery state (delivered / bounced / opened /
|
|
18
|
+
clicked / complained / unsubscribed; SMS undelivered / stopped / clicked).
|
|
19
|
+
- **Templates, attachments, custom headers, List-Unsubscribe, expiry, and
|
|
20
|
+
campaign metadata** — the full send surface.
|
|
21
|
+
- **Event callbacks** — register a mutation that runs whenever a delivery event
|
|
22
|
+
arrives.
|
|
23
|
+
- **Status, cancellation, and retention cleanup** out of the box.
|
|
24
|
+
|
|
25
|
+
No `svix` dependency and no Sweego SDK — the component calls the REST API with
|
|
26
|
+
`fetch` and verifies signatures with the Web Crypto API.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @christian-ek/sweego
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Create a [Sweego](https://app.sweego.io) account, verify a sending domain (and
|
|
35
|
+
set up an SMS channel if you want SMS), and create an API key. Set it in your
|
|
36
|
+
Convex deployment:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx convex env set SWEEGO_API_KEY swg_xxxxxxxx
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Add the component to your app in `convex/convex.config.ts`:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { defineApp } from "convex/server";
|
|
46
|
+
import sweego from "@christian-ek/sweego/convex.config";
|
|
47
|
+
|
|
48
|
+
const app = defineApp();
|
|
49
|
+
app.use(sweego);
|
|
50
|
+
|
|
51
|
+
export default app;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Get started
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// convex/sweego.ts
|
|
58
|
+
import { components } from "./_generated/api";
|
|
59
|
+
import { Sweego } from "@christian-ek/sweego";
|
|
60
|
+
import { internalMutation } from "./_generated/server";
|
|
61
|
+
|
|
62
|
+
export const sweego = new Sweego(components.sweego, {});
|
|
63
|
+
|
|
64
|
+
export const sendWelcome = internalMutation({
|
|
65
|
+
handler: async (ctx) => {
|
|
66
|
+
await sweego.sendEmail(ctx, {
|
|
67
|
+
from: "Acme <hello@yourdomain.com>",
|
|
68
|
+
to: "user@example.com",
|
|
69
|
+
subject: "Welcome!",
|
|
70
|
+
text: "Welcome to Acme!", // Sweego requires text (or a template)
|
|
71
|
+
html: "<h1>Welcome to Acme</h1>", // html is supplementary
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`sendEmail` (and `sendSms` / `sendBulkEmail`) can be called from a **mutation or
|
|
78
|
+
an action**. It enqueues the message and returns a `MessageId` immediately; the
|
|
79
|
+
component delivers it durably in the background.
|
|
80
|
+
|
|
81
|
+
`from`/`to`/`cc`/`bcc`/`replyTo` accept either `"Name <email>"` strings or
|
|
82
|
+
`{ email, name }` objects.
|
|
83
|
+
|
|
84
|
+
## Sending SMS
|
|
85
|
+
|
|
86
|
+
SMS goes through the same component. Sweego requires a `campaignType`
|
|
87
|
+
(`"transac"` or `"market"`), and a region for each recipient:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
await sweego.sendSms(ctx, {
|
|
91
|
+
to: "+33600000000",
|
|
92
|
+
region: "FR", // ISO-3166 alpha-2; applied to bare-string recipients
|
|
93
|
+
campaignType: "transac",
|
|
94
|
+
senderId: "Acme", // 3–11 chars; required if you have multiple sender IDs
|
|
95
|
+
text: "Your code is 123456",
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
You can also pass structured recipients: `to: [{ num: "+1...", region: "US" }]`.
|
|
100
|
+
|
|
101
|
+
Estimate cost/segments before sending (from an action):
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const estimate = await sweego.estimateSms(ctx, {
|
|
105
|
+
campaign_type: "transac",
|
|
106
|
+
message_txt: "Your code is 123456",
|
|
107
|
+
recipients: [{ num: "+33600000000", region: "FR" }],
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Templates
|
|
112
|
+
|
|
113
|
+
Reference a Sweego-hosted template by id and pass `variables` for
|
|
114
|
+
`{{ placeholder }}` interpolation:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
await sweego.sendEmail(ctx, {
|
|
118
|
+
from: "Acme <hello@yourdomain.com>",
|
|
119
|
+
to: "user@example.com",
|
|
120
|
+
subject: "Your receipt",
|
|
121
|
+
templateId: "your-template-uuid",
|
|
122
|
+
variables: { name: "Ada", amount: 42 },
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> You cannot combine `templateId` with `html`. On a single `/send`, `variables`
|
|
127
|
+
> are only applied for a single recipient — use `sendBulkEmail` for
|
|
128
|
+
> per-recipient personalization.
|
|
129
|
+
|
|
130
|
+
## Bulk personalized email
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
await sweego.sendBulkEmail(ctx, {
|
|
134
|
+
from: "Acme <hello@yourdomain.com>",
|
|
135
|
+
subject: "Newsletter",
|
|
136
|
+
templateId: "your-template-uuid",
|
|
137
|
+
recipients: [
|
|
138
|
+
{ email: "alice@example.com", variables: { name: "Alice" } },
|
|
139
|
+
{ email: "bob@example.com", variables: { name: "Bob" } },
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Bulk sends require ≥2 recipients and do not support `cc`/`bcc`/`replyTo`.
|
|
145
|
+
|
|
146
|
+
## Attachments, headers, and more
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
await sweego.sendEmail(ctx, {
|
|
150
|
+
from: "Acme <hello@yourdomain.com>",
|
|
151
|
+
to: "user@example.com",
|
|
152
|
+
subject: "Your invoice",
|
|
153
|
+
text: "Your invoice is attached.",
|
|
154
|
+
html: "<p>See attached.</p>",
|
|
155
|
+
attachments: [
|
|
156
|
+
{ filename: "invoice.pdf", content: base64Pdf /* base64-encoded bytes */ },
|
|
157
|
+
],
|
|
158
|
+
headers: { "Ref-1": "643524" }, // omit the X- prefix; max 5 headers
|
|
159
|
+
listUnsub: { method: "one-click", value: "<mailto:unsub@acme.com>,<https://acme.com/u>" },
|
|
160
|
+
expires: "2026-07-26T19:30:00+02:00", // or a delta like "1 day"
|
|
161
|
+
campaignType: "transac",
|
|
162
|
+
campaignTags: ["welcome"],
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> **Attachment size:** attachment bytes are stored inline with the message, so
|
|
167
|
+
> the whole message must fit within Convex's ~1 MiB document limit. Keep
|
|
168
|
+
> attachments small; host large files elsewhere and link to them.
|
|
169
|
+
|
|
170
|
+
## Tracking status
|
|
171
|
+
|
|
172
|
+
`sendEmail`/`sendSms` return a branded `MessageId`. Use it to:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
const status = await sweego.status(ctx, messageId);
|
|
176
|
+
// {
|
|
177
|
+
// status: "queued" | "sent" | "failed" | "cancelled",
|
|
178
|
+
// channel, transactionId, errorMessage, creditLeft,
|
|
179
|
+
// deliveries: [
|
|
180
|
+
// { swgUid, recipientKey, status, delivered, bounced, opened, clicked, ... }
|
|
181
|
+
// ],
|
|
182
|
+
// }
|
|
183
|
+
|
|
184
|
+
const full = await sweego.get(ctx, messageId); // full message + deliveries
|
|
185
|
+
const cancelled = await sweego.cancel(ctx, messageId); // true if not yet sent
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
A message produces one **delivery** per recipient (Sweego returns one `swg_uid`
|
|
189
|
+
per recipient), each tracked independently.
|
|
190
|
+
|
|
191
|
+
## Webhooks (delivery events)
|
|
192
|
+
|
|
193
|
+
Sending alone won't tell you whether a message was delivered, bounced, opened,
|
|
194
|
+
or clicked — for that, set up a webhook.
|
|
195
|
+
|
|
196
|
+
1. Mount an HTTP route in `convex/http.ts`:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { httpRouter } from "convex/server";
|
|
200
|
+
import { httpAction } from "./_generated/server";
|
|
201
|
+
import { sweego } from "./sweego";
|
|
202
|
+
|
|
203
|
+
const http = httpRouter();
|
|
204
|
+
http.route({
|
|
205
|
+
path: "/sweego-webhook",
|
|
206
|
+
method: "POST",
|
|
207
|
+
handler: httpAction(async (ctx, req) => sweego.handleSweegoWebhook(ctx, req)),
|
|
208
|
+
});
|
|
209
|
+
export default http;
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Your endpoint is then `https://<your-deployment>.convex.site/sweego-webhook`.
|
|
213
|
+
|
|
214
|
+
2. In the Sweego dashboard, create a webhook pointing at that URL and select the
|
|
215
|
+
email/SMS events you care about.
|
|
216
|
+
|
|
217
|
+
3. Copy the webhook's **signing secret** and set it in your deployment:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
npx convex env set SWEEGO_WEBHOOK_SECRET <secret>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The component verifies Sweego's `webhook-id` / `webhook-timestamp` /
|
|
224
|
+
`webhook-signature` HMAC-SHA256 signature against the raw request body before
|
|
225
|
+
processing anything. Set `webhookToleranceSeconds` in the options to also reject
|
|
226
|
+
stale (replayed) requests.
|
|
227
|
+
|
|
228
|
+
### Reacting to events
|
|
229
|
+
|
|
230
|
+
Register an `onEvent` mutation that runs whenever a delivery event arrives:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { components } from "./_generated/api";
|
|
234
|
+
import { internal } from "./_generated/api";
|
|
235
|
+
import { Sweego, vOnEventArgs } from "@christian-ek/sweego";
|
|
236
|
+
import { internalMutation } from "./_generated/server";
|
|
237
|
+
|
|
238
|
+
export const sweego = new Sweego(components.sweego, {
|
|
239
|
+
onEvent: internal.sweego.handleEvent,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
export const handleEvent = internalMutation({
|
|
243
|
+
args: vOnEventArgs, // { messageId, swgUid, event }
|
|
244
|
+
handler: async (ctx, { messageId, swgUid, event }) => {
|
|
245
|
+
// event.eventType e.g. "delivered", "hard_bounce", "email_opened",
|
|
246
|
+
// "sms_undelivered", ...; event.raw holds the full Sweego payload.
|
|
247
|
+
console.log(messageId, swgUid, event.eventType);
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
> With `vOnEventArgs`, `event` is loosely typed. For a fully-typed `event`
|
|
253
|
+
> (`SweegoEvent`), define the handler with `sweego.defineEventHandler(async (ctx, { messageId, swgUid, event }) => { ... })`
|
|
254
|
+
> instead — it registers an internal mutation with the right argument types.
|
|
255
|
+
|
|
256
|
+
> No webhooks yet? `sweego.refreshStatus(ctx, messageId)` (from an action) polls
|
|
257
|
+
> Sweego's logs and updates delivery state on demand.
|
|
258
|
+
|
|
259
|
+
## Options
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
new Sweego(components.sweego, {
|
|
263
|
+
apiKey, // default: process.env.SWEEGO_API_KEY
|
|
264
|
+
webhookSecret, // default: process.env.SWEEGO_WEBHOOK_SECRET
|
|
265
|
+
provider, // default: "sweego"
|
|
266
|
+
testMode, // default: false — see below
|
|
267
|
+
initialBackoffMs, // default: 30000
|
|
268
|
+
retryAttempts, // default: 5
|
|
269
|
+
webhookToleranceSeconds, // default: 0 (disabled)
|
|
270
|
+
onEvent, // your event-handler mutation reference
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**`testMode`** — when `true`, email sends are submitted with Sweego's `dry-run`
|
|
275
|
+
(validated by Sweego but never delivered) and SMS sends use BAT test mode. It is
|
|
276
|
+
**off by default**: because `dry-run` produces no real delivery and no webhooks,
|
|
277
|
+
you must opt in. You can also set `dryRun: true` (email) or `bat: true` (SMS) on
|
|
278
|
+
an individual send.
|
|
279
|
+
|
|
280
|
+
## Data retention
|
|
281
|
+
|
|
282
|
+
The component retains messages, deliveries, and raw events. Clean them up on a
|
|
283
|
+
schedule with the built-in mutations:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
// convex/crons.ts
|
|
287
|
+
import { cronJobs } from "convex/server";
|
|
288
|
+
import { components, internal } from "./_generated/api";
|
|
289
|
+
import { internalMutation } from "./_generated/server";
|
|
290
|
+
import { v } from "convex/values";
|
|
291
|
+
|
|
292
|
+
const crons = cronJobs();
|
|
293
|
+
crons.interval(
|
|
294
|
+
"Clean up old Sweego messages",
|
|
295
|
+
{ hours: 1 },
|
|
296
|
+
internal.crons.cleanupSweego,
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
300
|
+
export const cleanupSweego = internalMutation({
|
|
301
|
+
args: {},
|
|
302
|
+
returns: v.null(),
|
|
303
|
+
handler: async (ctx) => {
|
|
304
|
+
await ctx.scheduler.runAfter(0, components.sweego.lib.cleanupOldMessages, {
|
|
305
|
+
olderThan: ONE_WEEK_MS,
|
|
306
|
+
});
|
|
307
|
+
await ctx.scheduler.runAfter(
|
|
308
|
+
0,
|
|
309
|
+
components.sweego.lib.cleanupAbandonedMessages,
|
|
310
|
+
{ olderThan: 4 * ONE_WEEK_MS },
|
|
311
|
+
);
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
export default crons;
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
`cleanupOldMessages` deletes finalized messages (and their deliveries/events)
|
|
319
|
+
older than the cutoff (default 7 days); `cleanupAbandonedMessages` clears
|
|
320
|
+
never-finalized messages (default 30 days).
|
|
321
|
+
|
|
322
|
+
## Notes & gotchas
|
|
323
|
+
|
|
324
|
+
- **Email body:** Sweego requires **`text`** (the plain-text part) *or* a
|
|
325
|
+
**`templateId`**. `html` is supplementary — sending `html` **alone** is
|
|
326
|
+
rejected with `Either 'message-txt' or 'template-id' is required`. The
|
|
327
|
+
component enforces this locally (it throws before sending), so you get a clear
|
|
328
|
+
error instead of a 422. Always include `text` alongside `html`.
|
|
329
|
+
- **Auth:** Sweego authenticates with an `Api-Key:` header (not
|
|
330
|
+
`Authorization: Bearer`) — handled for you.
|
|
331
|
+
- **Field names:** Sweego's API uses hyphenated keys (`message-html`,
|
|
332
|
+
`template-id`, `campaign-type`, …). The component maps your camelCase options
|
|
333
|
+
to the exact wire format.
|
|
334
|
+
- **SMS:** there's no bulk SMS endpoint — multi-recipient SMS goes through one
|
|
335
|
+
`/send` call. `campaignType` is required, and each recipient's `region` must
|
|
336
|
+
match the number's country (e.g. `+46…` → `SE`) or Sweego 422s. SMS
|
|
337
|
+
`variables` are shared across all recipients.
|
|
338
|
+
- **Senders must be authorized by Sweego (account-level):** the email `from`
|
|
339
|
+
must be on a domain verified for your API key, and SMS sender IDs must be
|
|
340
|
+
registered — some regions (e.g. Sweden) *require* a verified alphanumeric
|
|
341
|
+
sender ID and reject the default numeric sender, and US/Canada require a
|
|
342
|
+
Toll-Free Number passed as `senderId`. These are dashboard settings; the
|
|
343
|
+
component surfaces Sweego's rejection but can't pre-validate them.
|
|
344
|
+
- **Open/click tracking** is enabled per-domain in the Sweego dashboard, not per
|
|
345
|
+
send. Tracking events can be delayed up to ~10 minutes.
|
|
346
|
+
- **Rate limiting:** Sweego does not publish API limits, so the component bounds
|
|
347
|
+
throughput via the send workpool's parallelism and retries 429s with backoff
|
|
348
|
+
rather than guessing a fixed rate.
|
|
349
|
+
- **Delivery is at-least-once.** Sweego's `/send` exposes no idempotency key, so
|
|
350
|
+
the component never retries once a request has been accepted (only transient
|
|
351
|
+
failures *before* acceptance are retried). In the rare event the process dies
|
|
352
|
+
between Sweego accepting a request and the component recording it, a retry
|
|
353
|
+
could re-send. This window is kept as small as possible.
|
|
354
|
+
|
|
355
|
+
## License
|
|
356
|
+
|
|
357
|
+
Apache-2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=_ignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_ignore.d.ts","sourceRoot":"","sources":["../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_ignore.js","sourceRoot":"","sources":["../../../src/client/_generated/_ignore.ts"],"names":[],"mappings":";AAAA,kEAAkE"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { type FunctionReference, type FunctionVisibility, type GenericDataModel, type GenericMutationCtx } from "convex/server";
|
|
2
|
+
import { type VString } from "convex/values";
|
|
3
|
+
import type { ComponentApi } from "../component/_generated/component.js";
|
|
4
|
+
import { type ActionCtx, type Attachment, type EmailAddress, type ListUnsub, type MutationCtx, type QueryCtx, type SmsCampaignType, type SmsRecipient, type SweegoEvent, type Variables } from "../component/shared.js";
|
|
5
|
+
export type SweegoComponent = ComponentApi;
|
|
6
|
+
export type MessageId = string & {
|
|
7
|
+
__isSweegoMessageId: true;
|
|
8
|
+
};
|
|
9
|
+
export declare const vMessageId: VString<MessageId>;
|
|
10
|
+
export { vSweegoEvent } from "../component/shared.js";
|
|
11
|
+
export type { Attachment, Channel, DeliveryStatus, EmailAddress, ListUnsub, SendStatus, SmsCampaignType, SmsRecipient, SweegoEvent, Variables, } from "../component/shared.js";
|
|
12
|
+
export declare const vOnEventArgs: {
|
|
13
|
+
messageId: VString<MessageId, "required">;
|
|
14
|
+
swgUid: VString<string, "required">;
|
|
15
|
+
event: import("convex/values").VAny<any, "required", string>;
|
|
16
|
+
};
|
|
17
|
+
type EventHandlerRef = FunctionReference<"mutation", FunctionVisibility, {
|
|
18
|
+
messageId: MessageId;
|
|
19
|
+
swgUid: string;
|
|
20
|
+
event: SweegoEvent;
|
|
21
|
+
}>;
|
|
22
|
+
export type SweegoOptions = {
|
|
23
|
+
/** Sweego API key. Defaults to `process.env.SWEEGO_API_KEY`. */
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Webhook signing secret (from the Sweego dashboard). Defaults to
|
|
27
|
+
* `process.env.SWEEGO_WEBHOOK_SECRET`. Required only to verify webhooks.
|
|
28
|
+
*/
|
|
29
|
+
webhookSecret?: string;
|
|
30
|
+
/** The Sweego provider. Defaults to "sweego". */
|
|
31
|
+
provider?: string;
|
|
32
|
+
/**
|
|
33
|
+
* When true, email sends are submitted with `dry-run` (Sweego validates but
|
|
34
|
+
* does not send) and SMS sends use BAT test mode. Defaults to false.
|
|
35
|
+
*/
|
|
36
|
+
testMode?: boolean;
|
|
37
|
+
/** Initial retry backoff in ms for the send workpool. Defaults to 30000. */
|
|
38
|
+
initialBackoffMs?: number;
|
|
39
|
+
/** Max send attempts before giving up. Defaults to 5. */
|
|
40
|
+
retryAttempts?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Reject webhooks whose timestamp differs from now by more than this many
|
|
43
|
+
* seconds (replay protection). Defaults to 300 (5 minutes), per the Standard
|
|
44
|
+
* Webhooks recommendation. Set to 0 to disable the timestamp check (not
|
|
45
|
+
* recommended — webhook-id deduplication still applies either way).
|
|
46
|
+
*/
|
|
47
|
+
webhookToleranceSeconds?: number;
|
|
48
|
+
/** A mutation in your app to run after each delivery event. */
|
|
49
|
+
onEvent?: EventHandlerRef | null;
|
|
50
|
+
};
|
|
51
|
+
type ResolvedConfig = {
|
|
52
|
+
provider: string;
|
|
53
|
+
testMode: boolean;
|
|
54
|
+
initialBackoffMs: number;
|
|
55
|
+
retryAttempts: number;
|
|
56
|
+
webhookToleranceSeconds: number;
|
|
57
|
+
};
|
|
58
|
+
type AddressInput = string | EmailAddress;
|
|
59
|
+
type CommonEmailOptions = {
|
|
60
|
+
/** Plain-text body. Required unless `templateId` is set. */
|
|
61
|
+
text?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Supplementary HTML body. Sweego rejects an email sent with `html` but no
|
|
64
|
+
* `text`/`templateId` — always pair `html` with `text` (or use a template).
|
|
65
|
+
*/
|
|
66
|
+
html?: string;
|
|
67
|
+
templateId?: string;
|
|
68
|
+
attachments?: Attachment[];
|
|
69
|
+
headers?: Record<string, string>;
|
|
70
|
+
listUnsub?: ListUnsub;
|
|
71
|
+
expires?: string;
|
|
72
|
+
campaignId?: string;
|
|
73
|
+
campaignTags?: string[];
|
|
74
|
+
campaignType?: "market" | "newsletter" | "transac";
|
|
75
|
+
compressStyle?: boolean;
|
|
76
|
+
forceInlineStyle?: boolean;
|
|
77
|
+
dryRun?: boolean;
|
|
78
|
+
};
|
|
79
|
+
export type SendEmailOptions = CommonEmailOptions & {
|
|
80
|
+
from: AddressInput;
|
|
81
|
+
to: AddressInput | AddressInput[];
|
|
82
|
+
cc?: AddressInput | AddressInput[];
|
|
83
|
+
bcc?: AddressInput | AddressInput[];
|
|
84
|
+
replyTo?: AddressInput;
|
|
85
|
+
subject?: string;
|
|
86
|
+
/** Template variables. Only applied for a single recipient on /send. */
|
|
87
|
+
variables?: Variables;
|
|
88
|
+
};
|
|
89
|
+
export type BulkEmailRecipient = {
|
|
90
|
+
email: string;
|
|
91
|
+
name?: string;
|
|
92
|
+
variables?: Variables;
|
|
93
|
+
};
|
|
94
|
+
export type SendBulkEmailOptions = CommonEmailOptions & {
|
|
95
|
+
from: AddressInput;
|
|
96
|
+
subject?: string;
|
|
97
|
+
/** At least 2 recipients; each may carry its own `variables`. */
|
|
98
|
+
recipients: Array<BulkEmailRecipient | string>;
|
|
99
|
+
};
|
|
100
|
+
export type SendSmsOptions = {
|
|
101
|
+
to: SmsRecipient | SmsRecipient[] | string | string[];
|
|
102
|
+
/** Default ISO region (e.g. "FR") for recipients given as bare strings. */
|
|
103
|
+
region?: string;
|
|
104
|
+
text?: string;
|
|
105
|
+
templateId?: string;
|
|
106
|
+
variables?: Variables;
|
|
107
|
+
/** REQUIRED by Sweego for SMS. */
|
|
108
|
+
campaignType: SmsCampaignType;
|
|
109
|
+
senderId?: string;
|
|
110
|
+
shortenUrls?: boolean;
|
|
111
|
+
shortenWithProtocol?: boolean;
|
|
112
|
+
/** BAT test mode. */
|
|
113
|
+
bat?: boolean;
|
|
114
|
+
campaignId?: string;
|
|
115
|
+
};
|
|
116
|
+
export declare class Sweego {
|
|
117
|
+
component: SweegoComponent;
|
|
118
|
+
readonly config: ResolvedConfig;
|
|
119
|
+
private readonly _apiKey?;
|
|
120
|
+
private readonly _webhookSecret?;
|
|
121
|
+
readonly onEvent?: EventHandlerRef | null;
|
|
122
|
+
/**
|
|
123
|
+
* @param component The mounted component, e.g. `components.sweego`.
|
|
124
|
+
* @param options {@link SweegoOptions}.
|
|
125
|
+
*/
|
|
126
|
+
constructor(component: SweegoComponent, options?: SweegoOptions);
|
|
127
|
+
private get apiKey();
|
|
128
|
+
private get webhookSecret();
|
|
129
|
+
private runtimeConfig;
|
|
130
|
+
/**
|
|
131
|
+
* Enqueue an email. It is sent durably (with retries) by the component's
|
|
132
|
+
* workpool. Returns the {@link MessageId} you can use to check status,
|
|
133
|
+
* cancel, or correlate webhook events.
|
|
134
|
+
*/
|
|
135
|
+
sendEmail(ctx: MutationCtx | ActionCtx, options: SendEmailOptions): Promise<MessageId>;
|
|
136
|
+
/**
|
|
137
|
+
* Enqueue a personalized bulk email (Sweego's `/send/bulk/email`). Each
|
|
138
|
+
* recipient may carry its own `variables`. No cc/bcc/replyTo support.
|
|
139
|
+
*/
|
|
140
|
+
sendBulkEmail(ctx: MutationCtx | ActionCtx, options: SendBulkEmailOptions): Promise<MessageId>;
|
|
141
|
+
/** Enqueue an SMS (Sweego's `/send` with `channel: "sms"`). */
|
|
142
|
+
sendSms(ctx: MutationCtx | ActionCtx, options: SendSmsOptions): Promise<MessageId>;
|
|
143
|
+
private enqueue;
|
|
144
|
+
/** Aggregate status of a message plus per-recipient delivery state. */
|
|
145
|
+
status(ctx: QueryCtx | MutationCtx | ActionCtx, messageId: MessageId): Promise<{
|
|
146
|
+
channel: "email" | "sms";
|
|
147
|
+
creditLeft: string | null;
|
|
148
|
+
deliveries: Array<{
|
|
149
|
+
bounced: boolean;
|
|
150
|
+
channel: "email" | "sms";
|
|
151
|
+
clicked: boolean;
|
|
152
|
+
complained: boolean;
|
|
153
|
+
delivered: boolean;
|
|
154
|
+
errorMessage: string | null;
|
|
155
|
+
lastEventType: string | null;
|
|
156
|
+
opened: boolean;
|
|
157
|
+
recipientKey: string;
|
|
158
|
+
softBounced: boolean;
|
|
159
|
+
status: "pending" | "sent" | "delivered" | "soft_bounced" | "bounced" | "undelivered" | "stopped";
|
|
160
|
+
stopped: boolean;
|
|
161
|
+
swgUid: string;
|
|
162
|
+
unsubscribed: boolean;
|
|
163
|
+
}>;
|
|
164
|
+
errorMessage: string | null;
|
|
165
|
+
status: "queued" | "sent" | "failed" | "cancelled";
|
|
166
|
+
transactionId: string | null;
|
|
167
|
+
} | null>;
|
|
168
|
+
/** The full stored message plus its deliveries. */
|
|
169
|
+
get(ctx: QueryCtx | MutationCtx | ActionCtx, messageId: MessageId): Promise<{
|
|
170
|
+
_creationTime: number;
|
|
171
|
+
_id: string;
|
|
172
|
+
attachments?: Array<{
|
|
173
|
+
content: string;
|
|
174
|
+
contentId?: string;
|
|
175
|
+
disposition?: "attachment" | "inline";
|
|
176
|
+
filename: string;
|
|
177
|
+
isRelated?: boolean;
|
|
178
|
+
}>;
|
|
179
|
+
bat?: boolean;
|
|
180
|
+
bcc?: Array<{
|
|
181
|
+
email: string;
|
|
182
|
+
name?: string;
|
|
183
|
+
}>;
|
|
184
|
+
bulk: boolean;
|
|
185
|
+
campaignId?: string;
|
|
186
|
+
campaignTags?: Array<string>;
|
|
187
|
+
campaignType?: string;
|
|
188
|
+
cc?: Array<{
|
|
189
|
+
email: string;
|
|
190
|
+
name?: string;
|
|
191
|
+
}>;
|
|
192
|
+
channel: "email" | "sms";
|
|
193
|
+
compressStyle?: boolean;
|
|
194
|
+
creditLeft?: string;
|
|
195
|
+
deliveries: Array<{
|
|
196
|
+
bounced: boolean;
|
|
197
|
+
channel: "email" | "sms";
|
|
198
|
+
clicked: boolean;
|
|
199
|
+
complained: boolean;
|
|
200
|
+
delivered: boolean;
|
|
201
|
+
errorMessage: string | null;
|
|
202
|
+
lastEventType: string | null;
|
|
203
|
+
opened: boolean;
|
|
204
|
+
recipientKey: string;
|
|
205
|
+
softBounced: boolean;
|
|
206
|
+
status: "pending" | "sent" | "delivered" | "soft_bounced" | "bounced" | "undelivered" | "stopped";
|
|
207
|
+
stopped: boolean;
|
|
208
|
+
swgUid: string;
|
|
209
|
+
unsubscribed: boolean;
|
|
210
|
+
}>;
|
|
211
|
+
dryRun?: boolean;
|
|
212
|
+
emailRecipients?: Array<{
|
|
213
|
+
email: string;
|
|
214
|
+
name?: string;
|
|
215
|
+
variables?: Record<string, string | number | boolean>;
|
|
216
|
+
}>;
|
|
217
|
+
errorMessage?: string;
|
|
218
|
+
expires?: string;
|
|
219
|
+
finalizedAt: number;
|
|
220
|
+
forceInlineStyle?: boolean;
|
|
221
|
+
from?: {
|
|
222
|
+
email: string;
|
|
223
|
+
name?: string;
|
|
224
|
+
};
|
|
225
|
+
headers?: Record<string, string>;
|
|
226
|
+
html?: string;
|
|
227
|
+
listUnsub?: {
|
|
228
|
+
method?: "mailto" | "one-click";
|
|
229
|
+
value: string;
|
|
230
|
+
};
|
|
231
|
+
provider: string;
|
|
232
|
+
replyTo?: {
|
|
233
|
+
email: string;
|
|
234
|
+
name?: string;
|
|
235
|
+
};
|
|
236
|
+
senderId?: string;
|
|
237
|
+
shortenUrls?: boolean;
|
|
238
|
+
shortenWithProtocol?: boolean;
|
|
239
|
+
smsRecipients?: Array<{
|
|
240
|
+
num: string;
|
|
241
|
+
region: string;
|
|
242
|
+
}>;
|
|
243
|
+
status: "queued" | "sent" | "failed" | "cancelled";
|
|
244
|
+
subject?: string;
|
|
245
|
+
templateId?: string;
|
|
246
|
+
text?: string;
|
|
247
|
+
transactionId?: string;
|
|
248
|
+
variables?: Record<string, string | number | boolean>;
|
|
249
|
+
} | null>;
|
|
250
|
+
/**
|
|
251
|
+
* Cancel a message if it has not yet been handed to Sweego. Returns true if
|
|
252
|
+
* it was cancelled, false if it had already been sent.
|
|
253
|
+
*/
|
|
254
|
+
cancel(ctx: MutationCtx | ActionCtx, messageId: MessageId): Promise<boolean>;
|
|
255
|
+
/** Estimate the cost/segments of an SMS send (Sweego `/sms/estimate`). */
|
|
256
|
+
estimateSms(ctx: ActionCtx, body: Record<string, unknown>): Promise<unknown>;
|
|
257
|
+
/**
|
|
258
|
+
* Poll Sweego's logs to refresh delivery status without webhooks. Returns the
|
|
259
|
+
* number of deliveries updated. Prefer webhooks where possible.
|
|
260
|
+
*/
|
|
261
|
+
refreshStatus(ctx: ActionCtx, messageId: MessageId): Promise<number>;
|
|
262
|
+
/**
|
|
263
|
+
* Verify and handle a Sweego webhook. Mount this on an HTTP route. Verifies
|
|
264
|
+
* the HMAC signature against the raw body, then updates delivery state and
|
|
265
|
+
* dispatches your `onEvent` handler.
|
|
266
|
+
*/
|
|
267
|
+
handleSweegoWebhook(ctx: MutationCtx | ActionCtx, request: Request): Promise<Response>;
|
|
268
|
+
/**
|
|
269
|
+
* Helper to define your `onEvent` mutation with the right argument validator.
|
|
270
|
+
* Equivalent to declaring an `internalMutation` with {@link vOnEventArgs}.
|
|
271
|
+
*/
|
|
272
|
+
defineEventHandler<DataModel extends GenericDataModel>(handler: (ctx: GenericMutationCtx<DataModel>, args: {
|
|
273
|
+
messageId: MessageId;
|
|
274
|
+
swgUid: string;
|
|
275
|
+
event: SweegoEvent;
|
|
276
|
+
}) => Promise<void>): import("convex/server").RegisteredMutation<"internal", {
|
|
277
|
+
messageId: MessageId;
|
|
278
|
+
swgUid: string;
|
|
279
|
+
event: SweegoEvent;
|
|
280
|
+
}, Promise<void>>;
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EAExB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,OAAO,EAAK,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EAEf,KAAK,YAAY,EACjB,KAAK,SAAS,EAEd,KAAK,WAAW,EAGhB,KAAK,QAAQ,EAEb,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EAEf,MAAM,wBAAwB,CAAC;AAOhC,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC;AAG3C,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,mBAAmB,EAAE,IAAI,CAAA;CAAE,CAAC;AAC/D,eAAO,MAAM,UAAU,EAAiB,OAAO,CAAC,SAAS,CAAC,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EACV,UAAU,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,SAAS,EACT,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,wBAAwB,CAAC;AAOhC,eAAO,MAAM,YAAY;;;;CAIxB,CAAC;AAEF,KAAK,eAAe,GAAG,iBAAiB,CACtC,UAAU,EACV,kBAAkB,EAClB;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAC7D,CAAC;AAMF,MAAM,MAAM,aAAa,GAAG;IAC1B,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAMF,KAAK,YAAY,GAAG,MAAM,GAAG,YAAY,CAAC;AAE1C,KAAK,kBAAkB,GAAG;IACxB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACnD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,kBAAkB,GAAG;IAClD,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IAClC,EAAE,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IACnC,GAAG,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG;IACtD,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,UAAU,EAAE,KAAK,CAAC,kBAAkB,GAAG,MAAM,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,YAAY,GAAG,YAAY,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACtD,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,kCAAkC;IAClC,YAAY,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAMF,qBAAa,MAAM;IAWR,SAAS,EAAE,eAAe;IAVnC,SAAgB,MAAM,EAAE,cAAc,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAS;IACzC,SAAgB,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAEjD;;;OAGG;gBAEM,SAAS,EAAE,eAAe,EACjC,OAAO,CAAC,EAAE,aAAa;IAezB,OAAO,KAAK,MAAM,GAQjB;IAED,OAAO,KAAK,aAAa,GAQxB;YAEa,aAAa;IAa3B;;;;OAIG;IACG,SAAS,CACb,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,SAAS,CAAC;IA+BrB;;;OAGG;IACG,aAAa,CACjB,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,SAAS,CAAC;IA4BrB,+DAA+D;IACzD,OAAO,CACX,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,SAAS,CAAC;YAkBP,OAAO;IAYrB,uEAAuE;IACjE,MAAM,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,EAAE,SAAS,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;IAI1E,mDAAmD;IAC7C,GAAG,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,EAAE,SAAS,EAAE,SAAS;;;;;qBA9PvE,CAAC;uBACS,CAAC;;qBAGS,CAAC;;;;;gBAI6B,CAAC;;;;;;;;gBAEsB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;gBAgC7D,CAAA;qBAA+B,CAAC;;;;;;;;gBAWjC,CAAC;;;;;kBAGC,CAAC;;;;;;gBAI4B,CAAA;;;;;;;;;;;;;;;;IAsM3C;;;OAGG;IACG,MAAM,CACV,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,OAAO,CAAC;IAInB,0EAA0E;IACpE,WAAW,CACf,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,OAAO,CAAC;IAOnB;;;OAGG;IACG,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAO1E;;;;OAIG;IACG,mBAAmB,CACvB,GAAG,EAAE,WAAW,GAAG,SAAS,EAC5B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,QAAQ,CAAC;IAiCpB;;;OAGG;IACH,kBAAkB,CAAC,SAAS,SAAS,gBAAgB,EACnD,OAAO,EAAE,CACP,GAAG,EAAE,kBAAkB,CAAC,SAAS,CAAC,EAClC,IAAI,EAAE;QAAE,SAAS,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,KAC/D,OAAO,CAAC,IAAI,CAAC;mBADG,SAAS;gBAAU,MAAM;eAAS,WAAW;;CAYrE"}
|