@strimz/shared-types 0.1.0 → 0.2.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 (97) hide show
  1. package/README.md +66 -36
  2. package/dist/agents.cjs.map +1 -1
  3. package/dist/agents.d.cts +1 -1
  4. package/dist/agents.d.ts +1 -1
  5. package/dist/agents.js.map +1 -1
  6. package/dist/api-keys.cjs +8 -3
  7. package/dist/api-keys.cjs.map +1 -1
  8. package/dist/api-keys.d.cts +15 -16
  9. package/dist/api-keys.d.ts +15 -16
  10. package/dist/api-keys.js +8 -3
  11. package/dist/api-keys.js.map +1 -1
  12. package/dist/common.cjs.map +1 -1
  13. package/dist/common.d.cts +2 -2
  14. package/dist/common.d.ts +2 -2
  15. package/dist/common.js.map +1 -1
  16. package/dist/compliance.cjs.map +1 -1
  17. package/dist/compliance.d.cts +1 -1
  18. package/dist/compliance.d.ts +1 -1
  19. package/dist/compliance.js.map +1 -1
  20. package/dist/customers.cjs.map +1 -1
  21. package/dist/customers.d.cts +1 -1
  22. package/dist/customers.d.ts +1 -1
  23. package/dist/customers.js.map +1 -1
  24. package/dist/events.cjs +24 -6
  25. package/dist/events.cjs.map +1 -1
  26. package/dist/events.d.cts +12 -12
  27. package/dist/events.d.ts +12 -12
  28. package/dist/events.js +24 -6
  29. package/dist/events.js.map +1 -1
  30. package/dist/index.cjs +188 -11
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +302 -17
  33. package/dist/index.d.ts +302 -17
  34. package/dist/index.js +167 -12
  35. package/dist/index.js.map +1 -1
  36. package/dist/invoices.cjs.map +1 -1
  37. package/dist/invoices.d.cts +1 -1
  38. package/dist/invoices.d.ts +1 -1
  39. package/dist/invoices.js.map +1 -1
  40. package/dist/merchants.cjs +59 -1
  41. package/dist/merchants.cjs.map +1 -1
  42. package/dist/merchants.d.cts +171 -1
  43. package/dist/merchants.d.ts +171 -1
  44. package/dist/merchants.js +55 -2
  45. package/dist/merchants.js.map +1 -1
  46. package/dist/payment-sessions.cjs +6 -2
  47. package/dist/payment-sessions.cjs.map +1 -1
  48. package/dist/payment-sessions.d.cts +20 -4
  49. package/dist/payment-sessions.d.ts +20 -4
  50. package/dist/payment-sessions.js +6 -3
  51. package/dist/payment-sessions.js.map +1 -1
  52. package/dist/refunds.cjs +12 -0
  53. package/dist/refunds.cjs.map +1 -1
  54. package/dist/refunds.d.cts +135 -2
  55. package/dist/refunds.d.ts +135 -2
  56. package/dist/refunds.js +11 -1
  57. package/dist/refunds.js.map +1 -1
  58. package/dist/storefronts.cjs +16 -2
  59. package/dist/storefronts.cjs.map +1 -1
  60. package/dist/storefronts.d.cts +38 -2
  61. package/dist/storefronts.d.ts +38 -2
  62. package/dist/storefronts.js +15 -3
  63. package/dist/storefronts.js.map +1 -1
  64. package/dist/subscriptions.cjs +2 -2
  65. package/dist/subscriptions.cjs.map +1 -1
  66. package/dist/subscriptions.d.cts +3 -3
  67. package/dist/subscriptions.d.ts +3 -3
  68. package/dist/subscriptions.js +2 -2
  69. package/dist/subscriptions.js.map +1 -1
  70. package/dist/transactions.cjs.map +1 -1
  71. package/dist/transactions.d.cts +2 -2
  72. package/dist/transactions.d.ts +2 -2
  73. package/dist/transactions.js.map +1 -1
  74. package/dist/webhooks.cjs +7 -1
  75. package/dist/webhooks.cjs.map +1 -1
  76. package/dist/webhooks.d.cts +63 -4
  77. package/dist/webhooks.d.ts +63 -4
  78. package/dist/webhooks.js +7 -2
  79. package/dist/webhooks.js.map +1 -1
  80. package/package.json +2 -2
  81. package/src/agents.ts +1 -1
  82. package/src/api-keys.ts +9 -5
  83. package/src/common.ts +2 -2
  84. package/src/compliance.ts +1 -1
  85. package/src/contact.ts +26 -0
  86. package/src/customers.ts +1 -1
  87. package/src/index.ts +2 -0
  88. package/src/invoices.ts +1 -1
  89. package/src/merchants.ts +84 -0
  90. package/src/notifications.ts +88 -0
  91. package/src/payment-sessions.ts +25 -3
  92. package/src/refunds.ts +20 -1
  93. package/src/storefronts.ts +25 -1
  94. package/src/subscriptions.ts +3 -3
  95. package/src/tokens.ts +7 -7
  96. package/src/transactions.ts +2 -2
  97. package/src/webhooks.ts +15 -3
