arispay 0.1.4 → 0.1.7
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 +61 -65
- package/package.json +1 -1
- package/src/cli.ts +71 -56
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
|
}
|
|
@@ -197,10 +191,11 @@ ${bold("Connect your agent to ArisPay")}`);
|
|
|
197
191
|
${dim("How does your agent make payments?")}
|
|
198
192
|
`);
|
|
199
193
|
console.log(` ${cyan("[1]")} Platform ${dim("\u2014 Your app triggers payments on behalf of the agent")}`);
|
|
200
|
-
console.log(` ${cyan("[2]")} Autonomous ${dim("\u2014 The agent decides when to pay, within spend limits you set")}
|
|
194
|
+
console.log(` ${cyan("[2]")} Autonomous ${dim("\u2014 The agent decides when to pay, within spend limits you set")}`);
|
|
195
|
+
console.log(` ${cyan("[3]")} Both ${dim("\u2014 Platform and autonomous, depending on the transaction")}
|
|
201
196
|
`);
|
|
202
197
|
const modeChoice = await prompt(` Enter choice ${dim("[1]")}: `);
|
|
203
|
-
const mode = modeChoice === "2" ? "autonomous" : "platform";
|
|
198
|
+
const mode = modeChoice === "2" ? "autonomous" : modeChoice === "3" ? "both" : "platform";
|
|
204
199
|
console.log(`
|
|
205
200
|
${dim("Connecting agent...")}`);
|
|
206
201
|
try {
|
|
@@ -225,7 +220,7 @@ ${bold("Connect your agent to ArisPay")}`);
|
|
|
225
220
|
console.log(` ${bold("Mode:")} ${a.mode || mode}`);
|
|
226
221
|
console.log(` ${bold("Status:")} ${a.status}
|
|
227
222
|
`);
|
|
228
|
-
if (mode === "autonomous") {
|
|
223
|
+
if (mode === "autonomous" || mode === "both") {
|
|
229
224
|
console.log(` ${bold("Set spend limits")}`);
|
|
230
225
|
console.log(` ${dim("Autonomous agents need spend limits so they can only spend within bounds you control.")}
|
|
231
226
|
`);
|
|
@@ -284,7 +279,7 @@ ${bold("Connect your agent to ArisPay")}`);
|
|
|
284
279
|
return;
|
|
285
280
|
}
|
|
286
281
|
}
|
|
287
|
-
const cardOk = await
|
|
282
|
+
const cardOk = await setupCardViaBrowser(endUserId, a.id);
|
|
288
283
|
if (!cardOk) return;
|
|
289
284
|
const topupStr = await prompt(`
|
|
290
285
|
Amount to load ${dim("(e.g. 50.00)")}: $`);
|
|
@@ -351,7 +346,8 @@ ${bold("Add a payment method")}`);
|
|
|
351
346
|
`);
|
|
352
347
|
const methodChoice = await prompt(` Enter choice: `);
|
|
353
348
|
if (methodChoice === "1") {
|
|
354
|
-
|
|
349
|
+
const storedAgentId = config.agentId;
|
|
350
|
+
await setupCardViaBrowser(userId, storedAgentId);
|
|
355
351
|
} else if (methodChoice === "2") {
|
|
356
352
|
console.log();
|
|
357
353
|
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
|
}
|
|
@@ -209,10 +222,11 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
|
|
|
209
222
|
|
|
210
223
|
console.log(`\n ${dim('How does your agent make payments?')}\n`);
|
|
211
224
|
console.log(` ${cyan('[1]')} Platform ${dim('— Your app triggers payments on behalf of the agent')}`);
|
|
212
|
-
console.log(` ${cyan('[2]')} Autonomous ${dim('— The agent decides when to pay, within spend limits you set')}
|
|
225
|
+
console.log(` ${cyan('[2]')} Autonomous ${dim('— The agent decides when to pay, within spend limits you set')}`);
|
|
226
|
+
console.log(` ${cyan('[3]')} Both ${dim('— Platform and autonomous, depending on the transaction')}\n`);
|
|
213
227
|
|
|
214
228
|
const modeChoice = await prompt(` Enter choice ${dim('[1]')}: `);
|
|
215
|
-
const mode = modeChoice === '2' ? 'autonomous' : 'platform';
|
|
229
|
+
const mode = modeChoice === '2' ? 'autonomous' : modeChoice === '3' ? 'both' : 'platform';
|
|
216
230
|
|
|
217
231
|
console.log(`\n ${dim('Connecting agent...')}`);
|
|
218
232
|
|
|
@@ -240,7 +254,7 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
|
|
|
240
254
|
console.log(` ${bold('Status:')} ${a.status}\n`);
|
|
241
255
|
|
|
242
256
|
// Prompt for spend limits when autonomous
|
|
243
|
-
if (mode === 'autonomous') {
|
|
257
|
+
if (mode === 'autonomous' || mode === 'both') {
|
|
244
258
|
console.log(` ${bold('Set spend limits')}`);
|
|
245
259
|
console.log(` ${dim('Autonomous agents need spend limits so they can only spend within bounds you control.')}\n`);
|
|
246
260
|
|
|
@@ -305,7 +319,7 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
|
|
|
305
319
|
}
|
|
306
320
|
|
|
307
321
|
// Collect card details and verify via 3DS
|
|
308
|
-
const cardOk = await
|
|
322
|
+
const cardOk = await setupCardViaBrowser(endUserId, a.id);
|
|
309
323
|
if (!cardOk) return;
|
|
310
324
|
|
|
311
325
|
// Top up
|
|
@@ -373,7 +387,8 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
|
|
|
373
387
|
const methodChoice = await prompt(` Enter choice: `);
|
|
374
388
|
|
|
375
389
|
if (methodChoice === '1') {
|
|
376
|
-
|
|
390
|
+
const storedAgentId = (config as any).agentId;
|
|
391
|
+
await setupCardViaBrowser(userId, storedAgentId);
|
|
377
392
|
} else if (methodChoice === '2') {
|
|
378
393
|
console.log();
|
|
379
394
|
const chain = await prompt(` Chain ${dim('(ethereum, base, polygon, solana)')}: `);
|