arispay 0.1.4 → 0.1.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/dist/cli.js +57 -62
- package/package.json +1 -1
- package/src/cli.ts +67 -53
package/dist/cli.js
CHANGED
|
@@ -110,75 +110,69 @@ ${bold("Get started")}
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
-
async function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const cardNumber = await promptSecret(` Card number: `);
|
|
119
|
-
if (!cardNumber) {
|
|
120
|
-
console.log(dim(" Cancelled."));
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
const expiry = await prompt(` Expiry ${dim("(MM/YY)")}: `);
|
|
124
|
-
if (!expiry) {
|
|
125
|
-
console.log(dim(" Cancelled."));
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
const securityCode = await promptSecret(` CVV: `);
|
|
129
|
-
if (!securityCode) {
|
|
130
|
-
console.log(dim(" Cancelled."));
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
const [expiryMonth, expiryYear] = expiry.split("/").map((s) => s.trim());
|
|
134
|
-
if (!expiryMonth || !expiryYear) {
|
|
135
|
-
console.log(` ${dim("Invalid expiry format. Use MM/YY.")}`);
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
113
|
+
async function setupCardViaBrowser(endUserId, agentId) {
|
|
114
|
+
const config = loadConfig(BRAND);
|
|
115
|
+
const { apiKey, environment, baseUrl } = config;
|
|
116
|
+
const defaultUrl = environment === "production" ? "https://api.arispay.app" : "https://api-production-79ea.up.railway.app";
|
|
117
|
+
const apiUrl = baseUrl || defaultUrl;
|
|
138
118
|
console.log(`
|
|
139
|
-
${dim("
|
|
119
|
+
${dim("Creating secure card setup link...")}`);
|
|
140
120
|
try {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
121
|
+
const res = await fetch(`${apiUrl}/v1/card-setup-sessions`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
Authorization: `Bearer ${apiKey}`
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({ endUserId, ...agentId ? { agentId } : {} }),
|
|
128
|
+
signal: AbortSignal.timeout(15e3)
|
|
148
129
|
});
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (challengeUrl) {
|
|
153
|
-
console.log();
|
|
154
|
-
console.log(` ${bold("Card verification required")}`);
|
|
155
|
-
console.log(` ${dim("Your bank requires 3D Secure verification. Open this link:")}
|
|
156
|
-
`);
|
|
157
|
-
console.log(` ${cyan(challengeUrl)}
|
|
158
|
-
`);
|
|
159
|
-
console.log(` ${dim("Complete the verification in your browser, then come back here.")}`);
|
|
160
|
-
await prompt(`
|
|
161
|
-
Press Enter when done...`);
|
|
162
|
-
success("Card added (verification pending)\n");
|
|
163
|
-
} else {
|
|
164
|
-
console.log();
|
|
165
|
-
success("Card tokenized (verification in progress)\n");
|
|
166
|
-
}
|
|
167
|
-
console.log(` ${bold("Card:")} ${r.cardBrand?.toUpperCase() || "Card"} ending in ${r.cardLast4 || "****"}
|
|
168
|
-
`);
|
|
169
|
-
return true;
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
const body = await res.json().catch(() => ({}));
|
|
132
|
+
throw new Error(body.error?.message || `Failed to create card setup (HTTP ${res.status})`);
|
|
170
133
|
}
|
|
134
|
+
const data = await res.json();
|
|
171
135
|
console.log();
|
|
172
|
-
|
|
136
|
+
console.log(` ${bold("Open this link to securely add and verify your card:")}
|
|
137
|
+
`);
|
|
138
|
+
console.log(` ${cyan(data.setupUrl)}
|
|
139
|
+
`);
|
|
140
|
+
console.log(` ${dim("Your card details are entered on a secure page hosted by ArisPay.")}`);
|
|
141
|
+
console.log(` ${dim("3D Secure verification is handled automatically in the browser.")}`);
|
|
142
|
+
console.log(` ${dim("This link expires in 15 minutes.")}
|
|
143
|
+
`);
|
|
144
|
+
console.log(` ${dim("Waiting for you to complete card setup...")}`);
|
|
145
|
+
const deadline = Date.now() + 15 * 60 * 1e3;
|
|
146
|
+
while (Date.now() < deadline) {
|
|
147
|
+
await new Promise((r) => setTimeout(r, 3e3));
|
|
148
|
+
try {
|
|
149
|
+
const statusRes = await fetch(`${apiUrl}/v1/card-setup-sessions/${data.token}/status`, {
|
|
150
|
+
signal: AbortSignal.timeout(1e4)
|
|
151
|
+
});
|
|
152
|
+
const statusData = await statusRes.json();
|
|
153
|
+
if (statusData.status === "completed") {
|
|
154
|
+
console.log();
|
|
155
|
+
success("Card verified!\n");
|
|
156
|
+
console.log(` ${bold("Card:")} ${statusData.cardBrand?.toUpperCase() || "Card"} ending in ${statusData.cardLast4 || "****"}`);
|
|
157
|
+
console.log(`
|
|
158
|
+
${dim("Your card is linked and verified. All payments will process instantly.")}
|
|
173
159
|
`);
|
|
174
|
-
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (statusData.status === "failed") {
|
|
163
|
+
console.log();
|
|
164
|
+
console.error(` \x1B[31m\u2717\x1B[0m Card verification failed. Please try again.`);
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
175
170
|
console.log(`
|
|
176
|
-
${dim("
|
|
177
|
-
|
|
178
|
-
return true;
|
|
171
|
+
${dim("Card setup link expired. Run option [2] to try again.")}`);
|
|
172
|
+
return false;
|
|
179
173
|
} catch (e) {
|
|
180
174
|
console.log();
|
|
181
|
-
console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to
|
|
175
|
+
console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to start card setup"}`);
|
|
182
176
|
return false;
|
|
183
177
|
}
|
|
184
178
|
}
|
|
@@ -284,7 +278,7 @@ ${bold("Connect your agent to ArisPay")}`);
|
|
|
284
278
|
return;
|
|
285
279
|
}
|
|
286
280
|
}
|
|
287
|
-
const cardOk = await
|
|
281
|
+
const cardOk = await setupCardViaBrowser(endUserId, a.id);
|
|
288
282
|
if (!cardOk) return;
|
|
289
283
|
const topupStr = await prompt(`
|
|
290
284
|
Amount to load ${dim("(e.g. 50.00)")}: $`);
|
|
@@ -351,7 +345,8 @@ ${bold("Add a payment method")}`);
|
|
|
351
345
|
`);
|
|
352
346
|
const methodChoice = await prompt(` Enter choice: `);
|
|
353
347
|
if (methodChoice === "1") {
|
|
354
|
-
|
|
348
|
+
const storedAgentId = config.agentId;
|
|
349
|
+
await setupCardViaBrowser(userId, storedAgentId);
|
|
355
350
|
} else if (methodChoice === "2") {
|
|
356
351
|
console.log();
|
|
357
352
|
const chain = await prompt(` Chain ${dim("(ethereum, base, polygon, solana)")}: `);
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -130,69 +130,82 @@ async function postInitMenu(config: { apiKey?: string; environment?: string; bas
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
// ── Card
|
|
133
|
+
// ── Card Setup Helper (browser-based with 3DS) ─────────────────────
|
|
134
134
|
|
|
135
|
-
async function
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
async function setupCardViaBrowser(
|
|
136
|
+
endUserId: string,
|
|
137
|
+
agentId?: string,
|
|
138
138
|
): Promise<boolean> {
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
const config = loadConfig(BRAND);
|
|
140
|
+
const { apiKey, environment, baseUrl } = config;
|
|
141
|
+
const defaultUrl = environment === 'production'
|
|
142
|
+
? 'https://api.arispay.app'
|
|
143
|
+
: 'https://api-production-79ea.up.railway.app';
|
|
144
|
+
const apiUrl = baseUrl || defaultUrl;
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
if (!cardNumber) { console.log(dim(' Cancelled.')); return false; }
|
|
146
|
+
console.log(`\n ${dim('Creating secure card setup link...')}`);
|
|
144
147
|
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
try {
|
|
149
|
+
// Create card setup session
|
|
150
|
+
const res = await fetch(`${apiUrl}/v1/card-setup-sessions`, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: {
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
Authorization: `Bearer ${apiKey}`,
|
|
155
|
+
},
|
|
156
|
+
body: JSON.stringify({ endUserId, ...(agentId ? { agentId } : {}) }),
|
|
157
|
+
signal: AbortSignal.timeout(15_000),
|
|
158
|
+
});
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
if (!res.ok) {
|
|
161
|
+
const body = await res.json().catch(() => ({}));
|
|
162
|
+
throw new Error((body as any).error?.message || `Failed to create card setup (HTTP ${res.status})`);
|
|
163
|
+
}
|
|
150
164
|
|
|
151
|
-
|
|
152
|
-
if (!expiryMonth || !expiryYear) {
|
|
153
|
-
console.log(` ${dim('Invalid expiry format. Use MM/YY.')}`);
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
165
|
+
const data = await res.json() as { token: string; setupUrl: string; expiresAt: string };
|
|
156
166
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
167
|
+
console.log();
|
|
168
|
+
console.log(` ${bold('Open this link to securely add and verify your card:')}\n`);
|
|
169
|
+
console.log(` ${cyan(data.setupUrl)}\n`);
|
|
170
|
+
console.log(` ${dim('Your card details are entered on a secure page hosted by ArisPay.')}`);
|
|
171
|
+
console.log(` ${dim('3D Secure verification is handled automatically in the browser.')}`);
|
|
172
|
+
console.log(` ${dim('This link expires in 15 minutes.')}\n`);
|
|
173
|
+
|
|
174
|
+
// Poll for completion
|
|
175
|
+
console.log(` ${dim('Waiting for you to complete card setup...')}`);
|
|
176
|
+
const deadline = Date.now() + 15 * 60 * 1000; // 15 min
|
|
177
|
+
while (Date.now() < deadline) {
|
|
178
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const statusRes = await fetch(`${apiUrl}/v1/card-setup-sessions/${data.token}/status`, {
|
|
182
|
+
signal: AbortSignal.timeout(10_000),
|
|
183
|
+
});
|
|
184
|
+
const statusData = await statusRes.json() as any;
|
|
185
|
+
|
|
186
|
+
if (statusData.status === 'completed') {
|
|
187
|
+
console.log();
|
|
188
|
+
success('Card verified!\n');
|
|
189
|
+
console.log(` ${bold('Card:')} ${statusData.cardBrand?.toUpperCase() || 'Card'} ending in ${statusData.cardLast4 || '****'}`);
|
|
190
|
+
console.log(`\n ${dim('Your card is linked and verified. All payments will process instantly.')}\n`);
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (statusData.status === 'failed') {
|
|
195
|
+
console.log();
|
|
196
|
+
console.error(` \x1b[31m✗\x1b[0m Card verification failed. Please try again.`);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
} catch {
|
|
200
|
+
// Network error — keep polling
|
|
183
201
|
}
|
|
184
|
-
console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}\n`);
|
|
185
|
-
return true;
|
|
186
202
|
}
|
|
187
203
|
|
|
188
|
-
console.log();
|
|
189
|
-
|
|
190
|
-
console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}`);
|
|
191
|
-
console.log(`\n ${dim('Your card is now linked and verified. You can make payments.')}\n`);
|
|
192
|
-
return true;
|
|
204
|
+
console.log(`\n ${dim('Card setup link expired. Run option [2] to try again.')}`);
|
|
205
|
+
return false;
|
|
193
206
|
} catch (e: any) {
|
|
194
207
|
console.log();
|
|
195
|
-
console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to
|
|
208
|
+
console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to start card setup'}`);
|
|
196
209
|
return false;
|
|
197
210
|
}
|
|
198
211
|
}
|
|
@@ -305,7 +318,7 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
|
|
|
305
318
|
}
|
|
306
319
|
|
|
307
320
|
// Collect card details and verify via 3DS
|
|
308
|
-
const cardOk = await
|
|
321
|
+
const cardOk = await setupCardViaBrowser(endUserId, a.id);
|
|
309
322
|
if (!cardOk) return;
|
|
310
323
|
|
|
311
324
|
// Top up
|
|
@@ -373,7 +386,8 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
|
|
|
373
386
|
const methodChoice = await prompt(` Enter choice: `);
|
|
374
387
|
|
|
375
388
|
if (methodChoice === '1') {
|
|
376
|
-
|
|
389
|
+
const storedAgentId = (config as any).agentId;
|
|
390
|
+
await setupCardViaBrowser(userId, storedAgentId);
|
|
377
391
|
} else if (methodChoice === '2') {
|
|
378
392
|
console.log();
|
|
379
393
|
const chain = await prompt(` Chain ${dim('(ethereum, base, polygon, solana)')}: `);
|