@diviswap/sdk 1.7.6
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 +21 -0
- package/README.md +510 -0
- package/bin/create-diviswap-app.js +25 -0
- package/bin/diviswap-sdk.js +4 -0
- package/dist/cli/index.js +1888 -0
- package/dist/cli/templates/nextjs-app/actions.ts.hbs +259 -0
- package/dist/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
- package/dist/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
- package/dist/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
- package/dist/cli/templates/nextjs-app/client.ts.hbs +116 -0
- package/dist/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
- package/dist/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
- package/dist/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
- package/dist/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
- package/dist/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
- package/dist/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
- package/dist/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
- package/dist/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
- package/dist/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
- package/dist/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
- package/dist/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
- package/dist/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
- package/dist/cli/templates/nextjs-app/types.ts.hbs +159 -0
- package/dist/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
- package/dist/cli/templates/react/example.tsx.hbs +69 -0
- package/dist/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
- package/dist/cli/templates/webhooks/nextjs.hbs +98 -0
- package/dist/index.d.mts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +2339 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2313 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +192 -0
- package/dist/react/index.d.ts +192 -0
- package/dist/react/index.js +1083 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +1064 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/wallet-BEGvzNtB.d.mts +1614 -0
- package/dist/wallet-BEGvzNtB.d.ts +1614 -0
- package/package.json +102 -0
- package/src/cli/templates/index.ts +65 -0
- package/src/cli/templates/nextjs-app/actions.ts.hbs +259 -0
- package/src/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
- package/src/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
- package/src/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
- package/src/cli/templates/nextjs-app/client.ts.hbs +116 -0
- package/src/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
- package/src/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
- package/src/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
- package/src/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
- package/src/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
- package/src/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
- package/src/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
- package/src/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
- package/src/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
- package/src/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
- package/src/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
- package/src/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
- package/src/cli/templates/nextjs-app/types.ts.hbs +159 -0
- package/src/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
- package/src/cli/templates/react/example.tsx.hbs +69 -0
- package/src/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
- package/src/cli/templates/shared/client.ts +78 -0
- package/src/cli/templates/webhooks/nextjs.hbs +98 -0
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { Diviswap } from '@diviswap/sdk';
|
|
3
|
+
import { cookies } from 'next/headers';
|
|
4
|
+
import type { Diviswap as DiviswapType } from '@diviswap/sdk';
|
|
5
|
+
|
|
6
|
+
// Initialize Diviswap SDK with partner authentication
|
|
7
|
+
function getDiviswap() {
|
|
8
|
+
const config = {
|
|
9
|
+
mode: 'partner' as const,
|
|
10
|
+
keyId: process.env.DIVISWAP_PARTNER_KEY_ID!,
|
|
11
|
+
secretKey: process.env.DIVISWAP_PARTNER_SECRET_KEY!,
|
|
12
|
+
authMethod: 'hmac' as const,
|
|
13
|
+
environment: (process.env.NEXT_PUBLIC_DIVISWAP_ENV as 'production' | 'sandbox') || 'sandbox'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
return Diviswap.init(config);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Helper function to handle errors
|
|
20
|
+
function handleError(error: unknown) {
|
|
21
|
+
console.error('Diviswap API error:', error);
|
|
22
|
+
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
return NextResponse.json(
|
|
25
|
+
{ error: error.message },
|
|
26
|
+
{ status: 500 }
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return NextResponse.json(
|
|
31
|
+
{ error: 'Internal server error' },
|
|
32
|
+
{ status: 500 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Type definitions for handlers
|
|
37
|
+
type HandlerContext = {
|
|
38
|
+
diviswap: DiviswapType;
|
|
39
|
+
cookieStore: Awaited<ReturnType<typeof cookies>>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type ActionHandler = (params: any, context: HandlerContext) => Promise<NextResponse>;
|
|
43
|
+
type ResourceHandler = (searchParams: URLSearchParams, context: HandlerContext) => Promise<NextResponse>;
|
|
44
|
+
|
|
45
|
+
// Helper function to set customer context from request
|
|
46
|
+
function setCustomerContext(diviswap: DiviswapType, params: any) {
|
|
47
|
+
// In partner authentication, you need to identify your user from your session/auth
|
|
48
|
+
// For this example, we'll expect customerId and customerEmail in the request
|
|
49
|
+
// In production, you'd get this from your own authentication system
|
|
50
|
+
|
|
51
|
+
const customerId = params.customerId || 'demo-customer-123';
|
|
52
|
+
const customerEmail = params.customerEmail || 'demo@yourapp.com';
|
|
53
|
+
|
|
54
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// POST action handlers
|
|
58
|
+
const postHandlers: Record<string, ActionHandler> = {
|
|
59
|
+
setCustomer: async (params, { diviswap }) => {
|
|
60
|
+
try {
|
|
61
|
+
diviswap.setCustomer(params.customerId, params.customerEmail);
|
|
62
|
+
return NextResponse.json({
|
|
63
|
+
success: true,
|
|
64
|
+
customerId: params.customerId,
|
|
65
|
+
customerEmail: params.customerEmail
|
|
66
|
+
});
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
console.error('Set customer error:', error);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
clearCustomer: async (_, { diviswap }) => {
|
|
74
|
+
try {
|
|
75
|
+
diviswap.clearCustomer();
|
|
76
|
+
return NextResponse.json({ success: true });
|
|
77
|
+
} catch (error: any) {
|
|
78
|
+
console.error('Clear customer error:', error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
createTransaction: async (params, { diviswap }) => {
|
|
84
|
+
// Set customer context before API calls
|
|
85
|
+
setCustomerContext(diviswap, params);
|
|
86
|
+
|
|
87
|
+
// Use the appropriate method based on transaction type
|
|
88
|
+
let transaction;
|
|
89
|
+
if (params.type === 'onramp') {
|
|
90
|
+
// Note: Onramp is not yet available in v1 API
|
|
91
|
+
return NextResponse.json(
|
|
92
|
+
{ error: 'Onramp transactions are not yet available' },
|
|
93
|
+
{ status: 400 }
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
// Validate required txHash for offramp
|
|
97
|
+
// Note: Frontend must send crypto FIRST, get txHash, then call this
|
|
98
|
+
if (!params.txHash) {
|
|
99
|
+
return NextResponse.json(
|
|
100
|
+
{ error: 'txHash is required for offramp transactions' },
|
|
101
|
+
{ status: 400 }
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Extract hash if it's an object (failsafe for different wallet types)
|
|
106
|
+
// Some wallets return {hash: '0x...'} instead of '0x...' directly
|
|
107
|
+
const txHashString = typeof params.txHash === 'string'
|
|
108
|
+
? params.txHash
|
|
109
|
+
: (params.txHash?.hash || params.txHash);
|
|
110
|
+
|
|
111
|
+
const sdkParams = {
|
|
112
|
+
amount: params.amount,
|
|
113
|
+
currency: params.currency || 'USD',
|
|
114
|
+
payeeId: params.payeeId,
|
|
115
|
+
fromAddress: params.fromAddress,
|
|
116
|
+
toAddress: params.toAddress,
|
|
117
|
+
chain: params.chain || 'ethereum',
|
|
118
|
+
txHash: txHashString
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Use environment-appropriate method
|
|
122
|
+
// Production: uses regular offramp (creates completed transaction)
|
|
123
|
+
// Sandbox/Development: uses offrampTest (creates pending transaction)
|
|
124
|
+
const isProduction = process.env.NEXT_PUBLIC_DIVISWAP_ENV === 'production';
|
|
125
|
+
transaction = isProduction
|
|
126
|
+
? await diviswap.transactions.offramp(sdkParams)
|
|
127
|
+
: await diviswap.transactions.offrampTest(sdkParams);
|
|
128
|
+
}
|
|
129
|
+
return NextResponse.json(transaction);
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
createPayee: async (params, { diviswap }) => {
|
|
133
|
+
// Set customer context before API calls
|
|
134
|
+
setCustomerContext(diviswap, params);
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
// Check if the SDK is sending structured debit card data
|
|
138
|
+
if (params.debitCard) {
|
|
139
|
+
// New SDK structure - debitCard object is already properly formatted
|
|
140
|
+
const debitCardPayload = {
|
|
141
|
+
nickname: params.nickname,
|
|
142
|
+
accountType: 'debit_card' as const,
|
|
143
|
+
debitCard: params.debitCard,
|
|
144
|
+
setAsDefault: params.setAsDefault || false
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const payee = await diviswap.payees.create(debitCardPayload);
|
|
148
|
+
return NextResponse.json(payee);
|
|
149
|
+
}
|
|
150
|
+
// Handle legacy flat structure for debit cards
|
|
151
|
+
else if (params.accountType === 'debit_card' || params.payeeType === 'debit') {
|
|
152
|
+
// Parse expiry date if needed
|
|
153
|
+
let expirationMonth = params.expirationMonth;
|
|
154
|
+
let expirationYear = params.expirationYear;
|
|
155
|
+
|
|
156
|
+
// If expiry is in MM/YY format in routingNumber field
|
|
157
|
+
if (params.routingNumber && params.routingNumber.includes('/')) {
|
|
158
|
+
const expiryParts = params.routingNumber.split('/');
|
|
159
|
+
expirationMonth = expiryParts[0];
|
|
160
|
+
expirationYear = expiryParts[1] ? `20${expiryParts[1]}` : '2025';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const debitCardPayload = {
|
|
164
|
+
nickname: params.nickname,
|
|
165
|
+
accountType: 'debit_card' as const,
|
|
166
|
+
debitCard: {
|
|
167
|
+
number: params.accountNumber?.replace(/\s+/g, '') || '', // Remove spaces
|
|
168
|
+
expirationMonth: expirationMonth || '12',
|
|
169
|
+
expirationYear: expirationYear || '2025',
|
|
170
|
+
cvv: params.cvv || '123'
|
|
171
|
+
},
|
|
172
|
+
setAsDefault: params.setAsDefault || false
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const payee = await diviswap.payees.create(debitCardPayload);
|
|
176
|
+
return NextResponse.json(payee);
|
|
177
|
+
} else {
|
|
178
|
+
// Bank account structure
|
|
179
|
+
const payee = await diviswap.payees.create({
|
|
180
|
+
nickname: params.nickname,
|
|
181
|
+
accountNumber: params.accountNumber,
|
|
182
|
+
routingNumber: params.routingNumber,
|
|
183
|
+
accountType: params.accountType || 'checking',
|
|
184
|
+
setAsDefault: params.setAsDefault || false
|
|
185
|
+
});
|
|
186
|
+
return NextResponse.json(payee);
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
{{#if (includes features "fees")}}
|
|
191
|
+
calculateFees: async (params, { diviswap }) => {
|
|
192
|
+
const fees = await diviswap.fees.calculateFees({
|
|
193
|
+
amount: params.amount,
|
|
194
|
+
userId: undefined
|
|
195
|
+
});
|
|
196
|
+
return NextResponse.json(fees);
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
getIntegratorFees: async (_, { diviswap }) => {
|
|
200
|
+
const fees = await diviswap.fees.getFees();
|
|
201
|
+
return NextResponse.json(fees);
|
|
202
|
+
},
|
|
203
|
+
{{/if}}
|
|
204
|
+
|
|
205
|
+
submitKYC: async (params, { diviswap }) => {
|
|
206
|
+
// Set customer context before KYC submission
|
|
207
|
+
setCustomerContext(diviswap, params);
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
|
|
211
|
+
// Extract data from nested structure
|
|
212
|
+
const personalInfo = params.personalInfo || {};
|
|
213
|
+
const address = params.address || {};
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
// Validate required address fields
|
|
217
|
+
if (!address.addressLine1 || !address.city || !address.state || !address.postalCode || !address.country) {
|
|
218
|
+
console.error('[API Route] Missing required address fields:', {
|
|
219
|
+
hasAddressLine1: !!address.addressLine1,
|
|
220
|
+
hasCity: !!address.city,
|
|
221
|
+
hasState: !!address.state,
|
|
222
|
+
hasPostalCode: !!address.postalCode,
|
|
223
|
+
hasCountry: !!address.country,
|
|
224
|
+
rawAddress: address
|
|
225
|
+
});
|
|
226
|
+
return NextResponse.json({
|
|
227
|
+
success: false,
|
|
228
|
+
error: 'Missing required address fields'
|
|
229
|
+
}, { status: 400 });
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Clean up the payload - remove undefined/null values and empty strings for optional fields
|
|
233
|
+
const street = address.addressLine1 + (address.addressLine2 && address.addressLine2.trim() ? ` ${address.addressLine2.trim()}` : '');
|
|
234
|
+
|
|
235
|
+
const kycPayload = {
|
|
236
|
+
firstName: personalInfo.firstName,
|
|
237
|
+
lastName: personalInfo.lastName,
|
|
238
|
+
dateOfBirth: personalInfo.dateOfBirth,
|
|
239
|
+
...(personalInfo.ssn && { ssn: personalInfo.ssn }),
|
|
240
|
+
...(personalInfo.phone && { phone: personalInfo.phone }),
|
|
241
|
+
address: {
|
|
242
|
+
street: street,
|
|
243
|
+
city: address.city,
|
|
244
|
+
state: address.state,
|
|
245
|
+
postalCode: address.postalCode,
|
|
246
|
+
country: address.country
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
const result = await diviswap.kyc.submitPersonalInfo(kycPayload);
|
|
252
|
+
|
|
253
|
+
return NextResponse.json(result);
|
|
254
|
+
} catch (error: any) {
|
|
255
|
+
console.error('[API Route] KYC submission failed:', error);
|
|
256
|
+
|
|
257
|
+
// Return the error to the client
|
|
258
|
+
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
createAddress: async (params, { diviswap }) => {
|
|
264
|
+
// Set customer context before API call
|
|
265
|
+
setCustomerContext(diviswap, params);
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const address = await diviswap.addresses.create({
|
|
269
|
+
chain_id: params.chain_id,
|
|
270
|
+
address: params.address,
|
|
271
|
+
is_default: params.is_default
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
return NextResponse.json(address);
|
|
275
|
+
} catch (error: any) {
|
|
276
|
+
console.error('[API Route] Address creation failed:', error);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
setDefaultAddress: async (params, { diviswap }) => {
|
|
282
|
+
// Set customer context before API call
|
|
283
|
+
setCustomerContext(diviswap, params);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
await diviswap.addresses.setDefault({
|
|
287
|
+
chain_id: params.chain_id,
|
|
288
|
+
address: params.address
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
return NextResponse.json({ success: true });
|
|
292
|
+
} catch (error: any) {
|
|
293
|
+
console.error('[API Route] Set default address failed:', error);
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
deleteAddress: async (params, { diviswap }) => {
|
|
299
|
+
// Set customer context before API call
|
|
300
|
+
setCustomerContext(diviswap, params);
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
await diviswap.addresses.delete({
|
|
304
|
+
chain_id: params.chain_id,
|
|
305
|
+
address: params.address
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
return NextResponse.json({ success: true });
|
|
309
|
+
} catch (error: any) {
|
|
310
|
+
console.error('[API Route] Address deletion failed:', error);
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export async function POST(request: NextRequest) {
|
|
317
|
+
try {
|
|
318
|
+
const body = await request.json();
|
|
319
|
+
const { action, ...params } = body;
|
|
320
|
+
|
|
321
|
+
// Get cookies for any cookie-based operations
|
|
322
|
+
const cookieStore = await cookies();
|
|
323
|
+
|
|
324
|
+
// Find and execute handler
|
|
325
|
+
const handler = postHandlers[action];
|
|
326
|
+
if (!handler) {
|
|
327
|
+
return NextResponse.json(
|
|
328
|
+
{ error: 'Invalid action' },
|
|
329
|
+
{ status: 400 }
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const diviswap = getDiviswap();
|
|
334
|
+
return await handler(params, { diviswap, cookieStore });
|
|
335
|
+
} catch (error) {
|
|
336
|
+
return handleError(error);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// GET resource handlers
|
|
341
|
+
const getHandlers: Record<string, ResourceHandler> = {
|
|
342
|
+
customerStatus: async (searchParams, { diviswap }) => {
|
|
343
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
344
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
345
|
+
|
|
346
|
+
// Set customer context
|
|
347
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
348
|
+
|
|
349
|
+
return NextResponse.json({
|
|
350
|
+
customerId,
|
|
351
|
+
customerEmail,
|
|
352
|
+
authenticated: true,
|
|
353
|
+
mode: 'partner'
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
payees: async (searchParams, { diviswap }) => {
|
|
358
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
359
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
360
|
+
|
|
361
|
+
// Set customer context before API call
|
|
362
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
363
|
+
|
|
364
|
+
const payees = await diviswap.payees.list();
|
|
365
|
+
return NextResponse.json(payees);
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
transactions: async (searchParams, { diviswap }) => {
|
|
369
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
370
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
371
|
+
|
|
372
|
+
// Set customer context before API call
|
|
373
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
374
|
+
|
|
375
|
+
const limit = searchParams.get('limit');
|
|
376
|
+
const offset = searchParams.get('offset');
|
|
377
|
+
const status = searchParams.get('status');
|
|
378
|
+
const type = searchParams.get('type');
|
|
379
|
+
|
|
380
|
+
const transactions = await diviswap.transactions.list({
|
|
381
|
+
limit: limit ? Number(limit) : 10,
|
|
382
|
+
offset: offset ? Number(offset) : 0,
|
|
383
|
+
status: status as 'pending' | 'processing' | 'completed' | 'failed' | undefined,
|
|
384
|
+
type: type as 'onramp' | 'offramp' | undefined
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
return NextResponse.json(transactions);
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
kycStatus: async (searchParams, { diviswap }) => {
|
|
391
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
392
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
393
|
+
|
|
394
|
+
// Set customer context before API call
|
|
395
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
|
|
399
|
+
const status = await diviswap.kyc.getComplianceStatus();
|
|
400
|
+
return NextResponse.json(status);
|
|
401
|
+
} catch (error: any) {
|
|
402
|
+
console.error('Failed to get KYC status:', error);
|
|
403
|
+
// Return default status on error
|
|
404
|
+
return NextResponse.json({
|
|
405
|
+
kycStatus: 'NOT_STARTED',
|
|
406
|
+
kybStatus: 'NOT_REQUIRED',
|
|
407
|
+
canTransact: false,
|
|
408
|
+
requiresAction: true,
|
|
409
|
+
verificationLevel: 'none',
|
|
410
|
+
nextStep: 'COMPLETE_KYC'
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
addresses: async (searchParams, { diviswap }) => {
|
|
416
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
417
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
418
|
+
|
|
419
|
+
// Set customer context before API call
|
|
420
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
421
|
+
|
|
422
|
+
const chain_id = searchParams.get('chain_id');
|
|
423
|
+
const is_default = searchParams.get('is_default');
|
|
424
|
+
|
|
425
|
+
const addresses = await diviswap.addresses.list({
|
|
426
|
+
...(chain_id && { chain_id: Number(chain_id) }),
|
|
427
|
+
...(is_default !== null && { is_default: is_default === 'true' })
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
return NextResponse.json(addresses);
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
export async function GET(request: NextRequest) {
|
|
436
|
+
try {
|
|
437
|
+
const { searchParams } = new URL(request.url);
|
|
438
|
+
const resource = searchParams.get('resource');
|
|
439
|
+
const cookieStore = await cookies();
|
|
440
|
+
|
|
441
|
+
// Find and execute handler
|
|
442
|
+
const handler = getHandlers[resource || ''];
|
|
443
|
+
if (!handler) {
|
|
444
|
+
return NextResponse.json(
|
|
445
|
+
{ error: 'Invalid resource' },
|
|
446
|
+
{ status: 400 }
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const diviswap = getDiviswap();
|
|
451
|
+
return await handler(searchParams, { diviswap, cookieStore });
|
|
452
|
+
} catch (error) {
|
|
453
|
+
return handleError(error);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
{{#if (includes features "webhooks")}}
|
|
458
|
+
// DELETE resource handlers
|
|
459
|
+
const deleteHandlers: Record<string, ResourceHandler> = {
|
|
460
|
+
payee: async (searchParams, { diviswap }) => {
|
|
461
|
+
const customerId = searchParams.get('customerId') || 'demo-customer-123';
|
|
462
|
+
const customerEmail = searchParams.get('customerEmail') || 'demo@yourapp.com';
|
|
463
|
+
const id = searchParams.get('id');
|
|
464
|
+
|
|
465
|
+
if (!id) {
|
|
466
|
+
return NextResponse.json(
|
|
467
|
+
{ error: 'Payee ID required' },
|
|
468
|
+
{ status: 400 }
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Set customer context before API call
|
|
473
|
+
diviswap.setCustomer(customerId, customerEmail);
|
|
474
|
+
|
|
475
|
+
await diviswap.payees.delete(id);
|
|
476
|
+
return NextResponse.json({ success: true });
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// DELETE method for cleanup operations
|
|
481
|
+
export async function DELETE(request: NextRequest) {
|
|
482
|
+
try {
|
|
483
|
+
const { searchParams } = new URL(request.url);
|
|
484
|
+
const resource = searchParams.get('resource');
|
|
485
|
+
const cookieStore = await cookies();
|
|
486
|
+
|
|
487
|
+
// Find and execute handler
|
|
488
|
+
const handler = deleteHandlers[resource || ''];
|
|
489
|
+
if (!handler) {
|
|
490
|
+
return NextResponse.json(
|
|
491
|
+
{ error: 'Invalid resource' },
|
|
492
|
+
{ status: 400 }
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const diviswap = getDiviswap();
|
|
497
|
+
return await handler(searchParams, { diviswap, cookieStore });
|
|
498
|
+
} catch (error) {
|
|
499
|
+
return handleError(error);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
{{/if}}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
interface {{prefix}}AuthContextType {
|
|
6
|
+
isAuthenticated: boolean;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
customerId: string | null;
|
|
9
|
+
customerEmail: string | null;
|
|
10
|
+
clearCustomer: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const {{prefix}}AuthContext = createContext<{{prefix}}AuthContextType>({
|
|
14
|
+
isAuthenticated: false,
|
|
15
|
+
isLoading: false,
|
|
16
|
+
customerId: null,
|
|
17
|
+
customerEmail: null,
|
|
18
|
+
clearCustomer: async () => {},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
interface {{prefix}}AuthProviderProps {
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
customerId: string | null;
|
|
24
|
+
customerEmail: string | null;
|
|
25
|
+
loading: boolean;
|
|
26
|
+
clearCustomer: () => Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// This provider receives props instead of using useDiviswap directly
|
|
30
|
+
// to avoid circular dependencies
|
|
31
|
+
export function {{prefix}}AuthProvider({
|
|
32
|
+
children,
|
|
33
|
+
customerId,
|
|
34
|
+
customerEmail,
|
|
35
|
+
loading,
|
|
36
|
+
clearCustomer
|
|
37
|
+
}: {{prefix}}AuthProviderProps) {
|
|
38
|
+
return (
|
|
39
|
+
<{{prefix}}AuthContext.Provider
|
|
40
|
+
value=\{{
|
|
41
|
+
isAuthenticated: !!(customerId && customerEmail),
|
|
42
|
+
isLoading: loading,
|
|
43
|
+
customerId,
|
|
44
|
+
customerEmail,
|
|
45
|
+
clearCustomer
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
</{{prefix}}AuthContext.Provider>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const use{{prefix}}Auth = () => {
|
|
54
|
+
const context = useContext({{prefix}}AuthContext);
|
|
55
|
+
if (!context) {
|
|
56
|
+
throw new Error('use{{prefix}}Auth must be used within {{prefix}}AuthProvider');
|
|
57
|
+
}
|
|
58
|
+
return context;
|
|
59
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// This file is auto-generated by Diviswap SDK CLI
|
|
2
|
+
// It provides a client for communicating with the Diviswap API routes
|
|
3
|
+
|
|
4
|
+
export class DiviswapClient {
|
|
5
|
+
constructor(private baseUrl: string = '/api/diviswap') {}
|
|
6
|
+
|
|
7
|
+
private async request<T = any>(
|
|
8
|
+
endpoint: string,
|
|
9
|
+
options: RequestInit = {}
|
|
10
|
+
): Promise<T> {
|
|
11
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
12
|
+
...options,
|
|
13
|
+
headers: {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
...options.headers,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const error = await response.json().catch(() => ({ message: 'Request failed' }));
|
|
21
|
+
throw new Error(error.error || error.message || 'Request failed');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Customer context management for partner authentication
|
|
28
|
+
async setCustomer(customerId: string, customerEmail: string) {
|
|
29
|
+
return this.request('', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
body: JSON.stringify({ action: 'setCustomer', customerId, customerEmail }),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async clearCustomer() {
|
|
36
|
+
return this.request('', {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
body: JSON.stringify({ action: 'clearCustomer' }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async getCustomerStatus(customerId: string, customerEmail: string) {
|
|
43
|
+
try {
|
|
44
|
+
return await this.request(`?resource=customerStatus&customerId=${encodeURIComponent(customerId)}&customerEmail=${encodeURIComponent(customerEmail)}`);
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Transaction methods
|
|
51
|
+
async createTransaction(data: any) {
|
|
52
|
+
return this.request('', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
body: JSON.stringify({ action: 'createTransaction', ...data }),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getTransactions(customerId: string, customerEmail: string, params?: {
|
|
59
|
+
limit?: number;
|
|
60
|
+
offset?: number;
|
|
61
|
+
status?: string;
|
|
62
|
+
type?: string;
|
|
63
|
+
}) {
|
|
64
|
+
const searchParams = new URLSearchParams({
|
|
65
|
+
resource: 'transactions',
|
|
66
|
+
customerId,
|
|
67
|
+
customerEmail,
|
|
68
|
+
...(params && {
|
|
69
|
+
limit: params.limit?.toString() || '10',
|
|
70
|
+
offset: params.offset?.toString() || '0',
|
|
71
|
+
...(params.status && { status: params.status }),
|
|
72
|
+
...(params.type && { type: params.type }),
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
return this.request(`?${searchParams}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async getTransaction(id: string) {
|
|
79
|
+
return this.request(`?resource=transaction&id=${id}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Payee methods
|
|
83
|
+
async getPayees(customerId: string, customerEmail: string) {
|
|
84
|
+
return this.request(`?resource=payees&customerId=${encodeURIComponent(customerId)}&customerEmail=${encodeURIComponent(customerEmail)}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async createPayee(data: any) {
|
|
88
|
+
return this.request('', {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: JSON.stringify({ action: 'createPayee', ...data }),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async deletePayee(id: string, customerId: string, customerEmail: string) {
|
|
95
|
+
return this.request(`?resource=payee&id=${id}&customerId=${encodeURIComponent(customerId)}&customerEmail=${encodeURIComponent(customerEmail)}`, {
|
|
96
|
+
method: 'DELETE',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
{{#if (includes features "fees")}}
|
|
101
|
+
// Fee calculation methods
|
|
102
|
+
async calculateFees(data: { amount: number; type: 'onramp' | 'offramp'; currency?: string }) {
|
|
103
|
+
return this.request('', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
body: JSON.stringify({ action: 'calculateFees', ...data }),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async getIntegratorFees() {
|
|
110
|
+
return this.request('', {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
body: JSON.stringify({ action: 'getIntegratorFees' }),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
{{/if}}
|
|
116
|
+
}
|