arispay 0.1.1 → 0.1.3

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 (3) hide show
  1. package/dist/cli.js +63 -24
  2. package/package.json +1 -1
  3. package/src/cli.ts +57 -23
package/dist/cli.js CHANGED
@@ -122,12 +122,13 @@ ${bold("Connect your agent to ArisPay")}`);
122
122
  return;
123
123
  }
124
124
  console.log(`
125
- ${dim("How does your agent make payments?")}`);
126
- console.log(` ${dim(" platform \u2014 Your app triggers payments on behalf of the agent (default)")}`);
127
- console.log(` ${dim(" autonomous \u2014 The agent decides when to pay, within spend limits you set")}
125
+ ${dim("How does your agent make payments?")}
128
126
  `);
129
- const modeInput = await prompt(` Mode ${dim("[platform]")}: `);
130
- const mode = modeInput === "autonomous" ? "autonomous" : "platform";
127
+ console.log(` ${cyan("[1]")} Platform ${dim("\u2014 Your app triggers payments on behalf of the agent")}`);
128
+ console.log(` ${cyan("[2]")} Autonomous ${dim("\u2014 The agent decides when to pay, within spend limits you set")}
129
+ `);
130
+ const modeChoice = await prompt(` Enter choice ${dim("[1]")}: `);
131
+ const mode = modeChoice === "2" ? "autonomous" : "platform";
131
132
  console.log(`
132
133
  ${dim("Connecting agent...")}`);
133
134
  try {
@@ -138,13 +139,14 @@ ${bold("Connect your agent to ArisPay")}`);
138
139
  });
139
140
  const a = agent;
140
141
  const config = loadConfig(BRAND);
141
- saveConfig(BRAND, { ...config, agentId: a.id });
142
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name });
142
143
  console.log();
143
144
  success(`Agent connected!
144
145
  `);
145
- console.log(` ${dim("ArisPay generated an Ed25519 keypair for your agent \u2014 this is its")}`);
146
- console.log(` ${dim("cryptographic identity for signing payments (RFC 9421 TAP).")}`);
147
- console.log(` ${dim("A circuit breaker has been set up to auto-pause if anything looks off.")}
146
+ console.log(` ${dim("ArisPay has created a Visa TAP cryptographic identity for your agent.")}`);
147
+ console.log(` ${dim("Every payment your agent makes is signed with this identity so merchants")}`);
148
+ console.log(` ${dim("can verify it is authorised. A circuit breaker is also in place to")}`);
149
+ console.log(` ${dim("auto-pause your agent if unusual spending is detected.")}
148
150
  `);
149
151
  console.log(` ${bold("Agent ID:")} ${a.id}`);
150
152
  console.log(` ${bold("Name:")} ${a.name}`);
@@ -188,26 +190,52 @@ ${bold("Add a payment method")}`);
188
190
  const methodChoice = await prompt(` Enter choice: `);
