@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.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -0
  3. package/package.json +55 -0
  4. package/pithy.manifest.json +73 -0
  5. package/src/analytics.ts +39 -0
  6. package/src/audit/actions.ts +48 -0
  7. package/src/bounce/classify.ts +103 -0
  8. package/src/bounce/handler.ts +136 -0
  9. package/src/capability.ts +385 -0
  10. package/src/cloudflare-test.d.ts +19 -0
  11. package/src/crypto/signingKey.ts +44 -0
  12. package/src/crypto/token.ts +148 -0
  13. package/src/data/emailEvent.ts +42 -0
  14. package/src/data/emailJob.ts +138 -0
  15. package/src/data/emailSuppression.ts +40 -0
  16. package/src/data/enums.ts +75 -0
  17. package/src/data/tables.ts +47 -0
  18. package/src/error/errors.ts +129 -0
  19. package/src/http/callbacks.ts +200 -0
  20. package/src/http/guards.ts +154 -0
  21. package/src/http/responses.ts +192 -0
  22. package/src/http/routes.ts +467 -0
  23. package/src/http/schemas.ts +203 -0
  24. package/src/http/view.ts +139 -0
  25. package/src/index.ts +73 -0
  26. package/src/jobs/read.ts +273 -0
  27. package/src/jobs/retry.ts +214 -0
  28. package/src/migrations/0001_init.ts +174 -0
  29. package/src/migrations/0001_suppressions.ts +40 -0
  30. package/src/provision/devDelivery.ts +47 -0
  31. package/src/provision/hostCatalogs.ts +107 -0
  32. package/src/provision/provisionEmail.ts +179 -0
  33. package/src/provision/resolveEmailConfig.ts +225 -0
  34. package/src/provision/settingsCheck.ts +212 -0
  35. package/src/send/batchIdentity.ts +47 -0
  36. package/src/send/enqueue.ts +391 -0
  37. package/src/send/errorMapping.ts +73 -0
  38. package/src/send/events.ts +34 -0
  39. package/src/send/fromComposition.ts +57 -0
  40. package/src/send/retryPolicy.ts +42 -0
  41. package/src/send/runSend.ts +320 -0
  42. package/src/send/sendAt.ts +77 -0
  43. package/src/send/sender.ts +44 -0
  44. package/src/send/senderBinding.ts +56 -0
  45. package/src/send/suppression.ts +194 -0
  46. package/src/templates/engine.ts +392 -0
  47. package/src/templates/messages.es.ts +109 -0
  48. package/src/templates/messages.ts +315 -0
  49. package/src/templates/partials.ts +88 -0
  50. package/src/templates/precompiled.generated.ts +1342 -0
  51. package/src/templates/registry.ts +550 -0
  52. package/src/templates/samples.ts +75 -0
  53. package/src/templates/severity.ts +102 -0
  54. package/src/templates/theme.ts +212 -0
  55. package/src/version.generated.ts +16 -0
  56. package/src/workflows/hostApp.ts +54 -0
  57. package/src/workflows/hostEnv.ts +219 -0
  58. package/src/workflows/instanceLiveness.ts +39 -0
  59. package/src/workflows/instances.ts +16 -0
  60. package/src/workflows/params.ts +35 -0
  61. package/src/workflows/scheduler.ts +220 -0
  62. package/src/workflows/sendBatch.ts +154 -0
  63. package/src/workflows/worker.ts +203 -0
  64. 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
+ }