@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.d.cts CHANGED
@@ -392,7 +392,23 @@ declare function getServicesByCapability(cap: ServiceCapability): ServiceDefinit
392
392
  declare function hasCapability(id: string | null | undefined, cap: ServiceCapability): boolean;
393
393
 
394
394
  declare function normalizeAddress(chain: Chain, address: string): string;
395
- declare function normalizeHash(hash: string): string;
395
+ declare const canonicalHashBrand: unique symbol;
396
+ /**
397
+ * A felt hash in exactly one spelling: lowercase, zero-padded to 64 hex digits.
398
+ *
399
+ * Felts have many equal spellings — `0x0ab`, `0xAB` and `0xab` are the same
400
+ * value on chain but three different strings. Anything that uses a hash as an
401
+ * identity or uniqueness key must therefore compare canonical form, or the
402
+ * same on-chain fact can be presented as several distinct records.
403
+ *
404
+ * Only `normalizeHash` can produce this type, so a function that demands a
405
+ * `CanonicalHash` cannot be handed a raw caller-supplied string. It remains
406
+ * assignable to `string`, so existing readers are unaffected.
407
+ */
408
+ type CanonicalHash = string & {
409
+ readonly [canonicalHashBrand]: true;
410
+ };
411
+ declare function normalizeHash(hash: string): CanonicalHash;
396
412
  declare function shortenAddress(chain: Chain, address: string, chars?: number): string;
397
413
 
398
414
  type SupportedToken = (typeof SUPPORTED_TOKENS)[number];
@@ -407,6 +423,22 @@ declare function u256ToBigInt(low: string, high: string): bigint;
407
423
  declare function encodeU256(n: bigint): [string, string];
408
424
 
409
425
  declare const PUBLIC_RPC_FALLBACKS: readonly string[];
426
+ /**
427
+ * Codes our own proxies emit to *refuse* a call on policy grounds: no API key,
428
+ * insufficient credits, rate limited, wrong origin.
429
+ *
430
+ * These must never be treated as transient. They sit inside the JSON-RPC
431
+ * reserved server-error range and carry messages like "Too many requests", so
432
+ * every generic transient heuristic below would otherwise match them — and a
433
+ * caller with a fallback list would quietly retry the same call against a
434
+ * different upstream. That turns a refusal into a redirect: the harder the
435
+ * meter says no, the faster traffic routes around it. A policy refusal is an
436
+ * answer, not a failure; retrying it elsewhere is always wrong.
437
+ */
438
+ declare const POLICY_REFUSAL_CODES: readonly number[];
439
+ declare function isPolicyRefusal(input: {
440
+ body?: unknown;
441
+ }): boolean;
410
442
  declare function isTransientRpcError(input: {
411
443
  status?: number;
412
444
  body?: unknown;
@@ -420,6 +452,19 @@ interface FailoverFetchOptions {
420
452
  }) => void;
421
453
  }
422
454
  declare function createFailoverFetch(urls: string[], options?: FailoverFetchOptions): typeof fetch;
455
+ /**
456
+ * Hostnames and env-var names that reach a paid upstream directly.
457
+ *
458
+ * An app must never name one of these. Everything paid goes through the
459
+ * backend, the only place a call can be authenticated, scoped, rate limited
460
+ * and billed. An app that knows a node's address has a route around all four —
461
+ * and since the address ships in the client bundle, so does every visitor.
462
+ *
463
+ * The list lives here, not in each app, because it is the part that drifts:
464
+ * adding an upstream must protect every consumer at once. Each app keeps its
465
+ * own small test that scans its source for these with its own file APIs.
466
+ */
467
+ declare const PAID_UPSTREAM_MARKERS: readonly string[];
423
468
 
