@pithy-sh/email 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/LICENSE +21 -0
- package/README.md +17 -0
- package/package.json +55 -0
- package/pithy.manifest.json +73 -0
- package/src/analytics.ts +39 -0
- package/src/audit/actions.ts +48 -0
- package/src/bounce/classify.ts +103 -0
- package/src/bounce/handler.ts +136 -0
- package/src/capability.ts +385 -0
- package/src/cloudflare-test.d.ts +19 -0
- package/src/crypto/signingKey.ts +44 -0
- package/src/crypto/token.ts +148 -0
- package/src/data/emailEvent.ts +42 -0
- package/src/data/emailJob.ts +138 -0
- package/src/data/emailSuppression.ts +40 -0
- package/src/data/enums.ts +75 -0
- package/src/data/tables.ts +47 -0
- package/src/error/errors.ts +129 -0
- package/src/http/callbacks.ts +200 -0
- package/src/http/guards.ts +154 -0
- package/src/http/responses.ts +192 -0
- package/src/http/routes.ts +467 -0
- package/src/http/schemas.ts +203 -0
- package/src/http/view.ts +139 -0
- package/src/index.ts +73 -0
- package/src/jobs/read.ts +273 -0
- package/src/jobs/retry.ts +214 -0
- package/src/migrations/0001_init.ts +174 -0
- package/src/migrations/0001_suppressions.ts +40 -0
- package/src/provision/devDelivery.ts +47 -0
- package/src/provision/hostCatalogs.ts +107 -0
- package/src/provision/provisionEmail.ts +179 -0
- package/src/provision/resolveEmailConfig.ts +225 -0
- package/src/provision/settingsCheck.ts +212 -0
- package/src/send/batchIdentity.ts +47 -0
- package/src/send/enqueue.ts +391 -0
- package/src/send/errorMapping.ts +73 -0
- package/src/send/events.ts +34 -0
- package/src/send/fromComposition.ts +57 -0
- package/src/send/retryPolicy.ts +42 -0
- package/src/send/runSend.ts +320 -0
- package/src/send/sendAt.ts +77 -0
- package/src/send/sender.ts +44 -0
- package/src/send/senderBinding.ts +56 -0
- package/src/send/suppression.ts +194 -0
- package/src/templates/engine.ts +392 -0
- package/src/templates/messages.es.ts +109 -0
- package/src/templates/messages.ts +315 -0
- package/src/templates/partials.ts +88 -0
- package/src/templates/precompiled.generated.ts +1342 -0
- package/src/templates/registry.ts +550 -0
- package/src/templates/samples.ts +75 -0
- package/src/templates/severity.ts +102 -0
- package/src/templates/theme.ts +212 -0
- package/src/version.generated.ts +16 -0
- package/src/workflows/hostApp.ts +54 -0
- package/src/workflows/hostEnv.ts +219 -0
- package/src/workflows/instanceLiveness.ts +39 -0
- package/src/workflows/instances.ts +16 -0
- package/src/workflows/params.ts +35 -0
- package/src/workflows/scheduler.ts +220 -0
- package/src/workflows/sendBatch.ts +154 -0
- package/src/workflows/worker.ts +203 -0
- package/src/workflows/wrangler.jsonc +75 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
// The prebuilt email worker. Like the secrets manager, this is a TEMPLATE, not a wrangler env-stanza
|
|
3
|
+
// file: staging and prod are genuinely separate workers. `pithy add email` resolves this into
|
|
4
|
+
// one complete config per environment — filling the `<...>` placeholders — and deploys each with
|
|
5
|
+
// `wrangler deploy --config <resolved>`. The user authors none of it. It hosts the send and scheduler
|
|
6
|
+
// Workflows and the every-minute scheduler cron, and holds the `send_email` binding that actually sends.
|
|
7
|
+
// Resolved per project and env → <project>-staging-email / <project>-prod-email. Worker script
|
|
8
|
+
// names are account-scoped, so the project segment is what stops a second Pithy project's deploy
|
|
9
|
+
// overwriting this one's running worker instead of colliding with it.
|
|
10
|
+
"name": "pithy-email",
|
|
11
|
+
"main": "./worker.ts",
|
|
12
|
+
// The compatibility date every Worker in this repository runs on. Stated once in the repository
|
|
13
|
+
// root's `compatibility.ts` and copied here because JSONC cannot import it —
|
|
14
|
+
// `cli/src/ci/compatibilityDates.test.ts` fails on any Worker older than it.
|
|
15
|
+
"compatibility_date": "2026-06-01",
|
|
16
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
17
|
+
|
|
18
|
+
// No public URL. The callback routes (click/open/unsubscribe) and the inbound bounce handler live in
|
|
19
|
+
// the app worker; this worker is reached only by Workflow dispatch and its cron.
|
|
20
|
+
"workers_dev": false,
|
|
21
|
+
|
|
22
|
+
// The app database — the email tables (pithy_email_jobs/events/suppressions) live here, alongside the
|
|
23
|
+
// app's own data. Plus the secrets database, read for the link-signing key.
|
|
24
|
+
"d1_databases": [
|
|
25
|
+
{ "binding": "DB", "database_name": "pithy-app", "database_id": "<filled-at-provision>" },
|
|
26
|
+
// The durable suppression database — one per PROJECT, shared across that project's environments,
|
|
27
|
+
// so an unsubscribe or hard bounce applies everywhere the project sends from. The same database id
|
|
28
|
+
// is bound in every environment; the name resolves to <project>-global-email-suppressions.
|
|
29
|
+
{
|
|
30
|
+
"binding": "EMAIL_SUPPRESSIONS",
|
|
31
|
+
"database_name": "pithy-email-suppressions",
|
|
32
|
+
"database_id": "<filled-at-provision>"
|
|
33
|
+
},
|
|
34
|
+
{ "binding": "SECRETS", "database_name": "pithy-secrets", "database_id": "<filled-at-provision>" }
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
// The Cloudflare Email Service send binding — the only thing in the kit that puts a message on the
|
|
38
|
+
// wire. `remote` is deliberately NOT written here: `resolveEmailConfig` adds it, because the
|
|
39
|
+
// resolver can only ever add the flag and a hardcoded `true` could never be turned off again. Real
|
|
40
|
+
// delivery is the default in every environment, including `dev`, where `remote: true` runs the
|
|
41
|
+
// Worker locally and sends through the service for real. `email({ devDelivery: "simulator" })`
|
|
42
|
+
// selects the local simulator instead; a deployed worker ignores the flag either way.
|
|
43
|
+
"send_email": [{ "name": "EMAIL" }],
|
|
44
|
+
|
|
45
|
+
// The master key for decrypting the link-signing secret, read through the secretsStore accessor.
|
|
46
|
+
"secrets_store_secrets": [
|
|
47
|
+
{
|
|
48
|
+
"binding": "SECRETS_ENCRYPTION_KEYS",
|
|
49
|
+
"store_id": "<filled-at-provision>",
|
|
50
|
+
"secret_name": "<filled-at-provision>"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
|
|
54
|
+
// The two Workflows this worker hosts. EMAIL_SENDER is the dispatch target for both immediate sends
|
|
55
|
+
// (from the app worker) and the scheduler's fan-out batches; EMAIL_SCHEDULER is fired by the cron.
|
|
56
|
+
"workflows": [
|
|
57
|
+
{ "binding": "EMAIL_SENDER", "name": "pithy-email-send", "class_name": "EmailSendWorkflow" },
|
|
58
|
+
{ "binding": "EMAIL_SCHEDULER", "name": "pithy-email-schedule", "class_name": "EmailSchedulerWorkflow" }
|
|
59
|
+
],
|
|
60
|
+
|
|
61
|
+
// The every-minute scheduler cron. Cheap: scheduled() fires the scheduler Workflow, which sends
|
|
62
|
+
// nothing when nothing is due.
|
|
63
|
+
"triggers": { "crons": ["* * * * *"] },
|
|
64
|
+
|
|
65
|
+
"vars": {
|
|
66
|
+
// The full brand theme as one JSON blob (the resolved EmailTheme), filled from the app's
|
|
67
|
+
// email() config at provision. The worker parses + validates it; absent falls back to the default.
|
|
68
|
+
"EMAIL_THEME": "<filled-at-provision>",
|
|
69
|
+
"BASE_URL": "<filled-at-provision>", // the app worker's public URL, for callback links
|
|
70
|
+
"ENVIRONMENT": "<filled-at-provision>", // stamped on each send (X-Pithy-Env) so the single inbound worker can route
|
|
71
|
+
"LINK_TTL_DAYS": "90",
|
|
72
|
+
"MAX_ATTEMPTS": "5",
|
|
73
|
+
"SCHEDULER_ENABLED": "true"
|
|
74
|
+
}
|
|
75
|
+
}
|