@alleyboss/micropay-solana-x402-paywall 1.0.1 → 2.0.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 +100 -167
- package/dist/client/index.cjs +99 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +112 -0
- package/dist/client/index.d.ts +112 -0
- package/dist/client/index.js +95 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client-CSZHI8o8.d.ts +32 -0
- package/dist/client-vRr48m2x.d.cts +32 -0
- package/dist/index.cjs +696 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +674 -16
- package/dist/index.js.map +1 -1
- package/dist/memory-Daxkczti.d.cts +29 -0
- package/dist/memory-Daxkczti.d.ts +29 -0
- package/dist/middleware/index.cjs +261 -0
- package/dist/middleware/index.cjs.map +1 -0
- package/dist/middleware/index.d.cts +90 -0
- package/dist/middleware/index.d.ts +90 -0
- package/dist/middleware/index.js +255 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/nextjs-BK0pVb9Y.d.ts +78 -0
- package/dist/nextjs-Bm272Jkj.d.cts +78 -0
- package/dist/{client-kfCr7G-P.d.cts → payment-CTxdtqmc.d.cts} +23 -34
- package/dist/{client-kfCr7G-P.d.ts → payment-CTxdtqmc.d.ts} +23 -34
- package/dist/pricing/index.cjs +142 -0
- package/dist/pricing/index.cjs.map +1 -0
- package/dist/pricing/index.d.cts +111 -0
- package/dist/pricing/index.d.ts +111 -0
- package/dist/pricing/index.js +133 -0
- package/dist/pricing/index.js.map +1 -0
- package/dist/session/index.d.cts +29 -1
- package/dist/session/index.d.ts +29 -1
- package/dist/{index-uxMb72hH.d.cts → session-D2IoWAWV.d.cts} +1 -27
- package/dist/{index-uxMb72hH.d.ts → session-D2IoWAWV.d.ts} +1 -27
- package/dist/solana/index.cjs +193 -0
- package/dist/solana/index.cjs.map +1 -1
- package/dist/solana/index.d.cts +60 -3
- package/dist/solana/index.d.ts +60 -3
- package/dist/solana/index.js +190 -1
- package/dist/solana/index.js.map +1 -1
- package/dist/store/index.cjs +99 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +38 -0
- package/dist/store/index.d.ts +38 -0
- package/dist/store/index.js +96 -0
- package/dist/store/index.js.map +1 -0
- package/dist/utils/index.cjs +68 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +30 -0
- package/dist/utils/index.d.ts +30 -0
- package/dist/utils/index.js +65 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/x402/index.cjs +2 -1
- package/dist/x402/index.cjs.map +1 -1
- package/dist/x402/index.d.cts +2 -1
- package/dist/x402/index.d.ts +2 -1
- package/dist/x402/index.js +2 -1
- package/dist/x402/index.js.map +1 -1
- package/package.json +56 -3
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/pricing/index.ts
|
|
4
|
+
var cachedPrice = null;
|
|
5
|
+
var config = {};
|
|
6
|
+
var lastProviderIndex = -1;
|
|
7
|
+
function configurePricing(newConfig) {
|
|
8
|
+
config = { ...config, ...newConfig };
|
|
9
|
+
cachedPrice = null;
|
|
10
|
+
}
|
|
11
|
+
var PROVIDERS = [
|
|
12
|
+
{
|
|
13
|
+
name: "coincap",
|
|
14
|
+
url: "https://api.coincap.io/v2/assets/solana",
|
|
15
|
+
parse: (data) => parseFloat(data.data?.priceUsd || "0")
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "binance",
|
|
19
|
+
url: "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT",
|
|
20
|
+
parse: (data) => parseFloat(data.price || "0")
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "coingecko",
|
|
24
|
+
url: "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
|
|
25
|
+
parse: (data) => data.solana?.usd || 0
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "kraken",
|
|
29
|
+
url: "https://api.kraken.com/0/public/Ticker?pair=SOLUSD",
|
|
30
|
+
parse: (data) => parseFloat(data.result?.SOLUSD?.c?.[0] || "0")
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
async function fetchFromProvider(provider, timeout) {
|
|
34
|
+
const controller = new AbortController();
|
|
35
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(provider.url, {
|
|
38
|
+
headers: { "Accept": "application/json" },
|
|
39
|
+
signal: controller.signal
|
|
40
|
+
});
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
throw new Error(`HTTP ${response.status}`);
|
|
43
|
+
}
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
const price = provider.parse(data);
|
|
46
|
+
if (!price || price <= 0) {
|
|
47
|
+
throw new Error("Invalid price");
|
|
48
|
+
}
|
|
49
|
+
return price;
|
|
50
|
+
} finally {
|
|
51
|
+
clearTimeout(timeoutId);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function getSolPrice() {
|
|
55
|
+
const cacheTTL = config.cacheTTL ?? 6e4;
|
|
56
|
+
const timeout = config.timeout ?? 5e3;
|
|
57
|
+
if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {
|
|
58
|
+
return cachedPrice;
|
|
59
|
+
}
|
|
60
|
+
if (config.customProvider) {
|
|
61
|
+
try {
|
|
62
|
+
const price = await config.customProvider();
|
|
63
|
+
if (price > 0) {
|
|
64
|
+
cachedPrice = {
|
|
65
|
+
solPrice: price,
|
|
66
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
67
|
+
source: "custom"
|
|
68
|
+
};
|
|
69
|
+
return cachedPrice;
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (let i = 0; i < PROVIDERS.length; i++) {
|
|
75
|
+
const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;
|
|
76
|
+
const provider = PROVIDERS[idx];
|
|
77
|
+
try {
|
|
78
|
+
const price = await fetchFromProvider(provider, timeout);
|
|
79
|
+
lastProviderIndex = idx;
|
|
80
|
+
cachedPrice = {
|
|
81
|
+
solPrice: price,
|
|
82
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
83
|
+
source: provider.name
|
|
84
|
+
};
|
|
85
|
+
return cachedPrice;
|
|
86
|
+
} catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (cachedPrice) {
|
|
91
|
+
return cachedPrice;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
solPrice: 150,
|
|
95
|
+
// Reasonable fallback
|
|
96
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
97
|
+
source: "fallback"
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function lamportsToUsd(lamports) {
|
|
101
|
+
const { solPrice } = await getSolPrice();
|
|
102
|
+
const sol = Number(lamports) / 1e9;
|
|
103
|
+
return sol * solPrice;
|
|
104
|
+
}
|
|
105
|
+
async function usdToLamports(usd) {
|
|
106
|
+
const { solPrice } = await getSolPrice();
|
|
107
|
+
const sol = usd / solPrice;
|
|
108
|
+
return BigInt(Math.floor(sol * 1e9));
|
|
109
|
+
}
|
|
110
|
+
async function formatPriceDisplay(lamports) {
|
|
111
|
+
const { solPrice } = await getSolPrice();
|
|
112
|
+
const sol = Number(lamports) / 1e9;
|
|
113
|
+
const usd = sol * solPrice;
|
|
114
|
+
return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;
|
|
115
|
+
}
|
|
116
|
+
function formatPriceSync(lamports, solPrice) {
|
|
117
|
+
const sol = Number(lamports) / 1e9;
|
|
118
|
+
const usd = sol * solPrice;
|
|
119
|
+
return {
|
|
120
|
+
sol,
|
|
121
|
+
usd,
|
|
122
|
+
formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function clearPriceCache() {
|
|
126
|
+
cachedPrice = null;
|
|
127
|
+
lastProviderIndex = -1;
|
|
128
|
+
}
|
|
129
|
+
function getProviders() {
|
|
130
|
+
return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.clearPriceCache = clearPriceCache;
|
|
134
|
+
exports.configurePricing = configurePricing;
|
|
135
|
+
exports.formatPriceDisplay = formatPriceDisplay;
|
|
136
|
+
exports.formatPriceSync = formatPriceSync;
|
|
137
|
+
exports.getProviders = getProviders;
|
|
138
|
+
exports.getSolPrice = getSolPrice;
|
|
139
|
+
exports.lamportsToUsd = lamportsToUsd;
|
|
140
|
+
exports.usdToLamports = usdToLamports;
|
|
141
|
+
//# sourceMappingURL=index.cjs.map
|
|
142
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pricing/index.ts"],"names":[],"mappings":";;;AAiCA,IAAI,WAAA,GAAgC,IAAA;AACpC,IAAI,SAAsB,EAAC;AAC3B,IAAI,iBAAA,GAAoB,EAAA;AAmBjB,SAAS,iBAAiB,SAAA,EAA8B;AAC3D,EAAA,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,GAAG,SAAA,EAAU;AACnC,EAAA,WAAA,GAAc,IAAA;AAClB;AAKA,IAAM,SAAA,GAAY;AAAA,EACd;AAAA,IACI,IAAA,EAAM,SAAA;AAAA,IACN,GAAA,EAAK,yCAAA;AAAA,IACL,OAAO,CAAC,IAAA,KAA2C,WAAW,IAAA,CAAK,IAAA,EAAM,YAAY,GAAG;AAAA,GAC5F;AAAA,EACA;AAAA,IACI,IAAA,EAAM,SAAA;AAAA,IACN,GAAA,EAAK,4DAAA;AAAA,IACL,OAAO,CAAC,IAAA,KAA6B,UAAA,CAAW,IAAA,CAAK,SAAS,GAAG;AAAA,GACrE;AAAA,EACA;AAAA,IACI,IAAA,EAAM,WAAA;AAAA,IACN,GAAA,EAAK,4EAAA;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,KAAwC,IAAA,CAAK,QAAQ,GAAA,IAAO;AAAA,GACxE;AAAA,EACA;AAAA,IACI,IAAA,EAAM,QAAA;AAAA,IACN,GAAA,EAAK,oDAAA;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,KACJ,UAAA,CAAW,IAAA,CAAK,QAAQ,MAAA,EAAQ,CAAA,GAAI,CAAC,CAAA,IAAK,GAAG;AAAA;AAEzD,CAAA;AAKA,eAAe,iBAAA,CACX,UACA,OAAA,EACe;AACf,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE9D,EAAA,IAAI;AACA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,QAAA,CAAS,GAAA,EAAK;AAAA,MACvC,OAAA,EAAS,EAAE,QAAA,EAAU,kBAAA,EAAmB;AAAA,MACxC,QAAQ,UAAA,CAAW;AAAA,KACtB,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7C;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,IAA4C,CAAA;AAEzE,IAAA,IAAI,CAAC,KAAA,IAAS,KAAA,IAAS,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,IACnC;AAEA,IAAA,OAAO,KAAA;AAAA,EACX,CAAA,SAAE;AACE,IAAA,YAAA,CAAa,SAAS,CAAA;AAAA,EAC1B;AACJ;AAiBA,eAAsB,WAAA,GAAkC;AACpD,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,GAAA;AACpC,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,GAAA;AAGlC,EAAA,IAAI,WAAA,IAAe,KAAK,GAAA,EAAI,GAAI,YAAY,SAAA,CAAU,OAAA,KAAY,QAAA,EAAU;AACxE,IAAA,OAAO,WAAA;AAAA,EACX;AAGA,EAAA,IAAI,OAAO,cAAA,EAAgB;AACvB,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,cAAA,EAAe;AAC1C,MAAA,IAAI,QAAQ,CAAA,EAAG;AACX,QAAA,WAAA,GAAc;AAAA,UACV,QAAA,EAAU,KAAA;AAAA,UACV,SAAA,sBAAe,IAAA,EAAK;AAAA,UACpB,MAAA,EAAQ;AAAA,SACZ;AACA,QAAA,OAAO,WAAA;AAAA,MACX;AAAA,IACJ,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACJ;AAGA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,GAAA,GAAA,CAAO,iBAAA,GAAoB,CAAA,GAAI,CAAA,IAAK,SAAA,CAAU,MAAA;AACpD,IAAA,MAAM,QAAA,GAAW,UAAU,GAAG,CAAA;AAE9B,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,QAAA,EAAU,OAAO,CAAA;AACvD,MAAA,iBAAA,GAAoB,GAAA;AAEpB,MAAA,WAAA,GAAc;AAAA,QACV,QAAA,EAAU,KAAA;AAAA,QACV,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,QAAQ,QAAA,CAAS;AAAA,OACrB;AACA,MAAA,OAAO,WAAA;AAAA,IACX,CAAA,CAAA,MAAQ;AAEJ,MAAA;AAAA,IACJ;AAAA,EACJ;AAGA,EAAA,IAAI,WAAA,EAAa;AACb,IAAA,OAAO,WAAA;AAAA,EACX;AAGA,EAAA,OAAO;AAAA,IACH,QAAA,EAAU,GAAA;AAAA;AAAA,IACV,SAAA,sBAAe,IAAA,EAAK;AAAA,IACpB,MAAA,EAAQ;AAAA,GACZ;AACJ;AAWA,eAAsB,cAAc,QAAA,EAAmC;AACnE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,OAAO,GAAA,GAAM,QAAA;AACjB;AAWA,eAAsB,cAAc,GAAA,EAA8B;AAC9D,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAClB,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,GAAa,CAAC,CAAA;AACjD;AAWA,eAAsB,mBAAmB,QAAA,EAAmC;AACxE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAElB,EAAA,OAAO,CAAA,EAAG,IAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AACrD;AAKO,SAAS,eAAA,CAAgB,UAAkB,QAAA,EAIhD;AACE,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAElB,EAAA,OAAO;AAAA,IACH,GAAA;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,CAAA,EAAG,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,GACzD;AACJ;AAKO,SAAS,eAAA,GAAwB;AACpC,EAAA,WAAA,GAAc,IAAA;AACd,EAAA,iBAAA,GAAoB,EAAA;AACxB;AAKO,SAAS,YAAA,GAAgD;AAC5D,EAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAA,CAAA,MAAM,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA,CAAE,GAAA,EAAI,CAAE,CAAA;AAC5D","file":"index.cjs","sourcesContent":["// Price Conversion Helpers\n// Multi-provider SOL price fetching with fallback rotation\n\n/**\n * Price data from API\n */\nexport interface PriceData {\n /** SOL price in USD */\n solPrice: number;\n /** Timestamp of price fetch */\n fetchedAt: Date;\n /** Source of price data */\n source: string;\n}\n\n/**\n * Custom price provider function type\n */\nexport type CustomPriceProvider = () => Promise<number>;\n\n/**\n * Price provider configuration\n */\nexport interface PriceConfig {\n /** Custom price provider (if set, skips built-in providers) */\n customProvider?: CustomPriceProvider;\n /** Cache TTL in milliseconds (default: 60000) */\n cacheTTL?: number;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n}\n\n// Cached price data\nlet cachedPrice: PriceData | null = null;\nlet config: PriceConfig = {};\nlet lastProviderIndex = -1;\n\n/**\n * Configure price fetching\n * \n * @example\n * ```typescript\n * // Use custom API\n * configurePricing({\n * customProvider: async () => {\n * const res = await fetch('https://my-api.com/sol-price');\n * return (await res.json()).price;\n * },\n * });\n * \n * // Or just adjust cache TTL\n * configurePricing({ cacheTTL: 30000 }); // 30 seconds\n * ```\n */\nexport function configurePricing(newConfig: PriceConfig): void {\n config = { ...config, ...newConfig };\n cachedPrice = null; // Clear cache on config change\n}\n\n/**\n * Built-in price providers with reliability rotation\n */\nconst PROVIDERS = [\n {\n name: 'coincap',\n url: 'https://api.coincap.io/v2/assets/solana',\n parse: (data: { data?: { priceUsd?: string } }) => parseFloat(data.data?.priceUsd || '0'),\n },\n {\n name: 'binance',\n url: 'https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT',\n parse: (data: { price?: string }) => parseFloat(data.price || '0'),\n },\n {\n name: 'coingecko',\n url: 'https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd',\n parse: (data: { solana?: { usd?: number } }) => data.solana?.usd || 0,\n },\n {\n name: 'kraken',\n url: 'https://api.kraken.com/0/public/Ticker?pair=SOLUSD',\n parse: (data: { result?: { SOLUSD?: { c?: string[] } } }) =>\n parseFloat(data.result?.SOLUSD?.c?.[0] || '0'),\n },\n];\n\n/**\n * Fetch price from a single provider\n */\nasync function fetchFromProvider(\n provider: typeof PROVIDERS[0],\n timeout: number\n): Promise<number> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(provider.url, {\n headers: { 'Accept': 'application/json' },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json() as Record<string, unknown>;\n const price = provider.parse(data as Parameters<typeof provider.parse>[0]);\n\n if (!price || price <= 0) {\n throw new Error('Invalid price');\n }\n\n return price;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Get SOL price with multi-provider fallback\n * \n * Provider rotation order:\n * 1. CoinCap (primary)\n * 2. Binance (backup #1)\n * 3. CoinGecko (backup #2)\n * 4. Kraken (backup #3)\n * \n * @example\n * ```typescript\n * const { solPrice, source } = await getSolPrice();\n * console.log(`SOL is $${solPrice} (from ${source})`);\n * ```\n */\nexport async function getSolPrice(): Promise<PriceData> {\n const cacheTTL = config.cacheTTL ?? 60000;\n const timeout = config.timeout ?? 5000;\n\n // Return cached price if valid\n if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {\n return cachedPrice;\n }\n\n // Try custom provider first if configured\n if (config.customProvider) {\n try {\n const price = await config.customProvider();\n if (price > 0) {\n cachedPrice = {\n solPrice: price,\n fetchedAt: new Date(),\n source: 'custom',\n };\n return cachedPrice;\n }\n } catch {\n // Fall through to built-in providers\n }\n }\n\n // Try providers in rotation, starting after the last successful one\n for (let i = 0; i < PROVIDERS.length; i++) {\n const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;\n const provider = PROVIDERS[idx];\n\n try {\n const price = await fetchFromProvider(provider, timeout);\n lastProviderIndex = idx;\n\n cachedPrice = {\n solPrice: price,\n fetchedAt: new Date(),\n source: provider.name,\n };\n return cachedPrice;\n } catch {\n // Try next provider\n continue;\n }\n }\n\n // All providers failed, use stale cache or fallback\n if (cachedPrice) {\n return cachedPrice;\n }\n\n // Last resort fallback\n return {\n solPrice: 150, // Reasonable fallback\n fetchedAt: new Date(),\n source: 'fallback',\n };\n}\n\n/**\n * Convert lamports to USD\n * \n * @example\n * ```typescript\n * const usd = await lamportsToUsd(10_000_000n); // 0.01 SOL\n * console.log(`$${usd.toFixed(2)}`);\n * ```\n */\nexport async function lamportsToUsd(lamports: bigint): Promise<number> {\n const { solPrice } = await getSolPrice();\n const sol = Number(lamports) / 1_000_000_000;\n return sol * solPrice;\n}\n\n/**\n * Convert USD to lamports\n * \n * @example\n * ```typescript\n * const lamports = await usdToLamports(1.50); // $1.50\n * console.log(`${lamports} lamports`);\n * ```\n */\nexport async function usdToLamports(usd: number): Promise<bigint> {\n const { solPrice } = await getSolPrice();\n const sol = usd / solPrice;\n return BigInt(Math.floor(sol * 1_000_000_000));\n}\n\n/**\n * Format a price for display with both SOL and USD\n * \n * @example\n * ```typescript\n * const display = await formatPriceDisplay(10_000_000n);\n * // Returns: \"0.0100 SOL (~$1.50)\"\n * ```\n */\nexport async function formatPriceDisplay(lamports: bigint): Promise<string> {\n const { solPrice } = await getSolPrice();\n const sol = Number(lamports) / 1_000_000_000;\n const usd = sol * solPrice;\n\n return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;\n}\n\n/**\n * Synchronous price formatting (requires pre-fetched price)\n */\nexport function formatPriceSync(lamports: bigint, solPrice: number): {\n sol: number;\n usd: number;\n formatted: string;\n} {\n const sol = Number(lamports) / 1_000_000_000;\n const usd = sol * solPrice;\n\n return {\n sol,\n usd,\n formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`,\n };\n}\n\n/**\n * Clear the price cache (for testing or manual refresh)\n */\nexport function clearPriceCache(): void {\n cachedPrice = null;\n lastProviderIndex = -1;\n}\n\n/**\n * Get list of available built-in providers\n */\nexport function getProviders(): { name: string; url: string }[] {\n return PROVIDERS.map(p => ({ name: p.name, url: p.url }));\n}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price data from API
|
|
3
|
+
*/
|
|
4
|
+
interface PriceData {
|
|
5
|
+
/** SOL price in USD */
|
|
6
|
+
solPrice: number;
|
|
7
|
+
/** Timestamp of price fetch */
|
|
8
|
+
fetchedAt: Date;
|
|
9
|
+
/** Source of price data */
|
|
10
|
+
source: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Custom price provider function type
|
|
14
|
+
*/
|
|
15
|
+
type CustomPriceProvider = () => Promise<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Price provider configuration
|
|
18
|
+
*/
|
|
19
|
+
interface PriceConfig {
|
|
20
|
+
/** Custom price provider (if set, skips built-in providers) */
|
|
21
|
+
customProvider?: CustomPriceProvider;
|
|
22
|
+
/** Cache TTL in milliseconds (default: 60000) */
|
|
23
|
+
cacheTTL?: number;
|
|
24
|
+
/** Request timeout in milliseconds (default: 5000) */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configure price fetching
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // Use custom API
|
|
33
|
+
* configurePricing({
|
|
34
|
+
* customProvider: async () => {
|
|
35
|
+
* const res = await fetch('https://my-api.com/sol-price');
|
|
36
|
+
* return (await res.json()).price;
|
|
37
|
+
* },
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Or just adjust cache TTL
|
|
41
|
+
* configurePricing({ cacheTTL: 30000 }); // 30 seconds
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function configurePricing(newConfig: PriceConfig): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get SOL price with multi-provider fallback
|
|
47
|
+
*
|
|
48
|
+
* Provider rotation order:
|
|
49
|
+
* 1. CoinCap (primary)
|
|
50
|
+
* 2. Binance (backup #1)
|
|
51
|
+
* 3. CoinGecko (backup #2)
|
|
52
|
+
* 4. Kraken (backup #3)
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const { solPrice, source } = await getSolPrice();
|
|
57
|
+
* console.log(`SOL is $${solPrice} (from ${source})`);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function getSolPrice(): Promise<PriceData>;
|
|
61
|
+
/**
|
|
62
|
+
* Convert lamports to USD
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const usd = await lamportsToUsd(10_000_000n); // 0.01 SOL
|
|
67
|
+
* console.log(`$${usd.toFixed(2)}`);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare function lamportsToUsd(lamports: bigint): Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Convert USD to lamports
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const lamports = await usdToLamports(1.50); // $1.50
|
|
77
|
+
* console.log(`${lamports} lamports`);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function usdToLamports(usd: number): Promise<bigint>;
|
|
81
|
+
/**
|
|
82
|
+
* Format a price for display with both SOL and USD
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const display = await formatPriceDisplay(10_000_000n);
|
|
87
|
+
* // Returns: "0.0100 SOL (~$1.50)"
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function formatPriceDisplay(lamports: bigint): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Synchronous price formatting (requires pre-fetched price)
|
|
93
|
+
*/
|
|
94
|
+
declare function formatPriceSync(lamports: bigint, solPrice: number): {
|
|
95
|
+
sol: number;
|
|
96
|
+
usd: number;
|
|
97
|
+
formatted: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Clear the price cache (for testing or manual refresh)
|
|
101
|
+
*/
|
|
102
|
+
declare function clearPriceCache(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Get list of available built-in providers
|
|
105
|
+
*/
|
|
106
|
+
declare function getProviders(): {
|
|
107
|
+
name: string;
|
|
108
|
+
url: string;
|
|
109
|
+
}[];
|
|
110
|
+
|
|
111
|
+
export { type CustomPriceProvider, type PriceConfig, type PriceData, clearPriceCache, configurePricing, formatPriceDisplay, formatPriceSync, getProviders, getSolPrice, lamportsToUsd, usdToLamports };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price data from API
|
|
3
|
+
*/
|
|
4
|
+
interface PriceData {
|
|
5
|
+
/** SOL price in USD */
|
|
6
|
+
solPrice: number;
|
|
7
|
+
/** Timestamp of price fetch */
|
|
8
|
+
fetchedAt: Date;
|
|
9
|
+
/** Source of price data */
|
|
10
|
+
source: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Custom price provider function type
|
|
14
|
+
*/
|
|
15
|
+
type CustomPriceProvider = () => Promise<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Price provider configuration
|
|
18
|
+
*/
|
|
19
|
+
interface PriceConfig {
|
|
20
|
+
/** Custom price provider (if set, skips built-in providers) */
|
|
21
|
+
customProvider?: CustomPriceProvider;
|
|
22
|
+
/** Cache TTL in milliseconds (default: 60000) */
|
|
23
|
+
cacheTTL?: number;
|
|
24
|
+
/** Request timeout in milliseconds (default: 5000) */
|
|
25
|
+
timeout?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configure price fetching
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // Use custom API
|
|
33
|
+
* configurePricing({
|
|
34
|
+
* customProvider: async () => {
|
|
35
|
+
* const res = await fetch('https://my-api.com/sol-price');
|
|
36
|
+
* return (await res.json()).price;
|
|
37
|
+
* },
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Or just adjust cache TTL
|
|
41
|
+
* configurePricing({ cacheTTL: 30000 }); // 30 seconds
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function configurePricing(newConfig: PriceConfig): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get SOL price with multi-provider fallback
|
|
47
|
+
*
|
|
48
|
+
* Provider rotation order:
|
|
49
|
+
* 1. CoinCap (primary)
|
|
50
|
+
* 2. Binance (backup #1)
|
|
51
|
+
* 3. CoinGecko (backup #2)
|
|
52
|
+
* 4. Kraken (backup #3)
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const { solPrice, source } = await getSolPrice();
|
|
57
|
+
* console.log(`SOL is $${solPrice} (from ${source})`);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function getSolPrice(): Promise<PriceData>;
|
|
61
|
+
/**
|
|
62
|
+
* Convert lamports to USD
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const usd = await lamportsToUsd(10_000_000n); // 0.01 SOL
|
|
67
|
+
* console.log(`$${usd.toFixed(2)}`);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
declare function lamportsToUsd(lamports: bigint): Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Convert USD to lamports
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const lamports = await usdToLamports(1.50); // $1.50
|
|
77
|
+
* console.log(`${lamports} lamports`);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function usdToLamports(usd: number): Promise<bigint>;
|
|
81
|
+
/**
|
|
82
|
+
* Format a price for display with both SOL and USD
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const display = await formatPriceDisplay(10_000_000n);
|
|
87
|
+
* // Returns: "0.0100 SOL (~$1.50)"
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function formatPriceDisplay(lamports: bigint): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Synchronous price formatting (requires pre-fetched price)
|
|
93
|
+
*/
|
|
94
|
+
declare function formatPriceSync(lamports: bigint, solPrice: number): {
|
|
95
|
+
sol: number;
|
|
96
|
+
usd: number;
|
|
97
|
+
formatted: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Clear the price cache (for testing or manual refresh)
|
|
101
|
+
*/
|
|
102
|
+
declare function clearPriceCache(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Get list of available built-in providers
|
|
105
|
+
*/
|
|
106
|
+
declare function getProviders(): {
|
|
107
|
+
name: string;
|
|
108
|
+
url: string;
|
|
109
|
+
}[];
|
|
110
|
+
|
|
111
|
+
export { type CustomPriceProvider, type PriceConfig, type PriceData, clearPriceCache, configurePricing, formatPriceDisplay, formatPriceSync, getProviders, getSolPrice, lamportsToUsd, usdToLamports };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/pricing/index.ts
|
|
2
|
+
var cachedPrice = null;
|
|
3
|
+
var config = {};
|
|
4
|
+
var lastProviderIndex = -1;
|
|
5
|
+
function configurePricing(newConfig) {
|
|
6
|
+
config = { ...config, ...newConfig };
|
|
7
|
+
cachedPrice = null;
|
|
8
|
+
}
|
|
9
|
+
var PROVIDERS = [
|
|
10
|
+
{
|
|
11
|
+
name: "coincap",
|
|
12
|
+
url: "https://api.coincap.io/v2/assets/solana",
|
|
13
|
+
parse: (data) => parseFloat(data.data?.priceUsd || "0")
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "binance",
|
|
17
|
+
url: "https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT",
|
|
18
|
+
parse: (data) => parseFloat(data.price || "0")
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "coingecko",
|
|
22
|
+
url: "https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd",
|
|
23
|
+
parse: (data) => data.solana?.usd || 0
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "kraken",
|
|
27
|
+
url: "https://api.kraken.com/0/public/Ticker?pair=SOLUSD",
|
|
28
|
+
parse: (data) => parseFloat(data.result?.SOLUSD?.c?.[0] || "0")
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
async function fetchFromProvider(provider, timeout) {
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(provider.url, {
|
|
36
|
+
headers: { "Accept": "application/json" },
|
|
37
|
+
signal: controller.signal
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(`HTTP ${response.status}`);
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
const price = provider.parse(data);
|
|
44
|
+
if (!price || price <= 0) {
|
|
45
|
+
throw new Error("Invalid price");
|
|
46
|
+
}
|
|
47
|
+
return price;
|
|
48
|
+
} finally {
|
|
49
|
+
clearTimeout(timeoutId);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function getSolPrice() {
|
|
53
|
+
const cacheTTL = config.cacheTTL ?? 6e4;
|
|
54
|
+
const timeout = config.timeout ?? 5e3;
|
|
55
|
+
if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {
|
|
56
|
+
return cachedPrice;
|
|
57
|
+
}
|
|
58
|
+
if (config.customProvider) {
|
|
59
|
+
try {
|
|
60
|
+
const price = await config.customProvider();
|
|
61
|
+
if (price > 0) {
|
|
62
|
+
cachedPrice = {
|
|
63
|
+
solPrice: price,
|
|
64
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
65
|
+
source: "custom"
|
|
66
|
+
};
|
|
67
|
+
return cachedPrice;
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (let i = 0; i < PROVIDERS.length; i++) {
|
|
73
|
+
const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;
|
|
74
|
+
const provider = PROVIDERS[idx];
|
|
75
|
+
try {
|
|
76
|
+
const price = await fetchFromProvider(provider, timeout);
|
|
77
|
+
lastProviderIndex = idx;
|
|
78
|
+
cachedPrice = {
|
|
79
|
+
solPrice: price,
|
|
80
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
81
|
+
source: provider.name
|
|
82
|
+
};
|
|
83
|
+
return cachedPrice;
|
|
84
|
+
} catch {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (cachedPrice) {
|
|
89
|
+
return cachedPrice;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
solPrice: 150,
|
|
93
|
+
// Reasonable fallback
|
|
94
|
+
fetchedAt: /* @__PURE__ */ new Date(),
|
|
95
|
+
source: "fallback"
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function lamportsToUsd(lamports) {
|
|
99
|
+
const { solPrice } = await getSolPrice();
|
|
100
|
+
const sol = Number(lamports) / 1e9;
|
|
101
|
+
return sol * solPrice;
|
|
102
|
+
}
|
|
103
|
+
async function usdToLamports(usd) {
|
|
104
|
+
const { solPrice } = await getSolPrice();
|
|
105
|
+
const sol = usd / solPrice;
|
|
106
|
+
return BigInt(Math.floor(sol * 1e9));
|
|
107
|
+
}
|
|
108
|
+
async function formatPriceDisplay(lamports) {
|
|
109
|
+
const { solPrice } = await getSolPrice();
|
|
110
|
+
const sol = Number(lamports) / 1e9;
|
|
111
|
+
const usd = sol * solPrice;
|
|
112
|
+
return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;
|
|
113
|
+
}
|
|
114
|
+
function formatPriceSync(lamports, solPrice) {
|
|
115
|
+
const sol = Number(lamports) / 1e9;
|
|
116
|
+
const usd = sol * solPrice;
|
|
117
|
+
return {
|
|
118
|
+
sol,
|
|
119
|
+
usd,
|
|
120
|
+
formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function clearPriceCache() {
|
|
124
|
+
cachedPrice = null;
|
|
125
|
+
lastProviderIndex = -1;
|
|
126
|
+
}
|
|
127
|
+
function getProviders() {
|
|
128
|
+
return PROVIDERS.map((p) => ({ name: p.name, url: p.url }));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { clearPriceCache, configurePricing, formatPriceDisplay, formatPriceSync, getProviders, getSolPrice, lamportsToUsd, usdToLamports };
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pricing/index.ts"],"names":[],"mappings":";AAiCA,IAAI,WAAA,GAAgC,IAAA;AACpC,IAAI,SAAsB,EAAC;AAC3B,IAAI,iBAAA,GAAoB,EAAA;AAmBjB,SAAS,iBAAiB,SAAA,EAA8B;AAC3D,EAAA,MAAA,GAAS,EAAE,GAAG,MAAA,EAAQ,GAAG,SAAA,EAAU;AACnC,EAAA,WAAA,GAAc,IAAA;AAClB;AAKA,IAAM,SAAA,GAAY;AAAA,EACd;AAAA,IACI,IAAA,EAAM,SAAA;AAAA,IACN,GAAA,EAAK,yCAAA;AAAA,IACL,OAAO,CAAC,IAAA,KAA2C,WAAW,IAAA,CAAK,IAAA,EAAM,YAAY,GAAG;AAAA,GAC5F;AAAA,EACA;AAAA,IACI,IAAA,EAAM,SAAA;AAAA,IACN,GAAA,EAAK,4DAAA;AAAA,IACL,OAAO,CAAC,IAAA,KAA6B,UAAA,CAAW,IAAA,CAAK,SAAS,GAAG;AAAA,GACrE;AAAA,EACA;AAAA,IACI,IAAA,EAAM,WAAA;AAAA,IACN,GAAA,EAAK,4EAAA;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,KAAwC,IAAA,CAAK,QAAQ,GAAA,IAAO;AAAA,GACxE;AAAA,EACA;AAAA,IACI,IAAA,EAAM,QAAA;AAAA,IACN,GAAA,EAAK,oDAAA;AAAA,IACL,KAAA,EAAO,CAAC,IAAA,KACJ,UAAA,CAAW,IAAA,CAAK,QAAQ,MAAA,EAAQ,CAAA,GAAI,CAAC,CAAA,IAAK,GAAG;AAAA;AAEzD,CAAA;AAKA,eAAe,iBAAA,CACX,UACA,OAAA,EACe;AACf,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE9D,EAAA,IAAI;AACA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,QAAA,CAAS,GAAA,EAAK;AAAA,MACvC,OAAA,EAAS,EAAE,QAAA,EAAU,kBAAA,EAAmB;AAAA,MACxC,QAAQ,UAAA,CAAW;AAAA,KACtB,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7C;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,IAA4C,CAAA;AAEzE,IAAA,IAAI,CAAC,KAAA,IAAS,KAAA,IAAS,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,IACnC;AAEA,IAAA,OAAO,KAAA;AAAA,EACX,CAAA,SAAE;AACE,IAAA,YAAA,CAAa,SAAS,CAAA;AAAA,EAC1B;AACJ;AAiBA,eAAsB,WAAA,GAAkC;AACpD,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,GAAA;AACpC,EAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,GAAA;AAGlC,EAAA,IAAI,WAAA,IAAe,KAAK,GAAA,EAAI,GAAI,YAAY,SAAA,CAAU,OAAA,KAAY,QAAA,EAAU;AACxE,IAAA,OAAO,WAAA;AAAA,EACX;AAGA,EAAA,IAAI,OAAO,cAAA,EAAgB;AACvB,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,cAAA,EAAe;AAC1C,MAAA,IAAI,QAAQ,CAAA,EAAG;AACX,QAAA,WAAA,GAAc;AAAA,UACV,QAAA,EAAU,KAAA;AAAA,UACV,SAAA,sBAAe,IAAA,EAAK;AAAA,UACpB,MAAA,EAAQ;AAAA,SACZ;AACA,QAAA,OAAO,WAAA;AAAA,MACX;AAAA,IACJ,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACJ;AAGA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,GAAA,GAAA,CAAO,iBAAA,GAAoB,CAAA,GAAI,CAAA,IAAK,SAAA,CAAU,MAAA;AACpD,IAAA,MAAM,QAAA,GAAW,UAAU,GAAG,CAAA;AAE9B,IAAA,IAAI;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,iBAAA,CAAkB,QAAA,EAAU,OAAO,CAAA;AACvD,MAAA,iBAAA,GAAoB,GAAA;AAEpB,MAAA,WAAA,GAAc;AAAA,QACV,QAAA,EAAU,KAAA;AAAA,QACV,SAAA,sBAAe,IAAA,EAAK;AAAA,QACpB,QAAQ,QAAA,CAAS;AAAA,OACrB;AACA,MAAA,OAAO,WAAA;AAAA,IACX,CAAA,CAAA,MAAQ;AAEJ,MAAA;AAAA,IACJ;AAAA,EACJ;AAGA,EAAA,IAAI,WAAA,EAAa;AACb,IAAA,OAAO,WAAA;AAAA,EACX;AAGA,EAAA,OAAO;AAAA,IACH,QAAA,EAAU,GAAA;AAAA;AAAA,IACV,SAAA,sBAAe,IAAA,EAAK;AAAA,IACpB,MAAA,EAAQ;AAAA,GACZ;AACJ;AAWA,eAAsB,cAAc,QAAA,EAAmC;AACnE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,OAAO,GAAA,GAAM,QAAA;AACjB;AAWA,eAAsB,cAAc,GAAA,EAA8B;AAC9D,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAClB,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,GAAa,CAAC,CAAA;AACjD;AAWA,eAAsB,mBAAmB,QAAA,EAAmC;AACxE,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAM,WAAA,EAAY;AACvC,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAElB,EAAA,OAAO,CAAA,EAAG,IAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA;AACrD;AAKO,SAAS,eAAA,CAAgB,UAAkB,QAAA,EAIhD;AACE,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,QAAQ,CAAA,GAAI,GAAA;AAC/B,EAAA,MAAM,MAAM,GAAA,GAAM,QAAA;AAElB,EAAA,OAAO;AAAA,IACH,GAAA;AAAA,IACA,GAAA;AAAA,IACA,SAAA,EAAW,CAAA,EAAG,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,QAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,GACzD;AACJ;AAKO,SAAS,eAAA,GAAwB;AACpC,EAAA,WAAA,GAAc,IAAA;AACd,EAAA,iBAAA,GAAoB,EAAA;AACxB;AAKO,SAAS,YAAA,GAAgD;AAC5D,EAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAA,CAAA,MAAM,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAK,CAAA,CAAE,GAAA,EAAI,CAAE,CAAA;AAC5D","file":"index.js","sourcesContent":["// Price Conversion Helpers\n// Multi-provider SOL price fetching with fallback rotation\n\n/**\n * Price data from API\n */\nexport interface PriceData {\n /** SOL price in USD */\n solPrice: number;\n /** Timestamp of price fetch */\n fetchedAt: Date;\n /** Source of price data */\n source: string;\n}\n\n/**\n * Custom price provider function type\n */\nexport type CustomPriceProvider = () => Promise<number>;\n\n/**\n * Price provider configuration\n */\nexport interface PriceConfig {\n /** Custom price provider (if set, skips built-in providers) */\n customProvider?: CustomPriceProvider;\n /** Cache TTL in milliseconds (default: 60000) */\n cacheTTL?: number;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n}\n\n// Cached price data\nlet cachedPrice: PriceData | null = null;\nlet config: PriceConfig = {};\nlet lastProviderIndex = -1;\n\n/**\n * Configure price fetching\n * \n * @example\n * ```typescript\n * // Use custom API\n * configurePricing({\n * customProvider: async () => {\n * const res = await fetch('https://my-api.com/sol-price');\n * return (await res.json()).price;\n * },\n * });\n * \n * // Or just adjust cache TTL\n * configurePricing({ cacheTTL: 30000 }); // 30 seconds\n * ```\n */\nexport function configurePricing(newConfig: PriceConfig): void {\n config = { ...config, ...newConfig };\n cachedPrice = null; // Clear cache on config change\n}\n\n/**\n * Built-in price providers with reliability rotation\n */\nconst PROVIDERS = [\n {\n name: 'coincap',\n url: 'https://api.coincap.io/v2/assets/solana',\n parse: (data: { data?: { priceUsd?: string } }) => parseFloat(data.data?.priceUsd || '0'),\n },\n {\n name: 'binance',\n url: 'https://api.binance.com/api/v3/ticker/price?symbol=SOLUSDT',\n parse: (data: { price?: string }) => parseFloat(data.price || '0'),\n },\n {\n name: 'coingecko',\n url: 'https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd',\n parse: (data: { solana?: { usd?: number } }) => data.solana?.usd || 0,\n },\n {\n name: 'kraken',\n url: 'https://api.kraken.com/0/public/Ticker?pair=SOLUSD',\n parse: (data: { result?: { SOLUSD?: { c?: string[] } } }) =>\n parseFloat(data.result?.SOLUSD?.c?.[0] || '0'),\n },\n];\n\n/**\n * Fetch price from a single provider\n */\nasync function fetchFromProvider(\n provider: typeof PROVIDERS[0],\n timeout: number\n): Promise<number> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(provider.url, {\n headers: { 'Accept': 'application/json' },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json() as Record<string, unknown>;\n const price = provider.parse(data as Parameters<typeof provider.parse>[0]);\n\n if (!price || price <= 0) {\n throw new Error('Invalid price');\n }\n\n return price;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\n/**\n * Get SOL price with multi-provider fallback\n * \n * Provider rotation order:\n * 1. CoinCap (primary)\n * 2. Binance (backup #1)\n * 3. CoinGecko (backup #2)\n * 4. Kraken (backup #3)\n * \n * @example\n * ```typescript\n * const { solPrice, source } = await getSolPrice();\n * console.log(`SOL is $${solPrice} (from ${source})`);\n * ```\n */\nexport async function getSolPrice(): Promise<PriceData> {\n const cacheTTL = config.cacheTTL ?? 60000;\n const timeout = config.timeout ?? 5000;\n\n // Return cached price if valid\n if (cachedPrice && Date.now() - cachedPrice.fetchedAt.getTime() < cacheTTL) {\n return cachedPrice;\n }\n\n // Try custom provider first if configured\n if (config.customProvider) {\n try {\n const price = await config.customProvider();\n if (price > 0) {\n cachedPrice = {\n solPrice: price,\n fetchedAt: new Date(),\n source: 'custom',\n };\n return cachedPrice;\n }\n } catch {\n // Fall through to built-in providers\n }\n }\n\n // Try providers in rotation, starting after the last successful one\n for (let i = 0; i < PROVIDERS.length; i++) {\n const idx = (lastProviderIndex + 1 + i) % PROVIDERS.length;\n const provider = PROVIDERS[idx];\n\n try {\n const price = await fetchFromProvider(provider, timeout);\n lastProviderIndex = idx;\n\n cachedPrice = {\n solPrice: price,\n fetchedAt: new Date(),\n source: provider.name,\n };\n return cachedPrice;\n } catch {\n // Try next provider\n continue;\n }\n }\n\n // All providers failed, use stale cache or fallback\n if (cachedPrice) {\n return cachedPrice;\n }\n\n // Last resort fallback\n return {\n solPrice: 150, // Reasonable fallback\n fetchedAt: new Date(),\n source: 'fallback',\n };\n}\n\n/**\n * Convert lamports to USD\n * \n * @example\n * ```typescript\n * const usd = await lamportsToUsd(10_000_000n); // 0.01 SOL\n * console.log(`$${usd.toFixed(2)}`);\n * ```\n */\nexport async function lamportsToUsd(lamports: bigint): Promise<number> {\n const { solPrice } = await getSolPrice();\n const sol = Number(lamports) / 1_000_000_000;\n return sol * solPrice;\n}\n\n/**\n * Convert USD to lamports\n * \n * @example\n * ```typescript\n * const lamports = await usdToLamports(1.50); // $1.50\n * console.log(`${lamports} lamports`);\n * ```\n */\nexport async function usdToLamports(usd: number): Promise<bigint> {\n const { solPrice } = await getSolPrice();\n const sol = usd / solPrice;\n return BigInt(Math.floor(sol * 1_000_000_000));\n}\n\n/**\n * Format a price for display with both SOL and USD\n * \n * @example\n * ```typescript\n * const display = await formatPriceDisplay(10_000_000n);\n * // Returns: \"0.0100 SOL (~$1.50)\"\n * ```\n */\nexport async function formatPriceDisplay(lamports: bigint): Promise<string> {\n const { solPrice } = await getSolPrice();\n const sol = Number(lamports) / 1_000_000_000;\n const usd = sol * solPrice;\n\n return `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`;\n}\n\n/**\n * Synchronous price formatting (requires pre-fetched price)\n */\nexport function formatPriceSync(lamports: bigint, solPrice: number): {\n sol: number;\n usd: number;\n formatted: string;\n} {\n const sol = Number(lamports) / 1_000_000_000;\n const usd = sol * solPrice;\n\n return {\n sol,\n usd,\n formatted: `${sol.toFixed(4)} SOL (~$${usd.toFixed(2)})`,\n };\n}\n\n/**\n * Clear the price cache (for testing or manual refresh)\n */\nexport function clearPriceCache(): void {\n cachedPrice = null;\n lastProviderIndex = -1;\n}\n\n/**\n * Get list of available built-in providers\n */\nexport function getProviders(): { name: string; url: string }[] {\n return PROVIDERS.map(p => ({ name: p.name, url: p.url }));\n}\n"]}
|
package/dist/session/index.d.cts
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
import { a as SessionConfig, S as SessionData, b as SessionValidation } from '../session-D2IoWAWV.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a new session after successful payment
|
|
5
|
+
* SECURITY: Validates inputs, enforces limits
|
|
6
|
+
*/
|
|
7
|
+
declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
|
|
8
|
+
token: string;
|
|
9
|
+
session: SessionData;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Validate an existing session token
|
|
13
|
+
* SECURITY: jose library handles timing-safe comparison internally
|
|
14
|
+
*/
|
|
15
|
+
declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
|
|
16
|
+
/**
|
|
17
|
+
* Add an article to an existing session
|
|
18
|
+
* SECURITY: Enforces article limit to prevent token bloat
|
|
19
|
+
*/
|
|
20
|
+
declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
|
|
21
|
+
token: string;
|
|
22
|
+
session: SessionData;
|
|
23
|
+
} | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Check if an article is unlocked for a session
|
|
26
|
+
*/
|
|
27
|
+
declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
|
|
28
|
+
|
|
29
|
+
export { addArticleToSession, createSession, isArticleUnlocked, validateSession };
|
package/dist/session/index.d.ts
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
import { a as SessionConfig, S as SessionData, b as SessionValidation } from '../session-D2IoWAWV.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a new session after successful payment
|
|
5
|
+
* SECURITY: Validates inputs, enforces limits
|
|
6
|
+
*/
|
|
7
|
+
declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
|
|
8
|
+
token: string;
|
|
9
|
+
session: SessionData;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Validate an existing session token
|
|
13
|
+
* SECURITY: jose library handles timing-safe comparison internally
|
|
14
|
+
*/
|
|
15
|
+
declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
|
|
16
|
+
/**
|
|
17
|
+
* Add an article to an existing session
|
|
18
|
+
* SECURITY: Enforces article limit to prevent token bloat
|
|
19
|
+
*/
|
|
20
|
+
declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
|
|
21
|
+
token: string;
|
|
22
|
+
session: SessionData;
|
|
23
|
+
} | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Check if an article is unlocked for a session
|
|
26
|
+
*/
|
|
27
|
+
declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
|
|
28
|
+
|
|
29
|
+
export { addArticleToSession, createSession, isArticleUnlocked, validateSession };
|
|
@@ -45,30 +45,4 @@ interface SessionJWTPayload {
|
|
|
45
45
|
exp: number;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
* Create a new session after successful payment
|
|
50
|
-
* SECURITY: Validates inputs, enforces limits
|
|
51
|
-
*/
|
|
52
|
-
declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
|
|
53
|
-
token: string;
|
|
54
|
-
session: SessionData;
|
|
55
|
-
}>;
|
|
56
|
-
/**
|
|
57
|
-
* Validate an existing session token
|
|
58
|
-
* SECURITY: jose library handles timing-safe comparison internally
|
|
59
|
-
*/
|
|
60
|
-
declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
|
|
61
|
-
/**
|
|
62
|
-
* Add an article to an existing session
|
|
63
|
-
* SECURITY: Enforces article limit to prevent token bloat
|
|
64
|
-
*/
|
|
65
|
-
declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
|
|
66
|
-
token: string;
|
|
67
|
-
session: SessionData;
|
|
68
|
-
} | null>;
|
|
69
|
-
/**
|
|
70
|
-
* Check if an article is unlocked for a session
|
|
71
|
-
*/
|
|
72
|
-
declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
|
|
73
|
-
|
|
74
|
-
export { type SessionData as S, type SessionConfig as a, type SessionValidation as b, type SessionJWTPayload as c, createSession as d, addArticleToSession as e, isArticleUnlocked as i, validateSession as v };
|
|
48
|
+
export type { SessionData as S, SessionConfig as a, SessionValidation as b, SessionJWTPayload as c };
|
|
@@ -45,30 +45,4 @@ interface SessionJWTPayload {
|
|
|
45
45
|
exp: number;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
* Create a new session after successful payment
|
|
50
|
-
* SECURITY: Validates inputs, enforces limits
|
|
51
|
-
*/
|
|
52
|
-
declare function createSession(walletAddress: string, articleId: string, config: SessionConfig, siteWide?: boolean): Promise<{
|
|
53
|
-
token: string;
|
|
54
|
-
session: SessionData;
|
|
55
|
-
}>;
|
|
56
|
-
/**
|
|
57
|
-
* Validate an existing session token
|
|
58
|
-
* SECURITY: jose library handles timing-safe comparison internally
|
|
59
|
-
*/
|
|
60
|
-
declare function validateSession(token: string, secret: string): Promise<SessionValidation>;
|
|
61
|
-
/**
|
|
62
|
-
* Add an article to an existing session
|
|
63
|
-
* SECURITY: Enforces article limit to prevent token bloat
|
|
64
|
-
*/
|
|
65
|
-
declare function addArticleToSession(token: string, articleId: string, secret: string): Promise<{
|
|
66
|
-
token: string;
|
|
67
|
-
session: SessionData;
|
|
68
|
-
} | null>;
|
|
69
|
-
/**
|
|
70
|
-
* Check if an article is unlocked for a session
|
|
71
|
-
*/
|
|
72
|
-
declare function isArticleUnlocked(token: string, articleId: string, secret: string): Promise<boolean>;
|
|
73
|
-
|
|
74
|
-
export { type SessionData as S, type SessionConfig as a, type SessionValidation as b, type SessionJWTPayload as c, createSession as d, addArticleToSession as e, isArticleUnlocked as i, validateSession as v };
|
|
48
|
+
export type { SessionData as S, SessionConfig as a, SessionValidation as b, SessionJWTPayload as c };
|