@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,26 @@
1
+ /// <reference types="vite/client" />
2
+ import { test } from "vitest";
3
+ import { convexTest } from "convex-test";
4
+ export const modules = import.meta.glob("./**/*.*s");
5
+
6
+ import {
7
+ defineSchema,
8
+ type GenericSchema,
9
+ type SchemaDefinition,
10
+ } from "convex/server";
11
+ import { type ComponentApi } from "../component/_generated/component.js";
12
+ import { componentsGeneric } from "convex/server";
13
+ import { register } from "../test.js";
14
+
15
+ export function initConvexTest<
16
+ Schema extends SchemaDefinition<GenericSchema, boolean>,
17
+ >(schema?: Schema) {
18
+ const t = convexTest(schema ?? defineSchema({}), modules);
19
+ register(t);
20
+ return t;
21
+ }
22
+ export const components = componentsGeneric() as unknown as {
23
+ adyenPayments: ComponentApi;
24
+ };
25
+
26
+ test("setup", () => {});
@@ -0,0 +1,182 @@
1
+ import { describe, expect, test, vi, beforeEach } from "vitest";
2
+ import type { HttpRouter } from "convex/server";
3
+ import { registerRoutes, type ActionCtx } from "./index.js";
4
+ import { components, initConvexTest } from "./setup.test.js";
5
+
6
+ // Mock the Adyen SDK hmacValidator
7
+ vi.mock("@adyen/api-library", () => {
8
+ class HmacValidatorMock {
9
+ validateHMAC = vi.fn().mockReturnValue(true);
10
+ validateBankingHMAC = vi.fn().mockReturnValue(true);
11
+ }
12
+ return {
13
+ Client: vi.fn(),
14
+ CheckoutAPI: vi.fn(),
15
+ hmacValidator: HmacValidatorMock,
16
+ };
17
+ });
18
+
19
+ describe("Adyen webhook processing tests", () => {
20
+ beforeEach(() => {
21
+ process.env.ADYEN_HMAC_KEY = "test_hmac_key";
22
+ });
23
+
24
+ test("route registration and authorisation success with tokenization", async () => {
25
+ const t = initConvexTest();
26
+
27
+ // Register routes with a mock HTTP router
28
+ const routes: Array<{ path: string; method: string; handler: (...args: any[]) => any }> = [];
29
+ const mockHttp = {
30
+ route: (r: { path: string; method: string; handler: (...args: any[]) => any }) => {
31
+ routes.push(r);
32
+ },
33
+ } as unknown as HttpRouter;
34
+
35
+ const onNotificationSpy = vi.fn();
36
+ const customAuthorisationSpy = vi.fn();
37
+
38
+ registerRoutes(mockHttp, components.adyenPayments, {
39
+ webhookPath: "/adyen/webhooks",
40
+ events: {
41
+ AUTHORISATION: customAuthorisationSpy,
42
+ },
43
+ onNotification: onNotificationSpy,
44
+ });
45
+
46
+ expect(routes).toHaveLength(1);
47
+ expect(routes[0].path).toBe("/adyen/webhooks");
48
+ expect(routes[0].method).toBe("POST");
49
+
50
+ const handler = routes[0].handler;
51
+
52
+ // Simulate an AUTHORISATION notification containing token details
53
+ const request = new Request("https://example.com/adyen/webhooks", {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ },
58
+ body: JSON.stringify({
59
+ notificationItems: [
60
+ {
61
+ NotificationRequestItem: {
62
+ eventCode: "AUTHORISATION",
63
+ pspReference: "psp_auth_1",
64
+ merchantReference: "order_123",
65
+ success: "true",
66
+ amount: { value: 5000, currency: "USD" },
67
+ shopperReference: "user_abc",
68
+ paymentMethod: "visa",
69
+ additionalData: {
70
+ hmacSignature: "mock_signature",
71
+ "recurring.recurringDetailReference": "token_xyz",
72
+ cardSummary: "1111",
73
+ expiryDate: "12/2030",
74
+ paymentMethod: "visa",
75
+ },
76
+ },
77
+ },
78
+ ],
79
+ }),
80
+ });
81
+
82
+ const response = await handler(t as unknown as ActionCtx, request);
83
+ expect(response.status).toBe(200);
84
+ expect(await response.text()).toBe("[accepted]");
85
+
86
+ // Verify DB states: payment transaction was recorded
87
+ const payment = await t.query(components.adyenPayments.public.getPayment, {
88
+ pspReference: "psp_auth_1",
89
+ });
90
+ expect(payment).not.toBeNull();
91
+ expect(payment!.status).toBe("authorised");
92
+ expect(payment!.amount).toBe(5000);
93
+ expect(payment!.shopperReference).toBe("user_abc");
94
+
95
+ // Verify DB states: payment method card was tokenized
96
+ const methods = await t.query(components.adyenPayments.public.listPaymentMethods, {
97
+ shopperReference: "user_abc",
98
+ });
99
+ expect(methods).toHaveLength(1);
100
+ expect(methods[0].recurringDetailReference).toBe("token_xyz");
101
+ expect(methods[0].cardLast4).toBe("1111");
102
+ expect(methods[0].cardExpiryMonth).toBe("12");
103
+ expect(methods[0].cardExpiryYear).toBe("2030");
104
+
105
+ // Verify custom handlers were triggered
106
+ expect(onNotificationSpy).toHaveBeenCalledOnce();
107
+ expect(customAuthorisationSpy).toHaveBeenCalledOnce();
108
+ });
109
+
110
+ test("modification notifications (CAPTURE, REFUND, CANCEL)", async () => {
111
+ const t = initConvexTest();
112
+
113
+ // Seed an authorised payment in the database
114
+ await t.mutation(components.adyenPayments.private.recordPayment, {
115
+ pspReference: "psp_auth_2",
116
+ merchantReference: "order_456",
117
+ amount: 1000,
118
+ currency: "EUR",
119
+ status: "authorised",
120
+ shopperReference: "user_def",
121
+ });
122
+
123
+ const routes: Array<{ path: string; method: string; handler: (...args: any[]) => any }> = [];
124
+ const mockHttp = {
125
+ route: (r: { path: string; method: string; handler: (...args: any[]) => any }) => {
126
+ routes.push(r);
127
+ },
128
+ } as unknown as HttpRouter;
129
+ registerRoutes(mockHttp, components.adyenPayments);
130
+ const handler = routes[0].handler;
131
+
132
+ // 1. CAPTURE webhook
133
+ const captureRequest = new Request("https://example.com/adyen/webhooks", {
134
+ method: "POST",
135
+ body: JSON.stringify({
136
+ notificationItems: [
137
+ {
138
+ NotificationRequestItem: {
139
+ eventCode: "CAPTURE",
140
+ pspReference: "psp_cap_2",
141
+ originalReference: "psp_auth_2",
142
+ merchantReference: "order_456",
143
+ success: "true",
144
+ amount: { value: 1000, currency: "EUR" },
145
+ },
146
+ },
147
+ ],
148
+ }),
149
+ });
150
+ await handler(t as unknown as ActionCtx, captureRequest);
151
+
152
+ const capturedPayment = await t.query(components.adyenPayments.public.getPayment, {
153
+ pspReference: "psp_auth_2",
154
+ });
155
+ expect(capturedPayment!.status).toBe("captured");
156
+
157
+ // 2. REFUND webhook
158
+ const refundRequest = new Request("https://example.com/adyen/webhooks", {
159
+ method: "POST",
160
+ body: JSON.stringify({
161
+ notificationItems: [
162
+ {
163
+ NotificationRequestItem: {
164
+ eventCode: "REFUND",
165
+ pspReference: "psp_ref_2",
166
+ originalReference: "psp_auth_2",
167
+ merchantReference: "order_456",
168
+ success: "true",
169
+ amount: { value: 1000, currency: "EUR" },
170
+ },
171
+ },
172
+ ],
173
+ }),
174
+ });
175
+ await handler(t as unknown as ActionCtx, refundRequest);
176
+
177
+ const refundedPayment = await t.query(components.adyenPayments.public.getPayment, {
178
+ pspReference: "psp_auth_2",
179
+ });
180
+ expect(refundedPayment!.status).toBe("refunded");
181
+ });
182
+ });
@@ -0,0 +1,52 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `api` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type * as private_ from "../private.js";
12
+ import type * as public_ from "../public.js";
13
+
14
+ import type {
15
+ ApiFromModules,
16
+ FilterApi,
17
+ FunctionReference,
18
+ } from "convex/server";
19
+ import { anyApi, componentsGeneric } from "convex/server";
20
+
21
+ const fullApi: ApiFromModules<{
22
+ private: typeof private_;
23
+ public: typeof public_;
24
+ }> = anyApi as any;
25
+
26
+ /**
27
+ * A utility for referencing Convex functions in your app's public API.
28
+ *
29
+ * Usage:
30
+ * ```js
31
+ * const myFunctionReference = api.myModule.myFunction;
32
+ * ```
33
+ */
34
+ export const api: FilterApi<
35
+ typeof fullApi,
36
+ FunctionReference<any, "public">
37
+ > = anyApi as any;
38
+
39
+ /**
40
+ * A utility for referencing Convex functions in your app's internal API.
41
+ *
42
+ * Usage:
43
+ * ```js
44
+ * const myFunctionReference = internal.myModule.myFunction;
45
+ * ```
46
+ */
47
+ export const internal: FilterApi<
48
+ typeof fullApi,
49
+ FunctionReference<any, "internal">
50
+ > = anyApi as any;
51
+
52
+ export const components = componentsGeneric() as unknown as {};
@@ -0,0 +1,293 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `ComponentApi` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type { FunctionReference } from "convex/server";
12
+
13
+ /**
14
+ * A utility for referencing a Convex component's exposed API.
15
+ *
16
+ * Useful when expecting a parameter like `components.myComponent`.
17
+ * Usage:
18
+ * ```ts
19
+ * async function myFunction(ctx: QueryCtx, component: ComponentApi) {
20
+ * return ctx.runQuery(component.someFile.someQuery, { ...args });
21
+ * }
22
+ * ```
23
+ */
24
+ export type ComponentApi<Name extends string | undefined = string | undefined> =
25
+ {
26
+ private: {
27
+ insertCheckoutSession: FunctionReference<
28
+ "mutation",
29
+ "internal",
30
+ {
31
+ amount: number;
32
+ autoCapture?: boolean;
33
+ currency: string;
34
+ merchantReference: string;
35
+ sessionData: string;
36
+ sessionId: string;
37
+ shopperReference?: string;
38
+ url?: string;
39
+ },
40
+ null,
41
+ Name
42
+ >;
43
+ insertPaymentMethod: FunctionReference<
44
+ "mutation",
45
+ "internal",
46
+ {
47
+ cardExpiryMonth?: string;
48
+ cardExpiryYear?: string;
49
+ cardLast4?: string;
50
+ metadata?: any;
51
+ recurringDetailReference: string;
52
+ shopperReference: string;
53
+ variant: string;
54
+ },
55
+ null,
56
+ Name
57
+ >;
58
+ recordPayment: FunctionReference<
59
+ "mutation",
60
+ "internal",
61
+ {
62
+ amount: number;
63
+ currency: string;
64
+ merchantReference: string;
65
+ metadata?: any;
66
+ orgId?: string;
67
+ originalReference?: string;
68
+ paymentMethod?: string;
69
+ pspReference: string;
70
+ shopperReference?: string;
71
+ status: string;
72
+ userId?: string;
73
+ },
74
+ null,
75
+ Name
76
+ >;
77
+ syncPaymentMethods: FunctionReference<
78
+ "mutation",
79
+ "internal",
80
+ {
81
+ paymentMethods: Array<{
82
+ cardExpiryMonth?: string;
83
+ cardExpiryYear?: string;
84
+ cardLast4?: string;
85
+ metadata?: any;
86
+ recurringDetailReference: string;
87
+ variant: string;
88
+ }>;
89
+ shopperReference: string;
90
+ },
91
+ null,
92
+ Name
93
+ >;
94
+ updateCheckoutSessionStatus: FunctionReference<
95
+ "mutation",
96
+ "internal",
97
+ { merchantReference: string; status: string },
98
+ null,
99
+ Name
100
+ >;
101
+ updatePaymentStatus: FunctionReference<
102
+ "mutation",
103
+ "internal",
104
+ { originalReference?: string; pspReference: string; status: string },
105
+ null,
106
+ Name
107
+ >;
108
+ };
109
+ public: {
110
+ createOrUpdateShopper: FunctionReference<
111
+ "mutation",
112
+ "internal",
113
+ {
114
+ email?: string;
115
+ metadata?: any;
116
+ name?: string;
117
+ shopperReference: string;
118
+ userId?: string;
119
+ },
120
+ string,
121
+ Name
122
+ >;
123
+ getCheckoutSession: FunctionReference<
124
+ "query",
125
+ "internal",
126
+ { sessionId: string },
127
+ {
128
+ amount: number;
129
+ autoCapture?: boolean;
130
+ currency: string;
131
+ merchantReference: string;
132
+ sessionData: string;
133
+ sessionId: string;
134
+ shopperReference?: string;
135
+ status: string;
136
+ url?: string;
137
+ } | null,
138
+ Name
139
+ >;
140
+ getCheckoutSessionByMerchantReference: FunctionReference<
141
+ "query",
142
+ "internal",
143
+ { merchantReference: string },
144
+ {
145
+ amount: number;
146
+ autoCapture?: boolean;
147
+ currency: string;
148
+ merchantReference: string;
149
+ sessionData: string;
150
+ sessionId: string;
151
+ shopperReference?: string;
152
+ status: string;
153
+ url?: string;
154
+ } | null,
155
+ Name
156
+ >;
157
+ getPayment: FunctionReference<
158
+ "query",
159
+ "internal",
160
+ { pspReference: string },
161
+ {
162
+ amount: number;
163
+ created: number;
164
+ currency: string;
165
+ merchantReference: string;
166
+ metadata?: any;
167
+ orgId?: string;
168
+ originalReference?: string;
169
+ paymentMethod?: string;
170
+ pspReference: string;
171
+ shopperReference?: string;
172
+ status: string;
173
+ userId?: string;
174
+ } | null,
175
+ Name
176
+ >;
177
+ getShopper: FunctionReference<
178
+ "query",
179
+ "internal",
180
+ { shopperReference: string },
181
+ {
182
+ email?: string;
183
+ metadata?: any;
184
+ name?: string;
185
+ shopperReference: string;
186
+ userId?: string;
187
+ } | null,
188
+ Name
189
+ >;
190
+ getShopperByEmail: FunctionReference<
191
+ "query",
192
+ "internal",
193
+ { email: string },
194
+ {
195
+ email?: string;
196
+ metadata?: any;
197
+ name?: string;
198
+ shopperReference: string;
199
+ userId?: string;
200
+ } | null,
201
+ Name
202
+ >;
203
+ getShopperByUserId: FunctionReference<
204
+ "query",
205
+ "internal",
206
+ { userId: string },
207
+ {
208
+ email?: string;
209
+ metadata?: any;
210
+ name?: string;
211
+ shopperReference: string;
212
+ userId?: string;
213
+ } | null,
214
+ Name
215
+ >;
216
+ listPaymentMethods: FunctionReference<
217
+ "query",
218
+ "internal",
219
+ { shopperReference: string },
220
+ Array<{
221
+ cardExpiryMonth?: string;
222
+ cardExpiryYear?: string;
223
+ cardLast4?: string;
224
+ metadata?: any;
225
+ recurringDetailReference: string;
226
+ shopperReference: string;
227
+ status: string;
228
+ variant: string;
229
+ }>,
230
+ Name
231
+ >;
232
+ listPayments: FunctionReference<
233
+ "query",
234
+ "internal",
235
+ { shopperReference: string },
236
+ Array<{
237
+ amount: number;
238
+ created: number;
239
+ currency: string;
240
+ merchantReference: string;
241
+ metadata?: any;
242
+ orgId?: string;
243
+ originalReference?: string;
244
+ paymentMethod?: string;
245
+ pspReference: string;
246
+ shopperReference?: string;
247
+ status: string;
248
+ userId?: string;
249
+ }>,
250
+ Name
251
+ >;
252
+ listPaymentsByOrgId: FunctionReference<
253
+ "query",
254
+ "internal",
255
+ { orgId: string },
256
+ Array<{
257
+ amount: number;
258
+ created: number;
259
+ currency: string;
260
+ merchantReference: string;
261
+ metadata?: any;
262
+ orgId?: string;
263
+ originalReference?: string;
264
+ paymentMethod?: string;
265
+ pspReference: string;
266
+ shopperReference?: string;
267
+ status: string;
268
+ userId?: string;
269
+ }>,
270
+ Name
271
+ >;
272
+ listPaymentsByUserId: FunctionReference<
273
+ "query",
274
+ "internal",
275
+ { userId: string },
276
+ Array<{
277
+ amount: number;
278
+ created: number;
279
+ currency: string;
280
+ merchantReference: string;
281
+ metadata?: any;
282
+ orgId?: string;
283
+ originalReference?: string;
284
+ paymentMethod?: string;
285
+ pspReference: string;
286
+ shopperReference?: string;
287
+ status: string;
288
+ userId?: string;
289
+ }>,
290
+ Name
291
+ >;
292
+ };
293
+ };
@@ -0,0 +1,60 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated data model types.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type {
12
+ DataModelFromSchemaDefinition,
13
+ DocumentByName,
14
+ TableNamesInDataModel,
15
+ SystemTableNames,
16
+ } from "convex/server";
17
+ import type { GenericId } from "convex/values";
18
+ import schema from "../schema.js";
19
+
20
+ /**
21
+ * The names of all of your Convex tables.
22
+ */
23
+ export type TableNames = TableNamesInDataModel<DataModel>;
24
+
25
+ /**
26
+ * The type of a document stored in Convex.
27
+ *
28
+ * @typeParam TableName - A string literal type of the table name (like "users").
29
+ */
30
+ export type Doc<TableName extends TableNames> = DocumentByName<
31
+ DataModel,
32
+ TableName
33
+ >;
34
+
35
+ /**
36
+ * An identifier for a document in Convex.
37
+ *
38
+ * Convex documents are uniquely identified by their `Id`, which is accessible
39
+ * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
40
+ *
41
+ * Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.
42
+ *
43
+ * IDs are just strings at runtime, but this type can be used to distinguish them from other
44
+ * strings when type checking.
45
+ *
46
+ * @typeParam TableName - A string literal type of the table name (like "users").
47
+ */
48
+ export type Id<TableName extends TableNames | SystemTableNames> =
49
+ GenericId<TableName>;
50
+
51
+ /**
52
+ * A type describing your Convex data model.
53
+ *
54
+ * This type includes information about what tables you have, the type of
55
+ * documents stored in those tables, and the indexes defined on them.
56
+ *
57
+ * This type is used to parameterize methods like `queryGeneric` and
58
+ * `mutationGeneric` to make them type-safe.
59
+ */
60
+ export type DataModel = DataModelFromSchemaDefinition<typeof schema>;