@conto_finance/sdk 0.7.0 → 0.8.0

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.
@@ -38,8 +38,13 @@ interface LinkSpendRequest {
38
38
  amountMinor?: number;
39
39
  merchantName?: string;
40
40
  merchantUrl?: string;
41
- /** Link page where the person can review the request. */
41
+ /**
42
+ * The Stripe Link page where the person can approve the request on the web
43
+ * while signed in to Link. Only an HTTPS link.com address is kept.
44
+ */
42
45
  approvalUrl?: string;
46
+ /** When Link stops accepting approval for the request, as an ISO 8601 time. */
47
+ approvalExpiresAt?: string;
43
48
  /** Set with requires_action. `auto_resume` means Link continues once the person finishes the step. */
44
49
  actionResolution?: string;
45
50
  /** Set with requires_action when Link gives the person a page to finish the step. */
@@ -38,8 +38,13 @@ interface LinkSpendRequest {
38
38
  amountMinor?: number;
39
39
  merchantName?: string;
40
40
  merchantUrl?: string;
41
- /** Link page where the person can review the request. */
41
+ /**
42
+ * The Stripe Link page where the person can approve the request on the web
43
+ * while signed in to Link. Only an HTTPS link.com address is kept.
44
+ */
42
45
  approvalUrl?: string;
46
+ /** When Link stops accepting approval for the request, as an ISO 8601 time. */
47
+ approvalExpiresAt?: string;
43
48
  /** Set with requires_action. `auto_resume` means Link continues once the person finishes the step. */
44
49
  actionResolution?: string;
45
50
  /** Set with requires_action when Link gives the person a page to finish the step. */
@@ -40,6 +40,34 @@ var import_node_fs = require("fs");
40
40
  var import_promises = require("fs/promises");
41
41
  var import_node_os = require("os");
42
42
  var import_node_path = __toESM(require("path"));
43
+
44
+ // src/link-approval.ts
45
+ function safeLinkApprovalUrl(value) {
46
+ if (typeof value !== "string" || value.length === 0 || value.length > 2048) return void 0;
47
+ let url;
48
+ try {
49
+ url = new URL(value);
50
+ } catch {
51
+ return void 0;
52
+ }
53
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || !(url.hostname === "link.com" || url.hostname.endsWith(".link.com"))) {
54
+ return void 0;
55
+ }
56
+ url.hash = "";
57
+ return url.toString();
58
+ }
59
+ function linkTime(value) {
60
+ let ms = Number.NaN;
61
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
62
+ ms = value < 1e12 ? value * 1e3 : value;
63
+ } else if (typeof value === "string" && value.length > 0 && value.length <= 64) {
64
+ ms = Date.parse(value);
65
+ }
66
+ const date = new Date(ms);
67
+ return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
68
+ }
69
+
70
+ // src/link-wallet.ts
43
71
  var LinkWalletError = class extends Error {
44
72
  constructor(reason, message, linkCode) {
45
73
  super(message);
@@ -102,13 +130,16 @@ function parseSpendRequest(value) {
102
130
  const status = typeof data.status === "string" && KNOWN_STATUSES.has(data.status) ? data.status : "unknown";
103
131
  const nextAction = record(record(record(data.status_details).requires_action).next_action);
104
132
  const amount = data.amount;
133
+ const approvalUrl = safeLinkApprovalUrl(data.approval_url);
134
+ const approvalExpiresAt = linkTime(data.approval_window_expires_at);
105
135
  return {
106
136
  id,
107
137
  status,
108
138
  ...Number.isSafeInteger(amount) ? { amountMinor: amount } : {},
109
139
  ...text(data.merchant_name) ? { merchantName: text(data.merchant_name) } : {},
110
140
  ...httpsUrl(data.merchant_url) ? { merchantUrl: httpsUrl(data.merchant_url) } : {},
111
- ...httpsUrl(data.approval_url) ? { approvalUrl: httpsUrl(data.approval_url) } : {},
141
+ ...approvalUrl ? { approvalUrl } : {},
142
+ ...approvalExpiresAt ? { approvalExpiresAt } : {},
112
143
  ...text(nextAction.resolution) ? { actionResolution: text(nextAction.resolution) } : {},
113
144
  ...httpsUrl(nextAction.action_url) ? { actionUrl: httpsUrl(nextAction.action_url) } : {}
114
145
  };
@@ -116,15 +147,6 @@ function parseSpendRequest(value) {
116
147
  function invalidCard() {
117
148
  return new LinkWalletError("invalid_response", "Link returned card data this SDK cannot read.");
118
149
  }
119
- function validUntil(value) {
120
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
121
- return new Date(value < 1e12 ? value * 1e3 : value).toISOString();
122
- }
123
- if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
124
- return new Date(value).toISOString();
125
- }
126
- return void 0;
127
- }
128
150
  function parseCard(value) {
129
151
  const card = record(value);
130
152
  const number = typeof card.number === "string" ? card.number.replace(/[\s-]/g, "") : "";
@@ -136,7 +158,7 @@ function parseCard(value) {
136
158
  if (!/^\d{12,19}$/.test(number) || !/^\d{3,4}$/.test(securityValue) || !Number.isInteger(expMonth) || expMonth < 1 || expMonth > 12 || !Number.isInteger(expYear) || expYear < 2e3) {
137
159
  throw invalidCard();
138
160
  }
139
- const until = validUntil(card.valid_until);
161
+ const until = linkTime(card.valid_until);
140
162
  const brand = text(card.brand);
141
163
  return {
142
164
  number,
@@ -1,3 +1,7 @@
1
+ import {
2
+ linkTime,
3
+ safeLinkApprovalUrl
4
+ } from "./chunk-PVMUL3JC.mjs";
1
5
  import "./chunk-TGOYFBKZ.mjs";
2
6
 
3
7
  // src/link-wallet.ts
@@ -68,13 +72,16 @@ function parseSpendRequest(value) {
68
72
  const status = typeof data.status === "string" && KNOWN_STATUSES.has(data.status) ? data.status : "unknown";
69
73
  const nextAction = record(record(record(data.status_details).requires_action).next_action);
70
74
  const amount = data.amount;
75
+ const approvalUrl = safeLinkApprovalUrl(data.approval_url);
76
+ const approvalExpiresAt = linkTime(data.approval_window_expires_at);
71
77
  return {
72
78
  id,
73
79
  status,
74
80
  ...Number.isSafeInteger(amount) ? { amountMinor: amount } : {},
75
81
  ...text(data.merchant_name) ? { merchantName: text(data.merchant_name) } : {},
76
82
  ...httpsUrl(data.merchant_url) ? { merchantUrl: httpsUrl(data.merchant_url) } : {},
77
- ...httpsUrl(data.approval_url) ? { approvalUrl: httpsUrl(data.approval_url) } : {},
83
+ ...approvalUrl ? { approvalUrl } : {},
84
+ ...approvalExpiresAt ? { approvalExpiresAt } : {},
78
85
  ...text(nextAction.resolution) ? { actionResolution: text(nextAction.resolution) } : {},
79
86
  ...httpsUrl(nextAction.action_url) ? { actionUrl: httpsUrl(nextAction.action_url) } : {}
80
87
  };
@@ -82,15 +89,6 @@ function parseSpendRequest(value) {
82
89
  function invalidCard() {
83
90
  return new LinkWalletError("invalid_response", "Link returned card data this SDK cannot read.");
84
91
  }
85
- function validUntil(value) {
86
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
87
- return new Date(value < 1e12 ? value * 1e3 : value).toISOString();
88
- }
89
- if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
90
- return new Date(value).toISOString();
91
- }
92
- return void 0;
93
- }
94
92
  function parseCard(value) {
95
93
  const card = record(value);
96
94
  const number = typeof card.number === "string" ? card.number.replace(/[\s-]/g, "") : "";
@@ -102,7 +100,7 @@ function parseCard(value) {
102
100
  if (!/^\d{12,19}$/.test(number) || !/^\d{3,4}$/.test(securityValue) || !Number.isInteger(expMonth) || expMonth < 1 || expMonth > 12 || !Number.isInteger(expYear) || expYear < 2e3) {
103
101
  throw invalidCard();
104
102
  }
105
- const until = validUntil(card.valid_until);
103
+ const until = linkTime(card.valid_until);
106
104
  const brand = text(card.brand);
107
105
  return {
108
106
  number,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conto_finance/sdk",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Conto SDK for AI agent payment authorization",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -46,7 +46,7 @@
46
46
  "dev": "tsup --watch",
47
47
  "lint": "tsc --noEmit",
48
48
  "test": "npm run lint && npm run test:contract && npm run test:consumer",
49
- "test:contract": "npm run build && node --test test/contract.test.mjs test/playwright.test.mjs test/browserbase.test.mjs test/checkout-verifier.test.mjs test/developer-experience.test.mjs test/checkout.test.mjs test/link-wallet.test.mjs test/purchases.test.mjs test/allowances.test.mjs test/purchase-watch-lifecycle.test.mjs ../../examples/link-wallet-agent/verify.test.mjs",
49
+ "test:contract": "npm run build && node --test test/contract.test.mjs test/playwright.test.mjs test/browserbase.test.mjs test/checkout-verifier.test.mjs test/developer-experience.test.mjs test/checkout.test.mjs test/link-wallet.test.mjs test/purchases.test.mjs test/allowances.test.mjs test/purchase-watch-lifecycle.test.mjs test/spending.test.mjs ../../examples/link-wallet-agent/verify.test.mjs",
50
50
  "test:consumer": "npm run build && node --test test/consumer.test.mjs",
51
51
  "verify:release": "node scripts/verify-release.mjs",
52
52
  "prepublishOnly": "npm run verify:release && npm run lint && npm run test:contract && npm run test:consumer"