better-ship 0.18.0 → 0.20.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 (58) hide show
  1. package/dist/{application-CNdzHIXk.js → application-Dg1jIKPe.js} +2 -2
  2. package/dist/{application-CNdzHIXk.js.map → application-Dg1jIKPe.js.map} +1 -1
  3. package/dist/application.js +1 -1
  4. package/dist/better-auth/apple-client-secret.js +1 -1
  5. package/dist/better-auth/auth-client.js +1 -1
  6. package/dist/better-auth/rate-limit.js +1 -1
  7. package/dist/better-auth.js +1 -1
  8. package/dist/billing/client.js +1 -1
  9. package/dist/cloudflare/auth-secondary-storage.js +1 -1
  10. package/dist/cloudflare/durable-object-client.js +1 -1
  11. package/dist/cloudflare/durable-object-errors.js +1 -1
  12. package/dist/cloudflare/kv-client.js +1 -1
  13. package/dist/cloudflare/kv-errors.js +1 -1
  14. package/dist/cloudflare/queue.js +2 -2
  15. package/dist/cloudflare/r2-client.js +1 -1
  16. package/dist/cloudflare/r2-errors.js +1 -1
  17. package/dist/cloudflare/scheduled.js +1 -1
  18. package/dist/cloudflare.js +3 -3
  19. package/dist/{core-UUW2unJd.js → core-BT1dSEQI.js} +2 -2
  20. package/dist/{core-UUW2unJd.js.map → core-BT1dSEQI.js.map} +1 -1
  21. package/dist/core.js +1 -1
  22. package/dist/http.d.ts +15 -7
  23. package/dist/http.d.ts.map +1 -1
  24. package/dist/http.js +50 -11
  25. package/dist/http.js.map +1 -1
  26. package/dist/{outbox-repository-options-CgdqU20T.js → outbox-repository-options-B8TnAE1h.js} +2 -2
  27. package/dist/{outbox-repository-options-CgdqU20T.js.map → outbox-repository-options-B8TnAE1h.js.map} +1 -1
  28. package/dist/postgres.js +3 -3
  29. package/dist/posthog/client.d.ts +9 -8
  30. package/dist/posthog/client.d.ts.map +1 -1
  31. package/dist/posthog/client.js.map +1 -1
  32. package/dist/posthog/server.js +1 -1
  33. package/dist/resend.d.ts +3 -3
  34. package/dist/resend.d.ts.map +1 -1
  35. package/dist/resend.js +30 -57
  36. package/dist/resend.js.map +1 -1
  37. package/dist/sentry/client.js +1 -1
  38. package/dist/stripe/payment-service.error.js +1 -1
  39. package/dist/stripe/payment-webhook.d.ts +3 -3
  40. package/dist/stripe/payment-webhook.d.ts.map +1 -1
  41. package/dist/stripe/payment-webhook.js +6 -18
  42. package/dist/stripe/payment-webhook.js.map +1 -1
  43. package/dist/tanstack.js +1 -1
  44. package/dist/{webhook-verification-BuxPzdr4.d.ts → webhook-verification-D1c7BY4q.d.ts} +8 -16
  45. package/dist/webhook-verification-D1c7BY4q.d.ts.map +1 -0
  46. package/dist/{webhook-verification-BBmjkHgI.js → webhook-verification-qSFXv5H3.js} +2 -2
  47. package/dist/webhook-verification-qSFXv5H3.js.map +1 -0
  48. package/package.json +1 -1
  49. package/src/core/console-log-sink.ts +1 -5
  50. package/src/infrastructure/http/index.ts +2 -6
  51. package/src/infrastructure/http/webhook-handler.ts +68 -11
  52. package/src/infrastructure/http/webhook-verification.ts +6 -9
  53. package/src/infrastructure/posthog/client.ts +10 -6
  54. package/src/infrastructure/resend/email-event.ts +14 -30
  55. package/src/infrastructure/resend/resend-webhook.ts +12 -22
  56. package/src/infrastructure/stripe/payment-webhook.ts +7 -20
  57. package/dist/webhook-verification-BBmjkHgI.js.map +0 -1
  58. package/dist/webhook-verification-BuxPzdr4.d.ts.map +0 -1
@@ -93,50 +93,34 @@ const EventHeaderSchema = z.object({
93
93
  })
94
94
 
95
95
  /** Validate signed provider data before projecting it into the public event contract. */
