@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/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/pay",
26
- development: "http://localhost:3000/pay"
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("successUrl", successUrl);
185
- if (cancelUrl) params.set("cancelUrl", cancelUrl);
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({ children, config }) {
433
- const { connection } = useConnection();
434
- const wallet = useWallet();
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: connection.rpcEndpoint
470
+ rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
439
471
  });
440
- }, [config, connection.rpcEndpoint]);
472
+ }, [config]);
441
473
  const value = useMemo(
442
474
  () => ({
443
475
  settlr,
444
- connected: wallet.connected,
476
+ authenticated,
445
477
  createPayment: (options) => {
446
478
  return settlr.createPayment(options);
447
479
  },
448
- pay: async (options) => {
449
- if (!wallet.publicKey || !wallet.signTransaction) {
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, wallet]
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 = false,
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 { pay, createPayment, connected } = useSettlr();
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
- if (useRedirect) {
563
- const payment = await createPayment({
564
- amount,
565
- memo,
566
- orderId,
567
- successUrl,
568
- cancelUrl
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
- pay,
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 || !connected,
621
+ disabled: disabled || loading,
622
622
  className,
623
623
  style: buttonStyle,
624
624
  type: "button",
625
- children: !connected ? "Connect Wallet" : buttonContent
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 { connected } = useSettlr();
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.1.0",
4
- "description": "Solana USDC payments in 7 lines of code",
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
- "@solana/wallet-adapter-base": ">=0.9.0"
54
+ "react": ">=18.0.0"
56
55
  },
57
56
  "peerDependenciesMeta": {
58
- "@solana/wallet-adapter-base": {
57
+ "react": {
59
58
  "optional": true
60
59
  }
61
60
  },