@conto_finance/sdk 0.7.0 → 0.7.1
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/README.md +5 -0
- package/dist/chunk-PVMUL3JC.mjs +30 -0
- package/dist/index.d.mts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +95 -7
- package/dist/index.mjs +73 -7
- package/dist/link-wallet.d.mts +6 -1
- package/dist/link-wallet.d.ts +6 -1
- package/dist/link-wallet.js +33 -11
- package/dist/link-wallet.mjs +9 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,6 +156,11 @@ const confirmed = await conto.checkout.confirm(result.checkpoint, {
|
|
|
156
156
|
held spend and throws `LinkCardDeniedError`, `LinkCardExpiredError`, `LinkCardTimeoutError`, or
|
|
157
157
|
`LinkWalletUnavailableError`. All extend `LinkCardError`. Do not pay.
|
|
158
158
|
- Retrying with the same input resumes the same checkpoint and Link request.
|
|
159
|
+
- Pass `onLinkApproval` to get Stripe Link's approval page, so a person without the Link app can
|
|
160
|
+
approve on the web while signed in to Link. It is called once, after Conto approves and Link
|
|
161
|
+
creates the request, with `{ checkpoint, linkRequestId, approvalUrl, approvalExpiresAt }`.
|
|
162
|
+
`approvalUrl` is always an HTTPS link.com address. A `LinkCardError` has it too when the SDK
|
|
163
|
+
stopped while the person had not decided.
|
|
159
164
|
- The card (`number`, `securityValue` for the CVC, `expMonth`, `expYear`, `validUntil`, `last4`,
|
|
160
165
|
`brand`) stays in this process. Printing or serializing the result shows only the last four
|
|
161
166
|
digits. It never appears in an error.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/link-approval.ts
|
|
2
|
+
function safeLinkApprovalUrl(value) {
|
|
3
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048) return void 0;
|
|
4
|
+
let url;
|
|
5
|
+
try {
|
|
6
|
+
url = new URL(value);
|
|
7
|
+
} catch {
|
|
8
|
+
return void 0;
|
|
9
|
+
}
|
|
10
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || !(url.hostname === "link.com" || url.hostname.endsWith(".link.com"))) {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
url.hash = "";
|
|
14
|
+
return url.toString();
|
|
15
|
+
}
|
|
16
|
+
function linkTime(value) {
|
|
17
|
+
let ms = Number.NaN;
|
|
18
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
19
|
+
ms = value < 1e12 ? value * 1e3 : value;
|
|
20
|
+
} else if (typeof value === "string" && value.length > 0 && value.length <= 64) {
|
|
21
|
+
ms = Date.parse(value);
|
|
22
|
+
}
|
|
23
|
+
const date = new Date(ms);
|
|
24
|
+
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
safeLinkApprovalUrl,
|
|
29
|
+
linkTime
|
|
30
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -2643,6 +2643,33 @@ interface WaitForCheckoutApprovalOptions {
|
|
|
2643
2643
|
signal?: AbortSignal;
|
|
2644
2644
|
}
|
|
2645
2645
|
|
|
2646
|
+
/**
|
|
2647
|
+
* The Link card request is waiting for the person. Conto has already approved
|
|
2648
|
+
* the purchase, and Link has created the request.
|
|
2649
|
+
*/
|
|
2650
|
+
interface LinkApprovalEvent {
|
|
2651
|
+
/** The checkpoint Conto approved. */
|
|
2652
|
+
checkpoint: CheckoutCheckpoint;
|
|
2653
|
+
/** The Link spend request id, such as lsrq_... */
|
|
2654
|
+
linkRequestId: string;
|
|
2655
|
+
/**
|
|
2656
|
+
* The Stripe Link page where the person can approve on the web while signed
|
|
2657
|
+
* in to Link, so they do not need the Link app. Only an HTTPS link.com address
|
|
2658
|
+
* is passed. Absent when Link gave none or it did not pass that check. The
|
|
2659
|
+
* person can still approve in the Link app.
|
|
2660
|
+
*/
|
|
2661
|
+
approvalUrl?: string;
|
|
2662
|
+
/** When Link stops accepting approval, as an ISO 8601 time, when Link reports it. */
|
|
2663
|
+
approvalExpiresAt?: string;
|
|
2664
|
+
}
|
|
2665
|
+
/**
|
|
2666
|
+
* Called once when the Link card request is waiting for the person, after
|
|
2667
|
+
* Conto approved the purchase and before the SDK starts waiting. Show
|
|
2668
|
+
* approvalUrl to the person. The SDK does not wait for it to finish, and an
|
|
2669
|
+
* error it throws or rejects with does not affect the purchase. A retry that
|
|
2670
|
+
* resumes a waiting request calls it again with the same URL.
|
|
2671
|
+
*/
|
|
2672
|
+
type LinkApprovalCallback = (event: LinkApprovalEvent) => void | Promise<void>;
|
|
2646
2673
|
/**
|
|
2647
2674
|
* A Link card for one purchase: the checkpoint begin input plus the Link
|
|
2648
2675
|
* wallet that runs in your environment. The checkout method is always LINK.
|
|
@@ -2654,6 +2681,8 @@ interface GetLinkCardInput extends Omit<BeginCheckoutCheckpointInput, 'checkoutM
|
|
|
2654
2681
|
ownerApprovalTimeoutMs?: number;
|
|
2655
2682
|
/** How long to wait for the person to approve in Link. Defaults to 10 minutes. */
|
|
2656
2683
|
linkApprovalTimeoutMs?: number;
|
|
2684
|
+
/** Called once with the Link approval page when the person needs to approve in Link. */
|
|
2685
|
+
onLinkApproval?: LinkApprovalCallback;
|
|
2657
2686
|
signal?: AbortSignal;
|
|
2658
2687
|
}
|
|
2659
2688
|
/** A new Link card for a changed final total. */
|
|
@@ -2667,6 +2696,8 @@ interface ReplaceLinkCardInput {
|
|
|
2667
2696
|
totals?: CommerceTotalInput[];
|
|
2668
2697
|
ownerApprovalTimeoutMs?: number;
|
|
2669
2698
|
linkApprovalTimeoutMs?: number;
|
|
2699
|
+
/** Called once with the Link approval page when the person needs to approve in Link. */
|
|
2700
|
+
onLinkApproval?: LinkApprovalCallback;
|
|
2670
2701
|
signal?: AbortSignal;
|
|
2671
2702
|
}
|
|
2672
2703
|
interface LinkCardResult {
|
|
@@ -3380,6 +3411,13 @@ declare class CheckoutApprovalTimeoutError extends ContoError {
|
|
|
3380
3411
|
declare class LinkCardError extends ContoError {
|
|
3381
3412
|
readonly checkpoint: CheckoutCheckpoint;
|
|
3382
3413
|
readonly linkRequestId?: string;
|
|
3414
|
+
/**
|
|
3415
|
+
* The Stripe Link page where the person could approve the request, set when
|
|
3416
|
+
* the SDK stopped while the request was waiting for them. It works only while
|
|
3417
|
+
* the request is still open in Link. When holdReleased is true, Conto has
|
|
3418
|
+
* already cancelled the request.
|
|
3419
|
+
*/
|
|
3420
|
+
readonly approvalUrl?: string;
|
|
3383
3421
|
/** True when Conto cancelled the checkpoint and released the held spend. */
|
|
3384
3422
|
readonly holdReleased: boolean;
|
|
3385
3423
|
constructor(input: {
|
|
@@ -3387,6 +3425,7 @@ declare class LinkCardError extends ContoError {
|
|
|
3387
3425
|
code: string;
|
|
3388
3426
|
checkpoint: CheckoutCheckpoint;
|
|
3389
3427
|
linkRequestId?: string;
|
|
3428
|
+
approvalUrl?: string;
|
|
3390
3429
|
holdReleased: boolean;
|
|
3391
3430
|
retryGuidance?: string;
|
|
3392
3431
|
});
|
|
@@ -3854,7 +3893,9 @@ declare class CheckoutClient {
|
|
|
3854
3893
|
* 1. Conto runs checkpoint 1 and holds the spend. When a rule requires the
|
|
3855
3894
|
* owner's approval, this waits for it.
|
|
3856
3895
|
* 2. Only then does the wallet ask Link for a card for exactly the approved
|
|
3857
|
-
* amount at this merchant. The person approves it in Link.
|
|
3896
|
+
* amount at this merchant. The person approves it in Link. Pass
|
|
3897
|
+
* onLinkApproval to get Link's approval page, so they can approve on the
|
|
3898
|
+
* web without the Link app.
|
|
3858
3899
|
* 3. The card is returned. It never reaches Conto.
|
|
3859
3900
|
*
|
|
3860
3901
|
* Then fill in the card, call confirm(result.checkpoint, { amountMinor,
|
|
@@ -3880,4 +3921,4 @@ declare class CheckoutClient {
|
|
|
3880
3921
|
}
|
|
3881
3922
|
|
|
3882
3923
|
export { AdminPurchasingClient, BrowserActionFinalizationPendingError, BrowserCheckoutTargetVerificationError, CardsClient, CheckoutApprovalDeniedError, CheckoutApprovalExpiredError, CheckoutApprovalPendingError, CheckoutApprovalTimeoutError, CheckoutCheckpointClosedError, CheckoutClient, ConnectedCardsClient, Conto, ContoAdmin, ContoAdminError, ContoError, ControlledExternalCardPaymentTool, ExternalCardConfirmationPendingError, Conto as Giro, ContoError as GiroError, LinkCardCredential, LinkCardDeniedError, LinkCardError, LinkCardExpiredError, LinkCardTimeoutError, LinkWallet, LinkWalletUnavailableError, OrganizationPurchasesClient, OrganizationRecurringPurchasesClient, PurchasesClient, RecurringPurchasesClient, TestCardsClient, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget, isFinalPurchaseStatus, parseServerSentEvents, verifyPurchaseWebhook };
|
|
3883
|
-
export type { AdminExternalCardOverlayEnforcement, Agent, AgentCheckoutAction, AgentCheckoutActionKind, AgentExternalCard, AgentSetupResult, AgentStatus, AgentType, AgentWalletLink, ApprovedExternalCardExecution, AssignExternalCardInput, AssignedPolicy, AuthorizeCheckoutActionResult, BeginCheckoutCheckpointInput, BeginCommerceExecutionInput, BrowserActionClaimResult, BrowserActionDispatchObservationInput, BrowserActionFinalizeResult, BrowserCheckoutAction, BrowserCheckoutTargetResolver, BrowserCheckoutTargetSnapshot, BrowserCheckoutTargetVerificationCode, CancellationOutcome, CanonicalBrowserCheckoutTargetSnapshot, ChainType, CheckoutActionAuthorization, CheckoutCheckpoint, CheckoutCheckpointApproval, CheckoutCheckpointMethod, CheckoutCheckpointNextAction, CheckoutCheckpointStage, CheckoutOutcome, CheckoutPaymentReference, CommerceCheckoutMethod, CommerceContextRequirement, CommerceExecution, CommerceExecutionAdapterKind, CommerceExecutionArtifactKind, CommerceExecutionChannel, CommerceExecutionConstraint, CommerceExecutionConstraintCoverage, CommerceExecutionConstraintCoverageLevel, CommerceExecutionDeliveryMode, CommerceExecutionEvidence, CommerceExecutionProvider, CommerceExecutionResult, CommerceExecutionSourceKind, CommerceExecutionStatus, CommerceFactConfidence, CommerceFactProvenanceInput, CommerceFactSource, CommerceFulfillmentInput, CommerceLineItemInput, CommerceProposalFactKey, CommerceProposalMissingFact, CommerceProposalResolution, CommerceProposalState, CommerceSettlementRail, CommerceTotalInput, CommerceTotalType, ComparePolicyVersionsResponse, ConfirmCheckoutCheckpointInput, ConnectedCardBrief, ConnectedCardCredential, ConnectedCardDrawInput, ConnectedCardDrawMerchant, ConnectedCardDrawResult, ConnectedCardDrawable, ConnectedCardListResult, ConnectedCardMandate, ConnectedCardMandateMerchant, ConnectedCardOutcomeReport, ConnectedCardOutcomeReportResult, ConnectedCardReference, ContoAdminConfig, ContoConfig, ContoRequestOptions, ControlledExternalCardPaymentResult, CreateAgentInput, CreatePolicyInput, CreatePolicyRuleInput, CreatePurchaseInput, CreateSdkKeyInput, CreateSdkKeyResult, CreateWalletInput, CustodyType, CustomerCustodyMode, CustomerWalletControlModel, CustomerWalletKeyAccess, DelegationType, ExecuteCommerceExecutionResult, ExternalCard, ExternalCardApprovalInput, ExternalCardApprovalResult, ExternalCardConfirmationInput, ExternalCardConfirmationResult, ExternalCardExecutionClaimResult, ExternalCardExecutionResult, ExternalCardExecutor, ExternalCardOverlayEnforcement, ExternalCardRequestStatusResult, ExternalWalletApprovalInput, ExternalWalletApprovalResult, ExternalWalletConfirmationInput, ExternalWalletConfirmationResult, FreezeAgentInput, GetLinkCardInput, ContoConfig as GiroConfig, GuardCheckoutResult, GuardedBrowserDispatchResult, GuardedCheckoutInput, LinkCardResult, LinkWalletInput, ListAgentsParams, ListAgentsResponse, ListPoliciesParams, ListPoliciesResponse, ListPolicyVersionsResponse, ListWalletsParams, ListWalletsResponse, MppBudgetResult, MppPreAuthorizeInput, MppPreAuthorizeResult, MppRecordInput, MppRecordResult, NormalizeCommerceProposalInput, OrganizationMember, PaginatedResponse, PaginationParams, PauseExternalCardAssignmentResult, PaymentExecuteResult, PaymentRequestInput, PaymentRequestResult, PaymentStatusResult, Policy, PolicyRule, PolicyType, PolicyVersionChangeType, PolicyVersionDetail, PolicyVersionDiff, PolicyVersionFieldChange, PolicyVersionSnapshot, PolicyVersionSnapshotRule, PolicyVersionSummary, PrivilegedBrowserCheckoutDriver, ProtocolBudgetResult, ProtocolPreAuthorizeResult, ProtocolRecordGrant, ProtocolRecordGrantResult, ProtocolServiceSummary, ProtocolServicesResult, ProveWalletOwnershipInput, ProvisionWalletResult, Purchase, PurchaseAction, PurchaseActionAuthority, PurchaseActionKind, PurchaseAllowance, PurchaseBuyer, PurchaseBuyerCompanyCard, PurchaseBuyerCompanyCardLimits, PurchaseBuyerKitchenContext, PurchaseCompanyCard, PurchaseDelegation, PurchaseEvent, PurchaseEventPage, PurchaseEvidence, PurchaseGrocery, PurchaseGroceryItem, PurchaseGroceryList, PurchaseHostedLink, PurchaseItem, PurchaseKitchenContext, PurchaseKitchenInventoryItem, PurchaseKitchenListItem, PurchaseKitchenPreferences, PurchaseKitchenRecipe, PurchaseKitchenUsual, PurchaseList, PurchaseMoney, PurchasePaymentMethod, PurchasePhase, PurchaseRequest, PurchaseResponseAck, PurchaseStatus, PurchasingCapabilities, PurchasingSettings, RecurringPurchase, RecurringPurchaseCycleResult, RecurringPurchaseCycleStatus, RefreshBalanceResult, RegisterExternalCardInput, ReplaceLinkCardInput, ReportCheckoutOutcomeInput, RollbackPolicyVersionResponse, RuleAction, RuleOperator, RuleType, RunGuardedCheckoutResult, SdkKey, SdkKeyType, SetupCapabilityState, SetupCardDiagnostics, SetupDiagnosticAction, SetupDiagnosticIssue, SetupDiagnosticIssueCode, SetupDiagnostics, SetupWalletDiagnostics, TestCardCredential, TestCardDrawResult, TestCardDrawable, TestCardListResult, TestCardReceipt, TestCheckoutInput, TestCheckoutResult, TestMerchant, TestMerchantProduct, UnfreezeAgentInput, UpdateAgentInput, UpdateExternalCardAssignmentInput, UpdatePolicyInput, UpdatePolicyRuleInput, UpdateWalletInput, VerifiedBrowserCheckoutTarget, WaitForCheckoutApprovalOptions, Wallet, WalletChainBalanceSnapshot, WalletOwnershipChallenge, WalletOwnershipProof, WalletStatus, WalletType, WatchPurchaseOptions, X402Authorization, X402BudgetResult, X402PayInput, X402PayResult, X402PaymentRequirements, X402PreAuthorizeInput, X402PreAuthorizeResult, X402RecordInput, X402RecordResult };
|
|
3924
|
+
export type { AdminExternalCardOverlayEnforcement, Agent, AgentCheckoutAction, AgentCheckoutActionKind, AgentExternalCard, AgentSetupResult, AgentStatus, AgentType, AgentWalletLink, ApprovedExternalCardExecution, AssignExternalCardInput, AssignedPolicy, AuthorizeCheckoutActionResult, BeginCheckoutCheckpointInput, BeginCommerceExecutionInput, BrowserActionClaimResult, BrowserActionDispatchObservationInput, BrowserActionFinalizeResult, BrowserCheckoutAction, BrowserCheckoutTargetResolver, BrowserCheckoutTargetSnapshot, BrowserCheckoutTargetVerificationCode, CancellationOutcome, CanonicalBrowserCheckoutTargetSnapshot, ChainType, CheckoutActionAuthorization, CheckoutCheckpoint, CheckoutCheckpointApproval, CheckoutCheckpointMethod, CheckoutCheckpointNextAction, CheckoutCheckpointStage, CheckoutOutcome, CheckoutPaymentReference, CommerceCheckoutMethod, CommerceContextRequirement, CommerceExecution, CommerceExecutionAdapterKind, CommerceExecutionArtifactKind, CommerceExecutionChannel, CommerceExecutionConstraint, CommerceExecutionConstraintCoverage, CommerceExecutionConstraintCoverageLevel, CommerceExecutionDeliveryMode, CommerceExecutionEvidence, CommerceExecutionProvider, CommerceExecutionResult, CommerceExecutionSourceKind, CommerceExecutionStatus, CommerceFactConfidence, CommerceFactProvenanceInput, CommerceFactSource, CommerceFulfillmentInput, CommerceLineItemInput, CommerceProposalFactKey, CommerceProposalMissingFact, CommerceProposalResolution, CommerceProposalState, CommerceSettlementRail, CommerceTotalInput, CommerceTotalType, ComparePolicyVersionsResponse, ConfirmCheckoutCheckpointInput, ConnectedCardBrief, ConnectedCardCredential, ConnectedCardDrawInput, ConnectedCardDrawMerchant, ConnectedCardDrawResult, ConnectedCardDrawable, ConnectedCardListResult, ConnectedCardMandate, ConnectedCardMandateMerchant, ConnectedCardOutcomeReport, ConnectedCardOutcomeReportResult, ConnectedCardReference, ContoAdminConfig, ContoConfig, ContoRequestOptions, ControlledExternalCardPaymentResult, CreateAgentInput, CreatePolicyInput, CreatePolicyRuleInput, CreatePurchaseInput, CreateSdkKeyInput, CreateSdkKeyResult, CreateWalletInput, CustodyType, CustomerCustodyMode, CustomerWalletControlModel, CustomerWalletKeyAccess, DelegationType, ExecuteCommerceExecutionResult, ExternalCard, ExternalCardApprovalInput, ExternalCardApprovalResult, ExternalCardConfirmationInput, ExternalCardConfirmationResult, ExternalCardExecutionClaimResult, ExternalCardExecutionResult, ExternalCardExecutor, ExternalCardOverlayEnforcement, ExternalCardRequestStatusResult, ExternalWalletApprovalInput, ExternalWalletApprovalResult, ExternalWalletConfirmationInput, ExternalWalletConfirmationResult, FreezeAgentInput, GetLinkCardInput, ContoConfig as GiroConfig, GuardCheckoutResult, GuardedBrowserDispatchResult, GuardedCheckoutInput, LinkApprovalCallback, LinkApprovalEvent, LinkCardResult, LinkWalletInput, ListAgentsParams, ListAgentsResponse, ListPoliciesParams, ListPoliciesResponse, ListPolicyVersionsResponse, ListWalletsParams, ListWalletsResponse, MppBudgetResult, MppPreAuthorizeInput, MppPreAuthorizeResult, MppRecordInput, MppRecordResult, NormalizeCommerceProposalInput, OrganizationMember, PaginatedResponse, PaginationParams, PauseExternalCardAssignmentResult, PaymentExecuteResult, PaymentRequestInput, PaymentRequestResult, PaymentStatusResult, Policy, PolicyRule, PolicyType, PolicyVersionChangeType, PolicyVersionDetail, PolicyVersionDiff, PolicyVersionFieldChange, PolicyVersionSnapshot, PolicyVersionSnapshotRule, PolicyVersionSummary, PrivilegedBrowserCheckoutDriver, ProtocolBudgetResult, ProtocolPreAuthorizeResult, ProtocolRecordGrant, ProtocolRecordGrantResult, ProtocolServiceSummary, ProtocolServicesResult, ProveWalletOwnershipInput, ProvisionWalletResult, Purchase, PurchaseAction, PurchaseActionAuthority, PurchaseActionKind, PurchaseAllowance, PurchaseBuyer, PurchaseBuyerCompanyCard, PurchaseBuyerCompanyCardLimits, PurchaseBuyerKitchenContext, PurchaseCompanyCard, PurchaseDelegation, PurchaseEvent, PurchaseEventPage, PurchaseEvidence, PurchaseGrocery, PurchaseGroceryItem, PurchaseGroceryList, PurchaseHostedLink, PurchaseItem, PurchaseKitchenContext, PurchaseKitchenInventoryItem, PurchaseKitchenListItem, PurchaseKitchenPreferences, PurchaseKitchenRecipe, PurchaseKitchenUsual, PurchaseList, PurchaseMoney, PurchasePaymentMethod, PurchasePhase, PurchaseRequest, PurchaseResponseAck, PurchaseStatus, PurchasingCapabilities, PurchasingSettings, RecurringPurchase, RecurringPurchaseCycleResult, RecurringPurchaseCycleStatus, RefreshBalanceResult, RegisterExternalCardInput, ReplaceLinkCardInput, ReportCheckoutOutcomeInput, RollbackPolicyVersionResponse, RuleAction, RuleOperator, RuleType, RunGuardedCheckoutResult, SdkKey, SdkKeyType, SetupCapabilityState, SetupCardDiagnostics, SetupDiagnosticAction, SetupDiagnosticIssue, SetupDiagnosticIssueCode, SetupDiagnostics, SetupWalletDiagnostics, TestCardCredential, TestCardDrawResult, TestCardDrawable, TestCardListResult, TestCardReceipt, TestCheckoutInput, TestCheckoutResult, TestMerchant, TestMerchantProduct, UnfreezeAgentInput, UpdateAgentInput, UpdateExternalCardAssignmentInput, UpdatePolicyInput, UpdatePolicyRuleInput, UpdateWalletInput, VerifiedBrowserCheckoutTarget, WaitForCheckoutApprovalOptions, Wallet, WalletChainBalanceSnapshot, WalletOwnershipChallenge, WalletOwnershipProof, WalletStatus, WalletType, WatchPurchaseOptions, X402Authorization, X402BudgetResult, X402PayInput, X402PayResult, X402PaymentRequirements, X402PreAuthorizeInput, X402PreAuthorizeResult, X402RecordInput, X402RecordResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -2643,6 +2643,33 @@ interface WaitForCheckoutApprovalOptions {
|
|
|
2643
2643
|
signal?: AbortSignal;
|
|
2644
2644
|
}
|
|
2645
2645
|
|
|
2646
|
+
/**
|
|
2647
|
+
* The Link card request is waiting for the person. Conto has already approved
|
|
2648
|
+
* the purchase, and Link has created the request.
|
|
2649
|
+
*/
|
|
2650
|
+
interface LinkApprovalEvent {
|
|
2651
|
+
/** The checkpoint Conto approved. */
|
|
2652
|
+
checkpoint: CheckoutCheckpoint;
|
|
2653
|
+
/** The Link spend request id, such as lsrq_... */
|
|
2654
|
+
linkRequestId: string;
|
|
2655
|
+
/**
|
|
2656
|
+
* The Stripe Link page where the person can approve on the web while signed
|
|
2657
|
+
* in to Link, so they do not need the Link app. Only an HTTPS link.com address
|
|
2658
|
+
* is passed. Absent when Link gave none or it did not pass that check. The
|
|
2659
|
+
* person can still approve in the Link app.
|
|
2660
|
+
*/
|
|
2661
|
+
approvalUrl?: string;
|
|
2662
|
+
/** When Link stops accepting approval, as an ISO 8601 time, when Link reports it. */
|
|
2663
|
+
approvalExpiresAt?: string;
|
|
2664
|
+
}
|
|
2665
|
+
/**
|
|
2666
|
+
* Called once when the Link card request is waiting for the person, after
|
|
2667
|
+
* Conto approved the purchase and before the SDK starts waiting. Show
|
|
2668
|
+
* approvalUrl to the person. The SDK does not wait for it to finish, and an
|
|
2669
|
+
* error it throws or rejects with does not affect the purchase. A retry that
|
|
2670
|
+
* resumes a waiting request calls it again with the same URL.
|
|
2671
|
+
*/
|
|
2672
|
+
type LinkApprovalCallback = (event: LinkApprovalEvent) => void | Promise<void>;
|
|
2646
2673
|
/**
|
|
2647
2674
|
* A Link card for one purchase: the checkpoint begin input plus the Link
|
|
2648
2675
|
* wallet that runs in your environment. The checkout method is always LINK.
|
|
@@ -2654,6 +2681,8 @@ interface GetLinkCardInput extends Omit<BeginCheckoutCheckpointInput, 'checkoutM
|
|
|
2654
2681
|
ownerApprovalTimeoutMs?: number;
|
|
2655
2682
|
/** How long to wait for the person to approve in Link. Defaults to 10 minutes. */
|
|
2656
2683
|
linkApprovalTimeoutMs?: number;
|
|
2684
|
+
/** Called once with the Link approval page when the person needs to approve in Link. */
|
|
2685
|
+
onLinkApproval?: LinkApprovalCallback;
|
|
2657
2686
|
signal?: AbortSignal;
|
|
2658
2687
|
}
|
|
2659
2688
|
/** A new Link card for a changed final total. */
|
|
@@ -2667,6 +2696,8 @@ interface ReplaceLinkCardInput {
|
|
|
2667
2696
|
totals?: CommerceTotalInput[];
|
|
2668
2697
|
ownerApprovalTimeoutMs?: number;
|
|
2669
2698
|
linkApprovalTimeoutMs?: number;
|
|
2699
|
+
/** Called once with the Link approval page when the person needs to approve in Link. */
|
|
2700
|
+
onLinkApproval?: LinkApprovalCallback;
|
|
2670
2701
|
signal?: AbortSignal;
|
|
2671
2702
|
}
|
|
2672
2703
|
interface LinkCardResult {
|
|
@@ -3380,6 +3411,13 @@ declare class CheckoutApprovalTimeoutError extends ContoError {
|
|
|
3380
3411
|
declare class LinkCardError extends ContoError {
|
|
3381
3412
|
readonly checkpoint: CheckoutCheckpoint;
|
|
3382
3413
|
readonly linkRequestId?: string;
|
|
3414
|
+
/**
|
|
3415
|
+
* The Stripe Link page where the person could approve the request, set when
|
|
3416
|
+
* the SDK stopped while the request was waiting for them. It works only while
|
|
3417
|
+
* the request is still open in Link. When holdReleased is true, Conto has
|
|
3418
|
+
* already cancelled the request.
|
|
3419
|
+
*/
|
|
3420
|
+
readonly approvalUrl?: string;
|
|
3383
3421
|
/** True when Conto cancelled the checkpoint and released the held spend. */
|
|
3384
3422
|
readonly holdReleased: boolean;
|
|
3385
3423
|
constructor(input: {
|
|
@@ -3387,6 +3425,7 @@ declare class LinkCardError extends ContoError {
|
|
|
3387
3425
|
code: string;
|
|
3388
3426
|
checkpoint: CheckoutCheckpoint;
|
|
3389
3427
|
linkRequestId?: string;
|
|
3428
|
+
approvalUrl?: string;
|
|
3390
3429
|
holdReleased: boolean;
|
|
3391
3430
|
retryGuidance?: string;
|
|
3392
3431
|
});
|
|
@@ -3854,7 +3893,9 @@ declare class CheckoutClient {
|
|
|
3854
3893
|
* 1. Conto runs checkpoint 1 and holds the spend. When a rule requires the
|
|
3855
3894
|
* owner's approval, this waits for it.
|
|
3856
3895
|
* 2. Only then does the wallet ask Link for a card for exactly the approved
|
|
3857
|
-
* amount at this merchant. The person approves it in Link.
|
|
3896
|
+
* amount at this merchant. The person approves it in Link. Pass
|
|
3897
|
+
* onLinkApproval to get Link's approval page, so they can approve on the
|
|
3898
|
+
* web without the Link app.
|
|
3858
3899
|
* 3. The card is returned. It never reaches Conto.
|
|
3859
3900
|
*
|
|
3860
3901
|
* Then fill in the card, call confirm(result.checkpoint, { amountMinor,
|
|
@@ -3880,4 +3921,4 @@ declare class CheckoutClient {
|
|
|
3880
3921
|
}
|
|
3881
3922
|
|
|
3882
3923
|
export { AdminPurchasingClient, BrowserActionFinalizationPendingError, BrowserCheckoutTargetVerificationError, CardsClient, CheckoutApprovalDeniedError, CheckoutApprovalExpiredError, CheckoutApprovalPendingError, CheckoutApprovalTimeoutError, CheckoutCheckpointClosedError, CheckoutClient, ConnectedCardsClient, Conto, ContoAdmin, ContoAdminError, ContoError, ControlledExternalCardPaymentTool, ExternalCardConfirmationPendingError, Conto as Giro, ContoError as GiroError, LinkCardCredential, LinkCardDeniedError, LinkCardError, LinkCardExpiredError, LinkCardTimeoutError, LinkWallet, LinkWalletUnavailableError, OrganizationPurchasesClient, OrganizationRecurringPurchasesClient, PurchasesClient, RecurringPurchasesClient, TestCardsClient, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget, isFinalPurchaseStatus, parseServerSentEvents, verifyPurchaseWebhook };
|
|
3883
|
-
export type { AdminExternalCardOverlayEnforcement, Agent, AgentCheckoutAction, AgentCheckoutActionKind, AgentExternalCard, AgentSetupResult, AgentStatus, AgentType, AgentWalletLink, ApprovedExternalCardExecution, AssignExternalCardInput, AssignedPolicy, AuthorizeCheckoutActionResult, BeginCheckoutCheckpointInput, BeginCommerceExecutionInput, BrowserActionClaimResult, BrowserActionDispatchObservationInput, BrowserActionFinalizeResult, BrowserCheckoutAction, BrowserCheckoutTargetResolver, BrowserCheckoutTargetSnapshot, BrowserCheckoutTargetVerificationCode, CancellationOutcome, CanonicalBrowserCheckoutTargetSnapshot, ChainType, CheckoutActionAuthorization, CheckoutCheckpoint, CheckoutCheckpointApproval, CheckoutCheckpointMethod, CheckoutCheckpointNextAction, CheckoutCheckpointStage, CheckoutOutcome, CheckoutPaymentReference, CommerceCheckoutMethod, CommerceContextRequirement, CommerceExecution, CommerceExecutionAdapterKind, CommerceExecutionArtifactKind, CommerceExecutionChannel, CommerceExecutionConstraint, CommerceExecutionConstraintCoverage, CommerceExecutionConstraintCoverageLevel, CommerceExecutionDeliveryMode, CommerceExecutionEvidence, CommerceExecutionProvider, CommerceExecutionResult, CommerceExecutionSourceKind, CommerceExecutionStatus, CommerceFactConfidence, CommerceFactProvenanceInput, CommerceFactSource, CommerceFulfillmentInput, CommerceLineItemInput, CommerceProposalFactKey, CommerceProposalMissingFact, CommerceProposalResolution, CommerceProposalState, CommerceSettlementRail, CommerceTotalInput, CommerceTotalType, ComparePolicyVersionsResponse, ConfirmCheckoutCheckpointInput, ConnectedCardBrief, ConnectedCardCredential, ConnectedCardDrawInput, ConnectedCardDrawMerchant, ConnectedCardDrawResult, ConnectedCardDrawable, ConnectedCardListResult, ConnectedCardMandate, ConnectedCardMandateMerchant, ConnectedCardOutcomeReport, ConnectedCardOutcomeReportResult, ConnectedCardReference, ContoAdminConfig, ContoConfig, ContoRequestOptions, ControlledExternalCardPaymentResult, CreateAgentInput, CreatePolicyInput, CreatePolicyRuleInput, CreatePurchaseInput, CreateSdkKeyInput, CreateSdkKeyResult, CreateWalletInput, CustodyType, CustomerCustodyMode, CustomerWalletControlModel, CustomerWalletKeyAccess, DelegationType, ExecuteCommerceExecutionResult, ExternalCard, ExternalCardApprovalInput, ExternalCardApprovalResult, ExternalCardConfirmationInput, ExternalCardConfirmationResult, ExternalCardExecutionClaimResult, ExternalCardExecutionResult, ExternalCardExecutor, ExternalCardOverlayEnforcement, ExternalCardRequestStatusResult, ExternalWalletApprovalInput, ExternalWalletApprovalResult, ExternalWalletConfirmationInput, ExternalWalletConfirmationResult, FreezeAgentInput, GetLinkCardInput, ContoConfig as GiroConfig, GuardCheckoutResult, GuardedBrowserDispatchResult, GuardedCheckoutInput, LinkCardResult, LinkWalletInput, ListAgentsParams, ListAgentsResponse, ListPoliciesParams, ListPoliciesResponse, ListPolicyVersionsResponse, ListWalletsParams, ListWalletsResponse, MppBudgetResult, MppPreAuthorizeInput, MppPreAuthorizeResult, MppRecordInput, MppRecordResult, NormalizeCommerceProposalInput, OrganizationMember, PaginatedResponse, PaginationParams, PauseExternalCardAssignmentResult, PaymentExecuteResult, PaymentRequestInput, PaymentRequestResult, PaymentStatusResult, Policy, PolicyRule, PolicyType, PolicyVersionChangeType, PolicyVersionDetail, PolicyVersionDiff, PolicyVersionFieldChange, PolicyVersionSnapshot, PolicyVersionSnapshotRule, PolicyVersionSummary, PrivilegedBrowserCheckoutDriver, ProtocolBudgetResult, ProtocolPreAuthorizeResult, ProtocolRecordGrant, ProtocolRecordGrantResult, ProtocolServiceSummary, ProtocolServicesResult, ProveWalletOwnershipInput, ProvisionWalletResult, Purchase, PurchaseAction, PurchaseActionAuthority, PurchaseActionKind, PurchaseAllowance, PurchaseBuyer, PurchaseBuyerCompanyCard, PurchaseBuyerCompanyCardLimits, PurchaseBuyerKitchenContext, PurchaseCompanyCard, PurchaseDelegation, PurchaseEvent, PurchaseEventPage, PurchaseEvidence, PurchaseGrocery, PurchaseGroceryItem, PurchaseGroceryList, PurchaseHostedLink, PurchaseItem, PurchaseKitchenContext, PurchaseKitchenInventoryItem, PurchaseKitchenListItem, PurchaseKitchenPreferences, PurchaseKitchenRecipe, PurchaseKitchenUsual, PurchaseList, PurchaseMoney, PurchasePaymentMethod, PurchasePhase, PurchaseRequest, PurchaseResponseAck, PurchaseStatus, PurchasingCapabilities, PurchasingSettings, RecurringPurchase, RecurringPurchaseCycleResult, RecurringPurchaseCycleStatus, RefreshBalanceResult, RegisterExternalCardInput, ReplaceLinkCardInput, ReportCheckoutOutcomeInput, RollbackPolicyVersionResponse, RuleAction, RuleOperator, RuleType, RunGuardedCheckoutResult, SdkKey, SdkKeyType, SetupCapabilityState, SetupCardDiagnostics, SetupDiagnosticAction, SetupDiagnosticIssue, SetupDiagnosticIssueCode, SetupDiagnostics, SetupWalletDiagnostics, TestCardCredential, TestCardDrawResult, TestCardDrawable, TestCardListResult, TestCardReceipt, TestCheckoutInput, TestCheckoutResult, TestMerchant, TestMerchantProduct, UnfreezeAgentInput, UpdateAgentInput, UpdateExternalCardAssignmentInput, UpdatePolicyInput, UpdatePolicyRuleInput, UpdateWalletInput, VerifiedBrowserCheckoutTarget, WaitForCheckoutApprovalOptions, Wallet, WalletChainBalanceSnapshot, WalletOwnershipChallenge, WalletOwnershipProof, WalletStatus, WalletType, WatchPurchaseOptions, X402Authorization, X402BudgetResult, X402PayInput, X402PayResult, X402PaymentRequirements, X402PreAuthorizeInput, X402PreAuthorizeResult, X402RecordInput, X402RecordResult };
|
|
3924
|
+
export type { AdminExternalCardOverlayEnforcement, Agent, AgentCheckoutAction, AgentCheckoutActionKind, AgentExternalCard, AgentSetupResult, AgentStatus, AgentType, AgentWalletLink, ApprovedExternalCardExecution, AssignExternalCardInput, AssignedPolicy, AuthorizeCheckoutActionResult, BeginCheckoutCheckpointInput, BeginCommerceExecutionInput, BrowserActionClaimResult, BrowserActionDispatchObservationInput, BrowserActionFinalizeResult, BrowserCheckoutAction, BrowserCheckoutTargetResolver, BrowserCheckoutTargetSnapshot, BrowserCheckoutTargetVerificationCode, CancellationOutcome, CanonicalBrowserCheckoutTargetSnapshot, ChainType, CheckoutActionAuthorization, CheckoutCheckpoint, CheckoutCheckpointApproval, CheckoutCheckpointMethod, CheckoutCheckpointNextAction, CheckoutCheckpointStage, CheckoutOutcome, CheckoutPaymentReference, CommerceCheckoutMethod, CommerceContextRequirement, CommerceExecution, CommerceExecutionAdapterKind, CommerceExecutionArtifactKind, CommerceExecutionChannel, CommerceExecutionConstraint, CommerceExecutionConstraintCoverage, CommerceExecutionConstraintCoverageLevel, CommerceExecutionDeliveryMode, CommerceExecutionEvidence, CommerceExecutionProvider, CommerceExecutionResult, CommerceExecutionSourceKind, CommerceExecutionStatus, CommerceFactConfidence, CommerceFactProvenanceInput, CommerceFactSource, CommerceFulfillmentInput, CommerceLineItemInput, CommerceProposalFactKey, CommerceProposalMissingFact, CommerceProposalResolution, CommerceProposalState, CommerceSettlementRail, CommerceTotalInput, CommerceTotalType, ComparePolicyVersionsResponse, ConfirmCheckoutCheckpointInput, ConnectedCardBrief, ConnectedCardCredential, ConnectedCardDrawInput, ConnectedCardDrawMerchant, ConnectedCardDrawResult, ConnectedCardDrawable, ConnectedCardListResult, ConnectedCardMandate, ConnectedCardMandateMerchant, ConnectedCardOutcomeReport, ConnectedCardOutcomeReportResult, ConnectedCardReference, ContoAdminConfig, ContoConfig, ContoRequestOptions, ControlledExternalCardPaymentResult, CreateAgentInput, CreatePolicyInput, CreatePolicyRuleInput, CreatePurchaseInput, CreateSdkKeyInput, CreateSdkKeyResult, CreateWalletInput, CustodyType, CustomerCustodyMode, CustomerWalletControlModel, CustomerWalletKeyAccess, DelegationType, ExecuteCommerceExecutionResult, ExternalCard, ExternalCardApprovalInput, ExternalCardApprovalResult, ExternalCardConfirmationInput, ExternalCardConfirmationResult, ExternalCardExecutionClaimResult, ExternalCardExecutionResult, ExternalCardExecutor, ExternalCardOverlayEnforcement, ExternalCardRequestStatusResult, ExternalWalletApprovalInput, ExternalWalletApprovalResult, ExternalWalletConfirmationInput, ExternalWalletConfirmationResult, FreezeAgentInput, GetLinkCardInput, ContoConfig as GiroConfig, GuardCheckoutResult, GuardedBrowserDispatchResult, GuardedCheckoutInput, LinkApprovalCallback, LinkApprovalEvent, LinkCardResult, LinkWalletInput, ListAgentsParams, ListAgentsResponse, ListPoliciesParams, ListPoliciesResponse, ListPolicyVersionsResponse, ListWalletsParams, ListWalletsResponse, MppBudgetResult, MppPreAuthorizeInput, MppPreAuthorizeResult, MppRecordInput, MppRecordResult, NormalizeCommerceProposalInput, OrganizationMember, PaginatedResponse, PaginationParams, PauseExternalCardAssignmentResult, PaymentExecuteResult, PaymentRequestInput, PaymentRequestResult, PaymentStatusResult, Policy, PolicyRule, PolicyType, PolicyVersionChangeType, PolicyVersionDetail, PolicyVersionDiff, PolicyVersionFieldChange, PolicyVersionSnapshot, PolicyVersionSnapshotRule, PolicyVersionSummary, PrivilegedBrowserCheckoutDriver, ProtocolBudgetResult, ProtocolPreAuthorizeResult, ProtocolRecordGrant, ProtocolRecordGrantResult, ProtocolServiceSummary, ProtocolServicesResult, ProveWalletOwnershipInput, ProvisionWalletResult, Purchase, PurchaseAction, PurchaseActionAuthority, PurchaseActionKind, PurchaseAllowance, PurchaseBuyer, PurchaseBuyerCompanyCard, PurchaseBuyerCompanyCardLimits, PurchaseBuyerKitchenContext, PurchaseCompanyCard, PurchaseDelegation, PurchaseEvent, PurchaseEventPage, PurchaseEvidence, PurchaseGrocery, PurchaseGroceryItem, PurchaseGroceryList, PurchaseHostedLink, PurchaseItem, PurchaseKitchenContext, PurchaseKitchenInventoryItem, PurchaseKitchenListItem, PurchaseKitchenPreferences, PurchaseKitchenRecipe, PurchaseKitchenUsual, PurchaseList, PurchaseMoney, PurchasePaymentMethod, PurchasePhase, PurchaseRequest, PurchaseResponseAck, PurchaseStatus, PurchasingCapabilities, PurchasingSettings, RecurringPurchase, RecurringPurchaseCycleResult, RecurringPurchaseCycleStatus, RefreshBalanceResult, RegisterExternalCardInput, ReplaceLinkCardInput, ReportCheckoutOutcomeInput, RollbackPolicyVersionResponse, RuleAction, RuleOperator, RuleType, RunGuardedCheckoutResult, SdkKey, SdkKeyType, SetupCapabilityState, SetupCardDiagnostics, SetupDiagnosticAction, SetupDiagnosticIssue, SetupDiagnosticIssueCode, SetupDiagnostics, SetupWalletDiagnostics, TestCardCredential, TestCardDrawResult, TestCardDrawable, TestCardListResult, TestCardReceipt, TestCheckoutInput, TestCheckoutResult, TestMerchant, TestMerchantProduct, UnfreezeAgentInput, UpdateAgentInput, UpdateExternalCardAssignmentInput, UpdatePolicyInput, UpdatePolicyRuleInput, UpdateWalletInput, VerifiedBrowserCheckoutTarget, WaitForCheckoutApprovalOptions, Wallet, WalletChainBalanceSnapshot, WalletOwnershipChallenge, WalletOwnershipProof, WalletStatus, WalletType, WatchPurchaseOptions, X402Authorization, X402BudgetResult, X402PayInput, X402PayResult, X402PaymentRequirements, X402PreAuthorizeInput, X402PreAuthorizeResult, X402RecordInput, X402RecordResult };
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ var require_package = __commonJS({
|
|
|
47
47
|
"package.json"(exports2, module2) {
|
|
48
48
|
module2.exports = {
|
|
49
49
|
name: "@conto_finance/sdk",
|
|
50
|
-
version: "0.7.
|
|
50
|
+
version: "0.7.1",
|
|
51
51
|
description: "Conto SDK for AI agent payment authorization",
|
|
52
52
|
main: "./dist/index.js",
|
|
53
53
|
module: "./dist/index.mjs",
|
|
@@ -197,6 +197,32 @@ var Sentry2 = __toESM(require("@sentry/node"));
|
|
|
197
197
|
var import_node_crypto3 = require("crypto");
|
|
198
198
|
var import_package_version2 = __toESM(require_package_version());
|
|
199
199
|
|
|
200
|
+
// src/link-approval.ts
|
|
201
|
+
function safeLinkApprovalUrl(value) {
|
|
202
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048) return void 0;
|
|
203
|
+
let url;
|
|
204
|
+
try {
|
|
205
|
+
url = new URL(value);
|
|
206
|
+
} catch {
|
|
207
|
+
return void 0;
|
|
208
|
+
}
|
|
209
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || !(url.hostname === "link.com" || url.hostname.endsWith(".link.com"))) {
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
url.hash = "";
|
|
213
|
+
return url.toString();
|
|
214
|
+
}
|
|
215
|
+
function linkTime(value) {
|
|
216
|
+
let ms = Number.NaN;
|
|
217
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
218
|
+
ms = value < 1e12 ? value * 1e3 : value;
|
|
219
|
+
} else if (typeof value === "string" && value.length > 0 && value.length <= 64) {
|
|
220
|
+
ms = Date.parse(value);
|
|
221
|
+
}
|
|
222
|
+
const date = new Date(ms);
|
|
223
|
+
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString();
|
|
224
|
+
}
|
|
225
|
+
|
|
200
226
|
// src/purchases.ts
|
|
201
227
|
var import_node_crypto = require("crypto");
|
|
202
228
|
var TERMINAL = /* @__PURE__ */ new Set(["succeeded", "blocked", "failed", "cancelled"]);
|
|
@@ -1684,6 +1710,8 @@ var LinkCardError = class extends ContoError {
|
|
|
1684
1710
|
this.name = "LinkCardError";
|
|
1685
1711
|
this.checkpoint = input.checkpoint;
|
|
1686
1712
|
if (input.linkRequestId) this.linkRequestId = input.linkRequestId;
|
|
1713
|
+
const approvalUrl = safeLinkApprovalUrl(input.approvalUrl);
|
|
1714
|
+
if (approvalUrl) this.approvalUrl = approvalUrl;
|
|
1687
1715
|
this.holdReleased = input.holdReleased;
|
|
1688
1716
|
}
|
|
1689
1717
|
};
|
|
@@ -2991,6 +3019,11 @@ async function closeLinkRequest(wallet, id) {
|
|
|
2991
3019
|
return status !== void 0 && LINK_CLOSED_STATUSES.has(status);
|
|
2992
3020
|
}
|
|
2993
3021
|
}
|
|
3022
|
+
function assertLinkApprovalCallback(callback) {
|
|
3023
|
+
if (callback !== void 0 && typeof callback !== "function") {
|
|
3024
|
+
throw checkoutError("onLinkApproval must be a function");
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
2994
3027
|
function linkCreatedNothing(error) {
|
|
2995
3028
|
return errorCode(error) === "LINK_WALLET_UNAVAILABLE" || errorReason(error) === "invalid_input";
|
|
2996
3029
|
}
|
|
@@ -3000,6 +3033,23 @@ var LinkFailureSignal = class extends Error {
|
|
|
3000
3033
|
this.failure = failure;
|
|
3001
3034
|
}
|
|
3002
3035
|
};
|
|
3036
|
+
function linkApprovalDetails(request) {
|
|
3037
|
+
const approvalUrl = safeLinkApprovalUrl(request.approvalUrl);
|
|
3038
|
+
const approvalExpiresAt = linkTime(request.approvalExpiresAt);
|
|
3039
|
+
return {
|
|
3040
|
+
...approvalUrl ? { approvalUrl } : {},
|
|
3041
|
+
...approvalExpiresAt ? { approvalExpiresAt } : {}
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
function notifyLinkApproval(callback, event) {
|
|
3045
|
+
try {
|
|
3046
|
+
const result = callback(Object.freeze(event));
|
|
3047
|
+
if (result !== null && typeof result === "object" && "then" in result) {
|
|
3048
|
+
Promise.resolve(result).catch(() => void 0);
|
|
3049
|
+
}
|
|
3050
|
+
} catch {
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3003
3053
|
var _client4, _CheckoutClient_instances, linkCardFor_fn;
|
|
3004
3054
|
var CheckoutClient = class {
|
|
3005
3055
|
constructor(client) {
|
|
@@ -3185,7 +3235,9 @@ var CheckoutClient = class {
|
|
|
3185
3235
|
* 1. Conto runs checkpoint 1 and holds the spend. When a rule requires the
|
|
3186
3236
|
* owner's approval, this waits for it.
|
|
3187
3237
|
* 2. Only then does the wallet ask Link for a card for exactly the approved
|
|
3188
|
-
* amount at this merchant. The person approves it in Link.
|
|
3238
|
+
* amount at this merchant. The person approves it in Link. Pass
|
|
3239
|
+
* onLinkApproval to get Link's approval page, so they can approve on the
|
|
3240
|
+
* web without the Link app.
|
|
3189
3241
|
* 3. The card is returned. It never reaches Conto.
|
|
3190
3242
|
*
|
|
3191
3243
|
* Then fill in the card, call confirm(result.checkpoint, { amountMinor,
|
|
@@ -3201,10 +3253,18 @@ var CheckoutClient = class {
|
|
|
3201
3253
|
* Link request.
|
|
3202
3254
|
*/
|
|
3203
3255
|
async getLinkCard(input) {
|
|
3204
|
-
const {
|
|
3256
|
+
const {
|
|
3257
|
+
wallet,
|
|
3258
|
+
ownerApprovalTimeoutMs,
|
|
3259
|
+
linkApprovalTimeoutMs,
|
|
3260
|
+
onLinkApproval,
|
|
3261
|
+
signal,
|
|
3262
|
+
...beginInput
|
|
3263
|
+
} = input;
|
|
3205
3264
|
if (!wallet || typeof wallet.createCardRequest !== "function") {
|
|
3206
3265
|
throw checkoutError("wallet must be a LinkWallet, such as linkCliWallet()");
|
|
3207
3266
|
}
|
|
3267
|
+
assertLinkApprovalCallback(onLinkApproval);
|
|
3208
3268
|
let checkpoint = await this.begin({ ...beginInput, checkoutMethod: "LINK" });
|
|
3209
3269
|
if (checkpoint.stage === "AWAITING_APPROVAL") {
|
|
3210
3270
|
checkpoint = await this.waitForApproval(checkpoint, {
|
|
@@ -3212,7 +3272,11 @@ var CheckoutClient = class {
|
|
|
3212
3272
|
...signal ? { signal } : {}
|
|
3213
3273
|
});
|
|
3214
3274
|
}
|
|
3215
|
-
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet,
|
|
3275
|
+
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet, {
|
|
3276
|
+
linkApprovalTimeoutMs,
|
|
3277
|
+
signal,
|
|
3278
|
+
onLinkApproval
|
|
3279
|
+
});
|
|
3216
3280
|
}
|
|
3217
3281
|
/**
|
|
3218
3282
|
* The final total differs from the one the Link card covers. This cancels
|
|
@@ -3221,10 +3285,18 @@ var CheckoutClient = class {
|
|
|
3221
3285
|
* for it. Confirm the returned checkpoint with the same total.
|
|
3222
3286
|
*/
|
|
3223
3287
|
async replaceLinkCard(previous, input) {
|
|
3224
|
-
const {
|
|
3288
|
+
const {
|
|
3289
|
+
wallet,
|
|
3290
|
+
amountMinor,
|
|
3291
|
+
ownerApprovalTimeoutMs,
|
|
3292
|
+
linkApprovalTimeoutMs,
|
|
3293
|
+
onLinkApproval,
|
|
3294
|
+
signal
|
|
3295
|
+
} = input;
|
|
3225
3296
|
if (!Number.isSafeInteger(amountMinor) || amountMinor <= 0) {
|
|
3226
3297
|
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
3227
3298
|
}
|
|
3299
|
+
assertLinkApprovalCallback(onLinkApproval);
|
|
3228
3300
|
if (amountMinor === previous.checkpoint.amountMinor) return previous;
|
|
3229
3301
|
const old = previous.checkpoint;
|
|
3230
3302
|
if (!await closeLinkRequest(wallet, previous.linkRequestId)) {
|
|
@@ -3263,12 +3335,17 @@ var CheckoutClient = class {
|
|
|
3263
3335
|
...signal ? { signal } : {}
|
|
3264
3336
|
});
|
|
3265
3337
|
}
|
|
3266
|
-
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet,
|
|
3338
|
+
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet, {
|
|
3339
|
+
linkApprovalTimeoutMs,
|
|
3340
|
+
signal,
|
|
3341
|
+
onLinkApproval
|
|
3342
|
+
});
|
|
3267
3343
|
}
|
|
3268
3344
|
};
|
|
3269
3345
|
_client4 = new WeakMap();
|
|
3270
3346
|
_CheckoutClient_instances = new WeakSet();
|
|
3271
|
-
linkCardFor_fn = async function(checkpoint, wallet,
|
|
3347
|
+
linkCardFor_fn = async function(checkpoint, wallet, options) {
|
|
3348
|
+
const { linkApprovalTimeoutMs = 10 * 6e4, signal, onLinkApproval } = options;
|
|
3272
3349
|
if (checkpoint.stage !== "APPROVED") {
|
|
3273
3350
|
throw checkoutError(
|
|
3274
3351
|
`Conto has not approved a card for this checkpoint (stage ${checkpoint.stage}). Do not pay.`,
|
|
@@ -3278,6 +3355,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3278
3355
|
const deadline = Date.now() + linkApprovalTimeoutMs;
|
|
3279
3356
|
const call = signal ? { signal } : {};
|
|
3280
3357
|
let linkRequestId;
|
|
3358
|
+
let approvalUrl;
|
|
3281
3359
|
let createStarted = false;
|
|
3282
3360
|
try {
|
|
3283
3361
|
const cardRequest = linkCardRequest(checkpoint);
|
|
@@ -3298,6 +3376,13 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3298
3376
|
message: "Link returned a request for a different amount."
|
|
3299
3377
|
});
|
|
3300
3378
|
}
|
|
3379
|
+
if (LINK_WAITING_STATUSES.has(request.status)) {
|
|
3380
|
+
const details = linkApprovalDetails(request);
|
|
3381
|
+
approvalUrl = details.approvalUrl;
|
|
3382
|
+
if (onLinkApproval) {
|
|
3383
|
+
notifyLinkApproval(onLinkApproval, { checkpoint, linkRequestId: request.id, ...details });
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3301
3386
|
while (linkRequestWaiting(request)) {
|
|
3302
3387
|
const remainingSeconds = Math.floor((deadline - Date.now()) / 1e3);
|
|
3303
3388
|
if (remainingSeconds <= 0) {
|
|
@@ -3312,6 +3397,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3312
3397
|
...call,
|
|
3313
3398
|
timeoutSeconds: remainingSeconds
|
|
3314
3399
|
});
|
|
3400
|
+
approvalUrl = LINK_WAITING_STATUSES.has(request.status) ? linkApprovalDetails(request).approvalUrl ?? approvalUrl : void 0;
|
|
3315
3401
|
if (linkRequestWaiting(request) && Date.now() - started < 1e3) {
|
|
3316
3402
|
await sleep2(1e3, signal);
|
|
3317
3403
|
}
|
|
@@ -3343,6 +3429,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3343
3429
|
code: "LINK_CARD_NOT_CANCELLED",
|
|
3344
3430
|
checkpoint,
|
|
3345
3431
|
linkRequestId,
|
|
3432
|
+
...approvalUrl ? { approvalUrl } : {},
|
|
3346
3433
|
holdReleased: false,
|
|
3347
3434
|
retryGuidance: "Retry with the same input to resume this Link request, or cancel it with wallet.cancel(error.linkRequestId) and then call checkout.cancel(error.checkpoint.id)."
|
|
3348
3435
|
});
|
|
@@ -3356,6 +3443,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3356
3443
|
code: failure.code,
|
|
3357
3444
|
checkpoint,
|
|
3358
3445
|
...linkRequestId ? { linkRequestId } : {},
|
|
3446
|
+
...linkRequestId && approvalUrl ? { approvalUrl } : {},
|
|
3359
3447
|
holdReleased
|
|
3360
3448
|
});
|
|
3361
3449
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
linkTime,
|
|
3
|
+
safeLinkApprovalUrl
|
|
4
|
+
} from "./chunk-PVMUL3JC.mjs";
|
|
1
5
|
import {
|
|
2
6
|
BrowserCheckoutTargetVerificationError,
|
|
3
7
|
canonicalizeBrowserCheckoutTarget,
|
|
@@ -18,7 +22,7 @@ var require_package = __commonJS({
|
|
|
18
22
|
"package.json"(exports, module) {
|
|
19
23
|
module.exports = {
|
|
20
24
|
name: "@conto_finance/sdk",
|
|
21
|
-
version: "0.7.
|
|
25
|
+
version: "0.7.1",
|
|
22
26
|
description: "Conto SDK for AI agent payment authorization",
|
|
23
27
|
main: "./dist/index.js",
|
|
24
28
|
module: "./dist/index.mjs",
|
|
@@ -1499,6 +1503,8 @@ var LinkCardError = class extends ContoError {
|
|
|
1499
1503
|
this.name = "LinkCardError";
|
|
1500
1504
|
this.checkpoint = input.checkpoint;
|
|
1501
1505
|
if (input.linkRequestId) this.linkRequestId = input.linkRequestId;
|
|
1506
|
+
const approvalUrl = safeLinkApprovalUrl(input.approvalUrl);
|
|
1507
|
+
if (approvalUrl) this.approvalUrl = approvalUrl;
|
|
1502
1508
|
this.holdReleased = input.holdReleased;
|
|
1503
1509
|
}
|
|
1504
1510
|
};
|
|
@@ -2806,6 +2812,11 @@ async function closeLinkRequest(wallet, id) {
|
|
|
2806
2812
|
return status !== void 0 && LINK_CLOSED_STATUSES.has(status);
|
|
2807
2813
|
}
|
|
2808
2814
|
}
|
|
2815
|
+
function assertLinkApprovalCallback(callback) {
|
|
2816
|
+
if (callback !== void 0 && typeof callback !== "function") {
|
|
2817
|
+
throw checkoutError("onLinkApproval must be a function");
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2809
2820
|
function linkCreatedNothing(error) {
|
|
2810
2821
|
return errorCode(error) === "LINK_WALLET_UNAVAILABLE" || errorReason(error) === "invalid_input";
|
|
2811
2822
|
}
|
|
@@ -2815,6 +2826,23 @@ var LinkFailureSignal = class extends Error {
|
|
|
2815
2826
|
this.failure = failure;
|
|
2816
2827
|
}
|
|
2817
2828
|
};
|
|
2829
|
+
function linkApprovalDetails(request) {
|
|
2830
|
+
const approvalUrl = safeLinkApprovalUrl(request.approvalUrl);
|
|
2831
|
+
const approvalExpiresAt = linkTime(request.approvalExpiresAt);
|
|
2832
|
+
return {
|
|
2833
|
+
...approvalUrl ? { approvalUrl } : {},
|
|
2834
|
+
...approvalExpiresAt ? { approvalExpiresAt } : {}
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
function notifyLinkApproval(callback, event) {
|
|
2838
|
+
try {
|
|
2839
|
+
const result = callback(Object.freeze(event));
|
|
2840
|
+
if (result !== null && typeof result === "object" && "then" in result) {
|
|
2841
|
+
Promise.resolve(result).catch(() => void 0);
|
|
2842
|
+
}
|
|
2843
|
+
} catch {
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2818
2846
|
var _client4, _CheckoutClient_instances, linkCardFor_fn;
|
|
2819
2847
|
var CheckoutClient = class {
|
|
2820
2848
|
constructor(client) {
|
|
@@ -3000,7 +3028,9 @@ var CheckoutClient = class {
|
|
|
3000
3028
|
* 1. Conto runs checkpoint 1 and holds the spend. When a rule requires the
|
|
3001
3029
|
* owner's approval, this waits for it.
|
|
3002
3030
|
* 2. Only then does the wallet ask Link for a card for exactly the approved
|
|
3003
|
-
* amount at this merchant. The person approves it in Link.
|
|
3031
|
+
* amount at this merchant. The person approves it in Link. Pass
|
|
3032
|
+
* onLinkApproval to get Link's approval page, so they can approve on the
|
|
3033
|
+
* web without the Link app.
|
|
3004
3034
|
* 3. The card is returned. It never reaches Conto.
|
|
3005
3035
|
*
|
|
3006
3036
|
* Then fill in the card, call confirm(result.checkpoint, { amountMinor,
|
|
@@ -3016,10 +3046,18 @@ var CheckoutClient = class {
|
|
|
3016
3046
|
* Link request.
|
|
3017
3047
|
*/
|
|
3018
3048
|
async getLinkCard(input) {
|
|
3019
|
-
const {
|
|
3049
|
+
const {
|
|
3050
|
+
wallet,
|
|
3051
|
+
ownerApprovalTimeoutMs,
|
|
3052
|
+
linkApprovalTimeoutMs,
|
|
3053
|
+
onLinkApproval,
|
|
3054
|
+
signal,
|
|
3055
|
+
...beginInput
|
|
3056
|
+
} = input;
|
|
3020
3057
|
if (!wallet || typeof wallet.createCardRequest !== "function") {
|
|
3021
3058
|
throw checkoutError("wallet must be a LinkWallet, such as linkCliWallet()");
|
|
3022
3059
|
}
|
|
3060
|
+
assertLinkApprovalCallback(onLinkApproval);
|
|
3023
3061
|
let checkpoint = await this.begin({ ...beginInput, checkoutMethod: "LINK" });
|
|
3024
3062
|
if (checkpoint.stage === "AWAITING_APPROVAL") {
|
|
3025
3063
|
checkpoint = await this.waitForApproval(checkpoint, {
|
|
@@ -3027,7 +3065,11 @@ var CheckoutClient = class {
|
|
|
3027
3065
|
...signal ? { signal } : {}
|
|
3028
3066
|
});
|
|
3029
3067
|
}
|
|
3030
|
-
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet,
|
|
3068
|
+
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet, {
|
|
3069
|
+
linkApprovalTimeoutMs,
|
|
3070
|
+
signal,
|
|
3071
|
+
onLinkApproval
|
|
3072
|
+
});
|
|
3031
3073
|
}
|
|
3032
3074
|
/**
|
|
3033
3075
|
* The final total differs from the one the Link card covers. This cancels
|
|
@@ -3036,10 +3078,18 @@ var CheckoutClient = class {
|
|
|
3036
3078
|
* for it. Confirm the returned checkpoint with the same total.
|
|
3037
3079
|
*/
|
|
3038
3080
|
async replaceLinkCard(previous, input) {
|
|
3039
|
-
const {
|
|
3081
|
+
const {
|
|
3082
|
+
wallet,
|
|
3083
|
+
amountMinor,
|
|
3084
|
+
ownerApprovalTimeoutMs,
|
|
3085
|
+
linkApprovalTimeoutMs,
|
|
3086
|
+
onLinkApproval,
|
|
3087
|
+
signal
|
|
3088
|
+
} = input;
|
|
3040
3089
|
if (!Number.isSafeInteger(amountMinor) || amountMinor <= 0) {
|
|
3041
3090
|
throw checkoutError("amountMinor must be a positive integer number of cents");
|
|
3042
3091
|
}
|
|
3092
|
+
assertLinkApprovalCallback(onLinkApproval);
|
|
3043
3093
|
if (amountMinor === previous.checkpoint.amountMinor) return previous;
|
|
3044
3094
|
const old = previous.checkpoint;
|
|
3045
3095
|
if (!await closeLinkRequest(wallet, previous.linkRequestId)) {
|
|
@@ -3078,12 +3128,17 @@ var CheckoutClient = class {
|
|
|
3078
3128
|
...signal ? { signal } : {}
|
|
3079
3129
|
});
|
|
3080
3130
|
}
|
|
3081
|
-
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet,
|
|
3131
|
+
return __privateMethod(this, _CheckoutClient_instances, linkCardFor_fn).call(this, checkpoint, wallet, {
|
|
3132
|
+
linkApprovalTimeoutMs,
|
|
3133
|
+
signal,
|
|
3134
|
+
onLinkApproval
|
|
3135
|
+
});
|
|
3082
3136
|
}
|
|
3083
3137
|
};
|
|
3084
3138
|
_client4 = new WeakMap();
|
|
3085
3139
|
_CheckoutClient_instances = new WeakSet();
|
|
3086
|
-
linkCardFor_fn = async function(checkpoint, wallet,
|
|
3140
|
+
linkCardFor_fn = async function(checkpoint, wallet, options) {
|
|
3141
|
+
const { linkApprovalTimeoutMs = 10 * 6e4, signal, onLinkApproval } = options;
|
|
3087
3142
|
if (checkpoint.stage !== "APPROVED") {
|
|
3088
3143
|
throw checkoutError(
|
|
3089
3144
|
`Conto has not approved a card for this checkpoint (stage ${checkpoint.stage}). Do not pay.`,
|
|
@@ -3093,6 +3148,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3093
3148
|
const deadline = Date.now() + linkApprovalTimeoutMs;
|
|
3094
3149
|
const call = signal ? { signal } : {};
|
|
3095
3150
|
let linkRequestId;
|
|
3151
|
+
let approvalUrl;
|
|
3096
3152
|
let createStarted = false;
|
|
3097
3153
|
try {
|
|
3098
3154
|
const cardRequest = linkCardRequest(checkpoint);
|
|
@@ -3113,6 +3169,13 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3113
3169
|
message: "Link returned a request for a different amount."
|
|
3114
3170
|
});
|
|
3115
3171
|
}
|
|
3172
|
+
if (LINK_WAITING_STATUSES.has(request.status)) {
|
|
3173
|
+
const details = linkApprovalDetails(request);
|
|
3174
|
+
approvalUrl = details.approvalUrl;
|
|
3175
|
+
if (onLinkApproval) {
|
|
3176
|
+
notifyLinkApproval(onLinkApproval, { checkpoint, linkRequestId: request.id, ...details });
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3116
3179
|
while (linkRequestWaiting(request)) {
|
|
3117
3180
|
const remainingSeconds = Math.floor((deadline - Date.now()) / 1e3);
|
|
3118
3181
|
if (remainingSeconds <= 0) {
|
|
@@ -3127,6 +3190,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3127
3190
|
...call,
|
|
3128
3191
|
timeoutSeconds: remainingSeconds
|
|
3129
3192
|
});
|
|
3193
|
+
approvalUrl = LINK_WAITING_STATUSES.has(request.status) ? linkApprovalDetails(request).approvalUrl ?? approvalUrl : void 0;
|
|
3130
3194
|
if (linkRequestWaiting(request) && Date.now() - started < 1e3) {
|
|
3131
3195
|
await sleep2(1e3, signal);
|
|
3132
3196
|
}
|
|
@@ -3158,6 +3222,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3158
3222
|
code: "LINK_CARD_NOT_CANCELLED",
|
|
3159
3223
|
checkpoint,
|
|
3160
3224
|
linkRequestId,
|
|
3225
|
+
...approvalUrl ? { approvalUrl } : {},
|
|
3161
3226
|
holdReleased: false,
|
|
3162
3227
|
retryGuidance: "Retry with the same input to resume this Link request, or cancel it with wallet.cancel(error.linkRequestId) and then call checkout.cancel(error.checkpoint.id)."
|
|
3163
3228
|
});
|
|
@@ -3171,6 +3236,7 @@ linkCardFor_fn = async function(checkpoint, wallet, linkApprovalTimeoutMs = 10 *
|
|
|
3171
3236
|
code: failure.code,
|
|
3172
3237
|
checkpoint,
|
|
3173
3238
|
...linkRequestId ? { linkRequestId } : {},
|
|
3239
|
+
...linkRequestId && approvalUrl ? { approvalUrl } : {},
|
|
3174
3240
|
holdReleased
|
|
3175
3241
|
});
|
|
3176
3242
|
}
|
package/dist/link-wallet.d.mts
CHANGED
|
@@ -38,8 +38,13 @@ interface LinkSpendRequest {
|
|
|
38
38
|
amountMinor?: number;
|
|
39
39
|
merchantName?: string;
|
|
40
40
|
merchantUrl?: string;
|
|
41
|
-
/**
|
|
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. */
|
package/dist/link-wallet.d.ts
CHANGED
|
@@ -38,8 +38,13 @@ interface LinkSpendRequest {
|
|
|
38
38
|
amountMinor?: number;
|
|
39
39
|
merchantName?: string;
|
|
40
40
|
merchantUrl?: string;
|
|
41
|
-
/**
|
|
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. */
|
package/dist/link-wallet.js
CHANGED
|
@@ -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
|
-
...
|
|
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 =
|
|
161
|
+
const until = linkTime(card.valid_until);
|
|
140
162
|
const brand = text(card.brand);
|
|
141
163
|
return {
|
|
142
164
|
number,
|
package/dist/link-wallet.mjs
CHANGED
|
@@ -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
|
-
...
|
|
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 =
|
|
103
|
+
const until = linkTime(card.valid_until);
|
|
106
104
|
const brand = text(card.brand);
|
|
107
105
|
return {
|
|
108
106
|
number,
|