@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.
- package/LICENSE +201 -0
- package/README.md +258 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +3 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +206 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +566 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +36 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +215 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +3 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/private.d.ts +71 -0
- package/dist/component/private.d.ts.map +1 -0
- package/dist/component/private.js +250 -0
- package/dist/component/private.js.map +1 -0
- package/dist/component/public.d.ts +170 -0
- package/dist/component/public.d.ts.map +1 -0
- package/dist/component/public.js +210 -0
- package/dist/component/public.js.map +1 -0
- package/dist/component/schema.d.ts +101 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +63 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/react/hooks.d.ts +182 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +215 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +104 -0
- package/src/client/_generated/_ignore.ts +1 -0
- package/src/client/index.test.ts +196 -0
- package/src/client/index.ts +823 -0
- package/src/client/setup.test.ts +26 -0
- package/src/client/webhooks.test.ts +182 -0
- package/src/component/_generated/api.ts +52 -0
- package/src/component/_generated/component.ts +293 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/private.ts +277 -0
- package/src/component/public.test.ts +92 -0
- package/src/component/public.ts +229 -0
- package/src/component/schema.ts +67 -0
- package/src/component/setup.test.ts +11 -0
- package/src/react/hooks.ts +488 -0
- package/src/react/index.ts +18 -0
- 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", () => {});
|