@settlr/sdk 0.1.0 → 0.3.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.
- package/README.md +33 -69
- package/dist/index.d.mts +174 -34
- package/dist/index.d.ts +174 -34
- package/dist/index.js +252 -62
- package/dist/index.mjs +252 -63
- package/package.json +5 -6
package/dist/index.mjs
CHANGED
|
@@ -22,8 +22,8 @@ var SETTLR_API_URL = {
|
|
|
22
22
|
development: "http://localhost:3000/api"
|
|
23
23
|
};
|
|
24
24
|
var SETTLR_CHECKOUT_URL = {
|
|
25
|
-
production: "https://settlr.dev/
|
|
26
|
-
development: "http://localhost:3000/
|
|
25
|
+
production: "https://settlr.dev/checkout",
|
|
26
|
+
development: "http://localhost:3000/checkout"
|
|
27
27
|
};
|
|
28
28
|
var SUPPORTED_NETWORKS = ["devnet", "mainnet-beta"];
|
|
29
29
|
var USDC_DECIMALS = 6;
|
|
@@ -148,6 +148,37 @@ var Settlr = class {
|
|
|
148
148
|
getTier() {
|
|
149
149
|
return this.tier;
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Get a checkout URL for redirect-based payments
|
|
153
|
+
*
|
|
154
|
+
* This is the simplest integration - just redirect users to this URL.
|
|
155
|
+
* Settlr handles auth (email or wallet) and payment processing.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const url = settlr.getCheckoutUrl({
|
|
160
|
+
* amount: 29.99,
|
|
161
|
+
* memo: 'Premium Pack',
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* // Redirect user to checkout
|
|
165
|
+
* window.location.href = url;
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
getCheckoutUrl(options) {
|
|
169
|
+
const { amount, memo, orderId, successUrl, cancelUrl } = options;
|
|
170
|
+
const baseUrl = this.config.testMode ? SETTLR_CHECKOUT_URL.development : SETTLR_CHECKOUT_URL.production;
|
|
171
|
+
const params = new URLSearchParams({
|
|
172
|
+
amount: amount.toString(),
|
|
173
|
+
merchant: this.config.merchant.name,
|
|
174
|
+
to: this.config.merchant.walletAddress
|
|
175
|
+
});
|
|
176
|
+
if (memo) params.set("memo", memo);
|
|
177
|
+
if (orderId) params.set("orderId", orderId);
|
|
178
|
+
if (successUrl) params.set("successUrl", successUrl);
|
|
179
|
+
if (cancelUrl) params.set("cancelUrl", cancelUrl);
|
|
180
|
+
return `${baseUrl}?${params.toString()}`;
|
|
181
|
+
}
|
|
151
182
|
/**
|
|
152
183
|
* Create a payment link
|
|
153
184
|
*
|
|
@@ -181,8 +212,8 @@ var Settlr = class {
|
|
|
181
212
|
});
|
|
182
213
|
if (memo) params.set("memo", memo);
|
|
183
214
|
if (orderId) params.set("orderId", orderId);
|
|
184
|
-
if (successUrl) params.set("
|
|
185
|
-
if (cancelUrl) params.set("
|
|
215
|
+
if (successUrl) params.set("success", successUrl);
|
|
216
|
+
if (cancelUrl) params.set("cancel", cancelUrl);
|
|
186
217
|
if (paymentId) params.set("paymentId", paymentId);
|
|
187
218
|
const checkoutUrl = `${baseUrl}?${params.toString()}`;
|
|
188
219
|
const qrCode = await this.generateQRCode(checkoutUrl);
|
|
@@ -426,49 +457,34 @@ var Settlr = class {
|
|
|
426
457
|
|
|
427
458
|
// src/react.tsx
|
|
428
459
|
import { createContext, useContext, useMemo } from "react";
|
|
429
|
-
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
|
|
430
460
|
import { jsx } from "react/jsx-runtime";
|
|
431
461
|
var SettlrContext = createContext(null);
|
|
432
|
-
function SettlrProvider({
|
|
433
|
-
|
|
434
|
-
|
|
462
|
+
function SettlrProvider({
|
|
463
|
+
children,
|
|
464
|
+
config,
|
|
465
|
+
authenticated = false
|
|
466
|
+
}) {
|
|
435
467
|
const settlr = useMemo(() => {
|
|
436
468
|
return new Settlr({
|
|
437
469
|
...config,
|
|
438
|
-
rpcEndpoint:
|
|
470
|
+
rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
|
|
439
471
|
});
|
|
440
|
-
}, [config
|
|
472
|
+
}, [config]);
|
|
441
473
|
const value = useMemo(
|
|
442
474
|
() => ({
|
|
443
475
|
settlr,
|
|
444
|
-
|
|
476
|
+
authenticated,
|
|
445
477
|
createPayment: (options) => {
|
|
446
478
|
return settlr.createPayment(options);
|
|
447
479
|
},
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return {
|
|
451
|
-
success: false,
|
|
452
|
-
signature: "",
|
|
453
|
-
amount: options.amount,
|
|
454
|
-
merchantAddress: settlr.getMerchantAddress().toBase58(),
|
|
455
|
-
error: "Wallet not connected"
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
return settlr.pay({
|
|
459
|
-
wallet: {
|
|
460
|
-
publicKey: wallet.publicKey,
|
|
461
|
-
signTransaction: wallet.signTransaction
|
|
462
|
-
},
|
|
463
|
-
amount: options.amount,
|
|
464
|
-
memo: options.memo
|
|
465
|
-
});
|
|
480
|
+
getCheckoutUrl: (options) => {
|
|
481
|
+
return settlr.getCheckoutUrl(options);
|
|
466
482
|
},
|
|
467
483
|
getBalance: () => {
|
|
468
484
|
return settlr.getMerchantBalance();
|
|
469
485
|
}
|
|
470
486
|
}),
|
|
471
|
-
[settlr,
|
|
487
|
+
[settlr, authenticated]
|
|
472
488
|
);
|
|
473
489
|
return /* @__PURE__ */ jsx(SettlrContext.Provider, { value, children });
|
|
474
490
|
}
|
|
@@ -483,7 +499,8 @@ function useSettlr() {
|
|
|
483
499
|
// src/components.tsx
|
|
484
500
|
import {
|
|
485
501
|
useState,
|
|
486
|
-
useCallback
|
|
502
|
+
useCallback,
|
|
503
|
+
useEffect
|
|
487
504
|
} from "react";
|
|
488
505
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
489
506
|
var defaultStyles = {
|
|
@@ -541,7 +558,8 @@ function BuyButton({
|
|
|
541
558
|
onSuccess,
|
|
542
559
|
onError,
|
|
543
560
|
onProcessing,
|
|
544
|
-
useRedirect =
|
|
561
|
+
useRedirect = true,
|
|
562
|
+
// Default to redirect flow (works with Privy)
|
|
545
563
|
successUrl,
|
|
546
564
|
cancelUrl,
|
|
547
565
|
className,
|
|
@@ -550,7 +568,7 @@ function BuyButton({
|
|
|
550
568
|
variant = "primary",
|
|
551
569
|
size = "md"
|
|
552
570
|
}) {
|
|
553
|
-
const {
|
|
571
|
+
const { getCheckoutUrl, createPayment } = useSettlr();
|
|
554
572
|
const [loading, setLoading] = useState(false);
|
|
555
573
|
const [status, setStatus] = useState("idle");
|
|
556
574
|
const handleClick = useCallback(async () => {
|
|
@@ -559,32 +577,17 @@ function BuyButton({
|
|
|
559
577
|
setStatus("processing");
|
|
560
578
|
onProcessing?.();
|
|
561
579
|
try {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
window.location.href = payment.checkoutUrl;
|
|
571
|
-
} else {
|
|
572
|
-
const result = await pay({ amount, memo });
|
|
573
|
-
if (result.success) {
|
|
574
|
-
setStatus("success");
|
|
575
|
-
onSuccess?.({
|
|
576
|
-
signature: result.signature,
|
|
577
|
-
amount: result.amount,
|
|
578
|
-
merchantAddress: result.merchantAddress
|
|
579
|
-
});
|
|
580
|
-
} else {
|
|
581
|
-
throw new Error(result.error || "Payment failed");
|
|
582
|
-
}
|
|
583
|
-
}
|
|
580
|
+
const url = getCheckoutUrl({
|
|
581
|
+
amount,
|
|
582
|
+
memo,
|
|
583
|
+
orderId,
|
|
584
|
+
successUrl,
|
|
585
|
+
cancelUrl
|
|
586
|
+
});
|
|
587
|
+
window.location.href = url;
|
|
584
588
|
} catch (error) {
|
|
585
589
|
setStatus("error");
|
|
586
590
|
onError?.(error instanceof Error ? error : new Error("Payment failed"));
|
|
587
|
-
} finally {
|
|
588
591
|
setLoading(false);
|
|
589
592
|
}
|
|
590
593
|
}, [
|
|
@@ -593,12 +596,9 @@ function BuyButton({
|
|
|
593
596
|
orderId,
|
|
594
597
|
disabled,
|
|
595
598
|
loading,
|
|
596
|
-
useRedirect,
|
|
597
599
|
successUrl,
|
|
598
600
|
cancelUrl,
|
|
599
|
-
|
|
600
|
-
createPayment,
|
|
601
|
-
onSuccess,
|
|
601
|
+
getCheckoutUrl,
|
|
602
602
|
onError,
|
|
603
603
|
onProcessing
|
|
604
604
|
]);
|
|
@@ -618,11 +618,11 @@ function BuyButton({
|
|
|
618
618
|
"button",
|
|
619
619
|
{
|
|
620
620
|
onClick: handleClick,
|
|
621
|
-
disabled: disabled || loading
|
|
621
|
+
disabled: disabled || loading,
|
|
622
622
|
className,
|
|
623
623
|
style: buttonStyle,
|
|
624
624
|
type: "button",
|
|
625
|
-
children:
|
|
625
|
+
children: buttonContent
|
|
626
626
|
}
|
|
627
627
|
);
|
|
628
628
|
}
|
|
@@ -746,7 +746,7 @@ function CheckoutWidget({
|
|
|
746
746
|
theme = "dark",
|
|
747
747
|
showBranding = true
|
|
748
748
|
}) {
|
|
749
|
-
const {
|
|
749
|
+
const { getCheckoutUrl } = useSettlr();
|
|
750
750
|
const [status, setStatus] = useState("idle");
|
|
751
751
|
const containerStyle = {
|
|
752
752
|
...widgetStyles.container,
|
|
@@ -857,6 +857,193 @@ function usePaymentLink(config) {
|
|
|
857
857
|
generateQRCode
|
|
858
858
|
};
|
|
859
859
|
}
|
|
860
|
+
var modalStyles = {
|
|
861
|
+
overlay: {
|
|
862
|
+
position: "fixed",
|
|
863
|
+
top: 0,
|
|
864
|
+
left: 0,
|
|
865
|
+
right: 0,
|
|
866
|
+
bottom: 0,
|
|
867
|
+
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
|
868
|
+
backdropFilter: "blur(4px)",
|
|
869
|
+
display: "flex",
|
|
870
|
+
alignItems: "center",
|
|
871
|
+
justifyContent: "center",
|
|
872
|
+
zIndex: 9999,
|
|
873
|
+
padding: "16px"
|
|
874
|
+
},
|
|
875
|
+
container: {
|
|
876
|
+
position: "relative",
|
|
877
|
+
width: "100%",
|
|
878
|
+
maxWidth: "480px",
|
|
879
|
+
height: "90vh",
|
|
880
|
+
maxHeight: "700px",
|
|
881
|
+
backgroundColor: "#12121a",
|
|
882
|
+
borderRadius: "16px",
|
|
883
|
+
overflow: "hidden",
|
|
884
|
+
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)"
|
|
885
|
+
},
|
|
886
|
+
closeButton: {
|
|
887
|
+
position: "absolute",
|
|
888
|
+
top: "12px",
|
|
889
|
+
right: "12px",
|
|
890
|
+
width: "32px",
|
|
891
|
+
height: "32px",
|
|
892
|
+
borderRadius: "50%",
|
|
893
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
894
|
+
border: "none",
|
|
895
|
+
cursor: "pointer",
|
|
896
|
+
display: "flex",
|
|
897
|
+
alignItems: "center",
|
|
898
|
+
justifyContent: "center",
|
|
899
|
+
zIndex: 10,
|
|
900
|
+
color: "white",
|
|
901
|
+
fontSize: "18px",
|
|
902
|
+
transition: "background-color 0.2s"
|
|
903
|
+
},
|
|
904
|
+
iframe: {
|
|
905
|
+
width: "100%",
|
|
906
|
+
height: "100%",
|
|
907
|
+
border: "none"
|
|
908
|
+
},
|
|
909
|
+
loading: {
|
|
910
|
+
position: "absolute",
|
|
911
|
+
top: "50%",
|
|
912
|
+
left: "50%",
|
|
913
|
+
transform: "translate(-50%, -50%)",
|
|
914
|
+
color: "white",
|
|
915
|
+
fontSize: "14px",
|
|
916
|
+
display: "flex",
|
|
917
|
+
flexDirection: "column",
|
|
918
|
+
alignItems: "center",
|
|
919
|
+
gap: "12px"
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
function PaymentModal({
|
|
923
|
+
amount,
|
|
924
|
+
merchantName,
|
|
925
|
+
merchantWallet,
|
|
926
|
+
memo,
|
|
927
|
+
orderId,
|
|
928
|
+
onSuccess,
|
|
929
|
+
onClose,
|
|
930
|
+
onError,
|
|
931
|
+
checkoutUrl = "https://settlr.dev/checkout"
|
|
932
|
+
}) {
|
|
933
|
+
const [loading, setLoading] = useState(true);
|
|
934
|
+
const params = new URLSearchParams({
|
|
935
|
+
amount: amount.toString(),
|
|
936
|
+
merchant: merchantName,
|
|
937
|
+
to: merchantWallet,
|
|
938
|
+
embed: "true"
|
|
939
|
+
});
|
|
940
|
+
if (memo) params.set("memo", memo);
|
|
941
|
+
if (orderId) params.set("orderId", orderId);
|
|
942
|
+
const iframeSrc = `${checkoutUrl}?${params.toString()}`;
|
|
943
|
+
useEffect(() => {
|
|
944
|
+
const handleMessage = (event) => {
|
|
945
|
+
if (!event.origin.includes("settlr.dev") && !event.origin.includes("localhost")) {
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const { type, data } = event.data || {};
|
|
949
|
+
switch (type) {
|
|
950
|
+
case "settlr:success":
|
|
951
|
+
onSuccess?.({
|
|
952
|
+
signature: data.signature,
|
|
953
|
+
amount: data.amount || amount
|
|
954
|
+
});
|
|
955
|
+
break;
|
|
956
|
+
case "settlr:error":
|
|
957
|
+
onError?.(new Error(data.message || "Payment failed"));
|
|
958
|
+
break;
|
|
959
|
+
case "settlr:close":
|
|
960
|
+
onClose?.();
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
window.addEventListener("message", handleMessage);
|
|
965
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
966
|
+
}, [amount, onSuccess, onError, onClose]);
|
|
967
|
+
useEffect(() => {
|
|
968
|
+
const handleEscape = (e) => {
|
|
969
|
+
if (e.key === "Escape") onClose?.();
|
|
970
|
+
};
|
|
971
|
+
window.addEventListener("keydown", handleEscape);
|
|
972
|
+
return () => window.removeEventListener("keydown", handleEscape);
|
|
973
|
+
}, [onClose]);
|
|
974
|
+
return /* @__PURE__ */ jsx2("div", { style: modalStyles.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs("div", { style: modalStyles.container, onClick: (e) => e.stopPropagation(), children: [
|
|
975
|
+
/* @__PURE__ */ jsx2(
|
|
976
|
+
"button",
|
|
977
|
+
{
|
|
978
|
+
style: modalStyles.closeButton,
|
|
979
|
+
onClick: onClose,
|
|
980
|
+
onMouseOver: (e) => e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.2)",
|
|
981
|
+
onMouseOut: (e) => e.currentTarget.style.backgroundColor = "rgba(255, 255, 255, 0.1)",
|
|
982
|
+
children: "\u2715"
|
|
983
|
+
}
|
|
984
|
+
),
|
|
985
|
+
loading && /* @__PURE__ */ jsxs("div", { style: modalStyles.loading, children: [
|
|
986
|
+
/* @__PURE__ */ jsx2(Spinner, {}),
|
|
987
|
+
/* @__PURE__ */ jsx2("span", { children: "Loading checkout..." })
|
|
988
|
+
] }),
|
|
989
|
+
/* @__PURE__ */ jsx2(
|
|
990
|
+
"iframe",
|
|
991
|
+
{
|
|
992
|
+
src: iframeSrc,
|
|
993
|
+
style: {
|
|
994
|
+
...modalStyles.iframe,
|
|
995
|
+
opacity: loading ? 0 : 1
|
|
996
|
+
},
|
|
997
|
+
onLoad: () => setLoading(false),
|
|
998
|
+
allow: "payment"
|
|
999
|
+
}
|
|
1000
|
+
)
|
|
1001
|
+
] }) });
|
|
1002
|
+
}
|
|
1003
|
+
function usePaymentModal(config) {
|
|
1004
|
+
const [modalState, setModalState] = useState({
|
|
1005
|
+
isOpen: false,
|
|
1006
|
+
amount: 0
|
|
1007
|
+
});
|
|
1008
|
+
const openPayment = useCallback(
|
|
1009
|
+
(options) => {
|
|
1010
|
+
setModalState({
|
|
1011
|
+
isOpen: true,
|
|
1012
|
+
...options
|
|
1013
|
+
});
|
|
1014
|
+
},
|
|
1015
|
+
[]
|
|
1016
|
+
);
|
|
1017
|
+
const closePayment = useCallback(() => {
|
|
1018
|
+
setModalState((prev) => ({ ...prev, isOpen: false }));
|
|
1019
|
+
}, []);
|
|
1020
|
+
const PaymentModalComponent = useCallback(() => {
|
|
1021
|
+
if (!modalState.isOpen) return null;
|
|
1022
|
+
return /* @__PURE__ */ jsx2(
|
|
1023
|
+
PaymentModal,
|
|
1024
|
+
{
|
|
1025
|
+
amount: modalState.amount,
|
|
1026
|
+
merchantName: config.merchantName,
|
|
1027
|
+
merchantWallet: config.merchantWallet,
|
|
1028
|
+
memo: modalState.memo,
|
|
1029
|
+
orderId: modalState.orderId,
|
|
1030
|
+
checkoutUrl: config.checkoutUrl,
|
|
1031
|
+
onSuccess: (result) => {
|
|
1032
|
+
modalState.onSuccess?.(result);
|
|
1033
|
+
closePayment();
|
|
1034
|
+
},
|
|
1035
|
+
onError: modalState.onError,
|
|
1036
|
+
onClose: closePayment
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
}, [modalState, config, closePayment]);
|
|
1040
|
+
return {
|
|
1041
|
+
openPayment,
|
|
1042
|
+
closePayment,
|
|
1043
|
+
isOpen: modalState.isOpen,
|
|
1044
|
+
PaymentModalComponent
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
860
1047
|
|
|
861
1048
|
// src/webhooks.ts
|
|
862
1049
|
import crypto from "crypto";
|
|
@@ -919,6 +1106,7 @@ function createWebhookHandler(options) {
|
|
|
919
1106
|
export {
|
|
920
1107
|
BuyButton,
|
|
921
1108
|
CheckoutWidget,
|
|
1109
|
+
PaymentModal,
|
|
922
1110
|
SETTLR_CHECKOUT_URL,
|
|
923
1111
|
SUPPORTED_NETWORKS,
|
|
924
1112
|
Settlr,
|
|
@@ -931,6 +1119,7 @@ export {
|
|
|
931
1119
|
parseWebhookPayload,
|
|
932
1120
|
shortenAddress,
|
|
933
1121
|
usePaymentLink,
|
|
1122
|
+
usePaymentModal,
|
|
934
1123
|
useSettlr,
|
|
935
1124
|
verifyWebhookSignature
|
|
936
1125
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@settlr/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Solana USDC payments
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Solana USDC payments for games - email checkout, no wallet required",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/ABFX15/x402-hack-payment"
|
|
39
|
+
"url": "git+https://github.com/ABFX15/x402-hack-payment.git"
|
|
40
40
|
},
|
|
41
41
|
"homepage": "https://settlr.dev",
|
|
42
42
|
"dependencies": {
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
"@solana/web3.js": "^1.98.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@solana/wallet-adapter-react": "^0.15.39",
|
|
48
47
|
"@types/node": "^20.0.0",
|
|
49
48
|
"@types/react": "^19.2.7",
|
|
50
49
|
"react": "^19.2.3",
|
|
@@ -52,10 +51,10 @@
|
|
|
52
51
|
"typescript": "^5.0.0"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
|
-
"
|
|
54
|
+
"react": ">=18.0.0"
|
|
56
55
|
},
|
|
57
56
|
"peerDependenciesMeta": {
|
|
58
|
-
"
|
|
57
|
+
"react": {
|
|
59
58
|
"optional": true
|
|
60
59
|
}
|
|
61
60
|
},
|