189
191
  if (methodChoice === "1") {
190
192
  console.log(`
191
- ${dim("Starting card setup...")}`);
193
+ ${dim("Enter your card details below. They are sent directly to Fiserv for")}`);
194
+ console.log(` ${dim("tokenization \u2014 ArisPay never sees or stores your full card number.")}
195
+ `);
196
+ const cardNumber = await promptSecret(` Card number: `);
197
+ if (!cardNumber) {
198
+ console.log(dim(" Cancelled."));
199
+ return;
200
+ }
201
+ const expiry = await prompt(` Expiry ${dim("(MM/YY)")}: `);
202
+ if (!expiry) {
203
+ console.log(dim(" Cancelled."));
204
+ return;
205
+ }
206
+ const securityCode = await promptSecret(` CVV: `);
207
+ if (!securityCode) {
208
+ console.log(dim(" Cancelled."));
209
+ return;
210
+ }
211
+ const [expiryMonth, expiryYear] = expiry.split("/").map((s) => s.trim());
212
+ if (!expiryMonth || !expiryYear) {
213
+ console.log(` ${dim("Invalid expiry format. Use MM/YY.")}`);
214
+ return;
215
+ }
216
+ console.log(`
217
+ ${dim("Tokenizing card...")}`);
192
218
  try {
193
219
  const result = await client.users.addPaymentMethod({
194
220
  userId,
195
221
  type: "card",
196
- returnUrl: "https://app.arispay.app/card-setup/complete"
222
+ cardNumber: cardNumber.replace(/\s/g, ""),
223
+ expiryMonth,
224
+ expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
225
+ securityCode
197
226
  });
198
227
  const r = result;
199
228
  console.log();
200
- success(`Card setup ready!
201
- `);
202
- console.log(` ${bold("Open this URL to securely enter your card details:")}
203
- `);
204
- console.log(` ${cyan(r.setupUrl)}
229
+ success(`Card tokenized!
205
230
  `);
206
- console.log(` ${dim("Your card is tokenized \u2014 ArisPay never sees or stores the full number.")}
231
+ console.log(` ${bold("Card:")} ${r.cardBrand?.toUpperCase() || "Card"} ending in ${r.cardLast4 || "****"}`);
232
+ console.log(` ${bold("Token:")} ${dim(r.tokenId || "stored securely")}`);
233
+ console.log(`
234
+ ${dim("Your card is now linked to your agent. You can make test payments.")}
207
235
  `);
208
236
  } catch (e) {
209
237
  console.log();
210
- console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to start card setup"}`);
238
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to tokenize card"}`);
211
239
  }
212
240
  } else if (methodChoice === "2") {
213
241
  console.log();
@@ -256,9 +284,11 @@ ${bold("Make a test payment")}`);
256
284
  `);
257
285
  const config = loadConfig(BRAND);
258
286
  const storedAgentId = config.agentId;
287
+ const storedAgentName = config.agentName;
259
288
  let agentId;
