@strimz/shared-types 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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/agents.cjs +148 -0
  4. package/dist/agents.cjs.map +1 -0
  5. package/dist/agents.d.cts +317 -0
  6. package/dist/agents.d.ts +317 -0
  7. package/dist/agents.js +137 -0
  8. package/dist/agents.js.map +1 -0
  9. package/dist/api-keys.cjs +91 -0
  10. package/dist/api-keys.cjs.map +1 -0
  11. package/dist/api-keys.d.cts +155 -0
  12. package/dist/api-keys.d.ts +155 -0
  13. package/dist/api-keys.js +84 -0
  14. package/dist/api-keys.js.map +1 -0
  15. package/dist/common.cjs +56 -0
  16. package/dist/common.cjs.map +1 -0
  17. package/dist/common.d.cts +82 -0
  18. package/dist/common.d.ts +82 -0
  19. package/dist/common.js +37 -0
  20. package/dist/common.js.map +1 -0
  21. package/dist/compliance.cjs +61 -0
  22. package/dist/compliance.cjs.map +1 -0
  23. package/dist/compliance.d.cts +59 -0
  24. package/dist/compliance.d.ts +59 -0
  25. package/dist/compliance.js +56 -0
  26. package/dist/compliance.js.map +1 -0
  27. package/dist/customers.cjs +56 -0
  28. package/dist/customers.cjs.map +1 -0
  29. package/dist/customers.d.cts +64 -0
  30. package/dist/customers.d.ts +64 -0
  31. package/dist/customers.js +53 -0
  32. package/dist/customers.js.map +1 -0
  33. package/dist/events.cjs +675 -0
  34. package/dist/events.cjs.map +1 -0
  35. package/dist/events.d.cts +7907 -0
  36. package/dist/events.d.ts +7907 -0
  37. package/dist/events.js +650 -0
  38. package/dist/events.js.map +1 -0
  39. package/dist/index.cjs +976 -0
  40. package/dist/index.cjs.map +1 -0
  41. package/dist/index.d.cts +113 -0
  42. package/dist/index.d.ts +113 -0
  43. package/dist/index.js +858 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/invoices.cjs +72 -0
  46. package/dist/invoices.cjs.map +1 -0
  47. package/dist/invoices.d.cts +159 -0
  48. package/dist/invoices.d.ts +159 -0
  49. package/dist/invoices.js +67 -0
  50. package/dist/invoices.js.map +1 -0
  51. package/dist/merchants.cjs +104 -0
  52. package/dist/merchants.cjs.map +1 -0
  53. package/dist/merchants.d.cts +259 -0
  54. package/dist/merchants.d.ts +259 -0
  55. package/dist/merchants.js +93 -0
  56. package/dist/merchants.js.map +1 -0
  57. package/dist/payment-sessions.cjs +125 -0
  58. package/dist/payment-sessions.cjs.map +1 -0
  59. package/dist/payment-sessions.d.cts +180 -0
  60. package/dist/payment-sessions.d.ts +180 -0
  61. package/dist/payment-sessions.js +120 -0
  62. package/dist/payment-sessions.js.map +1 -0
  63. package/dist/refunds.cjs +81 -0
  64. package/dist/refunds.cjs.map +1 -0
  65. package/dist/refunds.d.cts +91 -0
  66. package/dist/refunds.d.ts +91 -0
  67. package/dist/refunds.js +75 -0
  68. package/dist/refunds.js.map +1 -0
  69. package/dist/storefronts.cjs +223 -0
  70. package/dist/storefronts.cjs.map +1 -0
  71. package/dist/storefronts.d.cts +177 -0
  72. package/dist/storefronts.d.ts +177 -0
  73. package/dist/storefronts.js +216 -0
  74. package/dist/storefronts.js.map +1 -0
  75. package/dist/subscriptions.cjs +175 -0
  76. package/dist/subscriptions.cjs.map +1 -0
  77. package/dist/subscriptions.d.cts +290 -0
  78. package/dist/subscriptions.d.ts +290 -0
  79. package/dist/subscriptions.js +163 -0
  80. package/dist/subscriptions.js.map +1 -0
  81. package/dist/transactions.cjs +67 -0
  82. package/dist/transactions.cjs.map +1 -0
  83. package/dist/transactions.d.cts +78 -0
  84. package/dist/transactions.d.ts +78 -0
  85. package/dist/transactions.js +63 -0
  86. package/dist/transactions.js.map +1 -0
  87. package/dist/webhooks.cjs +116 -0
  88. package/dist/webhooks.cjs.map +1 -0
  89. package/dist/webhooks.d.cts +201 -0
  90. package/dist/webhooks.d.ts +201 -0
  91. package/dist/webhooks.js +107 -0
  92. package/dist/webhooks.js.map +1 -0
  93. package/package.json +134 -0
  94. package/src/agents.ts +149 -0
  95. package/src/api-keys.ts +78 -0
  96. package/src/common.ts +113 -0
  97. package/src/compliance.ts +40 -0
  98. package/src/customers.ts +40 -0
  99. package/src/events.ts +176 -0
  100. package/src/index.ts +23 -0
  101. package/src/invoices.ts +53 -0
  102. package/src/merchants.ts +104 -0
  103. package/src/payment-sessions.ts +131 -0
  104. package/src/refunds.ts +68 -0
  105. package/src/storefronts.ts +89 -0
  106. package/src/subscriptions.ts +180 -0
  107. package/src/tokens.ts +60 -0
  108. package/src/transactions.ts +52 -0
  109. package/src/webhooks.ts +109 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Payment session — a one-shot checkout intent.
