@mission_sciences/provider-sdk 0.2.0 → 0.3.0-dev.6e896da
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 +1 -40
- package/dist/adapters/react/index.d.ts +3 -0
- package/dist/adapters/react/index.d.ts.map +1 -0
- package/dist/adapters/react/index.js +75 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/react/useMarketplaceSession.d.ts +30 -0
- package/dist/adapters/react/useMarketplaceSession.d.ts.map +1 -0
- package/dist/adapters/vue/index.d.ts +3 -0
- package/dist/adapters/vue/index.d.ts.map +1 -0
- package/dist/adapters/vue/index.js +56 -0
- package/dist/adapters/vue/index.js.map +1 -0
- package/dist/adapters/vue/useMarketplaceSession.d.ts +78 -0
- package/dist/adapters/vue/useMarketplaceSession.d.ts.map +1 -0
- package/dist/core/HeartbeatManager.d.ts +43 -0
- package/dist/core/HeartbeatManager.d.ts.map +1 -0
- package/dist/core/JWKSValidator.d.ts +26 -0
- package/dist/core/JWKSValidator.d.ts.map +1 -0
- package/dist/core/JWTParser.d.ts +46 -0
- package/dist/core/JWTParser.d.ts.map +1 -0
- package/dist/core/MarketplaceSDK.d.ts +117 -0
- package/dist/core/MarketplaceSDK.d.ts.map +1 -0
- package/dist/core/PurchaseStateManager.d.ts +28 -0
- package/dist/core/PurchaseStateManager.d.ts.map +1 -0
- package/dist/core/TabSyncManager.d.ts +49 -0
- package/dist/core/TabSyncManager.d.ts.map +1 -0
- package/dist/core/TimerManager.d.ts +55 -0
- package/dist/core/TimerManager.d.ts.map +1 -0
- package/dist/index.d.ts +23 -769
- package/dist/index.d.ts.map +1 -0
- package/dist/marketplace-sdk.es.js +307 -4
- package/dist/marketplace-sdk.es.js.map +1 -1
- package/dist/marketplace-sdk.umd.js +1 -1
- package/dist/marketplace-sdk.umd.js.map +1 -1
- package/dist/styles/theme.d.ts +89 -0
- package/dist/styles/theme.d.ts.map +1 -0
- package/dist/types/index.d.ts +287 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/ui/PurchaseModal.d.ts +30 -0
- package/dist/ui/PurchaseModal.d.ts.map +1 -0
- package/dist/ui/SessionHeader.d.ts +46 -0
- package/dist/ui/SessionHeader.d.ts.map +1 -0
- package/dist/ui/WarningModal.d.ts +39 -0
- package/dist/ui/WarningModal.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +25 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/url.d.ts +12 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/package.json +17 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGxF,YAAY,EACV,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,OAAO,EACP,YAAY,EACZ,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,OAAO,EAAE,cAAc,IAAI,OAAO,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -20,6 +20,19 @@ class SDKError extends Error {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
class PurchaseError extends SDKError {
|
|
24
|
+
constructor(message2, code, itemId, statusCode) {
|
|
25
|
+
super(message2, code, statusCode);
|
|
26
|
+
this.itemId = itemId;
|
|
27
|
+
this.name = "PurchaseError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
var PurchaseState = /* @__PURE__ */ ((PurchaseState2) => {
|
|
31
|
+
PurchaseState2["AVAILABLE"] = "AVAILABLE";
|
|
32
|
+
PurchaseState2["PRIVY_REQUIRED"] = "PRIVY_REQUIRED";
|
|
33
|
+
PurchaseState2["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS";
|
|
34
|
+
return PurchaseState2;
|
|
35
|
+
})(PurchaseState || {});
|
|
23
36
|
class JWTParser {
|
|
24
37
|
/**
|
|
25
38
|
* Decode JWT payload without verification
|
|
@@ -2017,6 +2030,55 @@ class TabSyncManager {
|
|
|
2017
2030
|
this.logger.log("Tab sync destroyed");
|
|
2018
2031
|
}
|
|
2019
2032
|
}
|
|
2033
|
+
class PurchaseStateManager {
|
|
2034
|
+
constructor(config) {
|
|
2035
|
+
this.config = {
|
|
2036
|
+
timeout: 5e3,
|
|
2037
|
+
...config
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* Check purchase state for a specific item
|
|
2042
|
+
* Filters raw API response to expose only safe data to publisher apps
|
|
2043
|
+
*/
|
|
2044
|
+
async checkItemPurchaseState(itemId) {
|
|
2045
|
+
try {
|
|
2046
|
+
const response = await fetch(`${this.config.apiEndpoint}/items/${itemId}/purchase-state`, {
|
|
2047
|
+
method: "GET",
|
|
2048
|
+
headers: {
|
|
2049
|
+
"Content-Type": "application/json"
|
|
2050
|
+
},
|
|
2051
|
+
signal: AbortSignal.timeout(this.config.timeout)
|
|
2052
|
+
});
|
|
2053
|
+
if (!response.ok) {
|
|
2054
|
+
throw new Error(`API request failed: ${response.status} ${response.statusText}`);
|
|
2055
|
+
}
|
|
2056
|
+
const rawData = await response.json();
|
|
2057
|
+
return this.filterPurchaseStateResponse(rawData);
|
|
2058
|
+
} catch (error) {
|
|
2059
|
+
if (error instanceof Error) {
|
|
2060
|
+
throw error;
|
|
2061
|
+
}
|
|
2062
|
+
throw new Error("Unknown error occurred while checking purchase state");
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Filters raw API response to expose only safe data to publisher apps
|
|
2067
|
+
* CRITICAL: Raw privyEligibility map must NEVER be exposed to apps
|
|
2068
|
+
*/
|
|
2069
|
+
filterPurchaseStateResponse(rawResponse) {
|
|
2070
|
+
const filteredResponse = {
|
|
2071
|
+
state: rawResponse.state
|
|
2072
|
+
};
|
|
2073
|
+
if (rawResponse.state === PurchaseState.PRIVY_REQUIRED && rawResponse.privyEligibility) {
|
|
2074
|
+
const requiredLevels = Object.values(rawResponse.privyEligibility).filter((details) => details.requiresUpgrade).map((details) => details.requiredLevel);
|
|
2075
|
+
if (requiredLevels.length > 0) {
|
|
2076
|
+
filteredResponse.requiredLevel = Math.max(...requiredLevels);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
return filteredResponse;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2020
2082
|
const lightTheme = {
|
|
2021
2083
|
colors: {
|
|
2022
2084
|
// Background
|
|
@@ -2503,6 +2565,166 @@ function extractTokenFromURL(paramName = "gwSession", url) {
|
|
|
2503
2565
|
function isBrowser() {
|
|
2504
2566
|
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
2505
2567
|
}
|
|
2568
|
+
class PurchaseModal {
|
|
2569
|
+
constructor(themeMode = "light", customStyles) {
|
|
2570
|
+
this.modal = null;
|
|
2571
|
+
this.legacyStyles = null;
|
|
2572
|
+
const prefersDark = themeMode === "dark" || themeMode === "auto" && this.detectDarkMode();
|
|
2573
|
+
this.theme = getTheme(prefersDark);
|
|
2574
|
+
if (customStyles) {
|
|
2575
|
+
this.legacyStyles = {
|
|
2576
|
+
backgroundColor: customStyles.backgroundColor || "#ffffff",
|
|
2577
|
+
textColor: customStyles.textColor || "#333333",
|
|
2578
|
+
primaryColor: customStyles.primaryColor || "#007bff",
|
|
2579
|
+
borderRadius: customStyles.borderRadius || "8px",
|
|
2580
|
+
fontFamily: customStyles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
2581
|
+
};
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
detectDarkMode() {
|
|
2585
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
2586
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2587
|
+
}
|
|
2588
|
+
return false;
|
|
2589
|
+
}
|
|
2590
|
+
escapeHtml(text) {
|
|
2591
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* Show purchase confirmation modal
|
|
2595
|
+
*/
|
|
2596
|
+
show(options) {
|
|
2597
|
+
this.hide();
|
|
2598
|
+
this.modal = document.createElement("div");
|
|
2599
|
+
this.modal.id = "gw-purchase-modal";
|
|
2600
|
+
this.modal.style.cssText = `
|
|
2601
|
+
position: fixed;
|
|
2602
|
+
top: 0;
|
|
2603
|
+
left: 0;
|
|
2604
|
+
width: 100%;
|
|
2605
|
+
height: 100%;
|
|
2606
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
2607
|
+
display: flex;
|
|
2608
|
+
align-items: center;
|
|
2609
|
+
justify-content: center;
|
|
2610
|
+
z-index: 99999;
|
|
2611
|
+
font-family: ${this.legacyStyles?.fontFamily || this.theme.typography.fontFamily};
|
|
2612
|
+
`;
|
|
2613
|
+
const content = document.createElement("div");
|
|
2614
|
+
const bgColor = this.legacyStyles?.backgroundColor || this.theme.colors.card;
|
|
2615
|
+
const textColor = this.legacyStyles?.textColor || this.theme.colors.cardForeground;
|
|
2616
|
+
const borderRadius = this.legacyStyles?.borderRadius || this.theme.spacing.borderRadius.lg;
|
|
2617
|
+
content.style.cssText = `
|
|
2618
|
+
background-color: ${bgColor};
|
|
2619
|
+
color: ${textColor};
|
|
2620
|
+
border-radius: ${borderRadius};
|
|
2621
|
+
padding: ${this.theme.spacing.padding.lg};
|
|
2622
|
+
max-width: 400px;
|
|
2623
|
+
width: 90%;
|
|
2624
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
2625
|
+
border: 1px solid ${this.theme.colors.border};
|
|
2626
|
+
`;
|
|
2627
|
+
content.innerHTML = `
|
|
2628
|
+
<h2 style="margin: 0 0 ${this.theme.spacing.padding.md} 0; font-size: ${this.theme.typography.fontSize.xl}; font-weight: ${this.theme.typography.fontWeight.semibold}; color: ${textColor};">
|
|
2629
|
+
🛒 Confirm Purchase
|
|
2630
|
+
</h2>
|
|
2631
|
+
<p style="margin: 0 0 ${this.theme.spacing.padding.lg} 0; font-size: ${this.theme.typography.fontSize.base}; line-height: ${this.theme.typography.lineHeight.normal}; color: ${this.theme.colors.mutedForeground};">
|
|
2632
|
+
Are you sure you want to purchase item <strong style="color: ${textColor};">${this.escapeHtml(options.itemId)}</strong>?
|
|
2633
|
+
</p>
|
|
2634
|
+
<div style="display: flex; gap: ${this.theme.spacing.gap.md}; justify-content: flex-end;">
|
|
2635
|
+
<button id="gw-cancel-btn" style="
|
|
2636
|
+
padding: 10px 20px;
|
|
2637
|
+
background-color: ${this.theme.colors.secondary};
|
|
2638
|
+
color: ${this.theme.colors.secondaryForeground};
|
|
2639
|
+
border: 1px solid ${this.theme.colors.border};
|
|
2640
|
+
border-radius: ${this.theme.spacing.borderRadius.sm};
|
|
2641
|
+
font-size: ${this.theme.typography.fontSize.sm};
|
|
2642
|
+
font-weight: ${this.theme.typography.fontWeight.medium};
|
|
2643
|
+
cursor: pointer;
|
|
2644
|
+
transition: all 0.2s;
|
|
2645
|
+
font-family: ${this.theme.typography.fontFamily};
|
|
2646
|
+
">
|
|
2647
|
+
Cancel
|
|
2648
|
+
</button>
|
|
2649
|
+
<button id="gw-confirm-btn" style="
|
|
2650
|
+
padding: 10px 20px;
|
|
2651
|
+
background-color: ${this.theme.colors.primary};
|
|
2652
|
+
color: ${this.theme.colors.primaryForeground};
|
|
2653
|
+
border: none;
|
|
2654
|
+
border-radius: ${this.theme.spacing.borderRadius.sm};
|
|
2655
|
+
font-size: ${this.theme.typography.fontSize.sm};
|
|
2656
|
+
font-weight: ${this.theme.typography.fontWeight.medium};
|
|
2657
|
+
cursor: pointer;
|
|
2658
|
+
transition: all 0.2s;
|
|
2659
|
+
font-family: ${this.theme.typography.fontFamily};
|
|
2660
|
+
">
|
|
2661
|
+
Confirm Purchase
|
|
2662
|
+
</button>
|
|
2663
|
+
</div>
|
|
2664
|
+
`;
|
|
2665
|
+
this.modal.appendChild(content);
|
|
2666
|
+
document.body.appendChild(this.modal);
|
|
2667
|
+
const confirmBtn = document.getElementById("gw-confirm-btn");
|
|
2668
|
+
if (confirmBtn && options.onConfirm) {
|
|
2669
|
+
confirmBtn.addEventListener("click", () => {
|
|
2670
|
+
options.onConfirm?.();
|
|
2671
|
+
this.hide();
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
const cancelBtn = document.getElementById("gw-cancel-btn");
|
|
2675
|
+
if (cancelBtn) {
|
|
2676
|
+
cancelBtn.addEventListener("click", () => {
|
|
2677
|
+
options.onCancel?.();
|
|
2678
|
+
this.hide();
|
|
2679
|
+
});
|
|
2680
|
+
}
|
|
2681
|
+
const buttons = content.querySelectorAll("button");
|
|
2682
|
+
buttons.forEach((button) => {
|
|
2683
|
+
button.addEventListener("mouseenter", () => {
|
|
2684
|
+
button.style.opacity = "0.9";
|
|
2685
|
+
});
|
|
2686
|
+
button.addEventListener("mouseleave", () => {
|
|
2687
|
+
button.style.opacity = "1";
|
|
2688
|
+
});
|
|
2689
|
+
button.addEventListener("focus", () => {
|
|
2690
|
+
button.style.outline = `2px solid ${this.theme.colors.ring}`;
|
|
2691
|
+
button.style.outlineOffset = "2px";
|
|
2692
|
+
});
|
|
2693
|
+
button.addEventListener("blur", () => {
|
|
2694
|
+
button.style.outline = "none";
|
|
2695
|
+
});
|
|
2696
|
+
});
|
|
2697
|
+
const handleKeyDown = (e) => {
|
|
2698
|
+
if (e.key === "Escape") {
|
|
2699
|
+
options.onCancel?.();
|
|
2700
|
+
this.hide();
|
|
2701
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2702
|
+
}
|
|
2703
|
+
};
|
|
2704
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2705
|
+
this.modal.addEventListener("click", (e) => {
|
|
2706
|
+
if (e.target === this.modal) {
|
|
2707
|
+
options.onCancel?.();
|
|
2708
|
+
this.hide();
|
|
2709
|
+
}
|
|
2710
|
+
});
|
|
2711
|
+
}
|
|
2712
|
+
/**
|
|
2713
|
+
* Hide and remove modal
|
|
2714
|
+
*/
|
|
2715
|
+
hide() {
|
|
2716
|
+
if (this.modal && this.modal.parentNode) {
|
|
2717
|
+
this.modal.parentNode.removeChild(this.modal);
|
|
2718
|
+
this.modal = null;
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
/**
|
|
2722
|
+
* Check if modal is currently shown
|
|
2723
|
+
*/
|
|
2724
|
+
isShown() {
|
|
2725
|
+
return this.modal !== null;
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2506
2728
|
class MarketplaceSDK {
|
|
2507
2729
|
constructor(config) {
|
|
2508
2730
|
this.timer = null;
|
|
@@ -2513,17 +2735,19 @@ class MarketplaceSDK {
|
|
|
2513
2735
|
this.sessionData = null;
|
|
2514
2736
|
this.jwtToken = null;
|
|
2515
2737
|
this.endReason = "manual";
|
|
2738
|
+
this.purchaseModal = null;
|
|
2516
2739
|
this.config = {
|
|
2517
|
-
jwksUri: config.jwksUri || "https://api.generalwisdom.com/.well-known/jwks.json",
|
|
2740
|
+
jwksUri: config.jwksUri || "https://api.platform.generalwisdom.com/.well-known/jwks.json",
|
|
2518
2741
|
jwtParamName: config.jwtParamName || "gwSession",
|
|
2519
|
-
apiEndpoint: config.apiEndpoint || "
|
|
2742
|
+
apiEndpoint: config.apiEndpoint || "https://api.platform.generalwisdom.com",
|
|
2743
|
+
jwtIssuer: config.jwtIssuer || "generalwisdom.com",
|
|
2520
2744
|
debug: config.debug ?? false,
|
|
2521
2745
|
autoStart: config.autoStart ?? true,
|
|
2522
2746
|
warningThresholdSeconds: config.warningThresholdSeconds ?? 300,
|
|
2523
2747
|
customStyles: config.customStyles ?? {},
|
|
2524
2748
|
themeMode: config.themeMode ?? "light",
|
|
2525
2749
|
applicationId: config.applicationId ?? "",
|
|
2526
|
-
marketplaceUrl: config.marketplaceUrl ?? "https://
|
|
2750
|
+
marketplaceUrl: config.marketplaceUrl ?? "https://platform.generalwisdom.com/",
|
|
2527
2751
|
// Phase 2 options
|
|
2528
2752
|
enableHeartbeat: config.enableHeartbeat ?? false,
|
|
2529
2753
|
heartbeatIntervalSeconds: config.heartbeatIntervalSeconds ?? 30,
|
|
@@ -2536,6 +2760,9 @@ class MarketplaceSDK {
|
|
|
2536
2760
|
};
|
|
2537
2761
|
this.validator = new JWKSValidator(this.config.jwksUri, this.config.debug);
|
|
2538
2762
|
this.logger = new Logger(this.config.debug, "[MarketplaceSDK]");
|
|
2763
|
+
this.purchaseStateManager = new PurchaseStateManager({
|
|
2764
|
+
apiEndpoint: this.config.apiEndpoint
|
|
2765
|
+
});
|
|
2539
2766
|
this.logger.info("SDK initialized with config:", {
|
|
2540
2767
|
jwksUri: this.config.jwksUri,
|
|
2541
2768
|
jwtParamName: this.config.jwtParamName,
|
|
@@ -2624,7 +2851,7 @@ class MarketplaceSDK {
|
|
|
2624
2851
|
this.logger.log("Using JWKS validation");
|
|
2625
2852
|
verifiedClaims = await this.validator.verify(
|
|
2626
2853
|
this.jwtToken,
|
|
2627
|
-
|
|
2854
|
+
this.config.jwtIssuer,
|
|
2628
2855
|
this.config.applicationId || void 0
|
|
2629
2856
|
);
|
|
2630
2857
|
}
|
|
@@ -3045,6 +3272,79 @@ class MarketplaceSDK {
|
|
|
3045
3272
|
isTimerRunning() {
|
|
3046
3273
|
return this.timer?.isRunning() ?? false;
|
|
3047
3274
|
}
|
|
3275
|
+
/**
|
|
3276
|
+
* Request purchase of an item — opens PurchaseModal directly
|
|
3277
|
+
* Bypasses the add-ons panel; works for any active item (visible or hidden)
|
|
3278
|
+
*/
|
|
3279
|
+
requestPurchase(itemId) {
|
|
3280
|
+
if (!this.sessionData || !this.jwtToken) {
|
|
3281
|
+
throw new SDKError("No active session", "NO_SESSION");
|
|
3282
|
+
}
|
|
3283
|
+
this.logger.info("Requesting purchase for item:", itemId);
|
|
3284
|
+
this.events.onPurchaseStart?.({ itemId, quantity: 1 });
|
|
3285
|
+
if (!this.purchaseModal) {
|
|
3286
|
+
this.purchaseModal = new PurchaseModal(
|
|
3287
|
+
this.config.themeMode || "light",
|
|
3288
|
+
this.config.customStyles
|
|
3289
|
+
);
|
|
3290
|
+
}
|
|
3291
|
+
this.purchaseModal.show({
|
|
3292
|
+
itemId,
|
|
3293
|
+
onConfirm: async () => {
|
|
3294
|
+
try {
|
|
3295
|
+
const response = await fetch(
|
|
3296
|
+
`${this.config.apiEndpoint}/items/${itemId}/purchase`,
|
|
3297
|
+
{
|
|
3298
|
+
method: "POST",
|
|
3299
|
+
headers: {
|
|
3300
|
+
"Authorization": `Bearer ${this.jwtToken}`,
|
|
3301
|
+
"Content-Type": "application/json"
|
|
3302
|
+
},
|
|
3303
|
+
body: JSON.stringify({ item_id: itemId, quantity: 1 })
|
|
3304
|
+
}
|
|
3305
|
+
);
|
|
3306
|
+
if (!response.ok) {
|
|
3307
|
+
throw new PurchaseError(
|
|
3308
|
+
"Purchase failed",
|
|
3309
|
+
"PURCHASE_FAILED",
|
|
3310
|
+
itemId,
|
|
3311
|
+
response.status
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3314
|
+
const data = await response.json();
|
|
3315
|
+
const result = {
|
|
3316
|
+
itemId,
|
|
3317
|
+
transactionId: data.transactionId,
|
|
3318
|
+
amount: data.amount
|
|
3319
|
+
};
|
|
3320
|
+
this.events.onPurchaseSuccess?.(result);
|
|
3321
|
+
this.events.onPurchaseComplete?.(itemId);
|
|
3322
|
+
if (data.newBalance !== void 0) {
|
|
3323
|
+
this.events.onBalanceUpdate?.(data.newBalance);
|
|
3324
|
+
}
|
|
3325
|
+
this.logger.info("Purchase successful:", result);
|
|
3326
|
+
} catch (error) {
|
|
3327
|
+
const purchaseError = error instanceof PurchaseError ? error : new PurchaseError(
|
|
3328
|
+
error instanceof Error ? error.message : "Purchase failed",
|
|
3329
|
+
"PURCHASE_ERROR",
|
|
3330
|
+
itemId
|
|
3331
|
+
);
|
|
3332
|
+
this.events.onPurchaseError?.(purchaseError);
|
|
3333
|
+
this.logger.error("Purchase failed:", purchaseError);
|
|
3334
|
+
}
|
|
3335
|
+
},
|
|
3336
|
+
onCancel: () => {
|
|
3337
|
+
this.events.onPurchaseCancelled?.(itemId);
|
|
3338
|
+
this.logger.info("Purchase cancelled for item:", itemId);
|
|
3339
|
+
}
|
|
3340
|
+
});
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3343
|
+
* Get purchase state manager for item purchase state checking
|
|
3344
|
+
*/
|
|
3345
|
+
getPurchaseStateManager() {
|
|
3346
|
+
return this.purchaseStateManager;
|
|
3347
|
+
}
|
|
3048
3348
|
/**
|
|
3049
3349
|
* Cleanup and destroy SDK instance
|
|
3050
3350
|
*/
|
|
@@ -3054,6 +3354,7 @@ class MarketplaceSDK {
|
|
|
3054
3354
|
this.heartbeat?.stop();
|
|
3055
3355
|
this.tabSync?.destroy();
|
|
3056
3356
|
this.modal?.hide();
|
|
3357
|
+
this.purchaseModal?.hide();
|
|
3057
3358
|
if (typeof sessionStorage !== "undefined") {
|
|
3058
3359
|
sessionStorage.removeItem("gw_marketplace_jwt");
|
|
3059
3360
|
this.logger.log("JWT token cleared from storage");
|
|
@@ -3264,6 +3565,8 @@ export {
|
|
|
3264
3565
|
JWTParser,
|
|
3265
3566
|
Logger,
|
|
3266
3567
|
MarketplaceSDK,
|
|
3568
|
+
PurchaseError,
|
|
3569
|
+
PurchaseModal,
|
|
3267
3570
|
SDKError,
|
|
3268
3571
|
SessionHeader,
|
|
3269
3572
|
TabSyncManager,
|