package/src/api-keys.ts CHANGED
@@ -12,9 +12,8 @@ export const apiKeyKindSchema = z.enum(['secret', 'publishable'])
12
12
  export type ApiKeyKind = z.infer<typeof apiKeyKindSchema>
13
13
 
14
14
  /**
15
- * Underscore-separated to match the Prisma `ApiKeyScope` enum (Prisma
16
- * does not allow `:` in enum values). The DB and the wire format use the
17
- * same form so there is no boundary translation.
15
+ * Underscore-separated. The wire format and any database representation
16
+ * use the same form so there is no boundary translation.
18
17
  */
19
18
  export const apiKeyScopeSchema = z.enum([
20
19
  'sessions_read',
@@ -32,11 +31,16 @@ export const apiKeyScopeSchema = z.enum([
32
31
  'storefronts_write',
33
32
  'agents_read',
34
33
  'agents_write',
35
- // Meta-tx relayer — submitting payer-signed EIP-3009 / EIP-2612
34
+ // Meta-tx relayer. Submitting payer-signed EIP-3009 / EIP-2612
36
35
  // authorizations on the merchant's behalf. Granted to keys used by
37
36
  // hosted checkout and merchants embedding the SDK.
38
37
  'relay_read',
39
38
  'relay_write',
39
+ // Self-service key management from an API key holder. Rarely used
40
+ // day-to-day; needed for partner onboarding flows that mint scoped
41
+ // keys per sub-tenant.
42
+ 'api_keys_read',
43
+ 'api_keys_write',
40
44
  ])
41
45
  export type ApiKeyScope = z.infer<typeof apiKeyScopeSchema>
42
46
 
@@ -67,7 +71,7 @@ export type CreateApiKeyInput = z.infer<typeof createApiKeyInputSchema>
67
71
 
68
72
  export const createApiKeyOutputSchema = z.object({
69
73
  apiKey: apiKeySchema,
70
- /** Full plaintext key — shown exactly once. */
74
+ /** Full plaintext key. Shown exactly once. */
71
75
  secret: z.string(),
72
76
  })
73
77
  export type CreateApiKeyOutput = z.infer<typeof createApiKeyOutputSchema>
package/src/common.ts CHANGED
@@ -89,7 +89,7 @@ export const metadataSchema = z
89
89
  export const modeSchema = z.enum(['test', 'live'])
90
90
  export type Mode = z.infer<typeof modeSchema>
91
91
 
92
- /** Payment token enum — mirrors `@strimz/shared-config`. */
92
+ /** Payment token enum. */
93
93
  export const paymentCurrencySchema = z.enum(['USDC', 'EURC'])
94
94
  export type PaymentCurrency = z.infer<typeof paymentCurrencySchema>
95
95
 
@@ -97,7 +97,7 @@ export type PaymentCurrency = z.infer<typeof paymentCurrencySchema>
97
97
  export const tokenSymbolSchema = z.enum(['USDC', 'EURC', 'USYC'])
98
98
  export type TokenSymbol = z.infer<typeof tokenSymbolSchema>
99
99
 
100
- /** Merchant tier enum — mirrors `@strimz/shared-config`. */
100
+ /** Merchant tier enum. */
101
101
  export const merchantTierSchema = z.enum(['free', 'growth', 'business', 'enterprise'])
102
102
  export type MerchantTier = z.infer<typeof merchantTierSchema>
103
103
 
package/src/compliance.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Compliance — sanctions/AML screening log.
2
+ * Compliance: sanctions/AML screening log.
3
3
  *
4
4
  * Every wallet address that interacts with Strimz (merchant payout,
5
5
  * subscriber, payer) is screened. Results are logged; provider and score
package/src/contact.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Public marketing contact form. Not an authenticated API resource —
3
+ * routed straight to a support inbox by the contact module in
4
+ * `apps/api`. Kept shape-compatible with what the marketing form on
5
+ * the Strimz landing page already validates client-side.
6
+ */
7
+
8
+ import { z } from 'zod'
9
+ import { emailSchema } from './common.js'
10
+
11
+ export const contactTopicSchema = z.enum(['sales', 'support', 'partnership', 'security', 'other'])
12
+ export type ContactTopic = z.infer<typeof contactTopicSchema>
13
+
14
+ export const contactRequestInputSchema = z.object({
15
+ name: z.string().min(2).max(120),
16
+ email: emailSchema,
17
+ company: z.string().min(1).max(120).optional(),
18
+ topic: contactTopicSchema,
19
+ message: z.string().min(20).max(4000),
20
+ })
21
+ export type ContactRequestInput = z.infer<typeof contactRequestInputSchema>
22
+
23
+ export const contactRequestOutputSchema = z.object({
24
+ ok: z.literal(true),
25
+ })
26
+ export type ContactRequestOutput = z.infer<typeof contactRequestOutputSchema>
package/src/customers.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Customer — the payer on the merchant's side.
2
+ * Customer. The payer on the merchant's side.
3
3
  *
4
4
  * Customers are uniquely identified by (merchantId, walletAddress). Email and
5
5
  * externalRef are optional; merchants can associate their own customer id.
package/src/index.ts CHANGED
@@ -21,3 +21,5 @@ export * from './storefronts.js'
21
21
  export * from './invoices.js'
22
22
  export * from './events.js'
23
23
  export * from './tokens.js'
24
+ export * from './contact.js'
25
+ export * from './notifications.js'
package/src/invoices.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoices — shareable, expirable payment requests with structured line items.
2
+ * Invoices. Shareable, expirable payment requests with structured line items.
3
3
  */
4
4
 
5
5
  import { z } from 'zod'
package/src/merchants.ts CHANGED
@@ -30,6 +30,8 @@ export const merchantSchema = z.object({
30
30
  tier: merchantTierSchema,
31
31
  status: merchantStatusSchema,
32
32
  payoutAddress: evmAddressSchema.nullable(),
33
+ walletAddress: evmAddressSchema.nullable(),
34
+ onboardingCompleted: z.boolean(),
33
35
  defaultCurrency: z.enum(['USDC', 'EURC']),
34
36
  countryCode: z.string().length(2).nullable(),
35
37
  websiteUrl: z.string().url().nullable(),
@@ -52,6 +54,23 @@ export const createMerchantInputSchema = z.object({
52
54
  })
53
55
  export type CreateMerchantInput = z.infer<typeof createMerchantInputSchema>
54
56
 
57
+ /**
58
+ * Merchant email opt-outs, persisted at `Merchant.metadata.emailPrefs`.
59
+ * Both default to true. Welcome, refunds, and admin broadcasts always send.
60
+ */
61
+ export const merchantEmailPrefsSchema = z.object({
62
+ /** "You received X USDC" one-off payment notifications. */
63
+ paymentReceived: z.boolean(),
64
+ /** "You were paid X for subscription Y" per-charge notifications. */
65
+ subscriptionCharged: z.boolean(),
66
+ })
67
+ export type MerchantEmailPrefs = z.infer<typeof merchantEmailPrefsSchema>
68
+
69
+ export const DEFAULT_MERCHANT_EMAIL_PREFS: MerchantEmailPrefs = {
70
+ paymentReceived: true,
71
+ subscriptionCharged: true,
72
+ }
73
+
55
74
  export const updateMerchantInputSchema = z
56
75
  .object({
57
76
  businessName: z.string().min(2).max(120),
@@ -61,6 +80,7 @@ export const updateMerchantInputSchema = z
61
80
  logoUrl: z.string().url().nullable(),
62
81
  countryCode: z.string().length(2).nullable(),
63
82
  metadata: metadataSchema,
83
+ emailPrefs: merchantEmailPrefsSchema.partial(),
64
84
  })
65
85
  .partial()
66
86
  export type UpdateMerchantInput = z.infer<typeof updateMerchantInputSchema>
@@ -70,6 +90,70 @@ export const changeTierInputSchema = z.object({
70
90
  })
71
91
  export type ChangeTierInput = z.infer<typeof changeTierInputSchema>
72
92
 
93
+ /**
94
+ * Self-attested onboarding form the dashboard collects after a
95
+ * merchant first logs in via Privy. On success the API stamps
96
+ * `onboardingCompleted: true` on the row, and the dashboard exits
97
+ * the wizard. Shared here so the API's DTO and the web client's
98
+ * hook can enforce the same shape.
99
+ */
100
+ export const onboardMerchantInputSchema = z.object({
101
+ businessName: z.string().min(2).max(120),
102
+ businessSector: z.string().min(2).max(80),
103
+ countryCode: z
104
+ .string()
105
+ .length(2)
106
+ .regex(/^[A-Z]{2}$/, 'must be a 2-letter ISO country code'),
107
+ websiteUrl: z.string().url().optional(),
108
+ logoUrl: z.string().url().optional(),
109
+ phone: z.string().min(6).max(20).optional(),
110
+ payoutAddress: evmAddressSchema,
111
+ defaultCurrency: z.enum(['USDC', 'EURC']).optional(),
112
+ })
113
+ export type OnboardMerchantInput = z.infer<typeof onboardMerchantInputSchema>
114
+
115
+ export const merchantPublicBrandSchema = z.object({
116
+ id: idSchema,
117
+ businessName: z.string().min(2).max(120),
118
+ logoUrl: z.string().url().nullable(),
119
+ walletAddress: evmAddressSchema.nullable(),
120
+ })
121
+ export type MerchantPublicBrand = z.infer<typeof merchantPublicBrandSchema>
122
+
123
+ /**
124
+ * On-chain balance view for the withdraw page. Strimz is
125
+ * non-custodial: payments settle directly into the merchant's
126
+ * `payoutAddress`, and "withdrawal" means the merchant transferring
127
+ * out with their own wallet. This shape reports current on-chain
128
+ * state so the dashboard renders live balances + decides whether to
129
+ * offer the signing UI.
130
+ */
131
+ export const merchantBalanceSchema = z.object({
132
+ /** Payout wallet, checksummed; null when the merchant hasn't set one. */
133
+ payoutAddress: evmAddressSchema.nullable(),
134
+ /** Privy embedded wallet, checksummed if resolvable. */
135
+ walletAddress: evmAddressSchema.nullable(),
136
+ /**
137
+ * True when `payoutAddress === walletAddress`, i.e. the merchant
138
+ * can sign a transfer from the dashboard via Privy. False for
139
+ * merchants using an external wallet as payout — the UI falls back
140
+ * to "copy the address, transfer with your wallet."
141
+ */
142
+ canSignFromDashboard: z.boolean(),
143
+ balances: z.array(
144
+ z.object({
145
+ currency: z.enum(['USDC', 'EURC']),
146
+ contractAddress: evmAddressSchema,
147
+ /** Base-6 integer as string. */
148
+ raw: z.string(),
149
+ /** Human-formatted, e.g. `1234.56`. */
150
+ formatted: z.string(),
151
+ decimals: z.number().int().min(0).max(30),
152
+ }),
153
+ ),
154
+ })
155
+ export type MerchantBalanceView = z.infer<typeof merchantBalanceSchema>
156
+
73
157
  // ---------- Team members ----------
74
158
 
75
159
  export const merchantMemberSchema = z.object({
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Dashboard notifications. Derived server-side from recent activity
3
+ * (confirmed payment sessions, new subscribers, processed refunds).
4
+ * Read state is tracked on the merchant record via
5
+ * `notificationsLastReadAt` — `event.createdAt <= that timestamp` is
6
+ * "read", anything newer is "unread". No dedicated notifications
7
+ * table because the source rows already exist; a separate table would
8
+ * just be a denormalised copy.
9
+ */
10
+
11
+ import { z } from 'zod'
12
+ import { idSchema, isoTimestampSchema } from './common.js'
13
+
14
+ export const notificationKindSchema = z.enum([
15
+ 'payment_received',
16
+ 'subscription_started',
17
+ 'refund_processed',
18
+ /** Message an admin broadcast to this merchant (or all merchants). */
19
+ 'admin_broadcast',
20
+ ])
21
+ export type NotificationKind = z.infer<typeof notificationKindSchema>
22
+
23
+ // ---------- Admin broadcasts ----------
24
+
25
+ export const broadcastAudienceSchema = z.enum(['all', 'merchant'])
26
+ export type BroadcastAudience = z.infer<typeof broadcastAudienceSchema>
27
+
28
+ export const createBroadcastInputSchema = z
29
+ .object({
30
+ title: z.string().min(4).max(160),
31
+ body: z.string().min(4).max(4000),
32
+ audience: broadcastAudienceSchema.default('all'),
33
+ /** Required when `audience === 'merchant'`; ignored otherwise. */
34
+ merchantId: z.string().optional(),
35
+ })
36
+ .refine((v) => v.audience !== 'merchant' || !!v.merchantId, {
37
+ message: 'merchantId is required when audience is merchant',
38
+ path: ['merchantId'],
39
+ })
40
+ export type CreateBroadcastInput = z.infer<typeof createBroadcastInputSchema>
41
+
42
+ export const broadcastSchema = z.object({
43
+ id: idSchema,
44
+ title: z.string(),
45
+ body: z.string(),
46
+ audience: broadcastAudienceSchema,
47
+ merchantId: idSchema.nullable(),
48
+ merchantEmail: z.string().nullable(),
49
+ senderId: idSchema,
50
+ senderEmail: z.string(),
51
+ emailedAt: isoTimestampSchema.nullable(),
52
+ createdAt: isoTimestampSchema,
53
+ })
54
+ export type Broadcast = z.infer<typeof broadcastSchema>
55
+
56
+ export const broadcastListResponseSchema = z.object({
57
+ data: z.array(broadcastSchema),
58
+ })
59
+ export type BroadcastListResponse = z.infer<typeof broadcastListResponseSchema>
60
+
61
+ export const notificationSchema = z.object({
62
+ /** Deterministic client id — `{kind}:{sourceId}`. Safe for React keys. */
63
+ id: z.string().min(1),
64
+ kind: notificationKindSchema,
65
+ title: z.string().min(1),
66
+ detail: z.string(),
67
+ /** Dashboard route the tray links to. */
68
+ href: z.string().min(1),
69
+ /** ISO timestamp of the source event; drives sort + read comparison. */
70
+ createdAt: isoTimestampSchema,
71
+ /** Server-derived from the merchant's `notificationsLastReadAt`. */
72
+ read: z.boolean(),
73
+ /** Optional foreign key back to the source row (for deep-linking). */
74
+ sourceId: idSchema.optional(),
75
+ })
76
+ export type NotificationView = z.infer<typeof notificationSchema>
77
+
78
+ export const notificationListResponseSchema = z.object({
79
+ data: z.array(notificationSchema),
80
+ unreadCount: z.number().int().min(0),
81
+ lastReadAt: isoTimestampSchema.nullable(),
82
+ })
83
+ export type NotificationListResponse = z.infer<typeof notificationListResponseSchema>
84
+
85
+ export const markNotificationsReadResponseSchema = z.object({
86
+ lastReadAt: isoTimestampSchema,
87
+ })
88
+ export type MarkNotificationsReadResponse = z.infer<typeof markNotificationsReadResponseSchema>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Payment session — a one-shot checkout intent.
2
+ * Payment session. A one-shot checkout intent.
3
3
  *
4
4
  * State machine:
5
5
  * created → awaiting_payment → submitted → confirmed
@@ -31,6 +31,28 @@ export const paymentSessionStatusSchema = z.enum([
31
31
  ])
32
32
  export type PaymentSessionStatus = z.infer<typeof paymentSessionStatusSchema>
33
33
 
34
+ /**
35
+ * Merchant-supplied callback URL. The hosted checkout dispatches with
36
+ * `window.location.href = redirectUrl` on completion / cancellation,
37
+ * so we MUST reject anything other than `http://` and `https://`.
38
+ *
39
+ * Why this is a real risk: Zod's `.url()` validates RFC syntax, which
40
+ * accepts `javascript:`, `data:`, `vbscript:`, `file:`, blob:`, etc.
41
+ * A compromised merchant integration or an XSS upstream could ship a
42
+ * session whose redirect URL executes script (or exfiltrates session
43
+ * tokens) on every payer's browser. The damage is per-payer, but the
44
+ * blast radius is "every checkout the merchant runs."
45
+ *
46
+ * Mailto / tel and other handler protocols are also rejected — there
47
+ * is no legitimate flow on a payment checkout that would benefit.
48
+ */
49
+ export const callbackUrlSchema = z
50
+ .string()
51
+ .url()
52
+ .refine((v) => v.startsWith('https://') || v.startsWith('http://'), {
53
+ message: 'must be an http:// or https:// URL',
54
+ })
55
+
34
56
  export const paymentSessionSchema = z.object({
35
57
  id: idSchema,
36
58
  merchantId: idSchema,
@@ -63,8 +85,8 @@ export const paymentSessionSchema = z.object({
63
85
  description: z.string().max(500).nullable(),
64
86
  payerWalletAddress: evmAddressSchema.nullable(),
65
87
  payerEmail: z.string().email().nullable(),
66
- successUrl: z.string().url().nullable(),
67
- cancelUrl: z.string().url().nullable(),
88
+ successUrl: callbackUrlSchema.nullable(),
89
+ cancelUrl: callbackUrlSchema.nullable(),
68
90
  sourceChain: z
69
91
  .enum(['arc', 'ethereum', 'base', 'polygon', 'arbitrum', 'optimism', 'avalanche', 'solana'])
70
92
  .nullable(),
package/src/refunds.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Refund — a merchant-initiated return of funds to a payer.
2
+ * Refund. A merchant-initiated return of funds to a payer.
3
3
  *
4
4
  * Refunds are executed off-chain (from the merchant's wallet to the payer's
5
5
  * wallet). Strimz records the intent, validates constraints, and reconciles
@@ -66,3 +66,22 @@ export const submitRefundSignatureInputSchema = z.object({
66
66
  refundTxHash: evmTxHashSchema,
67
67
  })
68
68
  export type SubmitRefundSignatureInput = z.infer<typeof submitRefundSignatureInputSchema>
69
+
70
+ /**
71
+ * Response envelope for `POST /v1/refunds`. The API returns the newly
72
+ * created refund plus the concrete ERC-20 transfer the merchant now
73
+ * has to sign from their payout wallet.
74
+ */
75
+ export const refundSigningInstructionsSchema = z.object({
76
+ token: evmAddressSchema,
77
+ to: evmAddressSchema,
78
+ amount: tokenAmountSchema,
79
+ note: z.string(),
80
+ })
81
+ export type RefundSigningInstructions = z.infer<typeof refundSigningInstructionsSchema>
82
+
83
+ export const refundCreateOutputSchema = z.object({
84
+ refund: refundSchema,
85
+ signingInstructions: refundSigningInstructionsSchema,
86
+ })
87
+ export type RefundCreateOutput = z.infer<typeof refundCreateOutputSchema>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Storefronts — hosted product catalog with checkout baked in.
2
+ * Storefronts. Hosted product catalog with checkout baked in.
3
3
  */
4
4
 
5
5
  import { z } from 'zod'
@@ -87,3 +87,27 @@ export const createStorefrontProductInputSchema = storefrontProductSchema
87
87
  imageUrl: httpsUrlSchema.optional(),
88
88
  })
89
89
  export type CreateStorefrontProductInput = z.infer<typeof createStorefrontProductInputSchema>
90
+
91
+ /**
92
+ * Payload for the public `/store/:slug/products/:id/checkout` endpoint.
93
+ * Optional customer email flows through into the payment session so
94
+ * the receipt lands in the buyer's inbox after the tx confirms.
95
+ * `returnPath` is used to synthesise the success + cancel URLs when
96
+ * the merchant hasn't wired their own.
97
+ */
98
+ export const storefrontCheckoutInputSchema = z.object({
99
+ customerEmail: z.string().email().optional(),
100
+ returnPath: z.string().max(200).optional(),
101
+ })
102
+ export type StorefrontCheckoutInput = z.infer<typeof storefrontCheckoutInputSchema>
103
+
104
+ /** Response shape from the public product-checkout endpoint. */
105
+ export const storefrontCheckoutResponseSchema = z.object({
106
+ /** Fully-qualified checkout URL — payer redirects here to sign. */
107
+ checkoutUrl: z.string().url(),
108
+ /** Payment-session id (one-time) or plan id (subscription). */
109
+ ref: idSchema,
110
+ /** Which downstream checkout the URL points at. */
111
+ kind: z.enum(['payment_session', 'subscription_plan']),
112
+ })
113
+ export type StorefrontCheckoutResponse = z.infer<typeof storefrontCheckoutResponseSchema>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Subscriptions — plans, active subscriptions, and individual charges.
2
+ * Subscriptions: plans, active subscriptions, and individual charges.
3
3
  *
4
4
  * Design notes:
5
5
  * - A SubscriptionPlan is the template a merchant defines.
@@ -39,7 +39,7 @@ export const subscriptionPlanSchema = z.object({
39
39
  /**
40
40
  * On-chain StrimzRegistry merchant id (uint96) as a decimal string.
41
41
  * See `paymentSessionSchema.chainMerchantId`. Null when the merchant
42
- * hasn't been registered on-chain yet — the hosted enrolment page
42
+ * hasn't been registered on-chain yet. The hosted enrolment page
43
43
  * refuses to take signatures in that state.
44
44
  */
45
45
  chainMerchantId: z
@@ -47,7 +47,7 @@ export const subscriptionPlanSchema = z.object({
47
47
  .regex(/^[0-9]+$/u, 'must be a non-negative decimal integer string')
48
48
  .nullable(),
49
49
  /**
50
- * ERC-20 token contract address resolved from `currency` — the
50
+ * ERC-20 token contract address resolved from `currency`. This is the
51
51
  * EIP-2612 `verifyingContract` the wallet signs over.
52
52
  */
53
53
  tokenAddress: evmAddressSchema.nullable(),
package/src/tokens.ts CHANGED
@@ -3,16 +3,16 @@
3
3
  *
4
4
  * Read by the SDK's BrowserClient to (1) pick the right meta-tx path
5
5
  * for a given token and (2) build the EIP-712 typed-data domain. The
6
- * shape is intentionally derived from on-chain reads — name / version
7
- * from the token's ERC-5267 `eip712Domain()` (falling back to a
8
- * default), capabilities from Strimz's TokenWhitelist contract.
6
+ * shape is derived from on-chain reads. Name and version come from the
7
+ * token's ERC-5267 `eip712Domain()` (falling back to a default), and
8
+ * capabilities come from Strimz's TokenWhitelist contract.
9
9
  *
10
10
  * `capabilities.permit2612` means the token implements EIP-2612 (the
11
11
  * gasless allowance + subscription enrolment path).
12
12
  * `capabilities.transferAuth3009` means the token implements EIP-3009
13
13
  * (the gasless one-shot payment path).
14
14
  *
15
- * Tokens may have one capability or both — USDC and EURC on Arc
15
+ * Tokens may have one capability or both. USDC and EURC on Arc
16
16
  * advertise both.
17
17
  */
18
18
 
@@ -34,8 +34,8 @@ export const tokenMetadataSchema = z.object({
34
34
  symbol: z.string(),
35
35
  /**
36
36
  * EIP-712 domain version. Read from ERC-5267 `eip712Domain()` when
37
- * available; otherwise defaults to "1". Used by typed-data builders
38
- * — domain mismatch produces a different digest and the contract's
37
+ * available; otherwise defaults to "1". Used by typed-data builders.
38
+ * A domain mismatch produces a different digest, so the contract's
39
39
  * ecrecover would recover a different address.
40
40
  */
41
41
  version: z.string(),
@@ -46,7 +46,7 @@ export type TokenMetadata = z.infer<typeof tokenMetadataSchema>
46
46
 
47
47
  /**
48
48
  * Owner-specific permit nonce. The EIP-2612 standard tracks a per-
49
- * owner monotonic counter — every successful permit consumes one,
49
+ * owner monotonic counter, and every successful permit consumes one,
50
50
  * so signers must read the current value immediately before signing.
51
51
  *
52
52
  * Returned as a decimal string to avoid JS number truncation on the
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Transaction — the record of a confirmed on-chain payment.
2
+ * Transaction. The record of a confirmed on-chain payment.
3
3
  *
4
4
  * Every transaction corresponds to either a paid PaymentSession, a
5
- * SubscriptionCharge, or a Refund. The indexer writes these from the
5
+ * SubscriptionCharge, or a Refund. Records are derived from the
6
6
  * `PaymentExecuted`, `SubscriptionCharged`, and `RefundRecorded` events.
7
7
  */
8
8
 
package/src/webhooks.ts CHANGED
@@ -12,8 +12,8 @@ import { httpsUrlSchema, idSchema, isoTimestampSchema, modeSchema } from './comm
12
12
  // ---------- Event name ----------
13
13
 
14
14
  /**
15
- * Every webhook event name in the system. Listed here (not imported from
16
- * `@strimz/shared-config`) so Zod can produce a concrete string union.
15
+ * Every webhook event name in the system. Listed inline so Zod can
16
+ * produce a concrete string union.
17
17
  */
18
18
  export const webhookEventNameSchema = z.enum([
19
19
  'payment.created',
@@ -71,7 +71,7 @@ export type CreateWebhookEndpointInput = z.infer<typeof createWebhookEndpointInp
71
71
 
72
72
  export const createWebhookEndpointOutputSchema = z.object({
73
73
  endpoint: webhookEndpointSchema,
74
- /** Full signing secret — shown exactly once. */
74
+ /** Full signing secret. Shown exactly once. */
75
75
  signingSecret: z.string(),
76
76
  })
77
77
  export type CreateWebhookEndpointOutput = z.infer<typeof createWebhookEndpointOutputSchema>
@@ -103,6 +103,18 @@ export const webhookDeliverySchema = z.object({
103
103
  })
104
104
  export type WebhookDelivery = z.infer<typeof webhookDeliverySchema>
105
105
 
106
+ /**
107
+ * Detail projection returned by GET /v1/webhook-deliveries/:id.
108
+ * Carries the payload envelope, response body, and the deliveryId
109
+ * header the receiver saw. Kept separate so list responses stay slim.
110
+ */
111
+ export const webhookDeliveryDetailSchema = webhookDeliverySchema.extend({
112
+ deliveryId: z.string(),
113
+ responseBody: z.string().nullable(),
114
+ requestPayload: z.record(z.string(), z.unknown()),
115
+ })
116
+ export type WebhookDeliveryDetail = z.infer<typeof webhookDeliveryDetailSchema>
117
+
106
118
  export const replayDeliveryInputSchema = z.object({
107
119
  id: idSchema,
108
120
  })