424
469
  interface RpcProxyConfig {
425
470
  backendUrl: string;
@@ -484,6 +529,17 @@ declare function requestIp(req: Request): string;
484
529
 
485
530
  declare function isSameOrigin(req: Request): boolean;
486
531
 
532
+ declare const IDENTITY_TTL_SECONDS = 86400;
533
+ declare const ACCOUNT_SESSION_TTL_SECONDS: number;
534
+ interface SiwsIdentity {
535
+ address: string;
536
+ chain: Chain;
537
+ }
538
+ declare function issueSiwsToken(secret: string, chain: Chain, wallet: string, ttlSeconds?: number): string;
539
+ declare function verifySiwsToken(secret: string, raw: string): SiwsIdentity | null;
540
+ declare function issueAccountSessionToken(secret: string, accountId: string, ttlSeconds?: number): string;
541
+ declare function verifyAccountSessionToken(secret: string, raw: string): string | null;
542
+
487
543
  type AssetAttribute = {
488
544
  trait_type: string;
489
545
  value: string;
@@ -540,4 +596,4 @@ declare const IPFS_SAFE_CONTENT_TYPE_PREFIXES: readonly ["image/jpeg", "image/pn
540
596
  declare function resolveSafeImageContentType(contentType: string): string;
541
597
  declare const MAX_IPFS_GATEWAY_RESPONSE_BYTES: number;
542
598
 
543
- export { ALLOWED_IMAGE_CONTENT_TYPES, type AssetAttribute, type AssetMetadata, type BackendMetadataConfig, type BackendProxyConfig, type BackendUploadResult, type BuildAssetMetadataInput, Chain, DEFAULT_CURRENCY, type FailoverFetchOptions, type FeeEnv, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, type RemixPolicy, type RemixPolicyInput, ResolvedFeeConfig, type RpcProxyConfig, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, ServiceCapability, ServiceDefinition, type ServiceId, type SupportedToken, type SupportedTokenSymbol, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl };
599
+ export { ACCOUNT_SESSION_TTL_SECONDS, ALLOWED_IMAGE_CONTENT_TYPES, type AssetAttribute, type AssetMetadata, type BackendMetadataConfig, type BackendProxyConfig, type BackendUploadResult, type BuildAssetMetadataInput, type CanonicalHash, Chain, DEFAULT_CURRENCY, type FailoverFetchOptions, type FeeEnv, IDENTITY_TTL_SECONDS, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, PAID_UPSTREAM_MARKERS, POLICY_REFUSAL_CODES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, type RemixPolicy, type RemixPolicyInput, ResolvedFeeConfig, type RpcProxyConfig, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, ServiceCapability, ServiceDefinition, type ServiceId, type SiwsIdentity, type SupportedToken, type SupportedTokenSymbol, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, isPolicyRefusal, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, issueAccountSessionToken, issueSiwsToken, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl, verifyAccountSessionToken, verifySiwsToken };
package/dist/index.d.ts CHANGED
@@ -392,7 +392,23 @@ declare function getServicesByCapability(cap: ServiceCapability): ServiceDefinit
392
392
  declare function hasCapability(id: string | null | undefined, cap: ServiceCapability): boolean;
393
393
 
394
394
  declare function normalizeAddress(chain: Chain, address: string): string;
395
- declare function normalizeHash(hash: string): string;
395
+ declare const canonicalHashBrand: unique symbol;
396
+ /**
397
+ * A felt hash in exactly one spelling: lowercase, zero-padded to 64 hex digits.
398
+ *
399
+ * Felts have many equal spellings — `0x0ab`, `0xAB` and `0xab` are the same
400
+ * value on chain but three different strings. Anything that uses a hash as an
401
+ * identity or uniqueness key must therefore compare canonical form, or the
402
+ * same on-chain fact can be presented as several distinct records.
403
+ *
404
+ * Only `normalizeHash` can produce this type, so a function that demands a
405
+ * `CanonicalHash` cannot be handed a raw caller-supplied string. It remains
406
+ * assignable to `string`, so existing readers are unaffected.
407
+ */
408
+ type CanonicalHash = string & {
409
+ readonly [canonicalHashBrand]: true;
410
+ };
411
+ declare function normalizeHash(hash: string): CanonicalHash;
396
412
  declare function shortenAddress(chain: Chain, address: string, chars?: number): string;
397
413
 
398
414
  type SupportedToken = (typeof SUPPORTED_TOKENS)[number];
@@ -407,6 +423,22 @@ declare function u256ToBigInt(low: string, high: string): bigint;
407
423
  declare function encodeU256(n: bigint): [string, string];
408
424
 
409
425
  declare const PUBLIC_RPC_FALLBACKS: readonly string[];
426
+ /**
427
+ * Codes our own proxies emit to *refuse* a call on policy grounds: no API key,
428
+ * insufficient credits, rate limited, wrong origin.
429
+ *
430
+ * These must never be treated as transient. They sit inside the JSON-RPC
431
+ * reserved server-error range and carry messages like "Too many requests", so
432
+ * every generic transient heuristic below would otherwise match them — and a
433
+ * caller with a fallback list would quietly retry the same call against a
434
+ * different upstream. That turns a refusal into a redirect: the harder the
435
+ * meter says no, the faster traffic routes around it. A policy refusal is an
436
+ * answer, not a failure; retrying it elsewhere is always wrong.
437
+ */
438
+ declare const POLICY_REFUSAL_CODES: readonly number[];
439
+ declare function isPolicyRefusal(input: {
440
+ body?: unknown;
441
+ }): boolean;
410
442
  declare function isTransientRpcError(input: {
411
443
  status?: number;
412
444
  body?: unknown;
@@ -420,6 +452,19 @@ interface FailoverFetchOptions {
420
452
  }) => void;
421
453
  }
422
454
  declare function createFailoverFetch(urls: string[], options?: FailoverFetchOptions): typeof fetch;
455
+ /**
456
+ * Hostnames and env-var names that reach a paid upstream directly.
457
+ *
458
+ * An app must never name one of these. Everything paid goes through the
459
+ * backend, the only place a call can be authenticated, scoped, rate limited
460
+ * and billed. An app that knows a node's address has a route around all four —
461
+ * and since the address ships in the client bundle, so does every visitor.
462
+ *
463
+ * The list lives here, not in each app, because it is the part that drifts:
464
+ * adding an upstream must protect every consumer at once. Each app keeps its
465
+ * own small test that scans its source for these with its own file APIs.
466
+ */
467
+ declare const PAID_UPSTREAM_MARKERS: readonly string[];
423
468
 
424
469
  interface RpcProxyConfig {
425
470
  backendUrl: string;
@@ -484,6 +529,17 @@ declare function requestIp(req: Request): string;
484
529
 
485
530
  declare function isSameOrigin(req: Request): boolean;
486
531
 
532
+ declare const IDENTITY_TTL_SECONDS = 86400;
533
+ declare const ACCOUNT_SESSION_TTL_SECONDS: number;
534
+ interface SiwsIdentity {
535
+ address: string;
536
+ chain: Chain;
537
+ }
538
+ declare function issueSiwsToken(secret: string, chain: Chain, wallet: string, ttlSeconds?: number): string;
539
+ declare function verifySiwsToken(secret: string, raw: string): SiwsIdentity | null;
540
+ declare function issueAccountSessionToken(secret: string, accountId: string, ttlSeconds?: number): string;
541
+ declare function verifyAccountSessionToken(secret: string, raw: string): string | null;
542
+
487
543
  type AssetAttribute = {
488
544
  trait_type: string;
489
545
  value: string;
@@ -540,4 +596,4 @@ declare const IPFS_SAFE_CONTENT_TYPE_PREFIXES: readonly ["image/jpeg", "image/pn
540
596
  declare function resolveSafeImageContentType(contentType: string): string;
541
597
  declare const MAX_IPFS_GATEWAY_RESPONSE_BYTES: number;
542
598
 
543
- export { ALLOWED_IMAGE_CONTENT_TYPES, type AssetAttribute, type AssetMetadata, type BackendMetadataConfig, type BackendProxyConfig, type BackendUploadResult, type BuildAssetMetadataInput, Chain, DEFAULT_CURRENCY, type FailoverFetchOptions, type FeeEnv, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, type RemixPolicy, type RemixPolicyInput, ResolvedFeeConfig, type RpcProxyConfig, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, ServiceCapability, ServiceDefinition, type ServiceId, type SupportedToken, type SupportedTokenSymbol, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl };
599
+ export { ACCOUNT_SESSION_TTL_SECONDS, ALLOWED_IMAGE_CONTENT_TYPES, type AssetAttribute, type AssetMetadata, type BackendMetadataConfig, type BackendProxyConfig, type BackendUploadResult, type BuildAssetMetadataInput, type CanonicalHash, Chain, DEFAULT_CURRENCY, type FailoverFetchOptions, type FeeEnv, IDENTITY_TTL_SECONDS, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, PAID_UPSTREAM_MARKERS, POLICY_REFUSAL_CODES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, type RemixPolicy, type RemixPolicyInput, ResolvedFeeConfig, type RpcProxyConfig, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, ServiceCapability, ServiceDefinition, type ServiceId, type SiwsIdentity, type SupportedToken, type SupportedTokenSymbol, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getTokenByAddress, getTokenBySymbol, hasCapability, isPolicyRefusal, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, issueAccountSessionToken, issueSiwsToken, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl, verifyAccountSessionToken, verifySiwsToken };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { keccak_256 } from '@noble/hashes/sha3.js';
3
- import { base58, base32 } from '@scure/base';
3
+ import { base58, base32, base64urlnopad } from '@scure/base';
4
+ import { hmac } from '@noble/hashes/hmac.js';
5
+ import { sha256 } from '@noble/hashes/sha2.js';
4
6
 
5
7
  // src/config.ts
6
8
 
@@ -1278,8 +1280,23 @@ var PUBLIC_RPC_FALLBACKS = [
1278
1280
  "https://rpc.starknet.lava.build"
1279
1281
  ];
1280
1282
  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;
1283
+ var POLICY_REFUSAL_CODES = [-32003, -32005, -32600];
1284
+ function isPolicyRefusal(input) {
1285
+ let body = input.body;
1286
+ if (typeof body === "string") {
1287
+ try {
1288
+ body = JSON.parse(body);
1289
+ } catch {
1290
+ return false;
1291
+ }
1292
+ }
1293
+ const err = body?.error;
1294
+ const code = err && typeof err === "object" ? err.code : void 0;
1295
+ return typeof code === "number" && POLICY_REFUSAL_CODES.includes(code);
1296
+ }
1281
1297
  function isTransientRpcError(input) {
1282
1298
  const { status, body } = input;
1299
+ if (isPolicyRefusal({ body })) return false;
1283
1300
  if (typeof status === "number" && (status === 429 || status >= 500)) return true;
1284
1301
  if (body == null) return false;
1285
1302
  if (typeof body === "object") {
@@ -1325,6 +1342,16 @@ function createFailoverFetch(urls, options = {}) {
1325
1342
  };
1326
1343
  return failover;
1327
1344
  }
1345
+ var PAID_UPSTREAM_MARKERS = [
1346
+ "rpc.starknet.lava.build",
1347
+ "g.alchemy.com",
1348
+ "ALCHEMY_RPC_URL",
1349
+ "STARKNET_RPC_URL",
1350
+ "AVNU_PAYMASTER_API_KEY",
1351
+ "@avnu/avnu-sdk",
1352
+ "api.pinata.cloud",
1353
+ "PINATA_JWT"
1354
+ ];
1328
1355
 
1329
1356
  // src/server/rate-limit.ts
1330
1357
  function createRateLimiter(windowMs, max) {
@@ -1532,6 +1559,81 @@ async function getBackendSignedUrl(config, kind = "image") {
1532
1559
  if (!res.ok || !data.data) throw new Error(data.error ?? "Failed to create upload URL");
1533
1560
  return data.data.url;
1534
1561
  }
1562
+ var IDENTITY_PREFIX = "siws_";
1563
+ var ACCOUNT_SESSION_PREFIX = "account_session_";
1564
+ var IDENTITY_DOMAIN = "siws-identity-v1";
1565
+ var ACCOUNT_SESSION_DOMAIN = "account-session-v1";
1566
+ var IDENTITY_TTL_SECONDS = 86400;
1567
+ var ACCOUNT_SESSION_TTL_SECONDS = 30 * 24 * 60 * 60;
1568
+ var CLOCK_SKEW_SECONDS = 60;
1569
+ var encoder = new TextEncoder();
1570
+ var decoder = new TextDecoder();
1571
+ function toHex(bytes) {
1572
+ let out = "";
1573
+ for (const b of bytes) out += b.toString(16).padStart(2, "0");
1574
+ return out;
1575
+ }
1576
+ function sign(secret, domain, payload) {
1577
+ const message = domain === null ? payload : `${domain}.${payload}`;
1578
+ return toHex(hmac(sha256, encoder.encode(secret), encoder.encode(message)));
1579
+ }
1580
+ function constantTimeEquals(a, b) {
1581
+ if (a.length !== b.length) return false;
1582
+ let diff = 0;
1583
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
1584
+ return diff === 0;
1585
+ }
1586
+ function signatureMatches(secret, domain, payload, provided) {
1587
+ return constantTimeEquals(provided, sign(secret, domain, payload)) || constantTimeEquals(provided, sign(secret, null, payload));
1588
+ }
1589
+ function encodePayload(value) {
1590
+ return base64urlnopad.encode(encoder.encode(JSON.stringify(value)));
1591
+ }
1592
+ function decodePayload(payload) {
1593
+ try {
1594
+ return JSON.parse(decoder.decode(base64urlnopad.decode(payload)));
1595
+ } catch {
1596
+ return null;
1597
+ }
1598
+ }
1599
+ function splitToken(raw, prefix) {
1600
+ if (!raw.startsWith(prefix)) return null;
1601
+ const inner = raw.slice(prefix.length);
1602
+ const dot = inner.lastIndexOf(".");
1603
+ if (dot === -1) return null;
1604
+ return { payload: inner.slice(0, dot), signature: inner.slice(dot + 1) };
1605
+ }
1606
+ function withinLifetime(iat, exp) {
1607
+ if (!iat || !exp) return false;
1608
+ const now = Math.floor(Date.now() / 1e3);
1609
+ return exp >= now && iat <= now + CLOCK_SKEW_SECONDS;
1610
+ }
1611
+ function issueSiwsToken(secret, chain, wallet, ttlSeconds = IDENTITY_TTL_SECONDS) {
1612
+ const iat = Math.floor(Date.now() / 1e3);
1613
+ const payload = encodePayload({ sub: wallet, chain, iat, exp: iat + ttlSeconds });
1614
+ return `${IDENTITY_PREFIX}${payload}.${sign(secret, IDENTITY_DOMAIN, payload)}`;
1615
+ }
1616
+ function verifySiwsToken(secret, raw) {
1617
+ const parts = splitToken(raw, IDENTITY_PREFIX);
1618
+ if (!parts) return null;
1619
+ if (!signatureMatches(secret, IDENTITY_DOMAIN, parts.payload, parts.signature)) return null;
1620
+ const data = decodePayload(parts.payload);
1621
+ if (!data?.sub || !withinLifetime(data.iat, data.exp)) return null;
1622
+ return { address: data.sub, chain: data.chain ?? "STARKNET" };
1623
+ }
1624
+ function issueAccountSessionToken(secret, accountId, ttlSeconds = ACCOUNT_SESSION_TTL_SECONDS) {
1625
+ const iat = Math.floor(Date.now() / 1e3);
1626
+ const payload = encodePayload({ accountId, iat, exp: iat + ttlSeconds });
1627
+ return `${ACCOUNT_SESSION_PREFIX}${payload}.${sign(secret, ACCOUNT_SESSION_DOMAIN, payload)}`;
1628
+ }
1629
+ function verifyAccountSessionToken(secret, raw) {
1630
+ const parts = splitToken(raw, ACCOUNT_SESSION_PREFIX);
1631
+ if (!parts) return null;
1632
+ if (!signatureMatches(secret, ACCOUNT_SESSION_DOMAIN, parts.payload, parts.signature)) return null;
1633
+ const data = decodePayload(parts.payload);
1634
+ if (!data?.accountId || !withinLifetime(data.iat, data.exp)) return null;
1635
+ return data.accountId;
1636
+ }
1535
1637
 
1536
1638
  // src/metadata.ts
1537
1639
  var RESERVED_TRAITS = /* @__PURE__ */ new Set([
@@ -1626,6 +1728,6 @@ function resolveSafeImageContentType(contentType) {
1626
1728
  }
1627
1729
  var MAX_IPFS_GATEWAY_RESPONSE_BYTES = 25 * 1024 * 1024;
1628
1730
 
1629
- export { ALLOWED_IMAGE_CONTENT_TYPES, ApiClient, CHAINS, DEFAULT_CHAIN, DEFAULT_CURRENCY, FeeConfigSchema, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, MedialaneApiError, OPEN_LICENSES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getCoordinates, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getStarknetCoordinates, getTokenByAddress, getTokenBySymbol, hasCapability, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveConfig, resolveFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl };
1731
+ export { ACCOUNT_SESSION_TTL_SECONDS, ALLOWED_IMAGE_CONTENT_TYPES, ApiClient, CHAINS, DEFAULT_CHAIN, DEFAULT_CURRENCY, FeeConfigSchema, IDENTITY_TTL_SECONDS, IPFS_SAFE_CONTENT_TYPE_PREFIXES, MAX_IMAGE_PROXY_BYTES, MAX_IMAGE_REDIRECTS, MAX_IPFS_GATEWAY_RESPONSE_BYTES, MedialaneApiError, OPEN_LICENSES, PAID_UPSTREAM_MARKERS, POLICY_REFUSAL_CODES, PUBLIC_RPC_FALLBACKS, RESERVED_TRAITS, STARKNET_COLLECTION_1155_CLASS_HASH, STARKNET_COLLECTION_1155_CONTRACT, STARKNET_COLLECTION_1155_FACTORY_CLASS_HASH, STARKNET_COLLECTION_1155_START_BLOCK, STARKNET_COLLECTION_721_CONTRACT, STARKNET_COLLECTION_721_START_BLOCK, STARKNET_CREATOR_COIN_CLASS_HASH, STARKNET_CREATOR_COIN_EKUBO_LAUNCHER, STARKNET_CREATOR_COIN_FACTORY_CLASS_HASH, STARKNET_CREATOR_COIN_FACTORY_CONTRACT, STARKNET_CREATOR_COIN_START_BLOCK, STARKNET_DROP_COLLECTION_CLASS_HASH, STARKNET_DROP_FACTORY_CONTRACT, STARKNET_EKUBO_CORE, STARKNET_GENESIS_MINT_BR_CONTRACT, STARKNET_GENESIS_MINT_GLOBAL_CONTRACT, STARKNET_GENESIS_MINT_LAUNCH_CONTRACT, STARKNET_IPCOLLECTION_CLASS_HASH, STARKNET_IPNFT_CLASS_HASH, STARKNET_IP_CLUB_COLLECTION_CLASS_HASH, STARKNET_IP_CLUB_FACTORY_CONTRACT, STARKNET_IP_SPONSORSHIP_CLASS_HASH, STARKNET_IP_SPONSORSHIP_CONTRACT, STARKNET_IP_TICKETS_FACTORY_CONTRACT, STARKNET_IP_TICKET_COLLECTION_CLASS_HASH, STARKNET_MARKETPLACE_1155_CLASS_HASH, STARKNET_MARKETPLACE_1155_CONTRACT, STARKNET_MARKETPLACE_1155_START_BLOCK, STARKNET_MARKETPLACE_721_CLASS_HASH, STARKNET_MARKETPLACE_721_CONTRACT, STARKNET_MARKETPLACE_721_START_BLOCK, STARKNET_NFTCOMMENTS_CONTRACT, STARKNET_POP_COLLECTION_CLASS_HASH, STARKNET_POP_FACTORY_CONTRACT, SUPPORTED_TOKENS, SUPPORTED_URL_CHAINS, assetHref, buildAssetMetadata, chainFromSlug, chainSlug, coinHref, collectionHref, createBackendProxyHandler, createFailoverFetch, createRateLimiter, createRpcProxyHandler, encodeU256, formatAmount, getBackendSignedUrl, getCoordinates, getDerivativesTerm, getListableTokens, getService, getServicesByCapability, getStarknetCoordinates, getTokenByAddress, getTokenBySymbol, hasCapability, isPolicyRefusal, isPrivateHost, isSameOrigin, isServiceId, isTransientRpcError, isValidIpfsCidPath, issueAccountSessionToken, issueSiwsToken, listServices, normalizeAddress, normalizeHash, parseAmount, requestIp, resolveAppFeeConfig, resolveConfig, resolveFeeConfig, resolveRemixPolicy, resolveSafeImageContentType, shortenAddress, stringifyBigInts, u256ToBigInt, uploadDirectoryToBackend, uploadFileToBackend, uploadJsonToBackend, validateUrl, verifyAccountSessionToken, verifySiwsToken };
1630
1732
  //# sourceMappingURL=index.js.map
1631
1733
  //# sourceMappingURL=index.js.map