96
- export function parseEmailEvent(
97
- payload: WebhookEventPayload,
98
- id: string,
99
- ):
100
- | { readonly outcome: 'event'; readonly event: EmailEvent }
101
- | { readonly outcome: 'ignored'; readonly type: string }
102
- | { readonly outcome: 'invalid' } {
103
- const header = EventHeaderSchema.safeParse(payload)
104
- if (!header.success) return { outcome: 'invalid' }
105
- if (!Object.hasOwn(EMAIL_TYPES, header.data.type))
106
- return { outcome: 'ignored', type: header.data.type }
107
- const parsed = EmailPayloadSchema.safeParse(payload)
108
- if (!parsed.success) return { outcome: 'invalid' }
109
- const event = parsed.data
96
+ export function parseEmailEvent(payload: WebhookEventPayload, id: string): EmailEvent | null {
97
+ const header = EventHeaderSchema.parse(payload)
98
+ if (!Object.hasOwn(EMAIL_TYPES, header.type)) return null
99
+ const event = EmailPayloadSchema.parse(payload)
110
100
  const base: EmailEventBase = {
111
101
  id,
112
102
  emailId: event.data.email_id,
113
103
  recipients: event.data.to,
114
104
  subject: event.data.subject,
115
105
  tags: event.data.tags,
116
- occurredAt: header.data.created_at,
106
+ occurredAt: header.created_at,
117
107
  }
118
108
  switch (event.type) {
119
109
  case 'email.bounced':
120
110
  return {
121
- outcome: 'event',
122
- event: {
123
- ...base,
124
- type: event.type,
125
- bounce: {
126
- type: parseBounceType(event.data.bounce.type),
127
- subType: event.data.bounce.subType ?? null,
128
- message: event.data.bounce.message,
129
- },
111
+ ...base,
112
+ type: event.type,
113
+ bounce: {
114
+ type: parseBounceType(event.data.bounce.type),
115
+ subType: event.data.bounce.subType ?? null,
116
+ message: event.data.bounce.message,
130
117
  },
131
118
  }
132
119
  case 'email.failed':
133
- return {
134
- outcome: 'event',
135
- event: { ...base, type: event.type, reason: event.data.failed.reason },
136
- }
120
+ return { ...base, type: event.type, reason: event.data.failed.reason }
137
121
  case 'email.clicked':
138
- return { outcome: 'event', event: { ...base, type: event.type, link: event.data.click.link } }
122
+ return { ...base, type: event.type, link: event.data.click.link }
139
123
  default:
140
- return { outcome: 'event', event: { ...base, type: event.type } }
124
+ return { ...base, type: event.type }
141
125
  }
142
126
  }
@@ -1,11 +1,7 @@
1
1
  import type { Resend } from 'resend'
2
2
  import { z } from 'zod'
3
3
 
4
- import {
5
- WebhookVerificationError,
6
- type WebhookVerification,
7
- type WebhookVerifier,
8
- } from '../http/webhook-verification.ts'
4
+ import { WebhookVerificationError, type WebhookVerifier } from '../http/webhook-verification.ts'
9
5
  import { parseEmailEvent, type EmailEvent } from './email-event.ts'
10
6
 
11
7
  // Separate standardwebhooks versions have different prototypes; its error name remains the same.
@@ -35,13 +31,12 @@ export class ResendWebhook implements WebhookVerifier<EmailEvent> {
35
31
  private readonly verifier: () => Promise<ResendWebhookClient>,
36
32
  ) {}
37
33
 
38
- /** Verify the raw body and Svix headers. Invalid requests return rejected; configuration and SDK defects propagate. */
39
- async verify(body: string, headers: Headers): Promise<WebhookVerification<EmailEvent>> {
34
+ /** Verify the raw body and Svix headers. Invalid requests throw typed errors; other failures propagate. */
35
+ async verify(body: string, headers: Headers): Promise<EmailEvent | null> {
40
36
  const id = headers.get('svix-id')
41
37
  const timestamp = headers.get('svix-timestamp')
42
38
  const signature = headers.get('svix-signature')
43
- if (!id || !timestamp || !signature)
44
- return { outcome: 'rejected', error: new WebhookVerificationError('missing_headers') }
39
+ if (!id || !timestamp || !signature) throw new WebhookVerificationError('missing_headers')
45
40
  const client = await (this.client ??= this.verifier())
46
41
  let payload: ReturnType<ResendWebhookClient['verify']>
47
42
  try {
@@ -51,20 +46,15 @@ export class ResendWebhook implements WebhookVerifier<EmailEvent> {
51
46
  webhookSecret: this.webhookSecret,
52
47
  })
53
48
  } catch (cause) {
54
- if (cause instanceof SyntaxError)
55
- return {
56
- outcome: 'rejected',
57
- error: new WebhookVerificationError('invalid_payload', cause),
58
- }
49
+ if (cause instanceof SyntaxError) throw new WebhookVerificationError('invalid_payload', cause)
59
50
  if (!SignatureErrorSchema.safeParse(cause).success) throw cause
60
- return {
61
- outcome: 'rejected',
62
- error: new WebhookVerificationError('invalid_signature', cause),
63
- }
51
+ throw new WebhookVerificationError('invalid_signature', cause)
52
+ }
53
+ try {
54
+ return parseEmailEvent(payload, id)
55
+ } catch (cause) {
56
+ if (cause instanceof z.ZodError) throw new WebhookVerificationError('invalid_payload', cause)
57
+ throw cause
64
58
  }
65
- const result = parseEmailEvent(payload, id)
66
- if (result.outcome === 'invalid')
67
- return { outcome: 'rejected', error: new WebhookVerificationError('invalid_payload') }
68
- return result
69
59
  }
70
60
  }
@@ -1,10 +1,6 @@
1
1
  import Stripe from 'stripe'
2
2
 
3
- import {
4
- WebhookVerificationError,
5
- type WebhookVerification,
6
- type WebhookVerifier,
7
- } from '../http/webhook-verification.ts'
3
+ import { WebhookVerificationError, type WebhookVerifier } from '../http/webhook-verification.ts'
8
4
 
9
5
  /**
10
6
  * Authenticate raw Stripe webhook bodies with the SDK's timestamp tolerance and Web Crypto.
@@ -18,31 +14,22 @@ export class StripeWebhookVerifier implements WebhookVerifier<Stripe.Event> {
18
14
  private readonly tolerance?: number,
19
15
  ) {}
20
16
 
21
- /** Reject signature and JSON failures. Operational failures propagate without logging. */
22
- async verify(body: string, headers: Headers): Promise<WebhookVerification<Stripe.Event>> {
17
+ /** Throw typed signature and JSON failures. Operational failures propagate without logging. */
18
+ async verify(body: string, headers: Headers): Promise<Stripe.Event> {
23
19
  const signature = headers.get('stripe-signature')
24
- if (!signature)
25
- return { outcome: 'rejected', error: new WebhookVerificationError('missing_headers') }
20
+ if (!signature) throw new WebhookVerificationError('missing_headers')
26
21
  try {
27
- const event = await this.stripe.webhooks.constructEventAsync(
22
+ return await this.stripe.webhooks.constructEventAsync(
28
23
  body,
29
24
  signature,
30
25
  this.signingSecret,
31
26
  this.tolerance,
32
27
  Stripe.createSubtleCryptoProvider(),
33
28
  )
34
- return { outcome: 'event', event }
35
29
  } catch (cause) {
36
30
  if (cause instanceof Stripe.errors.StripeSignatureVerificationError)
37
- return {
38
- outcome: 'rejected',
39
- error: new WebhookVerificationError('invalid_signature', cause),
40
- }
41
- if (cause instanceof SyntaxError)
42
- return {
43
- outcome: 'rejected',
44
- error: new WebhookVerificationError('invalid_payload', cause),
45
- }
31
+ throw new WebhookVerificationError('invalid_signature', cause)
32
+ if (cause instanceof SyntaxError) throw new WebhookVerificationError('invalid_payload', cause)
46
33
  throw cause
47
34
  }
48
35
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhook-verification-BBmjkHgI.js","names":[],"sources":["../src/infrastructure/http/webhook-verification.ts"],"sourcesContent":["import { AppError } from '@/core'\n\n/** A webhook cannot be trusted or parsed. The HTTP handler logs the rejection once. */\nexport class WebhookVerificationError extends AppError {\n readonly _tag = 'WebhookVerificationError'\n readonly classification = 'terminal'\n\n /** Keep secrets and payload details out of the public message. */\n constructor(\n readonly reason: 'missing_headers' | 'invalid_signature' | 'invalid_payload',\n cause?: unknown,\n ) {\n super(`Webhook rejected: ${reason}`, { cause })\n }\n}\n\n/** A verified event, an ignored event, or an invalid request. */\nexport type WebhookVerification<Event> =\n | { readonly outcome: 'event'; readonly event: Event }\n | { readonly outcome: 'ignored'; readonly type: string }\n | { readonly outcome: 'rejected'; readonly error: WebhookVerificationError }\n\n/** The provider owns signature verification, timestamp tolerance, and payload parsing. */\nexport interface WebhookVerifier<Event> {\n /** Verify the exact body before parsing it. Return invalid requests; throw operational failures. */\n verify(body: string, headers: Headers): Promise<WebhookVerification<Event>>\n}\n"],"mappings":";;;;AAGA,IAAa,2BAAb,cAA8C,SAAS;CAM1C;CALX,AAAS,OAAO;CAChB,AAAS,iBAAiB;;CAG1B,YACE,AAAS,QACT,OACA;EACA,MAAM,qBAAqB,UAAU,EAAE,MAAM,CAAC;EAHrC;CAIX;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhook-verification-BuxPzdr4.d.ts","names":[],"sources":["../src/infrastructure/http/webhook-verification.ts"],"mappings":";;;cAGa,iCAAiC;WAMjC;WALF;WACA;;EAGT,YACW,qEACT;;;KAOQ,oBAAoB;WACjB;WAA2B,OAAO;;WAClC;WAA6B;;WAC7B;WAA8B,OAAO;;;UAGnC,gBAAgB;;EAE/B,OAAO,cAAc,SAAS,UAAU,QAAQ,oBAAoB"}