3
+ *
4
+ * State machine:
5
+ * created → awaiting_payment → submitted → confirmed
6
+ * \
7
+ * → failed
8
+ * → expired
9
+ * → cancelled
10
+ */
11
+
12
+ import { z } from 'zod'
13
+ import {
14
+ evmAddressSchema,
15
+ evmTxHashSchema,
16
+ idSchema,
17
+ isoTimestampSchema,
18
+ metadataSchema,
19
+ paymentCurrencySchema,
20
+ tokenAmountSchema,
21
+ } from './common.js'
22
+
23
+ export const paymentSessionStatusSchema = z.enum([
24
+ 'created',
25
+ 'awaiting_payment',
26
+ 'submitted',
27
+ 'confirmed',
28
+ 'failed',
29
+ 'expired',
30
+ 'cancelled',
31
+ ])
32
+ export type PaymentSessionStatus = z.infer<typeof paymentSessionStatusSchema>
33
+
34
+ export const paymentSessionSchema = z.object({
35
+ id: idSchema,
36
+ merchantId: idSchema,
37
+ /**
38
+ * On-chain StrimzRegistry merchant id (uint96) as a decimal string.
39
+ * Set when the merchant has been registered on-chain; null when the
40
+ * merchant exists in our DB but the registry transaction hasn't
41
+ * been broadcast yet. Hosted checkout uses this to populate the
42
+ * meta-tx calldata; if null, the checkout refuses to accept
43
+ * payments.
44
+ */
45
+ chainMerchantId: z
46
+ .string()
47
+ .regex(/^[0-9]+$/u, 'must be a non-negative decimal integer string')
48
+ .nullable(),
49
+ /**
50
+ * ERC-20 token contract address resolved from `currency` on the
51
+ * active chain (Arc Testnet / Mainnet). Used as the `verifyingContract`
52
+ * in the EIP-712 domain for both EIP-3009 and EIP-2612 signing.
53
+ * Null on the (vanishingly unlikely) path where the API has no
54
+ * configured address for the session's currency.
55
+ */
56
+ tokenAddress: evmAddressSchema.nullable(),
57
+ customerId: idSchema.nullable(),
58
+ status: paymentSessionStatusSchema,
59
+ amount: tokenAmountSchema,
60
+ currency: paymentCurrencySchema,
61
+ feeAmount: tokenAmountSchema,
62
+ netAmount: tokenAmountSchema,
63
+ description: z.string().max(500).nullable(),
64
+ payerWalletAddress: evmAddressSchema.nullable(),
65
+ payerEmail: z.string().email().nullable(),
66
+ successUrl: z.string().url().nullable(),
67
+ cancelUrl: z.string().url().nullable(),
68
+ sourceChain: z
69
+ .enum(['arc', 'ethereum', 'base', 'polygon', 'arbitrum', 'optimism', 'avalanche', 'solana'])
70
+ .nullable(),
71
+ bridgeTxHash: evmTxHashSchema.nullable(),
72
+ onchainTxHash: evmTxHashSchema.nullable(),
73
+ checkoutUrl: z.string().url(),
74
+ metadata: metadataSchema,
75
+ expiresAt: isoTimestampSchema,
76
+ createdAt: isoTimestampSchema,
77
+ updatedAt: isoTimestampSchema,
78
+ })
79
+ export type PaymentSession = z.infer<typeof paymentSessionSchema>
80
+
81
+ // ---------- DTOs ----------
82
+
83
+ export const createPaymentSessionInputSchema = z.object({
84
+ amount: tokenAmountSchema,
85
+ currency: paymentCurrencySchema,
86
+ description: z.string().max(500).optional(),
87
+ customer: z
88
+ .object({
89
+ walletAddress: evmAddressSchema.optional(),
90
+ email: z.string().email().optional(),
91
+ externalRef: z.string().max(120).optional(),
92
+ })
93
+ .optional(),
94
+ successUrl: z.string().url().optional(),
95
+ cancelUrl: z.string().url().optional(),
96
+ /** Minutes until the session expires. Default 30, max 60*24 (one day). */
97
+ expiresInMinutes: z
98
+ .number()
99
+ .int()
100
+ .min(1)
101
+ .max(60 * 24)
102
+ .default(30),
103
+ /**
104
+ * Allowed source chains a payer can bridge USDC from via CCTP. Omit to
105
+ * accept every CCTP-supported chain.
106
+ */
107
+ supportedSourceChains: z
108
+ .array(
109
+ z.enum(['arc', 'ethereum', 'base', 'polygon', 'arbitrum', 'optimism', 'avalanche', 'solana']),
110
+ )
111
+ .optional(),
112
+ metadata: metadataSchema.optional(),
113
+ })
114
+ export type CreatePaymentSessionInput = z.infer<typeof createPaymentSessionInputSchema>
115
+
116
+ export const submitPaymentSessionInputSchema = z.object({
117
+ sourceChain: z.enum([
118
+ 'arc',
119
+ 'ethereum',
120
+ 'base',
121
+ 'polygon',
122
+ 'arbitrum',
123
+ 'optimism',
124
+ 'avalanche',
125
+ 'solana',
126
+ ]),
127
+ onchainTxHash: evmTxHashSchema,
128
+ bridgeTxHash: evmTxHashSchema.optional(),
129
+ payerWalletAddress: evmAddressSchema,
130
+ })
131
+ export type SubmitPaymentSessionInput = z.infer<typeof submitPaymentSessionInputSchema>
package/src/refunds.ts ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Refund — a merchant-initiated return of funds to a payer.
3
+ *
4
+ * Refunds are executed off-chain (from the merchant's wallet to the payer's
5
+ * wallet). Strimz records the intent, validates constraints, and reconciles
6
+ * via the merchant-signed on-chain transfer.
7
+ */
8
+
9
+ import { z } from 'zod'
10
+ import {
11
+ evmAddressSchema,
12
+ evmTxHashSchema,
13
+ idSchema,
14
+ isoTimestampSchema,
15
+ paymentCurrencySchema,
16
+ tokenAmountSchema,
17
+ } from './common.js'
18
+
19
+ export const refundReasonSchema = z.enum([
20
+ 'customer_request',
21
+ 'product_issue',
22
+ 'duplicate_charge',
23
+ 'fraudulent',
24
+ 'other',
25
+ ])
26
+ export type RefundReason = z.infer<typeof refundReasonSchema>
27
+
28
+ export const refundStatusSchema = z.enum([
29
+ 'pending',
30
+ 'awaiting_signature',
31
+ 'submitted',
32
+ 'completed',
33
+ 'failed',
34
+ 'cancelled',
35
+ ])
36
+ export type RefundStatus = z.infer<typeof refundStatusSchema>
37
+
38
+ export const refundSchema = z.object({
39
+ id: idSchema,
40
+ merchantId: idSchema,
41
+ transactionId: idSchema,
42
+ amount: tokenAmountSchema,
43
+ currency: paymentCurrencySchema,
44
+ reason: refundReasonSchema,
45
+ note: z.string().max(500).nullable(),
46
+ status: refundStatusSchema,
47
+ payerAddress: evmAddressSchema,
48
+ refundTxHash: evmTxHashSchema.nullable(),
49
+ failureReason: z.string().max(500).nullable(),
50
+ initiatedBy: idSchema,
51
+ createdAt: isoTimestampSchema,
52
+ completedAt: isoTimestampSchema.nullable(),
53
+ })
54
+ export type Refund = z.infer<typeof refundSchema>
55
+
56
+ export const createRefundInputSchema = z.object({
57
+ transactionId: idSchema,
58
+ amount: tokenAmountSchema,
59
+ reason: refundReasonSchema,
60
+ note: z.string().max(500).optional(),
61
+ })
62
+ export type CreateRefundInput = z.infer<typeof createRefundInputSchema>
63
+
64
+ export const submitRefundSignatureInputSchema = z.object({
65
+ id: idSchema,
66
+ refundTxHash: evmTxHashSchema,
67
+ })
68
+ export type SubmitRefundSignatureInput = z.infer<typeof submitRefundSignatureInputSchema>
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Storefronts — hosted product catalog with checkout baked in.
3
+ */
4
+
5
+ import { z } from 'zod'
6
+ import {
7
+ httpsUrlSchema,
8
+ idSchema,
9
+ isoTimestampSchema,
10
+ paymentCurrencySchema,
11
+ tokenAmountSchema,
12
+ } from './common.js'
13
+ import { subscriptionIntervalSchema } from './subscriptions.js'
14
+
15
+ export const storefrontStatusSchema = z.enum(['draft', 'published', 'archived'])
16
+ export type StorefrontStatus = z.infer<typeof storefrontStatusSchema>
17
+
18
+ export const storefrontSchema = z.object({
19
+ id: idSchema,
20
+ merchantId: idSchema,
21
+ slug: z
22
+ .string()
23
+ .min(3)
24
+ .max(40)
25
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'slug must be lowercase alphanumeric with hyphens'),
26
+ name: z.string().min(2).max(120),
27
+ description: z.string().max(2000).nullable(),
28
+ logoUrl: httpsUrlSchema.nullable(),
29
+ coverImageUrl: httpsUrlSchema.nullable(),
30
+ accentColor: z
31
+ .string()
32
+ .regex(/^#[0-9a-fA-F]{6}$/)
33
+ .nullable(),
34
+ socialLinks: z.array(httpsUrlSchema).max(10).default([]),
35
+ status: storefrontStatusSchema,
36
+ createdAt: isoTimestampSchema,
37
+ updatedAt: isoTimestampSchema,
38
+ })
39
+ export type Storefront = z.infer<typeof storefrontSchema>
40
+
41
+ export const createStorefrontInputSchema = storefrontSchema.pick({
42
+ slug: true,
43
+ name: true,
44
+ description: true,
45
+ logoUrl: true,
46
+ coverImageUrl: true,
47
+ accentColor: true,
48
+ socialLinks: true,
49
+ })
50
+ export type CreateStorefrontInput = z.infer<typeof createStorefrontInputSchema>
51
+
52
+ // ---------- Products ----------
53
+
54
+ export const storefrontProductTypeSchema = z.enum(['one_time', 'subscription'])
55
+ export type StorefrontProductType = z.infer<typeof storefrontProductTypeSchema>
56
+
57
+ export const storefrontProductSchema = z.object({
58
+ id: idSchema,
59
+ storefrontId: idSchema,
60
+ name: z.string().min(1).max(120),
61
+ description: z.string().max(2000).nullable(),
62
+ imageUrl: httpsUrlSchema.nullable(),
63
+ price: tokenAmountSchema,
64
+ currency: paymentCurrencySchema,
65
+ type: storefrontProductTypeSchema,
66
+ interval: subscriptionIntervalSchema.nullable(),
67
+ intervalCount: z.number().int().min(1).max(365).nullable(),
68
+ /** null = unlimited stock. */
69
+ stock: z.number().int().min(0).nullable(),
70
+ planId: idSchema.nullable(),
71
+ isActive: z.boolean(),
72
+ sortOrder: z.number().int().nonnegative().default(0),
73
+ createdAt: isoTimestampSchema,
74
+ updatedAt: isoTimestampSchema,
75
+ })
76
+ export type StorefrontProduct = z.infer<typeof storefrontProductSchema>
77
+
78
+ export const createStorefrontProductInputSchema = storefrontProductSchema
79
+ .omit({
80
+ id: true,
81
+ storefrontId: true,
82
+ planId: true,
83
+ createdAt: true,
84
+ updatedAt: true,
85
+ })
86
+ .extend({
87
+ imageUrl: httpsUrlSchema.optional(),
88
+ })
89
+ export type CreateStorefrontProductInput = z.infer<typeof createStorefrontProductInputSchema>
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Subscriptions — plans, active subscriptions, and individual charges.
3
+ *
4
+ * Design notes:
5
+ * - A SubscriptionPlan is the template a merchant defines.
6
+ * - A Subscription is an active, customer-scoped instance of a plan.
7
+ * - Each billing period produces a SubscriptionCharge with a unique
8
+ * chargeAttemptId used to enforce idempotency at the contract level.
9
+ */
10
+
11
+ import { z } from 'zod'
12
+ import {
13
+ evmAddressSchema,
14
+ evmTxHashSchema,
15
+ idSchema,
16
+ isoTimestampSchema,
17
+ metadataSchema,
18
+ paymentCurrencySchema,
19
+ tokenAmountSchema,
20
+ } from './common.js'
21
+
22
+ // ---------- Plans ----------
23
+
24
+ export const subscriptionIntervalSchema = z.enum([
25
+ 'daily',
26
+ 'weekly',
27
+ 'monthly',
28
+ 'quarterly',
29
+ 'yearly',
30
+ ])
31
+ export type SubscriptionInterval = z.infer<typeof subscriptionIntervalSchema>
32
+
33
+ export const subscriptionPlanStatusSchema = z.enum(['active', 'archived'])
34
+ export type SubscriptionPlanStatus = z.infer<typeof subscriptionPlanStatusSchema>
35
+
36
+ export const subscriptionPlanSchema = z.object({
37
+ id: idSchema,
38
+ merchantId: idSchema,
39
+ /**
40
+ * On-chain StrimzRegistry merchant id (uint96) as a decimal string.
41
+ * See `paymentSessionSchema.chainMerchantId`. Null when the merchant
42
+ * hasn't been registered on-chain yet — the hosted enrolment page
43
+ * refuses to take signatures in that state.
44
+ */
45
+ chainMerchantId: z
46
+ .string()
47
+ .regex(/^[0-9]+$/u, 'must be a non-negative decimal integer string')
48
+ .nullable(),
49
+ /**
50
+ * ERC-20 token contract address resolved from `currency` — the
51
+ * EIP-2612 `verifyingContract` the wallet signs over.
52
+ */
53
+ tokenAddress: evmAddressSchema.nullable(),
54
+ /**
55
+ * Charge cadence in seconds, derived from `interval` + `intervalCount`
56
+ * so the meta-tx layer can pass a uint32 to StrimzSubscriptions
57
+ * without re-deriving the conversion on the client.
58
+ */
59
+ intervalSeconds: z.number().int().positive(),
60
+ name: z.string().min(1).max(120),
61
+ description: z.string().max(500).nullable(),
62
+ amount: tokenAmountSchema,
63
+ currency: paymentCurrencySchema,
64
+ interval: subscriptionIntervalSchema,
65
+ intervalCount: z.number().int().min(1).max(365),
66
+ trialPeriodDays: z.number().int().min(0).max(365).nullable(),
67
+ status: subscriptionPlanStatusSchema,
68
+ metadata: metadataSchema,
69
+ createdAt: isoTimestampSchema,
70
+ updatedAt: isoTimestampSchema,
71
+ })
72
+ export type SubscriptionPlan = z.infer<typeof subscriptionPlanSchema>
73
+
74
+ export const createSubscriptionPlanInputSchema = z.object({
75
+ name: z.string().min(1).max(120),
76
+ description: z.string().max(500).optional(),
77
+ amount: tokenAmountSchema,
78
+ currency: paymentCurrencySchema,
79
+ interval: subscriptionIntervalSchema,
80
+ intervalCount: z.number().int().min(1).max(365).default(1),
81
+ trialPeriodDays: z.number().int().min(0).max(365).optional(),
82
+ metadata: metadataSchema.optional(),
83
+ })
84
+ export type CreateSubscriptionPlanInput = z.infer<typeof createSubscriptionPlanInputSchema>
85
+
86
+ // ---------- Subscriptions ----------
87
+
88
+ export const subscriptionStatusSchema = z.enum([
89
+ 'trialing',
90
+ 'active',
91
+ 'at_risk',
92
+ 'paused',
93
+ 'cancelled',
94
+ 'lapsed',
95
+ ])
96
+ export type SubscriptionStatus = z.infer<typeof subscriptionStatusSchema>
97
+
98
+ export const subscriptionSchema = z.object({
99
+ id: idSchema,
100
+ onchainSubscriptionId: z.number().int().nonnegative().nullable(),
101
+ merchantId: idSchema,
102
+ customerId: idSchema,
103
+ planId: idSchema,
104
+ status: subscriptionStatusSchema,
105
+ payerAddress: evmAddressSchema,
106
+ currency: paymentCurrencySchema,
107
+ amount: tokenAmountSchema,
108
+ interval: subscriptionIntervalSchema,
109
+ intervalCount: z.number().int().min(1),
110
+ trialEndsAt: isoTimestampSchema.nullable(),
111
+ currentPeriodStartAt: isoTimestampSchema,
112
+ currentPeriodEndAt: isoTimestampSchema,
113
+ nextChargeAt: isoTimestampSchema.nullable(),
114
+ gracePeriodHours: z.number().int().min(0).max(72),
115
+ cancelledAt: isoTimestampSchema.nullable(),
116
+ metadata: metadataSchema,
117
+ createdAt: isoTimestampSchema,
118
+ updatedAt: isoTimestampSchema,
119
+ })
120
+ export type Subscription = z.infer<typeof subscriptionSchema>
121
+
122
+ export const createSubscriptionInputSchema = z.object({
123
+ planId: idSchema,
124
+ customer: z.object({
125
+ walletAddress: evmAddressSchema,
126
+ email: z.string().email().optional(),
127
+ externalRef: z.string().max(120).optional(),
128
+ }),
129
+ gracePeriodHours: z.union([z.literal(24), z.literal(48), z.literal(72)]).default(48),
130
+ metadata: metadataSchema.optional(),
131
+ })
132
+ export type CreateSubscriptionInput = z.infer<typeof createSubscriptionInputSchema>
133
+
134
+ export const cancelSubscriptionInputSchema = z.object({
135
+ id: idSchema,
136
+ reason: z.string().max(500).optional(),
137
+ })
138
+ export type CancelSubscriptionInput = z.infer<typeof cancelSubscriptionInputSchema>
139
+
140
+ // ---------- Charges ----------
141
+
142
+ export const subscriptionChargeOutcomeSchema = z.enum([
143
+ 'charged',
144
+ 'insufficient_funds',
145
+ 'revoked_approval',
146
+ 'cancelled',
147
+ 'skipped',
148
+ ])
149
+ export type SubscriptionChargeOutcome = z.infer<typeof subscriptionChargeOutcomeSchema>
150
+
151
+ export const subscriptionChargeStatusSchema = z.enum([
152
+ 'pending',
153
+ 'in_flight',
154
+ 'succeeded',
155
+ 'failed',
156
+ 'retrying',
157
+ 'abandoned',
158
+ ])
159
+ export type SubscriptionChargeStatus = z.infer<typeof subscriptionChargeStatusSchema>
160
+
161
+ export const subscriptionChargeSchema = z.object({
162
+ id: idSchema,
163
+ subscriptionId: idSchema,
164
+ merchantId: idSchema,
165
+ chargeAttemptId: z.string().length(66, 'must be a 32-byte 0x-prefixed hex string'),
166
+ periodStartAt: isoTimestampSchema,
167
+ periodEndAt: isoTimestampSchema,
168
+ amount: tokenAmountSchema,
169
+ currency: paymentCurrencySchema,
170
+ status: subscriptionChargeStatusSchema,
171
+ outcome: subscriptionChargeOutcomeSchema.nullable(),
172
+ attemptNumber: z.number().int().min(1),
173
+ scheduledAt: isoTimestampSchema,
174
+ executedAt: isoTimestampSchema.nullable(),
175
+ onchainTxHash: evmTxHashSchema.nullable(),
176
+ failureReason: z.string().max(500).nullable(),
177
+ createdAt: isoTimestampSchema,
178
+ updatedAt: isoTimestampSchema,
179
+ })
180
+ export type SubscriptionCharge = z.infer<typeof subscriptionChargeSchema>
package/src/tokens.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Token metadata + capability descriptor.
3
+ *
4
+ * Read by the SDK's BrowserClient to (1) pick the right meta-tx path
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.
9
+ *
10
+ * `capabilities.permit2612` means the token implements EIP-2612 (the
11
+ * gasless allowance + subscription enrolment path).
12
+ * `capabilities.transferAuth3009` means the token implements EIP-3009
13
+ * (the gasless one-shot payment path).
14
+ *
15
+ * Tokens may have one capability or both — USDC and EURC on Arc
16
+ * advertise both.
17
+ */
18
+
19
+ import { z } from 'zod'
20
+
21
+ const addressSchema = z
22
+ .string()
23
+ .regex(/^0x[0-9a-fA-F]{40}$/u, 'must be a 0x-prefixed 20-byte address')
24
+
25
+ export const tokenCapabilitiesSchema = z.object({
26
+ permit2612: z.boolean(),
27
+ transferAuth3009: z.boolean(),
28
+ })
29
+ export type TokenCapabilities = z.infer<typeof tokenCapabilitiesSchema>
30
+
31
+ export const tokenMetadataSchema = z.object({
32
+ address: addressSchema,
33
+ name: z.string(),
34
+ symbol: z.string(),
35
+ /**
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
39
+ * ecrecover would recover a different address.
40
+ */
41
+ version: z.string(),
42
+ decimals: z.number().int().min(0).max(255),
43
+ capabilities: tokenCapabilitiesSchema,
44
+ })
45
+ export type TokenMetadata = z.infer<typeof tokenMetadataSchema>
46
+
47
+ /**
48
+ * Owner-specific permit nonce. The EIP-2612 standard tracks a per-
49
+ * owner monotonic counter — every successful permit consumes one,
50
+ * so signers must read the current value immediately before signing.
51
+ *
52
+ * Returned as a decimal string to avoid JS number truncation on the
53
+ * uint256 values some long-lived owners can accumulate.
54
+ */
55
+ export const tokenPermitNonceSchema = z.object({
56
+ token: addressSchema,
57
+ owner: addressSchema,
58
+ nonce: z.string().regex(/^[0-9]+$/u, 'must be a decimal integer string'),
59
+ })
60
+ export type TokenPermitNonce = z.infer<typeof tokenPermitNonceSchema>
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Transaction — the record of a confirmed on-chain payment.
3
+ *
4
+ * Every transaction corresponds to either a paid PaymentSession, a
5
+ * SubscriptionCharge, or a Refund. The indexer writes these from the
6
+ * `PaymentExecuted`, `SubscriptionCharged`, and `RefundRecorded` events.
7
+ */
8
+
9
+ import { z } from 'zod'
10
+ import {
11
+ evmAddressSchema,
12
+ evmTxHashSchema,
13
+ idSchema,
14
+ isoTimestampSchema,
15
+ paymentCurrencySchema,
16
+ tokenAmountSchema,
17
+ } from './common.js'
18
+
19
+ export const transactionKindSchema = z.enum([
20
+ 'one_shot',
21
+ 'subscription_charge',
22
+ 'refund',
23
+ 'invoice_payment',
24
+ 'storefront_purchase',
25
+ ])
26
+ export type TransactionKind = z.infer<typeof transactionKindSchema>
27
+
28
+ export const transactionStatusSchema = z.enum(['pending', 'confirmed', 'failed'])
29
+ export type TransactionStatus = z.infer<typeof transactionStatusSchema>
30
+
31
+ export const transactionSchema = z.object({
32
+ id: idSchema,
33
+ merchantId: idSchema,
34
+ kind: transactionKindSchema,
35
+ status: transactionStatusSchema,
36
+ sessionId: idSchema.nullable(),
37
+ subscriptionId: idSchema.nullable(),
38
+ subscriptionChargeId: idSchema.nullable(),
39
+ refundId: idSchema.nullable(),
40
+ customerId: idSchema.nullable(),
41
+ amount: tokenAmountSchema,
42
+ feeAmount: tokenAmountSchema,
43
+ netAmount: tokenAmountSchema,
44
+ currency: paymentCurrencySchema,
45
+ payerAddress: evmAddressSchema,
46
+ merchantAddress: evmAddressSchema,
47
+ onchainTxHash: evmTxHashSchema,
48
+ blockNumber: z.number().int().nonnegative(),
49
+ blockTimestamp: isoTimestampSchema,
50
+ createdAt: isoTimestampSchema,
51
+ })
52
+ export type Transaction = z.infer<typeof transactionSchema>
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Webhook endpoints and deliveries.
3
+ *
4
+ * Endpoint = the URL the merchant registered.
5
+ * Event = the thing that happened.
6
+ * Delivery = one attempt to POST a specific event to a specific endpoint.
7
+ */
8
+
9
+ import { z } from 'zod'
10
+ import { httpsUrlSchema, idSchema, isoTimestampSchema, modeSchema } from './common.js'
11
+
12
+ // ---------- Event name ----------
13
+
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.
17
+ */
18
+ export const webhookEventNameSchema = z.enum([
19
+ 'payment.created',
20
+ 'payment.completed',
21
+ 'payment.failed',
22
+ 'subscription.created',
23
+ 'subscription.charged',
24
+ 'subscription.charge_failed',
25
+ 'subscription.recovery_attempt',
26
+ 'subscription.recovery_outcome',
27
+ 'subscription.cancelled',
28
+ 'subscription.lapsed',
29
+ 'refund.created',
30
+ 'refund.completed',
31
+ 'refund.failed',
32
+ 'invoice.created',
33
+ 'invoice.paid',
34
+ 'invoice.overdue',
35
+ 'agent.action_executed',
36
+ 'agent.job_proposed',
37
+ 'agent.job_completed',
38
+ 'agent.job_disputed',
39
+ 'compliance.wallet_flagged',
40
+ 'compliance.wallet_blocked',
41
+ ])
42
+ export type WebhookEventName = z.infer<typeof webhookEventNameSchema>
43
+
44
+ // ---------- Endpoints ----------
45
+
46
+ export const webhookEndpointStatusSchema = z.enum(['active', 'disabled'])
47
+ export type WebhookEndpointStatus = z.infer<typeof webhookEndpointStatusSchema>
48
+
49
+ export const webhookEndpointSchema = z.object({
50
+ id: idSchema,
51
+ merchantId: idSchema,
52
+ mode: modeSchema,
53
+ url: httpsUrlSchema,
54
+ description: z.string().max(200).nullable(),
55
+ events: z.array(webhookEventNameSchema).nonempty(),
56
+ status: webhookEndpointStatusSchema,
57
+ signingSecretPrefix: z.string().min(4).max(12),
58
+ lastDeliveredAt: isoTimestampSchema.nullable(),
59
+ createdAt: isoTimestampSchema,
60
+ updatedAt: isoTimestampSchema,
61
+ })
62
+ export type WebhookEndpoint = z.infer<typeof webhookEndpointSchema>
63
+
64
+ export const createWebhookEndpointInputSchema = z.object({
65
+ url: httpsUrlSchema,
66
+ events: z.array(webhookEventNameSchema).nonempty(),
67
+ description: z.string().max(200).optional(),
68
+ mode: modeSchema,
69
+ })
70
+ export type CreateWebhookEndpointInput = z.infer<typeof createWebhookEndpointInputSchema>
71
+
72
+ export const createWebhookEndpointOutputSchema = z.object({
73
+ endpoint: webhookEndpointSchema,
74
+ /** Full signing secret — shown exactly once. */
75
+ signingSecret: z.string(),
76
+ })
77
+ export type CreateWebhookEndpointOutput = z.infer<typeof createWebhookEndpointOutputSchema>
78
+
79
+ // ---------- Deliveries ----------
80
+
81
+ export const webhookDeliveryStatusSchema = z.enum([
82
+ 'pending',
83
+ 'delivered',
84
+ 'retrying',
85
+ 'permanently_failed',
86
+ ])
87
+ export type WebhookDeliveryStatus = z.infer<typeof webhookDeliveryStatusSchema>
88
+
89
+ export const webhookDeliverySchema = z.object({
90
+ id: idSchema,
91
+ merchantId: idSchema,
92
+ endpointId: idSchema,
93
+ eventId: idSchema,
94
+ eventName: webhookEventNameSchema,
95
+ status: webhookDeliveryStatusSchema,
96
+ attempt: z.number().int().min(1).max(6),
97
+ responseCode: z.number().int().min(100).max(599).nullable(),
98
+ responseMs: z.number().int().min(0).nullable(),
99
+ lastError: z.string().max(1000).nullable(),
100
+ nextAttemptAt: isoTimestampSchema.nullable(),
101
+ deliveredAt: isoTimestampSchema.nullable(),
102
+ createdAt: isoTimestampSchema,
103
+ })
104
+ export type WebhookDelivery = z.infer<typeof webhookDeliverySchema>
105
+
106
+ export const replayDeliveryInputSchema = z.object({
107
+ id: idSchema,
108
+ })
109
+ export type ReplayDeliveryInput = z.infer<typeof replayDeliveryInputSchema>