260
289
  if (storedAgentId) {
261
- const useStored = await prompt(` Use agent ${dim(storedAgentId.slice(0, 12) + "...")}? ${dim("(Y/n)")}: `);
290
+ const agentLabel = storedAgentName ? bold(storedAgentName) : dim(storedAgentId.slice(0, 12) + "...");
291
+ const useStored = await prompt(` Use agent ${agentLabel}? ${dim("(Y/n)")}: `);
262
292
  if (useStored.toLowerCase() === "n") {
263
293
  agentId = await prompt(` Agent ID: `);
264
294
  if (!agentId) {
@@ -275,25 +305,34 @@ ${bold("Make a test payment")}`);
275
305
  return;
276
306
  }
277
307
  }
278
- const amountStr = await prompt(` Amount in cents ${dim("(e.g. 500 = $5.00)")}: `);
279
- const amount = Number(amountStr);
280
- if (!amount || isNaN(amount)) {
308
+ const amountStr = await prompt(` Amount ${dim("(e.g. 5.00)")}: $`);
309
+ const dollars = parseFloat(amountStr);
310
+ if (!dollars || isNaN(dollars)) {
281
311
  console.log(dim(" Invalid amount. Cancelled."));
282
312
  return;
283
313
  }
284
- const memo = await prompt(` What is this payment for? `);
314
+ const amount = Math.round(dollars * 100);
315
+ const memo = await prompt(` Description ${dim("(appears on the transaction record)")}: `);
285
316
  if (!memo) {
286
317
  console.log(dim(" Cancelled."));
287
318
  return;
288
319
  }
320
+ const userId = config.endUserId;
321
+ if (!userId) {
322
+ console.log(`
323
+ ${dim("No payment method set up yet. Run option [2] first.")}`);
324
+ return;
325
+ }
289
326
  console.log(`
290
- ${dim(`Sending $${(amount / 100).toFixed(2)} test payment...`)}`);
327
+ ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
291
328
  try {
292
329
  const payment = await client.payments.create({
293
330
  agentId,
331
+ userId,
294
332
  amount,
295
333
  currency: "USD",
296
334
  memo,
335
+ merchantUrl: "https://test.arispay.app",
297
336
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
298
337
  });
299
338
  const p = payment;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arispay",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "SDK and CLI for enabling agent-initiated payments via Visa TAP + Fiserv",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/cli.ts CHANGED
@@ -140,12 +140,12 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
140
140
  const name = await prompt(` What is your agent called? `);
141
141
  if (!name) { console.log(dim(' Cancelled.')); return; }
142
142
 
143
- console.log(`\n ${dim('How does your agent make payments?')}`);
144
- console.log(` ${dim(' platform — Your app triggers payments on behalf of the agent (default)')}`);
145
- console.log(` ${dim(' autonomous — The agent decides when to pay, within spend limits you set')}\n`);
143
+ console.log(`\n ${dim('How does your agent make payments?')}\n`);
144
+ console.log(` ${cyan('[1]')} Platform ${dim('— Your app triggers payments on behalf of the agent')}`);
145
+ console.log(` ${cyan('[2]')} Autonomous ${dim('— The agent decides when to pay, within spend limits you set')}\n`);
146
146
 
147
- const modeInput = await prompt(` Mode ${dim('[platform]')}: `);
148
- const mode = modeInput === 'autonomous' ? 'autonomous' : 'platform';
147
+ const modeChoice = await prompt(` Enter choice ${dim('[1]')}: `);
148
+ const mode = modeChoice === '2' ? 'autonomous' : 'platform';
149
149
 
150
150
  console.log(`\n ${dim('Connecting agent...')}`);
151
151
 
@@ -159,13 +159,14 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
159
159
 
160
160
  // Store agent ID so other steps can auto-fill it
161
161
  const config = loadConfig(BRAND);
162
- saveConfig(BRAND, { ...config, agentId: a.id } as any);
162
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name } as any);
163
163
 
164
164
  console.log();
165
165
  success(`Agent connected!\n`);
166
- console.log(` ${dim('ArisPay generated an Ed25519 keypair for your agent — this is its')}`);
167
- console.log(` ${dim('cryptographic identity for signing payments (RFC 9421 TAP).')}`);
168
- console.log(` ${dim('A circuit breaker has been set up to auto-pause if anything looks off.')}\n`);
166
+ console.log(` ${dim('ArisPay has created a Visa TAP cryptographic identity for your agent.')}`);
167
+ console.log(` ${dim('Every payment your agent makes is signed with this identity so merchants')}`);
168
+ console.log(` ${dim('can verify it is authorised. A circuit breaker is also in place to')}`);
169
+ console.log(` ${dim('auto-pause your agent if unusual spending is detected.')}\n`);
169
170
  console.log(` ${bold('Agent ID:')} ${a.id}`);
170
171
  console.log(` ${bold('Name:')} ${a.name}`);
171
172
  console.log(` ${bold('Mode:')} ${a.mode || mode}`);
@@ -210,22 +211,43 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
210
211
  const methodChoice = await prompt(` Enter choice: `);
211
212
 
212
213
  if (methodChoice === '1') {
213
- console.log(`\n ${dim('Starting card setup...')}`);
214
+ console.log(`\n ${dim('Enter your card details below. They are sent directly to Fiserv for')}`);
215
+ console.log(` ${dim('tokenization — ArisPay never sees or stores your full card number.')}\n`);
216
+
217
+ const cardNumber = await promptSecret(` Card number: `);
218
+ if (!cardNumber) { console.log(dim(' Cancelled.')); return; }
219
+
220
+ const expiry = await prompt(` Expiry ${dim('(MM/YY)')}: `);
221
+ if (!expiry) { console.log(dim(' Cancelled.')); return; }
222
+
223
+ const securityCode = await promptSecret(` CVV: `);
224
+ if (!securityCode) { console.log(dim(' Cancelled.')); return; }
225
+
226
+ const [expiryMonth, expiryYear] = expiry.split('/').map(s => s.trim());
227
+ if (!expiryMonth || !expiryYear) {
228
+ console.log(` ${dim('Invalid expiry format. Use MM/YY.')}`);
229
+ return;
230
+ }
231
+
232
+ console.log(`\n ${dim('Tokenizing card...')}`);
214
233
  try {
215
234
  const result = await client.users.addPaymentMethod({
216
235
  userId,
217
236
  type: 'card',
218
- returnUrl: 'https://app.arispay.app/card-setup/complete',
237
+ cardNumber: cardNumber.replace(/\s/g, ''),
238
+ expiryMonth,
239
+ expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
240
+ securityCode,
219
241
  });
220
242
  const r = result as any;
221
243
  console.log();
222
- success(`Card setup ready!\n`);
223
- console.log(` ${bold('Open this URL to securely enter your card details:')}\n`);
224
- console.log(` ${cyan(r.setupUrl)}\n`);
225
- console.log(` ${dim('Your card is tokenized ArisPay never sees or stores the full number.')}\n`);
244
+ success(`Card tokenized!\n`);
245
+ console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}`);
246
+ console.log(` ${bold('Token:')} ${dim(r.tokenId || 'stored securely')}`);
247
+ console.log(`\n ${dim('Your card is now linked to your agent. You can make test payments.')}\n`);
226
248
  } catch (e: any) {
227
249
  console.log();
228
- console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to start card setup'}`);
250
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to tokenize card'}`);
229
251
  }
230
252
  } else if (methodChoice === '2') {
231
253
  console.log();
@@ -262,14 +284,17 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
262
284
 
263
285
  async function wizardTestPayment(client: ArisPayClient): Promise<void> {
264
286
  console.log(`\n${bold('Make a test payment')}`);
265
- console.log(` ${dim('Verify your integration works by sending a test payment.')}\n`);
287
+ console.log(` ${dim('Verify your integration works by sending a test payment.')}`);
288
+ console.log(` ${dim('This is a sandbox test — no real funds are moved.')}\n`);
266
289
 
267
290
  const config = loadConfig(BRAND);
268
291
  const storedAgentId = (config as any).agentId;
292
+ const storedAgentName = (config as any).agentName;
269
293
 
270
294
  let agentId: string;
271
295
  if (storedAgentId) {
272
- const useStored = await prompt(` Use agent ${dim(storedAgentId.slice(0, 12) + '...')}? ${dim('(Y/n)')}: `);
296
+ const agentLabel = storedAgentName ? bold(storedAgentName) : dim(storedAgentId.slice(0, 12) + '...');
297
+ const useStored = await prompt(` Use agent ${agentLabel}? ${dim('(Y/n)')}: `);
273
298
  if (useStored.toLowerCase() === 'n') {
274
299
  agentId = await prompt(` Agent ID: `);
275
300
  if (!agentId) { console.log(dim(' Cancelled.')); return; }
@@ -281,21 +306,30 @@ async function wizardTestPayment(client: ArisPayClient): Promise<void> {
281
306
  if (!agentId) { console.log(dim(' Cancelled.')); return; }
282
307
  }
283
308
 
284
- const amountStr = await prompt(` Amount in cents ${dim('(e.g. 500 = $5.00)')}: `);
285
- const amount = Number(amountStr);
286
- if (!amount || isNaN(amount)) { console.log(dim(' Invalid amount. Cancelled.')); return; }
309
+ const amountStr = await prompt(` Amount ${dim('(e.g. 5.00)')}: $`);
310
+ const dollars = parseFloat(amountStr);
311
+ if (!dollars || isNaN(dollars)) { console.log(dim(' Invalid amount. Cancelled.')); return; }
312
+ const amount = Math.round(dollars * 100);
287
313
 
288
- const memo = await prompt(` What is this payment for? `);
314
+ const memo = await prompt(` Description ${dim('(appears on the transaction record)')}: `);
289
315
  if (!memo) { console.log(dim(' Cancelled.')); return; }
290
316
 
291
- console.log(`\n ${dim(`Sending $${(amount / 100).toFixed(2)} test payment...`)}`);
317
+ const userId = (config as any).endUserId;
318
+ if (!userId) {
319
+ console.log(`\n ${dim('No payment method set up yet. Run option [2] first.')}`);
320
+ return;
321
+ }
322
+
323
+ console.log(`\n ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
292
324
 
293
325
  try {
294
326
  const payment = await client.payments.create({
295
327
  agentId,
328
+ userId,
296
329
  amount,
297
330
  currency: 'USD',
298
331
  memo,
332
+ merchantUrl: 'https://test.arispay.app',
299
333
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
300
334
  } as any);
301
335
  const p = payment as any;