@abdssamie/adyen-payments 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 (69) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +258 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/index.d.ts +206 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +566 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/component/_generated/api.d.ts +36 -0
  12. package/dist/component/_generated/api.d.ts.map +1 -0
  13. package/dist/component/_generated/api.js +31 -0
  14. package/dist/component/_generated/api.js.map +1 -0
  15. package/dist/component/_generated/component.d.ts +215 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -0
  17. package/dist/component/_generated/component.js +11 -0
  18. package/dist/component/_generated/component.js.map +1 -0
  19. package/dist/component/_generated/dataModel.d.ts +46 -0
  20. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  21. package/dist/component/_generated/dataModel.js +11 -0
  22. package/dist/component/_generated/dataModel.js.map +1 -0
  23. package/dist/component/_generated/server.d.ts +121 -0
  24. package/dist/component/_generated/server.d.ts.map +1 -0
  25. package/dist/component/_generated/server.js +78 -0
  26. package/dist/component/_generated/server.js.map +1 -0
  27. package/dist/component/convex.config.d.ts +3 -0
  28. package/dist/component/convex.config.d.ts.map +1 -0
  29. package/dist/component/convex.config.js +3 -0
  30. package/dist/component/convex.config.js.map +1 -0
  31. package/dist/component/private.d.ts +71 -0
  32. package/dist/component/private.d.ts.map +1 -0
  33. package/dist/component/private.js +250 -0
  34. package/dist/component/private.js.map +1 -0
  35. package/dist/component/public.d.ts +170 -0
  36. package/dist/component/public.d.ts.map +1 -0
  37. package/dist/component/public.js +210 -0
  38. package/dist/component/public.js.map +1 -0
  39. package/dist/component/schema.d.ts +101 -0
  40. package/dist/component/schema.d.ts.map +1 -0
  41. package/dist/component/schema.js +63 -0
  42. package/dist/component/schema.js.map +1 -0
  43. package/dist/react/hooks.d.ts +182 -0
  44. package/dist/react/hooks.d.ts.map +1 -0
  45. package/dist/react/hooks.js +215 -0
  46. package/dist/react/hooks.js.map +1 -0
  47. package/dist/react/index.d.ts +3 -0
  48. package/dist/react/index.d.ts.map +1 -0
  49. package/dist/react/index.js +3 -0
  50. package/dist/react/index.js.map +1 -0
  51. package/package.json +104 -0
  52. package/src/client/_generated/_ignore.ts +1 -0
  53. package/src/client/index.test.ts +196 -0
  54. package/src/client/index.ts +823 -0
  55. package/src/client/setup.test.ts +26 -0
  56. package/src/client/webhooks.test.ts +182 -0
  57. package/src/component/_generated/api.ts +52 -0
  58. package/src/component/_generated/component.ts +293 -0
  59. package/src/component/_generated/dataModel.ts +60 -0
  60. package/src/component/_generated/server.ts +156 -0
  61. package/src/component/convex.config.ts +3 -0
  62. package/src/component/private.ts +277 -0
  63. package/src/component/public.test.ts +92 -0
  64. package/src/component/public.ts +229 -0
  65. package/src/component/schema.ts +67 -0
  66. package/src/component/setup.test.ts +11 -0
  67. package/src/react/hooks.ts +488 -0
  68. package/src/react/index.ts +18 -0
  69. package/src/test.ts +18 -0
