@medialane/sdk 0.103.0 → 0.105.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.cjs CHANGED
@@ -3,6 +3,8 @@
3
3
  var zod = require('zod');
4
4
  var sha3_js = require('@noble/hashes/sha3.js');
5
5
  var base = require('@scure/base');
6
+ var hmac_js = require('@noble/hashes/hmac.js');
7
+ var sha2_js = require('@noble/hashes/sha2.js');
6
8
 
7
9
  // src/config.ts
8
10
 
@@ -1280,8 +1282,23 @@ var PUBLIC_RPC_FALLBACKS = [
1280
1282
  "https://rpc.starknet.lava.build"
1281
1283
  ];
1282
1284
  var TRANSIENT_BODY_RE = /"code"\s*:\s*-32001|"code"\s*:\s*-32603|unable to complete|rate.?limit|too many|throttl|exceed.*quota|temporarily unavailable|service unavailable|overload|gateway.*time|upstream.*time|backend.*error/i;
1285
+ var POLICY_REFUSAL_CODES = [-32003, -32005, -32600];
1286
+ function isPolicyRefusal(input) {
1287
+ let body = input.body;
1288
+ if (typeof body === "string") {
1289
+ try {
1290
+ body = JSON.parse(body);
1291
+ } catch {
1292
+ return false;
1293
+ }
1294
+ }
1295
+ const err = body?.error;
1296
+ const code = err && typeof err === "object" ? err.code : void 0;
1297
+ return typeof code === "number" && POLICY_REFUSAL_CODES.includes(code);
1298
+ }
1283
1299
  function isTransientRpcError(input) {
1284
1300
  const { status, body } = input;
1301
+ if (isPolicyRefusal({ body })) return false;
1285
1302
  if (typeof status === "number" && (status === 429 || status >= 500)) return true;
1286
1303
  if (body == null) return false;
1287
1304
  if (typeof body === "object") {
@@ -1327,6 +1344,16 @@ function createFailoverFetch(urls, options = {}) {
1327
1344
  };
1328
1345
  return failover;
1329
1346
  }
1347
+ var PAID_UPSTREAM_MARKERS = [
1348
+ "rpc.starknet.lava.build",
1349
+ "g.alchemy.com",
1350
+ "ALCHEMY_RPC_URL",
1351
+ "STARKNET_RPC_URL",
1352
+ "AVNU_PAYMASTER_API_KEY",
1353
+ "@avnu/avnu-sdk",
1354
+ "api.pinata.cloud",
1355
+ "PINATA_JWT"
1356
+ ];
1330
1357
 
1331
1358
  // src/server/rate-limit.ts
1332
1359
  function createRateLimiter(windowMs, max) {
@@ -1534,6 +1561,81 @@ async function getBackendSignedUrl(config, kind = "image") {
1534
1561
  if (!res.ok || !data.data) throw new Error(data.error ?? "Failed to create upload URL");
1535
1562
  return data.data.url;
1536
1563
  }
1564
+ var IDENTITY_PREFIX = "siws_";
1565
+ var ACCOUNT_SESSION_PREFIX = "account_session_";
1566
+ var IDENTITY_DOMAIN = "siws-identity-v1";
1567
+ var ACCOUNT_SESSION_DOMAIN = "account-session-v1";
1568
+ var IDENTITY_TTL_SECONDS = 86400;
1569
+ var ACCOUNT_SESSION_TTL_SECONDS = 30 * 24 * 60 * 60;
1570
+ var CLOCK_SKEW_SECONDS = 60;
1571
+ var encoder = new TextEncoder();
1572
+ var decoder = new TextDecoder();
1573
+ function toHex(bytes) {
1574
+ let out = "";
1575
+ for (const b of bytes) out += b.toString(16).padStart(2, "0");
1576
+ return out;
1577
+ }
1578
+ function sign(secret, domain, payload) {
1579
+ const message = domain === null ? payload : `${domain}.${payload}`;
1580
+ return toHex(hmac_js.hmac(sha2_js.sha256, encoder.encode(secret), encoder.encode(message)));
1581
+ }
1582
+ function constantTimeEquals(a, b) {
1583
+ if (a.length !== b.length) return false;
1584
+ let diff = 0;
1585
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
1586
+ return diff === 0;
1587
+ }
1588
+ function signatureMatches(secret, domain, payload, provided) {
1589
+ return constantTimeEquals(provided, sign(secret, domain, payload)) || constantTimeEquals(provided, sign(secret, null, payload));
1590
+ }
1591
+ function encodePayload(value) {
1592
+ return base.base64urlnopad.encode(encoder.encode(JSON.stringify(value)));
1593
+ }
1594
+ function decodePayload(payload) {
1595
+ try {
1596
+ return JSON.parse(decoder.decode(base.base64urlnopad.decode(payload)));
1597
+ } catch {
1598
+ return null;
1599
+ }
1600
+ }
1601
+ function splitToken(raw, prefix) {
1602
+ if (!raw.startsWith(prefix)) return null;
1603
+ const inner = raw.slice(prefix.length);
1604
+ const dot = inner.lastIndexOf(".");
1605
+ if (dot === -1) return null;
1606
+ return { payload: inner.slice(0, dot), signature: inner.slice(dot + 1) };
1607
+ }
1608
+ function withinLifetime(iat, exp) {
1609
+ if (!iat || !exp) return false;
1610
+ const now = Math.floor(Date.now() / 1e3);
1611
+ return exp >= now && iat <= now + CLOCK_SKEW_SECONDS;
1612
+ }
1613
+ function issueSiwsToken(secret, chain, wallet, ttlSeconds = IDENTITY_TTL_SECONDS) {
1614
+ const iat = Math.floor(Date.now() / 1e3);
1615
+ const payload = encodePayload({ sub: wallet, chain, iat, exp: iat + ttlSeconds });
1616
+ return `${IDENTITY_PREFIX}${payload}.${sign(secret, IDENTITY_DOMAIN, payload)}`;
1617
+ }
1618
+ function verifySiwsToken(secret, raw) {
1619
+ const parts = splitToken(raw, IDENTITY_PREFIX);
1620
+ if (!parts) return null;
1621
+ if (!signatureMatches(secret, IDENTITY_DOMAIN, parts.payload, parts.signature)) return null;
1622
+ const data = decodePayload(parts.payload);
1623
+ if (!data?.sub || !withinLifetime(data.iat, data.exp)) return null;
1624
+ return { address: data.sub, chain: data.chain ?? "STARKNET" };
1625
+ }
1626
+ function issueAccountSessionToken(secret, accountId, ttlSeconds = ACCOUNT_SESSION_TTL_SECONDS) {
1627
+ const iat = Math.floor(Date.now() / 1e3);
1628
+ const payload = encodePayload({ accountId, iat, exp: iat + ttlSeconds });
1629
+ return `${ACCOUNT_SESSION_PREFIX}${payload}.${sign(secret, ACCOUNT_SESSION_DOMAIN, payload)}`;
1630
+ }
1631
+ function verifyAccountSessionToken(secret, raw) {
1632
+ const parts = splitToken(raw, ACCOUNT_SESSION_PREFIX);
1633
+ if (!parts) return null;
1634
+ if (!signatureMatches(secret, ACCOUNT_SESSION_DOMAIN, parts.payload, parts.signature)) return null;
1635
+ const data = decodePayload(parts.payload);
1636
+ if (!data?.accountId || !withinLifetime(data.iat, data.exp)) return null;
1637
+ return data.accountId;
1638
+ }
1537
1639
 
1538
1640
  // src/metadata.ts
1539
1641
  var RESERVED_TRAITS = /* @__PURE__ */ new Set([
@@ -1628,18 +1730,22 @@ function resolveSafeImageContentType(contentType) {
1628
1730
  }
1629
1731
  var MAX_IPFS_GATEWAY_RESPONSE_BYTES = 25 * 1024 * 1024;
1630
1732
 
1733
+ exports.ACCOUNT_SESSION_TTL_SECONDS = ACCOUNT_SESSION_TTL_SECONDS;
1631
1734
  exports.ALLOWED_IMAGE_CONTENT_TYPES = ALLOWED_IMAGE_CONTENT_TYPES;
1632
1735
  exports.ApiClient = ApiClient;
1633
1736
  exports.CHAINS = CHAINS;
1634
1737
  exports.DEFAULT_CHAIN = DEFAULT_CHAIN;
1635
1738
  exports.DEFAULT_CURRENCY = DEFAULT_CURRENCY;
1636
1739
  exports.FeeConfigSchema = FeeConfigSchema;
1740
+ exports.IDENTITY_TTL_SECONDS = IDENTITY_TTL_SECONDS;
1637
1741
  exports.IPFS_SAFE_CONTENT_TYPE_PREFIXES = IPFS_SAFE_CONTENT_TYPE_PREFIXES;
1638
1742
  exports.MAX_IMAGE_PROXY_BYTES = MAX_IMAGE_PROXY_BYTES;
1639
1743
  exports.MAX_IMAGE_REDIRECTS = MAX_IMAGE_REDIRECTS;
1640
1744
  exports.MAX_IPFS_GATEWAY_RESPONSE_BYTES = MAX_IPFS_GATEWAY_RESPONSE_BYTES;
1641
1745
  exports.MedialaneApiError = MedialaneApiError;
1642
1746
  exports.OPEN_LICENSES = OPEN_LICENSES;
1747
+ exports.PAID_UPSTREAM_MARKERS = PAID_UPSTREAM_MARKERS;
1748
+ exports.POLICY_REFUSAL_CODES = POLICY_REFUSAL_CODES;
1643
1749
  exports.PUBLIC_RPC_FALLBACKS = PUBLIC_RPC_FALLBACKS;
1644
1750
  exports.RESERVED_TRAITS = RESERVED_TRAITS;
1645
1751
  exports.STARKNET_COLLECTION_1155_CLASS_HASH = STARKNET_COLLECTION_1155_CLASS_HASH;
@@ -1700,11 +1806,14 @@ exports.getStarknetCoordinates = getStarknetCoordinates;
1700
1806
  exports.getTokenByAddress = getTokenByAddress;
1701
1807
  exports.getTokenBySymbol = getTokenBySymbol;
1702
1808
  exports.hasCapability = hasCapability;
1809
+ exports.isPolicyRefusal = isPolicyRefusal;
1703
1810
  exports.isPrivateHost = isPrivateHost;
1704
1811
  exports.isSameOrigin = isSameOrigin;
1705
1812
  exports.isServiceId = isServiceId;
1706
1813
  exports.isTransientRpcError = isTransientRpcError;
1707
1814
  exports.isValidIpfsCidPath = isValidIpfsCidPath;
1815
+ exports.issueAccountSessionToken = issueAccountSessionToken;
1816
+ exports.issueSiwsToken = issueSiwsToken;
1708
1817
  exports.listServices = listServices;
1709
1818
  exports.normalizeAddress = normalizeAddress;
1710
1819
  exports.normalizeHash = normalizeHash;
@@ -1722,5 +1831,7 @@ exports.uploadDirectoryToBackend = uploadDirectoryToBackend;
1722
1831
  exports.uploadFileToBackend = uploadFileToBackend;
1723
1832
  exports.uploadJsonToBackend = uploadJsonToBackend;
1724
1833
  exports.validateUrl = validateUrl;
1834
+ exports.verifyAccountSessionToken = verifyAccountSessionToken;
1835
+ exports.verifySiwsToken = verifySiwsToken;
1725
1836
  //# sourceMappingURL=index.cjs.map
1726
1837
  //# sourceMappingURL=index.cjs.map