lane-sdk 0.3.11 → 0.3.12
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/adapters/crewai/index.cjs +12 -14
- package/dist/adapters/crewai/index.d.cts +1 -1
- package/dist/adapters/crewai/index.d.ts +1 -1
- package/dist/adapters/crewai/index.js +12 -14
- package/dist/adapters/langchain/index.cjs +12 -14
- package/dist/adapters/langchain/index.d.cts +1 -1
- package/dist/adapters/langchain/index.d.ts +1 -1
- package/dist/adapters/langchain/index.js +12 -14
- package/dist/adapters/openai/index.cjs +12 -14
- package/dist/adapters/openai/index.d.cts +1 -1
- package/dist/adapters/openai/index.d.ts +1 -1
- package/dist/adapters/openai/index.js +12 -14
- package/dist/adapters/vercel-ai/index.cjs +12 -14
- package/dist/adapters/vercel-ai/index.d.cts +1 -1
- package/dist/adapters/vercel-ai/index.d.ts +1 -1
- package/dist/adapters/vercel-ai/index.js +12 -14
- package/dist/cli/index.js +6 -7
- package/dist/cli/postinstall.js +0 -1
- package/dist/index.cjs +12 -936
- package/dist/index.d.cts +3 -354
- package/dist/index.d.ts +3 -354
- package/dist/index.js +13 -928
- package/dist/{lane-CATn69s2.d.cts → lane-BgdqOeXo.d.cts} +5 -5
- package/dist/{lane-CATn69s2.d.ts → lane-BgdqOeXo.d.ts} +5 -5
- package/dist/server-http.cjs +12 -14
- package/dist/server-http.js +12 -14
- package/dist/server-stdio.cjs +12 -14
- package/dist/server-stdio.js +12 -14
- package/dist/skills/lane.md +5 -5
- package/package.json +5 -2
- package/plugin/skills/commerce-agent/SKILL.md +2 -2
- package/dist/adapters/crewai/index.cjs.map +0 -1
- package/dist/adapters/crewai/index.js.map +0 -1
- package/dist/adapters/langchain/index.cjs.map +0 -1
- package/dist/adapters/langchain/index.js.map +0 -1
- package/dist/adapters/openai/index.cjs.map +0 -1
- package/dist/adapters/openai/index.js.map +0 -1
- package/dist/adapters/vercel-ai/index.cjs.map +0 -1
- package/dist/adapters/vercel-ai/index.js.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/postinstall.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/server-http.cjs.map +0 -1
- package/dist/server-http.js.map +0 -1
- package/dist/server-stdio.cjs.map +0 -1
- package/dist/server-stdio.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5138,7 +5138,7 @@ var ConfirmInstructionTool = class extends LaneTool {
|
|
|
5138
5138
|
}
|
|
5139
5139
|
};
|
|
5140
5140
|
var inputSchema27 = z.object({
|
|
5141
|
-
platform: z.
|
|
5141
|
+
platform: z.string().describe("Commerce platform to query. The server resolves available platforms.")
|
|
5142
5142
|
});
|
|
5143
5143
|
var CommerceGetLocationsTool = class extends LaneTool {
|
|
5144
5144
|
get definition() {
|
|
@@ -5153,7 +5153,7 @@ var CommerceGetLocationsTool = class extends LaneTool {
|
|
|
5153
5153
|
}
|
|
5154
5154
|
};
|
|
5155
5155
|
var inputSchema28 = z.object({
|
|
5156
|
-
platform: z.
|
|
5156
|
+
platform: z.string().describe("Commerce platform. The server resolves available platforms."),
|
|
5157
5157
|
locationId: z.string().describe("Location ID to fetch the menu for.")
|
|
5158
5158
|
});
|
|
5159
5159
|
var CommerceGetMenuTool = class extends LaneTool {
|
|
@@ -5169,7 +5169,7 @@ var CommerceGetMenuTool = class extends LaneTool {
|
|
|
5169
5169
|
}
|
|
5170
5170
|
};
|
|
5171
5171
|
var inputSchema29 = z.object({
|
|
5172
|
-
platform: z.
|
|
5172
|
+
platform: z.string().describe("Commerce platform. The server resolves available platforms."),
|
|
5173
5173
|
itemId: z.string().describe("Item ID to fetch modifiers for.")
|
|
5174
5174
|
});
|
|
5175
5175
|
var CommerceGetModifiersTool = class extends LaneTool {
|
|
@@ -5196,7 +5196,7 @@ var inputSchema30 = z.object({
|
|
|
5196
5196
|
text: z.string().optional().describe('Natural language order request (e.g., "4 cold brews for pickup at Equator tomorrow 2pm"). If provided, server auto-resolves item, quantity, location, time, and modifiers.'),
|
|
5197
5197
|
// Option B: structured params (agent already resolved from menu)
|
|
5198
5198
|
description: z.string().optional().describe("Order summary (required if text not provided)."),
|
|
5199
|
-
platform: z.
|
|
5199
|
+
platform: z.string().optional().describe("Auto-detected by the server if omitted."),
|
|
5200
5200
|
merchant: z.string().optional().describe("Merchant name (auto-detected from text if provided)."),
|
|
5201
5201
|
walletId: z.string().default("default").describe("Wallet ID."),
|
|
5202
5202
|
locationId: z.string().optional().describe("Location ID (auto-resolved from text if provided)."),
|
|
@@ -5229,7 +5229,7 @@ var CommerceOrderIntentTool = class extends LaneTool {
|
|
|
5229
5229
|
};
|
|
5230
5230
|
}
|
|
5231
5231
|
async run(input) {
|
|
5232
|
-
const platform2 = input.platform ??
|
|
5232
|
+
const platform2 = input.platform ?? "auto";
|
|
5233
5233
|
return this.getLane().commerce.orders.createIntent(platform2, {
|
|
5234
5234
|
...input,
|
|
5235
5235
|
description: input.description ?? input.text ?? "",
|
|
@@ -5240,7 +5240,7 @@ var CommerceOrderIntentTool = class extends LaneTool {
|
|
|
5240
5240
|
}
|
|
5241
5241
|
};
|
|
5242
5242
|
var inputSchema31 = z.object({
|
|
5243
|
-
platform: z.
|
|
5243
|
+
platform: z.string().optional().describe("Auto-detected from instruction if omitted."),
|
|
5244
5244
|
instructionId: z.string().describe("Instruction ID from order intent."),
|
|
5245
5245
|
mandateId: z.string().describe("Mandate ID from order intent.")
|
|
5246
5246
|
});
|
|
@@ -5253,7 +5253,7 @@ var CommerceExecuteOrderTool = class extends LaneTool {
|
|
|
5253
5253
|
};
|
|
5254
5254
|
}
|
|
5255
5255
|
async run(input) {
|
|
5256
|
-
const platform2 = input.platform ?? "
|
|
5256
|
+
const platform2 = input.platform ?? "auto";
|
|
5257
5257
|
return this.getLane().commerce.orders.executeIntent(
|
|
5258
5258
|
platform2,
|
|
5259
5259
|
input.instructionId,
|
|
@@ -5262,7 +5262,7 @@ var CommerceExecuteOrderTool = class extends LaneTool {
|
|
|
5262
5262
|
}
|
|
5263
5263
|
};
|
|
5264
5264
|
var inputSchema32 = z.object({
|
|
5265
|
-
platform: z.
|
|
5265
|
+
platform: z.string().describe("Commerce platform to connect. The server resolves available platforms."),
|
|
5266
5266
|
walletId: z.string().optional().describe("Wallet ID to associate."),
|
|
5267
5267
|
userEmail: z.string().optional().describe("User email for the platform."),
|
|
5268
5268
|
displayName: z.string().optional().describe("Display name for the connection.")
|
|
@@ -5295,7 +5295,7 @@ var CommerceProviderStatusTool = class extends LaneTool {
|
|
|
5295
5295
|
}
|
|
5296
5296
|
};
|
|
5297
5297
|
var inputSchema34 = z.object({
|
|
5298
|
-
platform: z.
|
|
5298
|
+
platform: z.string().optional().describe("Auto-detected from instruction if omitted."),
|
|
5299
5299
|
orderId: z.string().describe("Order ID from the create order step."),
|
|
5300
5300
|
instructionId: z.string().describe("Instruction ID from order intent."),
|
|
5301
5301
|
cardId: z.string().optional().describe("Payment card ID. If omitted, server resolves first saved card."),
|
|
@@ -5311,7 +5311,7 @@ var CommerceCheckoutConfigTool = class extends LaneTool {
|
|
|
5311
5311
|
};
|
|
5312
5312
|
}
|
|
5313
5313
|
async run(input) {
|
|
5314
|
-
const platform2 = input.platform ?? "
|
|
5314
|
+
const platform2 = input.platform ?? "auto";
|
|
5315
5315
|
return this.getLane().commerce.orders.configureCheckout(platform2, input.orderId, {
|
|
5316
5316
|
instructionId: input.instructionId,
|
|
5317
5317
|
cardId: input.cardId,
|
|
@@ -5321,7 +5321,7 @@ var CommerceCheckoutConfigTool = class extends LaneTool {
|
|
|
5321
5321
|
}
|
|
5322
5322
|
};
|
|
5323
5323
|
var inputSchema35 = z.object({
|
|
5324
|
-
platform: z.
|
|
5324
|
+
platform: z.string().optional().describe("Auto-detected from instruction if omitted."),
|
|
5325
5325
|
orderId: z.string().describe("Order ID to submit."),
|
|
5326
5326
|
instructionId: z.string().describe("Instruction ID from order intent."),
|
|
5327
5327
|
mandateId: z.string().describe("Mandate ID from order intent.")
|
|
@@ -5335,7 +5335,7 @@ var CommerceSubmitOrderTool = class extends LaneTool {
|
|
|
5335
5335
|
};
|
|
5336
5336
|
}
|
|
5337
5337
|
async run(input) {
|
|
5338
|
-
const platform2 = input.platform ?? "
|
|
5338
|
+
const platform2 = input.platform ?? "auto";
|
|
5339
5339
|
return this.getLane().commerce.orders.submit(platform2, input.orderId, {
|
|
5340
5340
|
instructionId: input.instructionId,
|
|
5341
5341
|
mandateId: input.mandateId
|
|
@@ -5462,139 +5462,6 @@ var LaneMCPServer = class {
|
|
|
5462
5462
|
}
|
|
5463
5463
|
};
|
|
5464
5464
|
|
|
5465
|
-
// src/vgs/token.ts
|
|
5466
|
-
var TOKEN_REFRESH_MARGIN_MS = 6e4;
|
|
5467
|
-
var VGSTokenManager = class {
|
|
5468
|
-
constructor(config) {
|
|
5469
|
-
this.config = config;
|
|
5470
|
-
}
|
|
5471
|
-
cached = null;
|
|
5472
|
-
clearTimer = null;
|
|
5473
|
-
/**
|
|
5474
|
-
* Get a valid access token, refreshing if expired or near-expiry.
|
|
5475
|
-
*/
|
|
5476
|
-
async getAccessToken() {
|
|
5477
|
-
if (this.cached && Date.now() < this.cached.expiresAt - TOKEN_REFRESH_MARGIN_MS) {
|
|
5478
|
-
return this.cached.accessToken;
|
|
5479
|
-
}
|
|
5480
|
-
return this.refresh();
|
|
5481
|
-
}
|
|
5482
|
-
/**
|
|
5483
|
-
* Force-refresh the token.
|
|
5484
|
-
*/
|
|
5485
|
-
async refresh() {
|
|
5486
|
-
const tokenUrl = this.getTokenUrl();
|
|
5487
|
-
const body = new URLSearchParams({
|
|
5488
|
-
grant_type: "client_credentials",
|
|
5489
|
-
client_id: this.config.clientId,
|
|
5490
|
-
client_secret: this.config.clientSecret
|
|
5491
|
-
});
|
|
5492
|
-
const response = await fetch(tokenUrl, {
|
|
5493
|
-
method: "POST",
|
|
5494
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
5495
|
-
body: body.toString()
|
|
5496
|
-
});
|
|
5497
|
-
if (!response.ok) {
|
|
5498
|
-
throw LaneAuthError.invalidApiKey(
|
|
5499
|
-
`VGS token exchange failed: ${response.status} ${response.statusText}`
|
|
5500
|
-
);
|
|
5501
|
-
}
|
|
5502
|
-
const data = await response.json();
|
|
5503
|
-
this.clearCachedToken();
|
|
5504
|
-
this.cached = {
|
|
5505
|
-
accessToken: data.access_token,
|
|
5506
|
-
expiresAt: Date.now() + data.expires_in * 1e3
|
|
5507
|
-
};
|
|
5508
|
-
this.clearTimer = setTimeout(() => {
|
|
5509
|
-
this.clearCachedToken();
|
|
5510
|
-
}, data.expires_in * 1e3);
|
|
5511
|
-
this.clearTimer.unref();
|
|
5512
|
-
return this.cached.accessToken;
|
|
5513
|
-
}
|
|
5514
|
-
/**
|
|
5515
|
-
* Invalidate the cached token.
|
|
5516
|
-
*/
|
|
5517
|
-
invalidate() {
|
|
5518
|
-
this.clearCachedToken();
|
|
5519
|
-
}
|
|
5520
|
-
/**
|
|
5521
|
-
* Overwrite and release the cached token from memory.
|
|
5522
|
-
*/
|
|
5523
|
-
clearCachedToken() {
|
|
5524
|
-
if (this.clearTimer) {
|
|
5525
|
-
clearTimeout(this.clearTimer);
|
|
5526
|
-
this.clearTimer = null;
|
|
5527
|
-
}
|
|
5528
|
-
if (this.cached) {
|
|
5529
|
-
this.cached.accessToken = "";
|
|
5530
|
-
this.cached = null;
|
|
5531
|
-
}
|
|
5532
|
-
}
|
|
5533
|
-
getTokenUrl() {
|
|
5534
|
-
const env = this.config.environment === "live" ? "live" : "sandbox";
|
|
5535
|
-
return `https://auth.verygoodsecurity.com/vaults/${this.config.vaultId}/tokens?env=${env}`;
|
|
5536
|
-
}
|
|
5537
|
-
};
|
|
5538
|
-
|
|
5539
|
-
// src/vgs/proxy.ts
|
|
5540
|
-
var VGSOutboundProxy = class {
|
|
5541
|
-
constructor(config) {
|
|
5542
|
-
this.config = config;
|
|
5543
|
-
this.tokenManager = new VGSTokenManager(config);
|
|
5544
|
-
}
|
|
5545
|
-
tokenManager;
|
|
5546
|
-
/**
|
|
5547
|
-
* Send a request through the VGS outbound proxy.
|
|
5548
|
-
* VGS aliases in the body are de-tokenized and revealed to the target PSP.
|
|
5549
|
-
*/
|
|
5550
|
-
async forward(request) {
|
|
5551
|
-
const accessToken = await this.tokenManager.getAccessToken();
|
|
5552
|
-
const proxyUrl = this.getProxyUrl();
|
|
5553
|
-
const response = await fetch(proxyUrl, {
|
|
5554
|
-
method: request.method,
|
|
5555
|
-
headers: {
|
|
5556
|
-
...request.headers,
|
|
5557
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
5558
|
-
"X-VGS-Route-Id": this.config.routeId,
|
|
5559
|
-
"X-VGS-Upstream-Url": request.url,
|
|
5560
|
-
"Content-Type": "application/json"
|
|
5561
|
-
},
|
|
5562
|
-
body: JSON.stringify(request.body)
|
|
5563
|
-
});
|
|
5564
|
-
const responseBody = await response.json().catch(() => null);
|
|
5565
|
-
if (!response.ok) {
|
|
5566
|
-
throw new LanePaymentError(
|
|
5567
|
-
`VGS proxy request failed: ${response.status}`,
|
|
5568
|
-
{
|
|
5569
|
-
code: "vgs_proxy_error",
|
|
5570
|
-
statusCode: response.status,
|
|
5571
|
-
retryable: response.status >= 500,
|
|
5572
|
-
suggestedAction: "Check VGS vault configuration and PSP endpoint whitelist."
|
|
5573
|
-
}
|
|
5574
|
-
);
|
|
5575
|
-
}
|
|
5576
|
-
const responseHeaders = {};
|
|
5577
|
-
response.headers.forEach((value, key) => {
|
|
5578
|
-
responseHeaders[key] = value;
|
|
5579
|
-
});
|
|
5580
|
-
return {
|
|
5581
|
-
status: response.status,
|
|
5582
|
-
headers: responseHeaders,
|
|
5583
|
-
body: responseBody
|
|
5584
|
-
};
|
|
5585
|
-
}
|
|
5586
|
-
/**
|
|
5587
|
-
* Invalidate the cached VGS access token.
|
|
5588
|
-
*/
|
|
5589
|
-
invalidateToken() {
|
|
5590
|
-
this.tokenManager.invalidate();
|
|
5591
|
-
}
|
|
5592
|
-
getProxyUrl() {
|
|
5593
|
-
const env = this.config.environment === "live" ? "live" : "sandbox";
|
|
5594
|
-
return `https://${this.config.vaultId}.${env}.verygoodproxy.com`;
|
|
5595
|
-
}
|
|
5596
|
-
};
|
|
5597
|
-
|
|
5598
5465
|
// src/vgs/card-types.ts
|
|
5599
5466
|
var BIN_RANGES = [
|
|
5600
5467
|
{ brand: "visa", prefixes: ["4"], lengths: [13, 16, 19] },
|
|
@@ -5638,638 +5505,6 @@ function maskCardNumber(cardNumber) {
|
|
|
5638
5505
|
return `****${digits.slice(-4)}`;
|
|
5639
5506
|
}
|
|
5640
5507
|
|
|
5641
|
-
// src/vgs/collect.ts
|
|
5642
|
-
function generateCollectPage(config) {
|
|
5643
|
-
const vgsEnv = config.environment === "live" ? "live" : "sandbox";
|
|
5644
|
-
`https://${config.vaultId}.${vgsEnv}.verygoodproxy.com`;
|
|
5645
|
-
return `<!DOCTYPE html>
|
|
5646
|
-
<html lang="en">
|
|
5647
|
-
<head>
|
|
5648
|
-
<meta charset="UTF-8">
|
|
5649
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5650
|
-
<title>Lane \u2014 Add Payment Method</title>
|
|
5651
|
-
<script src="https://js.verygoodvault.com/vgs-collect/2.18.0/vgs-collect.js"></script>
|
|
5652
|
-
<style>
|
|
5653
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
5654
|
-
body {
|
|
5655
|
-
font-family: 'At Aero', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
5656
|
-
background: #0A0A0A;
|
|
5657
|
-
color: #FFFFFF;
|
|
5658
|
-
display: flex;
|
|
5659
|
-
justify-content: center;
|
|
5660
|
-
align-items: center;
|
|
5661
|
-
min-height: 100vh;
|
|
5662
|
-
}
|
|
5663
|
-
.container {
|
|
5664
|
-
width: 100%;
|
|
5665
|
-
max-width: 440px;
|
|
5666
|
-
padding: 40px 32px;
|
|
5667
|
-
background: #141414;
|
|
5668
|
-
border: 1px solid #2A2A2A;
|
|
5669
|
-
border-radius: 16px;
|
|
5670
|
-
}
|
|
5671
|
-
.logo {
|
|
5672
|
-
font-size: 24px;
|
|
5673
|
-
font-weight: 700;
|
|
5674
|
-
color: #1201FF;
|
|
5675
|
-
letter-spacing: -0.5px;
|
|
5676
|
-
margin-bottom: 8px;
|
|
5677
|
-
}
|
|
5678
|
-
.subtitle {
|
|
5679
|
-
color: #888;
|
|
5680
|
-
font-size: 14px;
|
|
5681
|
-
margin-bottom: 32px;
|
|
5682
|
-
}
|
|
5683
|
-
.field-group {
|
|
5684
|
-
margin-bottom: 20px;
|
|
5685
|
-
}
|
|
5686
|
-
.field-group label {
|
|
5687
|
-
display: block;
|
|
5688
|
-
font-size: 12px;
|
|
5689
|
-
font-weight: 600;
|
|
5690
|
-
color: #888;
|
|
5691
|
-
text-transform: uppercase;
|
|
5692
|
-
letter-spacing: 0.5px;
|
|
5693
|
-
margin-bottom: 8px;
|
|
5694
|
-
}
|
|
5695
|
-
.field-wrapper {
|
|
5696
|
-
background: #1A1A1A;
|
|
5697
|
-
border: 1px solid #333;
|
|
5698
|
-
border-radius: 8px;
|
|
5699
|
-
padding: 0;
|
|
5700
|
-
height: 48px;
|
|
5701
|
-
transition: border-color 0.2s;
|
|
5702
|
-
}
|
|
5703
|
-
.field-wrapper:focus-within {
|
|
5704
|
-
border-color: #1201FF;
|
|
5705
|
-
}
|
|
5706
|
-
.field-wrapper iframe {
|
|
5707
|
-
height: 48px !important;
|
|
5708
|
-
}
|
|
5709
|
-
.row {
|
|
5710
|
-
display: flex;
|
|
5711
|
-
gap: 12px;
|
|
5712
|
-
}
|
|
5713
|
-
.row .field-group {
|
|
5714
|
-
flex: 1;
|
|
5715
|
-
}
|
|
5716
|
-
.submit-btn {
|
|
5717
|
-
width: 100%;
|
|
5718
|
-
height: 48px;
|
|
5719
|
-
background: #1201FF;
|
|
5720
|
-
color: #FFFFFF;
|
|
5721
|
-
border: none;
|
|
5722
|
-
border-radius: 8px;
|
|
5723
|
-
font-size: 16px;
|
|
5724
|
-
font-weight: 600;
|
|
5725
|
-
cursor: pointer;
|
|
5726
|
-
margin-top: 24px;
|
|
5727
|
-
transition: background 0.2s;
|
|
5728
|
-
}
|
|
5729
|
-
.submit-btn:hover { background: #0E01CC; }
|
|
5730
|
-
.submit-btn:disabled {
|
|
5731
|
-
background: #333;
|
|
5732
|
-
cursor: not-allowed;
|
|
5733
|
-
}
|
|
5734
|
-
.security-note {
|
|
5735
|
-
text-align: center;
|
|
5736
|
-
margin-top: 16px;
|
|
5737
|
-
font-size: 12px;
|
|
5738
|
-
color: #555;
|
|
5739
|
-
}
|
|
5740
|
-
.security-note svg {
|
|
5741
|
-
vertical-align: middle;
|
|
5742
|
-
margin-right: 4px;
|
|
5743
|
-
}
|
|
5744
|
-
.error-msg {
|
|
5745
|
-
color: #FF4444;
|
|
5746
|
-
font-size: 13px;
|
|
5747
|
-
margin-top: 8px;
|
|
5748
|
-
display: none;
|
|
5749
|
-
}
|
|
5750
|
-
.success-container {
|
|
5751
|
-
text-align: center;
|
|
5752
|
-
display: none;
|
|
5753
|
-
}
|
|
5754
|
-
.success-container .check {
|
|
5755
|
-
font-size: 48px;
|
|
5756
|
-
margin-bottom: 16px;
|
|
5757
|
-
}
|
|
5758
|
-
</style>
|
|
5759
|
-
</head>
|
|
5760
|
-
<body>
|
|
5761
|
-
<div class="container">
|
|
5762
|
-
<div id="form-view">
|
|
5763
|
-
<div class="logo">Lane</div>
|
|
5764
|
-
<div class="subtitle">Add a payment method. Your card data goes directly to our PCI Level 1 vault.</div>
|
|
5765
|
-
|
|
5766
|
-
<form id="card-form">
|
|
5767
|
-
<div class="field-group">
|
|
5768
|
-
<label>Card Number</label>
|
|
5769
|
-
<div id="cc-number" class="field-wrapper"></div>
|
|
5770
|
-
</div>
|
|
5771
|
-
|
|
5772
|
-
<div class="row">
|
|
5773
|
-
<div class="field-group">
|
|
5774
|
-
<label>Expiry</label>
|
|
5775
|
-
<div id="cc-expiry" class="field-wrapper"></div>
|
|
5776
|
-
</div>
|
|
5777
|
-
<div class="field-group">
|
|
5778
|
-
<label>CVC</label>
|
|
5779
|
-
<div id="cc-cvc" class="field-wrapper"></div>
|
|
5780
|
-
</div>
|
|
5781
|
-
</div>
|
|
5782
|
-
|
|
5783
|
-
<div class="field-group">
|
|
5784
|
-
<label>Cardholder Name</label>
|
|
5785
|
-
<div id="cc-name" class="field-wrapper"></div>
|
|
5786
|
-
</div>
|
|
5787
|
-
|
|
5788
|
-
<div id="error-msg" class="error-msg"></div>
|
|
5789
|
-
|
|
5790
|
-
<button type="submit" id="submit-btn" class="submit-btn" disabled>
|
|
5791
|
-
Add Card
|
|
5792
|
-
</button>
|
|
5793
|
-
</form>
|
|
5794
|
-
|
|
5795
|
-
<div class="security-note">
|
|
5796
|
-
<svg width="12" height="12" viewBox="0 0 12 12" fill="#555"><path d="M6 1a3 3 0 0 0-3 3v1H2.5A.5.5 0 0 0 2 5.5v5a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5v-5A.5.5 0 0 0 9.5 5H9V4a3 3 0 0 0-3-3zm2 4H4V4a2 2 0 1 1 4 0v1z"/></svg>
|
|
5797
|
-
Secured by VGS. Lane never sees your card number.
|
|
5798
|
-
</div>
|
|
5799
|
-
</div>
|
|
5800
|
-
|
|
5801
|
-
<div id="success-view" class="success-container">
|
|
5802
|
-
<div class="check">✓</div>
|
|
5803
|
-
<div class="logo">Card Added</div>
|
|
5804
|
-
<div class="subtitle">You can close this window and return to your terminal.</div>
|
|
5805
|
-
</div>
|
|
5806
|
-
</div>
|
|
5807
|
-
|
|
5808
|
-
<script>
|
|
5809
|
-
const form = VGSCollect.create('${config.vaultId}', '${vgsEnv}', function(state) {});
|
|
5810
|
-
const css = {
|
|
5811
|
-
'font-family': '"JetBrains Mono", monospace',
|
|
5812
|
-
'font-size': '16px',
|
|
5813
|
-
'color': '#FFFFFF',
|
|
5814
|
-
'padding': '12px 16px',
|
|
5815
|
-
'&::placeholder': { color: '#555' },
|
|
5816
|
-
};
|
|
5817
|
-
|
|
5818
|
-
form.field('#cc-number', {
|
|
5819
|
-
type: 'card-number',
|
|
5820
|
-
name: 'card_number',
|
|
5821
|
-
placeholder: '4242 4242 4242 4242',
|
|
5822
|
-
validations: ['required', 'validCardNumber'],
|
|
5823
|
-
css: css,
|
|
5824
|
-
});
|
|
5825
|
-
|
|
5826
|
-
form.field('#cc-expiry', {
|
|
5827
|
-
type: 'card-expiration-date',
|
|
5828
|
-
name: 'card_exp',
|
|
5829
|
-
placeholder: 'MM / YY',
|
|
5830
|
-
validations: ['required', 'validCardExpirationDate'],
|
|
5831
|
-
css: css,
|
|
5832
|
-
});
|
|
5833
|
-
|
|
5834
|
-
form.field('#cc-cvc', {
|
|
5835
|
-
type: 'card-security-code',
|
|
5836
|
-
name: 'card_cvc',
|
|
5837
|
-
placeholder: 'CVC',
|
|
5838
|
-
validations: ['required', 'validCardSecurityCode'],
|
|
5839
|
-
css: css,
|
|
5840
|
-
});
|
|
5841
|
-
|
|
5842
|
-
form.field('#cc-name', {
|
|
5843
|
-
type: 'text',
|
|
5844
|
-
name: 'card_name',
|
|
5845
|
-
placeholder: 'Name on card',
|
|
5846
|
-
validations: ['required'],
|
|
5847
|
-
css: css,
|
|
5848
|
-
});
|
|
5849
|
-
|
|
5850
|
-
// Enable submit when all fields are valid
|
|
5851
|
-
let fieldStates = {};
|
|
5852
|
-
form.on('change', function(state) {
|
|
5853
|
-
fieldStates = state;
|
|
5854
|
-
const allValid = Object.values(state).every(function(f) { return f.isValid; });
|
|
5855
|
-
document.getElementById('submit-btn').disabled = !allValid;
|
|
5856
|
-
});
|
|
5857
|
-
|
|
5858
|
-
document.getElementById('card-form').addEventListener('submit', function(e) {
|
|
5859
|
-
e.preventDefault();
|
|
5860
|
-
var btn = document.getElementById('submit-btn');
|
|
5861
|
-
btn.disabled = true;
|
|
5862
|
-
btn.textContent = 'Processing...';
|
|
5863
|
-
document.getElementById('error-msg').style.display = 'none';
|
|
5864
|
-
|
|
5865
|
-
form.submit(
|
|
5866
|
-
'/post',
|
|
5867
|
-
{
|
|
5868
|
-
headers: { 'Content-Type': 'application/json' },
|
|
5869
|
-
data: function(fields) {
|
|
5870
|
-
return {
|
|
5871
|
-
card_number: fields.card_number,
|
|
5872
|
-
card_exp: fields.card_exp,
|
|
5873
|
-
card_cvc: fields.card_cvc,
|
|
5874
|
-
card_name: fields.card_name,
|
|
5875
|
-
developer_id: '${config.developerId}',
|
|
5876
|
-
};
|
|
5877
|
-
},
|
|
5878
|
-
},
|
|
5879
|
-
function(status, data) {
|
|
5880
|
-
if (status >= 200 && status < 300) {
|
|
5881
|
-
document.getElementById('form-view').style.display = 'none';
|
|
5882
|
-
document.getElementById('success-view').style.display = 'block';
|
|
5883
|
-
// Notify callback
|
|
5884
|
-
fetch('${config.callbackUrl}', {
|
|
5885
|
-
method: 'POST',
|
|
5886
|
-
headers: { 'Content-Type': 'application/json' },
|
|
5887
|
-
body: JSON.stringify({
|
|
5888
|
-
alias: data.card_number,
|
|
5889
|
-
last4: data.last4 || 'xxxx',
|
|
5890
|
-
brand: data.brand || 'unknown',
|
|
5891
|
-
}),
|
|
5892
|
-
});
|
|
5893
|
-
} else {
|
|
5894
|
-
var errEl = document.getElementById('error-msg');
|
|
5895
|
-
errEl.textContent = 'Card could not be saved. Please check your details and try again.';
|
|
5896
|
-
errEl.style.display = 'block';
|
|
5897
|
-
btn.disabled = false;
|
|
5898
|
-
btn.textContent = 'Add Card';
|
|
5899
|
-
}
|
|
5900
|
-
},
|
|
5901
|
-
function(errors) {
|
|
5902
|
-
var errEl = document.getElementById('error-msg');
|
|
5903
|
-
errEl.textContent = 'Validation failed. Please check all fields.';
|
|
5904
|
-
errEl.style.display = 'block';
|
|
5905
|
-
btn.disabled = false;
|
|
5906
|
-
btn.textContent = 'Add Card';
|
|
5907
|
-
}
|
|
5908
|
-
);
|
|
5909
|
-
});
|
|
5910
|
-
</script>
|
|
5911
|
-
</body>
|
|
5912
|
-
</html>`;
|
|
5913
|
-
}
|
|
5914
|
-
|
|
5915
|
-
// src/psp/registry.ts
|
|
5916
|
-
var PSPRegistry = class {
|
|
5917
|
-
adapters = /* @__PURE__ */ new Map();
|
|
5918
|
-
/**
|
|
5919
|
-
* Register an adapter with a priority (lower = higher priority).
|
|
5920
|
-
*/
|
|
5921
|
-
register(adapter, priority = 100) {
|
|
5922
|
-
this.adapters.set(adapter.name, { adapter, priority });
|
|
5923
|
-
}
|
|
5924
|
-
/**
|
|
5925
|
-
* Remove an adapter from the registry.
|
|
5926
|
-
*/
|
|
5927
|
-
unregister(name) {
|
|
5928
|
-
this.adapters.delete(name);
|
|
5929
|
-
}
|
|
5930
|
-
/**
|
|
5931
|
-
* Get a specific adapter by name.
|
|
5932
|
-
*/
|
|
5933
|
-
get(name) {
|
|
5934
|
-
return this.adapters.get(name)?.adapter;
|
|
5935
|
-
}
|
|
5936
|
-
/**
|
|
5937
|
-
* Get the highest-priority adapter (lowest priority number).
|
|
5938
|
-
* Optionally exclude specific adapters (e.g., after a failure).
|
|
5939
|
-
*/
|
|
5940
|
-
getPrimary(exclude) {
|
|
5941
|
-
let best;
|
|
5942
|
-
for (const [name, entry] of this.adapters) {
|
|
5943
|
-
if (exclude?.has(name)) continue;
|
|
5944
|
-
if (!best || entry.priority < best.priority) {
|
|
5945
|
-
best = entry;
|
|
5946
|
-
}
|
|
5947
|
-
}
|
|
5948
|
-
return best?.adapter;
|
|
5949
|
-
}
|
|
5950
|
-
/**
|
|
5951
|
-
* Get all registered adapters sorted by priority.
|
|
5952
|
-
*/
|
|
5953
|
-
getAll() {
|
|
5954
|
-
return Array.from(this.adapters.values()).sort((a, b) => a.priority - b.priority).map((entry) => entry.adapter);
|
|
5955
|
-
}
|
|
5956
|
-
/**
|
|
5957
|
-
* Run health checks on all adapters. Returns names of healthy adapters.
|
|
5958
|
-
*/
|
|
5959
|
-
async healthCheckAll() {
|
|
5960
|
-
const results = await Promise.allSettled(
|
|
5961
|
-
Array.from(this.adapters.entries()).map(async ([name, { adapter }]) => {
|
|
5962
|
-
const ok = await adapter.healthCheck();
|
|
5963
|
-
return ok ? name : null;
|
|
5964
|
-
})
|
|
5965
|
-
);
|
|
5966
|
-
return results.filter((r) => r.status === "fulfilled" && r.value !== null).map((r) => r.value);
|
|
5967
|
-
}
|
|
5968
|
-
};
|
|
5969
|
-
|
|
5970
|
-
// src/psp/adapters/stripe.ts
|
|
5971
|
-
var StripeAdapter = class {
|
|
5972
|
-
name = "stripe";
|
|
5973
|
-
config;
|
|
5974
|
-
constructor(config) {
|
|
5975
|
-
this.config = config;
|
|
5976
|
-
}
|
|
5977
|
-
async charge(params) {
|
|
5978
|
-
const now = /* @__PURE__ */ new Date();
|
|
5979
|
-
const expiryDate = new Date(params.expYear, params.expMonth);
|
|
5980
|
-
if (expiryDate <= now) {
|
|
5981
|
-
return {
|
|
5982
|
-
pspTransactionId: "",
|
|
5983
|
-
status: "failed",
|
|
5984
|
-
declineReason: "Card has expired",
|
|
5985
|
-
rawResponse: { error: "card_expired", expMonth: params.expMonth, expYear: params.expYear }
|
|
5986
|
-
};
|
|
5987
|
-
}
|
|
5988
|
-
const body = {
|
|
5989
|
-
amount: params.amount,
|
|
5990
|
-
currency: params.currency.toLowerCase(),
|
|
5991
|
-
source: {
|
|
5992
|
-
object: "card",
|
|
5993
|
-
number: params.cardAlias,
|
|
5994
|
-
// VGS reveals this to Stripe
|
|
5995
|
-
exp_month: params.expMonth,
|
|
5996
|
-
exp_year: params.expYear,
|
|
5997
|
-
cvc: params.cvvAlias
|
|
5998
|
-
},
|
|
5999
|
-
description: params.merchantDescriptor,
|
|
6000
|
-
metadata: params.metadata ?? {}
|
|
6001
|
-
};
|
|
6002
|
-
const response = await this.config.proxy.forward({
|
|
6003
|
-
url: "https://api.stripe.com/v1/charges",
|
|
6004
|
-
method: "POST",
|
|
6005
|
-
headers: {
|
|
6006
|
-
"Authorization": `Bearer ${this.config.secretKey}`,
|
|
6007
|
-
"Stripe-Version": this.config.apiVersion ?? "2024-12-18.acacia",
|
|
6008
|
-
...params.idempotencyKey ? { "Idempotency-Key": params.idempotencyKey } : {}
|
|
6009
|
-
},
|
|
6010
|
-
body
|
|
6011
|
-
});
|
|
6012
|
-
const data = response.body;
|
|
6013
|
-
const status = data["status"] === "succeeded" ? "succeeded" : data["status"] === "pending" ? "pending" : "failed";
|
|
6014
|
-
return {
|
|
6015
|
-
pspTransactionId: String(data["id"] ?? ""),
|
|
6016
|
-
status,
|
|
6017
|
-
authorizationCode: data["authorization_code"],
|
|
6018
|
-
declineReason: status === "failed" ? String(data["failure_message"] ?? "unknown") : void 0,
|
|
6019
|
-
rawResponse: data
|
|
6020
|
-
};
|
|
6021
|
-
}
|
|
6022
|
-
async refund(params) {
|
|
6023
|
-
const body = {
|
|
6024
|
-
charge: params.pspTransactionId,
|
|
6025
|
-
...params.amount !== void 0 ? { amount: params.amount } : {},
|
|
6026
|
-
...params.reason ? { reason: params.reason } : {}
|
|
6027
|
-
};
|
|
6028
|
-
const response = await this.config.proxy.forward({
|
|
6029
|
-
url: "https://api.stripe.com/v1/refunds",
|
|
6030
|
-
method: "POST",
|
|
6031
|
-
headers: {
|
|
6032
|
-
"Authorization": `Bearer ${this.config.secretKey}`,
|
|
6033
|
-
"Stripe-Version": this.config.apiVersion ?? "2024-12-18.acacia",
|
|
6034
|
-
...params.idempotencyKey ? { "Idempotency-Key": params.idempotencyKey } : {}
|
|
6035
|
-
},
|
|
6036
|
-
body
|
|
6037
|
-
});
|
|
6038
|
-
const data = response.body;
|
|
6039
|
-
const status = data["status"] === "succeeded" ? "succeeded" : data["status"] === "pending" ? "pending" : "failed";
|
|
6040
|
-
return {
|
|
6041
|
-
pspRefundId: String(data["id"] ?? ""),
|
|
6042
|
-
status,
|
|
6043
|
-
amount: Number(data["amount"] ?? 0),
|
|
6044
|
-
rawResponse: data
|
|
6045
|
-
};
|
|
6046
|
-
}
|
|
6047
|
-
async healthCheck() {
|
|
6048
|
-
try {
|
|
6049
|
-
const response = await fetch("https://api.stripe.com/v1/balance", {
|
|
6050
|
-
headers: { "Authorization": `Bearer ${this.config.secretKey}` }
|
|
6051
|
-
});
|
|
6052
|
-
return response.ok;
|
|
6053
|
-
} catch {
|
|
6054
|
-
return false;
|
|
6055
|
-
}
|
|
6056
|
-
}
|
|
6057
|
-
};
|
|
6058
|
-
|
|
6059
|
-
// src/psp/adapters/worldpay.ts
|
|
6060
|
-
var WorldpayAdapter = class {
|
|
6061
|
-
name = "worldpay";
|
|
6062
|
-
config;
|
|
6063
|
-
constructor(config) {
|
|
6064
|
-
this.config = config;
|
|
6065
|
-
}
|
|
6066
|
-
async charge(params) {
|
|
6067
|
-
const now = /* @__PURE__ */ new Date();
|
|
6068
|
-
const expiryDate = new Date(params.expYear, params.expMonth);
|
|
6069
|
-
if (expiryDate <= now) {
|
|
6070
|
-
return {
|
|
6071
|
-
pspTransactionId: "",
|
|
6072
|
-
status: "failed",
|
|
6073
|
-
declineReason: "Card has expired",
|
|
6074
|
-
rawResponse: { error: "card_expired", expMonth: params.expMonth, expYear: params.expYear }
|
|
6075
|
-
};
|
|
6076
|
-
}
|
|
6077
|
-
const body = {
|
|
6078
|
-
transactionType: "sale",
|
|
6079
|
-
amount: {
|
|
6080
|
-
value: params.amount,
|
|
6081
|
-
currencyCode: params.currency.toUpperCase()
|
|
6082
|
-
},
|
|
6083
|
-
paymentInstrument: {
|
|
6084
|
-
type: "card/plain",
|
|
6085
|
-
cardNumber: params.cardAlias,
|
|
6086
|
-
// VGS reveals to Worldpay
|
|
6087
|
-
expiryDate: {
|
|
6088
|
-
month: params.expMonth,
|
|
6089
|
-
year: params.expYear
|
|
6090
|
-
},
|
|
6091
|
-
cvc: params.cvvAlias
|
|
6092
|
-
},
|
|
6093
|
-
merchant: {
|
|
6094
|
-
entity: this.config.merchantId
|
|
6095
|
-
},
|
|
6096
|
-
narrative: {
|
|
6097
|
-
line1: params.merchantDescriptor
|
|
6098
|
-
}
|
|
6099
|
-
};
|
|
6100
|
-
const response = await this.config.proxy.forward({
|
|
6101
|
-
url: `${this.config.baseUrl}/payments/authorizations`,
|
|
6102
|
-
method: "POST",
|
|
6103
|
-
headers: {
|
|
6104
|
-
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
6105
|
-
...params.idempotencyKey ? { "Idempotency-Key": params.idempotencyKey } : {}
|
|
6106
|
-
},
|
|
6107
|
-
body
|
|
6108
|
-
});
|
|
6109
|
-
const data = response.body;
|
|
6110
|
-
const outcome = data["outcome"];
|
|
6111
|
-
const status = outcome === "approved" ? "succeeded" : outcome === "pending" ? "pending" : "failed";
|
|
6112
|
-
return {
|
|
6113
|
-
pspTransactionId: String(data["_links"] && data["_links"]["self"] || ""),
|
|
6114
|
-
status,
|
|
6115
|
-
authorizationCode: data["authorizationCode"],
|
|
6116
|
-
declineReason: status === "failed" ? String(data["description"] ?? "declined") : void 0,
|
|
6117
|
-
rawResponse: data
|
|
6118
|
-
};
|
|
6119
|
-
}
|
|
6120
|
-
async refund(params) {
|
|
6121
|
-
const body = {
|
|
6122
|
-
...params.amount !== void 0 ? { value: { amount: params.amount, currencyCode: "USD" } } : {},
|
|
6123
|
-
...params.reason ? { reference: params.reason } : {}
|
|
6124
|
-
};
|
|
6125
|
-
const response = await this.config.proxy.forward({
|
|
6126
|
-
url: `${this.config.baseUrl}/payments/${params.pspTransactionId}/refunds`,
|
|
6127
|
-
method: "POST",
|
|
6128
|
-
headers: {
|
|
6129
|
-
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
6130
|
-
...params.idempotencyKey ? { "Idempotency-Key": params.idempotencyKey } : {}
|
|
6131
|
-
},
|
|
6132
|
-
body
|
|
6133
|
-
});
|
|
6134
|
-
const data = response.body;
|
|
6135
|
-
const outcome = data["outcome"];
|
|
6136
|
-
const refundStatus = outcome === "failed" ? "failed" : outcome === "pending" ? "pending" : "succeeded";
|
|
6137
|
-
return {
|
|
6138
|
-
pspRefundId: String(data["refundId"] ?? ""),
|
|
6139
|
-
status: refundStatus,
|
|
6140
|
-
amount: params.amount ?? 0,
|
|
6141
|
-
rawResponse: data
|
|
6142
|
-
};
|
|
6143
|
-
}
|
|
6144
|
-
async healthCheck() {
|
|
6145
|
-
try {
|
|
6146
|
-
const response = await fetch(`${this.config.baseUrl}/health`, {
|
|
6147
|
-
headers: { "Authorization": `Bearer ${this.config.apiKey}` }
|
|
6148
|
-
});
|
|
6149
|
-
return response.ok;
|
|
6150
|
-
} catch {
|
|
6151
|
-
return false;
|
|
6152
|
-
}
|
|
6153
|
-
}
|
|
6154
|
-
};
|
|
6155
|
-
|
|
6156
|
-
// src/psp/adapters/cybersource.ts
|
|
6157
|
-
var CyberSourceAdapter = class {
|
|
6158
|
-
name = "cybersource";
|
|
6159
|
-
config;
|
|
6160
|
-
constructor(config) {
|
|
6161
|
-
this.config = config;
|
|
6162
|
-
}
|
|
6163
|
-
async charge(params) {
|
|
6164
|
-
const now = /* @__PURE__ */ new Date();
|
|
6165
|
-
const expiryDate = new Date(params.expYear, params.expMonth);
|
|
6166
|
-
if (expiryDate <= now) {
|
|
6167
|
-
return {
|
|
6168
|
-
pspTransactionId: "",
|
|
6169
|
-
status: "failed",
|
|
6170
|
-
declineReason: "Card has expired",
|
|
6171
|
-
rawResponse: { error: "card_expired", expMonth: params.expMonth, expYear: params.expYear }
|
|
6172
|
-
};
|
|
6173
|
-
}
|
|
6174
|
-
const csParams = params;
|
|
6175
|
-
const paymentInformation = csParams.isNetworkToken ? {
|
|
6176
|
-
tokenizedCard: {
|
|
6177
|
-
number: params.cardAlias,
|
|
6178
|
-
// VGS reveals to CyberSource
|
|
6179
|
-
expirationMonth: String(params.expMonth).padStart(2, "0"),
|
|
6180
|
-
expirationYear: String(params.expYear),
|
|
6181
|
-
cryptogram: csParams.cryptogram,
|
|
6182
|
-
type: "001"
|
|
6183
|
-
// Visa network token
|
|
6184
|
-
}
|
|
6185
|
-
} : {
|
|
6186
|
-
card: {
|
|
6187
|
-
number: params.cardAlias,
|
|
6188
|
-
// VGS reveals to CyberSource
|
|
6189
|
-
expirationMonth: String(params.expMonth).padStart(2, "0"),
|
|
6190
|
-
expirationYear: String(params.expYear),
|
|
6191
|
-
securityCode: params.cvvAlias
|
|
6192
|
-
}
|
|
6193
|
-
};
|
|
6194
|
-
const body = {
|
|
6195
|
-
clientReferenceInformation: {
|
|
6196
|
-
code: params.idempotencyKey ?? `lane_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`
|
|
6197
|
-
},
|
|
6198
|
-
processingInformation: {
|
|
6199
|
-
capture: true,
|
|
6200
|
-
...csParams.isNetworkToken ? { paymentSolution: "015" } : {},
|
|
6201
|
-
...csParams.eci ? { commerceIndicator: csParams.eci } : {}
|
|
6202
|
-
},
|
|
6203
|
-
orderInformation: {
|
|
6204
|
-
amountDetails: {
|
|
6205
|
-
totalAmount: (params.amount / 100).toFixed(2),
|
|
6206
|
-
currency: params.currency.toUpperCase()
|
|
6207
|
-
}
|
|
6208
|
-
},
|
|
6209
|
-
paymentInformation
|
|
6210
|
-
};
|
|
6211
|
-
const response = await this.config.proxy.forward({
|
|
6212
|
-
url: `${this.config.baseUrl}/pts/v2/payments`,
|
|
6213
|
-
method: "POST",
|
|
6214
|
-
headers: {
|
|
6215
|
-
"v-c-merchant-id": this.config.merchantId,
|
|
6216
|
-
"Content-Type": "application/json"
|
|
6217
|
-
},
|
|
6218
|
-
body
|
|
6219
|
-
});
|
|
6220
|
-
const data = response.body;
|
|
6221
|
-
const csStatus = data["status"];
|
|
6222
|
-
const status = csStatus === "AUTHORIZED" || csStatus === "PENDING" ? csStatus === "AUTHORIZED" ? "succeeded" : "pending" : "failed";
|
|
6223
|
-
return {
|
|
6224
|
-
pspTransactionId: String(data["id"] ?? ""),
|
|
6225
|
-
status,
|
|
6226
|
-
authorizationCode: data["processorInformation"]?.["approvalCode"],
|
|
6227
|
-
declineReason: status === "failed" ? String(data["errorInformation"]?.["message"] ?? "declined") : void 0,
|
|
6228
|
-
rawResponse: data
|
|
6229
|
-
};
|
|
6230
|
-
}
|
|
6231
|
-
async refund(params) {
|
|
6232
|
-
const body = {
|
|
6233
|
-
clientReferenceInformation: {
|
|
6234
|
-
code: params.idempotencyKey ?? `lane_ref_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`
|
|
6235
|
-
},
|
|
6236
|
-
orderInformation: {
|
|
6237
|
-
amountDetails: {
|
|
6238
|
-
...params.amount !== void 0 ? { totalAmount: (params.amount / 100).toFixed(2) } : {},
|
|
6239
|
-
currency: "USD"
|
|
6240
|
-
}
|
|
6241
|
-
}
|
|
6242
|
-
};
|
|
6243
|
-
const response = await this.config.proxy.forward({
|
|
6244
|
-
url: `${this.config.baseUrl}/pts/v2/payments/${params.pspTransactionId}/refunds`,
|
|
6245
|
-
method: "POST",
|
|
6246
|
-
headers: {
|
|
6247
|
-
"v-c-merchant-id": this.config.merchantId,
|
|
6248
|
-
"Content-Type": "application/json"
|
|
6249
|
-
},
|
|
6250
|
-
body
|
|
6251
|
-
});
|
|
6252
|
-
const data = response.body;
|
|
6253
|
-
const csStatus = data["status"];
|
|
6254
|
-
return {
|
|
6255
|
-
pspRefundId: String(data["id"] ?? ""),
|
|
6256
|
-
status: csStatus === "PENDING" ? "pending" : "succeeded",
|
|
6257
|
-
amount: params.amount ?? 0,
|
|
6258
|
-
rawResponse: data
|
|
6259
|
-
};
|
|
6260
|
-
}
|
|
6261
|
-
async healthCheck() {
|
|
6262
|
-
try {
|
|
6263
|
-
const response = await fetch(`${this.config.baseUrl}/reporting/v3/report-definitions`, {
|
|
6264
|
-
headers: { "v-c-merchant-id": this.config.merchantId }
|
|
6265
|
-
});
|
|
6266
|
-
return response.status !== 500;
|
|
6267
|
-
} catch {
|
|
6268
|
-
return false;
|
|
6269
|
-
}
|
|
6270
|
-
}
|
|
6271
|
-
};
|
|
6272
|
-
|
|
6273
5508
|
// src/merchants/billing-api-directory.ts
|
|
6274
5509
|
var BILLING_API_MERCHANTS = Object.freeze([
|
|
6275
5510
|
{
|
|
@@ -6309,158 +5544,8 @@ new Map(
|
|
|
6309
5544
|
...m.aliases.map((a) => [a.toLowerCase(), m])
|
|
6310
5545
|
])
|
|
6311
5546
|
);
|
|
6312
|
-
function toBillingAPICapabilities() {
|
|
6313
|
-
return BILLING_API_MERCHANTS.map((m) => ({
|
|
6314
|
-
merchantId: m.domain,
|
|
6315
|
-
hasBillingAPI: true,
|
|
6316
|
-
supportsACP: false,
|
|
6317
|
-
supportsUCP: false,
|
|
6318
|
-
supportsX402: false,
|
|
6319
|
-
supportsVIC: true,
|
|
6320
|
-
supportsRye: false,
|
|
6321
|
-
acceptsVisa: true,
|
|
6322
|
-
acceptsMastercard: true,
|
|
6323
|
-
mccs: m.mccs
|
|
6324
|
-
}));
|
|
6325
|
-
}
|
|
6326
|
-
|
|
6327
|
-
// src/routing/engine.ts
|
|
6328
|
-
var MerchantRegistry = class _MerchantRegistry {
|
|
6329
|
-
merchants = /* @__PURE__ */ new Map();
|
|
6330
|
-
register(capabilities) {
|
|
6331
|
-
this.merchants.set(capabilities.merchantId, capabilities);
|
|
6332
|
-
}
|
|
6333
|
-
get(merchantId) {
|
|
6334
|
-
return this.merchants.get(merchantId);
|
|
6335
|
-
}
|
|
6336
|
-
registerBatch(merchants) {
|
|
6337
|
-
for (const m of merchants) {
|
|
6338
|
-
this.merchants.set(m.merchantId, m);
|
|
6339
|
-
}
|
|
6340
|
-
}
|
|
6341
|
-
/** Create a registry pre-populated from directory capabilities. */
|
|
6342
|
-
static fromDirectory(capabilities) {
|
|
6343
|
-
const registry = new _MerchantRegistry();
|
|
6344
|
-
registry.registerBatch(capabilities);
|
|
6345
|
-
return registry;
|
|
6346
|
-
}
|
|
6347
|
-
/** Clear and repopulate with new capabilities. */
|
|
6348
|
-
reload(capabilities) {
|
|
6349
|
-
this.merchants.clear();
|
|
6350
|
-
this.registerBatch(capabilities);
|
|
6351
|
-
}
|
|
6352
|
-
/** Number of registered merchants. */
|
|
6353
|
-
get size() {
|
|
6354
|
-
return this.merchants.size;
|
|
6355
|
-
}
|
|
6356
|
-
/** List all registered merchant IDs. */
|
|
6357
|
-
listIds() {
|
|
6358
|
-
return Array.from(this.merchants.keys());
|
|
6359
|
-
}
|
|
6360
|
-
/**
|
|
6361
|
-
* Create a registry pre-seeded with the built-in UCP merchant directory.
|
|
6362
|
-
*
|
|
6363
|
-
* These merchants have verified `/.well-known/ucp` endpoints, so the
|
|
6364
|
-
* routing engine can immediately route to Tier 3 (UCP) without a server
|
|
6365
|
-
* round-trip for discovery. Additional merchants from the Lane backend
|
|
6366
|
-
* can be merged in later via `register()` or `registerBatch()`.
|
|
6367
|
-
*/
|
|
6368
|
-
static withUCPDirectory() {
|
|
6369
|
-
return _MerchantRegistry.fromDirectory(toMerchantCapabilities());
|
|
6370
|
-
}
|
|
6371
|
-
/**
|
|
6372
|
-
* Create a registry pre-seeded with ALL built-in merchant directories:
|
|
6373
|
-
* - Billing API merchants (Tier 1) — SaaS/API merchants with direct endpoints
|
|
6374
|
-
* - UCP merchants (Tier 3) — ecommerce merchants with /.well-known/ucp
|
|
6375
|
-
*
|
|
6376
|
-
* This gives agents instant routing for known merchants without any server
|
|
6377
|
-
* round-trip. Use this for the best out-of-the-box experience.
|
|
6378
|
-
*/
|
|
6379
|
-
static withBuiltinDirectory() {
|
|
6380
|
-
return _MerchantRegistry.fromDirectory([
|
|
6381
|
-
...toBillingAPICapabilities(),
|
|
6382
|
-
...toMerchantCapabilities()
|
|
6383
|
-
]);
|
|
6384
|
-
}
|
|
6385
|
-
};
|
|
6386
|
-
var PaymentRouter = class {
|
|
6387
|
-
constructor(registry) {
|
|
6388
|
-
this.registry = registry;
|
|
6389
|
-
}
|
|
6390
|
-
/**
|
|
6391
|
-
* Decide the payment route for a transaction.
|
|
6392
|
-
*/
|
|
6393
|
-
route(context) {
|
|
6394
|
-
const merchant = this.registry.get(context.merchantId);
|
|
6395
|
-
const fallbacks = [];
|
|
6396
|
-
if (context.budget && context.currentSpend !== void 0) {
|
|
6397
|
-
const limit = context.budget.perTaskLimit ?? context.budget.dailyLimit;
|
|
6398
|
-
if (limit !== void 0 && context.amount > limit - context.currentSpend) {
|
|
6399
|
-
return {
|
|
6400
|
-
route: "fallback",
|
|
6401
|
-
merchantId: context.merchantId,
|
|
6402
|
-
reason: "Transaction would exceed budget limits.",
|
|
6403
|
-
fallbacks: []
|
|
6404
|
-
};
|
|
6405
|
-
}
|
|
6406
|
-
}
|
|
6407
|
-
if (merchant?.hasBillingAPI) {
|
|
6408
|
-
fallbacks.push("acp", "ucp", "x402", "fallback");
|
|
6409
|
-
return {
|
|
6410
|
-
route: "billing_api",
|
|
6411
|
-
merchantId: context.merchantId,
|
|
6412
|
-
reason: "Merchant has direct billing API integration (cheapest path).",
|
|
6413
|
-
fallbacks: this.filterFallbacks(fallbacks, merchant)
|
|
6414
|
-
};
|
|
6415
|
-
}
|
|
6416
|
-
if (merchant?.supportsACP) {
|
|
6417
|
-
fallbacks.push("ucp", "x402", "fallback");
|
|
6418
|
-
return {
|
|
6419
|
-
route: "acp",
|
|
6420
|
-
merchantId: context.merchantId,
|
|
6421
|
-
reason: "Merchant supports Agent Commerce Protocol checkout.",
|
|
6422
|
-
fallbacks: this.filterFallbacks(fallbacks, merchant)
|
|
6423
|
-
};
|
|
6424
|
-
}
|
|
6425
|
-
if (merchant?.supportsUCP) {
|
|
6426
|
-
fallbacks.push("x402", "fallback");
|
|
6427
|
-
return {
|
|
6428
|
-
route: "ucp",
|
|
6429
|
-
merchantId: context.merchantId,
|
|
6430
|
-
reason: "Merchant supports Universal Checkout Protocol.",
|
|
6431
|
-
fallbacks: this.filterFallbacks(fallbacks, merchant)
|
|
6432
|
-
};
|
|
6433
|
-
}
|
|
6434
|
-
if (merchant?.supportsX402) {
|
|
6435
|
-
fallbacks.push("fallback");
|
|
6436
|
-
return {
|
|
6437
|
-
route: "x402",
|
|
6438
|
-
merchantId: context.merchantId,
|
|
6439
|
-
reason: "Merchant supports x402 HTTP payment protocol.",
|
|
6440
|
-
fallbacks
|
|
6441
|
-
};
|
|
6442
|
-
}
|
|
6443
|
-
const fallbackStrategies = ["rye", "browser_use", "vgs_proxy"];
|
|
6444
|
-
return {
|
|
6445
|
-
route: "fallback",
|
|
6446
|
-
merchantId: context.merchantId,
|
|
6447
|
-
reason: merchant ? "No preferred protocol available; using fallback strategies (Rye \u2192 browser use \u2192 VGS proxy)." : "Unknown merchant; using fallback strategies (Rye \u2192 browser use \u2192 VGS proxy).",
|
|
6448
|
-
fallbacks: fallbackStrategies
|
|
6449
|
-
};
|
|
6450
|
-
}
|
|
6451
|
-
filterFallbacks(routes, merchant) {
|
|
6452
|
-
return routes.filter((r) => {
|
|
6453
|
-
if (r === "acp") return merchant.supportsACP;
|
|
6454
|
-
if (r === "ucp") return merchant.supportsUCP;
|
|
6455
|
-
if (r === "x402") return merchant.supportsX402;
|
|
6456
|
-
return true;
|
|
6457
|
-
});
|
|
6458
|
-
}
|
|
6459
|
-
};
|
|
6460
5547
|
|
|
6461
5548
|
// src/index.ts
|
|
6462
5549
|
var index_default = Lane;
|
|
6463
5550
|
|
|
6464
|
-
export { Admin, Agents, Audit, Auth, BiometricVerifier, Budgets, Cards, Checkout, Commerce, CommerceCatalog, CommerceOrders, CommerceProviders,
|
|
6465
|
-
//# sourceMappingURL=index.js.map
|
|
6466
|
-
//# sourceMappingURL=index.js.map
|
|
5551
|
+
export { Admin, Agents, Audit, Auth, BiometricVerifier, Budgets, Cards, Checkout, Commerce, CommerceCatalog, CommerceOrders, CommerceProviders, FileTokenStore, Fleet, HMACSignature, Identity, Instructions, Lane, LaneAuthError, LaneBudgetError, LaneClient, LaneConfirmationError, LaneError, LaneMCPServer, LaneNotFoundError, LanePaymentError, LaneRateLimitError, LaneValidationError, Merchants, Metering, Pay, Payouts, Products, Resource, Sell, Subscriptions, Teams, Tokens, Transactions, Users, VIC, Wallets, Webhooks, createErrorFromResponse, index_default as default, detectCardBrand, getLaneInstructions, listUCPByVertical, listUCPMerchants, luhnCheck, maskCardNumber, requireBiometricConfirmation, resolveConfig, resolveUCPByBrand, resolveUCPByDomain, toUCPEndpoint, toMerchantCapabilities as toUCPMerchantCapabilities, verifyWebhookSignature };
|