@@ -0,0 +1,229 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server.js";
3
+ import schema from "./schema.js";
4
+
5
+ // Reusable validators that omit system fields (_id, _creationTime)
6
+ const shopperValidator = schema.tables.shoppers.validator;
7
+ const paymentMethodValidator = schema.tables.payment_methods.validator;
8
+ const paymentValidator = schema.tables.payments.validator;
9
+ const checkoutSessionValidator = schema.tables.checkout_sessions.validator;
10
+
11
+ // ============================================================================
12
+ // PUBLIC QUERIES
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Get a shopper by their shopperReference.
17
+ */
18
+ export const getShopper = query({
19
+ args: { shopperReference: v.string() },
20
+ returns: v.union(shopperValidator, v.null()),
21
+ handler: async (ctx, args) => {
22
+ const shopper = await ctx.db
23
+ .query("shoppers")
24
+ .withIndex("by_shopper_reference", (q) =>
25
+ q.eq("shopperReference", args.shopperReference)
26
+ )
27
+ .unique();
28
+ if (!shopper) return null;
29
+ const { _id, _creationTime, ...data } = shopper;
30
+ return data;
31
+ },
32
+ });
33
+
34
+ /**
35
+ * Get a shopper by their email address.
36
+ */
37
+ export const getShopperByEmail = query({
38
+ args: { email: v.string() },
39
+ returns: v.union(shopperValidator, v.null()),
40
+ handler: async (ctx, args) => {
41
+ const shopper = await ctx.db
42
+ .query("shoppers")
43
+ .withIndex("by_email", (q) => q.eq("email", args.email))
44
+ .first();
45
+ if (!shopper) return null;
46
+ const { _id, _creationTime, ...data } = shopper;
47
+ return data;
48
+ },
49
+ });
50
+
51
+ /**
52
+ * Get a shopper by their user ID.
53
+ */
54
+ export const getShopperByUserId = query({
55
+ args: { userId: v.string() },
56
+ returns: v.union(shopperValidator, v.null()),
57
+ handler: async (ctx, args) => {
58
+ const shopper = await ctx.db
59
+ .query("shoppers")
60
+ .withIndex("by_user_id", (q) => q.eq("userId", args.userId))
61
+ .first();
62
+ if (!shopper) return null;
63
+ const { _id, _creationTime, ...data } = shopper;
64
+ return data;
65
+ },
66
+ });
67
+
68
+ /**
69
+ * Get a payment transaction by its PSP reference.
70
+ */
71
+ export const getPayment = query({
72
+ args: { pspReference: v.string() },
73
+ returns: v.union(paymentValidator, v.null()),
74
+ handler: async (ctx, args) => {
75
+ const payment = await ctx.db
76
+ .query("payments")
77
+ .withIndex("by_psp_reference", (q) =>
78
+ q.eq("pspReference", args.pspReference)
79
+ )
80
+ .unique();
81
+ if (!payment) return null;
82
+ const { _id, _creationTime, ...data } = payment;
83
+ return data;
84
+ },
85
+ });
86
+
87
+ /**
88
+ * List all payments for a shopper.
89
+ */
90
+ export const listPayments = query({
91
+ args: { shopperReference: v.string() },
92
+ returns: v.array(paymentValidator),
93
+ handler: async (ctx, args) => {
94
+ const payments = await ctx.db
95
+ .query("payments")
96
+ .withIndex("by_shopper_reference", (q) =>
97
+ q.eq("shopperReference", args.shopperReference)
98
+ )
99
+ .collect();
100
+ return payments.map(({ _id, _creationTime, ...data }) => data);
101
+ },
102
+ });
103
+
104
+ /**
105
+ * List all payments for an organization ID.
106
+ */
107
+ export const listPaymentsByOrgId = query({
108
+ args: { orgId: v.string() },
109
+ returns: v.array(paymentValidator),
110
+ handler: async (ctx, args) => {
111
+ const payments = await ctx.db
112
+ .query("payments")
113
+ .withIndex("by_org_id", (q) => q.eq("orgId", args.orgId))
114
+ .collect();
115
+ return payments.map(({ _id, _creationTime, ...data }) => data);
116
+ },
117
+ });
118
+
119
+ /**
120
+ * List all payments for a user ID.
121
+ */
122
+ export const listPaymentsByUserId = query({
123
+ args: { userId: v.string() },
124
+ returns: v.array(paymentValidator),
125
+ handler: async (ctx, args) => {
126
+ const payments = await ctx.db
127
+ .query("payments")
128
+ .withIndex("by_user_id", (q) => q.eq("userId", args.userId))
129
+ .collect();
130
+ return payments.map(({ _id, _creationTime, ...data }) => data);
131
+ },
132
+ });
133
+
134
+ /**
135
+ * List stored payment methods for a shopper.
136
+ */
137
+ export const listPaymentMethods = query({
138
+ args: { shopperReference: v.string() },
139
+ returns: v.array(paymentMethodValidator),
140
+ handler: async (ctx, args) => {
141
+ const methods = await ctx.db
142
+ .query("payment_methods")
143
+ .withIndex("by_shopper_reference", (q) =>
144
+ q.eq("shopperReference", args.shopperReference)
145
+ )
146
+ .collect();
147
+ return methods.map(({ _id, _creationTime, ...data }) => data);
148
+ },
149
+ });
150
+
151
+ /**
152
+ * Get a checkout session by its session ID.
153
+ */
154
+ export const getCheckoutSession = query({
155
+ args: { sessionId: v.string() },
156
+ returns: v.union(checkoutSessionValidator, v.null()),
157
+ handler: async (ctx, args) => {
158
+ const session = await ctx.db
159
+ .query("checkout_sessions")
160
+ .withIndex("by_session_id", (q) => q.eq("sessionId", args.sessionId))
161
+ .unique();
162
+ if (!session) return null;
163
+ const { _id, _creationTime, ...data } = session;
164
+ return data;
165
+ },
166
+ });
167
+
168
+ // ============================================================================
169
+ // PUBLIC MUTATIONS
170
+ // ============================================================================
171
+
172
+ /**
173
+ * Create or update a shopper mapping with optional metadata.
174
+ */
175
+ export const createOrUpdateShopper = mutation({
176
+ args: {
177
+ shopperReference: v.string(),
178
+ email: v.optional(v.string()),
179
+ name: v.optional(v.string()),
180
+ userId: v.optional(v.string()),
181
+ metadata: v.optional(v.any()),
182
+ },
183
+ returns: v.string(),
184
+ handler: async (ctx, args) => {
185
+ const existing = await ctx.db
186
+ .query("shoppers")
187
+ .withIndex("by_shopper_reference", (q) =>
188
+ q.eq("shopperReference", args.shopperReference)
189
+ )
190
+ .unique();
191
+
192
+ if (existing) {
193
+ await ctx.db.patch("shoppers", existing._id, {
194
+ ...(args.email !== undefined && { email: args.email }),
195
+ ...(args.name !== undefined && { name: args.name }),
196
+ ...(args.userId !== undefined && { userId: args.userId }),
197
+ ...(args.metadata !== undefined && { metadata: args.metadata }),
198
+ });
199
+ } else {
200
+ await ctx.db.insert("shoppers", {
201
+ shopperReference: args.shopperReference,
202
+ email: args.email,
203
+ name: args.name,
204
+ userId: args.userId,
205
+ metadata: args.metadata,
206
+ });
207
+ }
208
+ return args.shopperReference;
209
+ },
210
+ });
211
+
212
+ /**
213
+ * Get a checkout session by its merchantReference.
214
+ */
215
+ export const getCheckoutSessionByMerchantReference = query({
216
+ args: { merchantReference: v.string() },
217
+ returns: v.union(checkoutSessionValidator, v.null()),
218
+ handler: async (ctx, args) => {
219
+ const session = await ctx.db
220
+ .query("checkout_sessions")
221
+ .withIndex("by_merchant_reference", (q) =>
222
+ q.eq("merchantReference", args.merchantReference)
223
+ )
224
+ .unique();
225
+ if (!session) return null;
226
+ const { _id, _creationTime, ...data } = session;
227
+ return data;
228
+ },
229
+ });
@@ -0,0 +1,67 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+
4
+ export default defineSchema({
5
+ shoppers: defineTable({
6
+ shopperReference: v.string(), // Unique key defined by the merchant (e.g. userId)
7
+ email: v.optional(v.string()),
8
+ name: v.optional(v.string()),
9
+ userId: v.optional(v.string()),
10
+ metadata: v.optional(v.any()),
11
+ })
12
+ .index("by_shopper_reference", ["shopperReference"])
13
+ .index("by_email", ["email"])
14
+ .index("by_user_id", ["userId"]),
15
+
16
+ // Tokenized payment instruments (stored details)
17
+ payment_methods: defineTable({
18
+ shopperReference: v.string(),
19
+ recurringDetailReference: v.string(), // Token used for recurring charges
20
+ variant: v.string(), // e.g. "visa", "mc", "ideal"
21
+ cardLast4: v.optional(v.string()),
22
+ cardExpiryMonth: v.optional(v.string()),
23
+ cardExpiryYear: v.optional(v.string()),
24
+ status: v.string(), // "active" or "disabled"
25
+ metadata: v.optional(v.any()),
26
+ })
27
+ .index("by_recurring_detail_reference", ["recurringDetailReference"])
28
+ .index("by_shopper_reference", ["shopperReference"]),
29
+
30
+ // Transaction history synced from webhooks
31
+ payments: defineTable({
32
+ pspReference: v.string(), // Adyen transaction ID
33
+ originalReference: v.optional(v.string()), // For refunds/captures referencing the auth
34
+ shopperReference: v.optional(v.string()),
35
+ merchantReference: v.string(), // App's order reference
36
+ amount: v.number(), // Value in minor units (e.g. cents)
37
+ currency: v.string(),
38
+ status: v.string(), // "authorised", "captured", "refused", "cancelled", "refunded"
39
+ paymentMethod: v.optional(v.string()),
40
+ created: v.number(),
41
+ userId: v.optional(v.string()),
42
+ orgId: v.optional(v.string()),
43
+ metadata: v.optional(v.any()),
44
+ })
45
+ .index("by_psp_reference", ["pspReference"])
46
+ .index("by_shopper_reference", ["shopperReference"])
47
+ .index("by_merchant_reference", ["merchantReference"])
48
+ .index("by_user_id", ["userId"])
49
+ .index("by_org_id", ["orgId"]),
50
+
51
+ // Checkout sessions for payment initialization
52
+ checkout_sessions: defineTable({
53
+ sessionId: v.string(),
54
+ sessionData: v.string(), // Frontend config string
55
+ shopperReference: v.optional(v.string()),
56
+ merchantReference: v.string(),
57
+ status: v.string(), // "active" or "completed"
58
+ amount: v.number(),
59
+ currency: v.string(),
60
+ url: v.optional(v.string()), // Hosted Checkout URL (if applicable)
61
+ autoCapture: v.optional(v.boolean()),
62
+ })
63
+ .index("by_session_id", ["sessionId"])
64
+ .index("by_shopper_reference", ["shopperReference"])
65
+ .index("by_merchant_reference", ["merchantReference"]),
66
+ });
67
+
@@ -0,0 +1,11 @@
1
+ /// <reference types="vite/client" />
2
+ import { test } from "vitest";
3
+ import schema from "./schema.js";
4
+ import { convexTest } from "convex-test";
5
+ export const modules = import.meta.glob("./**/*.*s");
6
+
7
+ export function initConvexTest() {
8
+ const t = convexTest(schema, modules);
9
+ return t;
10
+ }
11
+ test("setup", () => {});