@bloque/sdk-core 0.0.42 → 0.0.43

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.
@@ -31,13 +31,13 @@ export declare class HttpClient {
31
31
  */
32
32
  setAccessToken(token: string): void;
33
33
  /**
34
- * Persist JWT token in configured token storage.
35
- * @internal - Called internally for frontend JWT sessions.
34
+ * Persist JWT token in configured token storage, when provided.
35
+ * @internal - Optional for cookie-based JWT sessions.
36
36
  */
37
37
  setJwtToken(token: string): void;
38
38
  /**
39
- * Get JWT token from configured token storage.
40
- * @internal - Used internally to resume frontend JWT sessions.
39
+ * Get JWT token from configured token storage, when provided.
40
+ * @internal - Optional helper for sessions that persist tokens client-side.
41
41
  */
42
42
  getJwtToken(): string | null;
43
43
  /**
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,r)=>{for(var t in r)__webpack_require__.o(r,t)&&!__webpack_require__.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},__webpack_require__.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{BloqueInsufficientFundsError:()=>BloqueInsufficientFundsError,API_BASE_URLS:()=>API_BASE_URLS,BloqueNetworkError:()=>BloqueNetworkError,createBloqueError:()=>createBloqueError,BloqueConfigError:()=>BloqueConfigError,BaseClient:()=>BaseClient,BloqueNotFoundError:()=>BloqueNotFoundError,HttpClient:()=>HttpClient,SUPPORTED_ASSETS:()=>SUPPORTED_ASSETS,BloqueAuthenticationError:()=>BloqueAuthenticationError,BloqueRateLimitError:()=>BloqueRateLimitError,DEFAULT_HEADERS:()=>DEFAULT_HEADERS,BloqueAPIError:()=>BloqueAPIError,BloqueValidationError:()=>BloqueValidationError,isSupportedAsset:()=>isSupportedAsset,BloqueTimeoutError:()=>BloqueTimeoutError});class BaseClient{httpClient;constructor(e){this.httpClient=e}}const API_BASE_URLS={sandbox:"https://dev.bloque.app",production:"https://api.bloque.app"},DEFAULT_HEADERS={"Content-Type":"application/json"},SUPPORTED_ASSETS=["DUSD/6","COPB/6","COPM/2","KSM/12"];function isSupportedAsset(e){return SUPPORTED_ASSETS.includes(e)}class BloqueAPIError extends Error{status;code;requestId;timestamp;response;cause;constructor(e,r){super(e),this.name="BloqueAPIError",this.status=r?.status,this.code=r?.code,this.requestId=r?.requestId,this.response=r?.response,this.cause=r?.cause,this.timestamp=new Date,Object.setPrototypeOf(this,BloqueAPIError.prototype)}toJSON(){return{name:this.name,message:this.message,status:this.status,code:this.code,requestId:this.requestId,timestamp:this.timestamp.toISOString(),response:this.response,stack:this.stack}}}class BloqueRateLimitError extends BloqueAPIError{retryAfter;constructor(e,r){super(e,{...r,status:429}),this.name="BloqueRateLimitError",this.retryAfter=r?.retryAfter,Object.setPrototypeOf(this,BloqueRateLimitError.prototype)}toJSON(){return{...super.toJSON(),retryAfter:this.retryAfter}}}class BloqueAuthenticationError extends BloqueAPIError{constructor(e,r){super(e,r),this.name="BloqueAuthenticationError",Object.setPrototypeOf(this,BloqueAuthenticationError.prototype)}}class BloqueValidationError extends BloqueAPIError{validationErrors;constructor(e,r){super(e,{...r,status:400}),this.name="BloqueValidationError",this.validationErrors=r?.validationErrors,Object.setPrototypeOf(this,BloqueValidationError.prototype)}toJSON(){return{...super.toJSON(),validationErrors:this.validationErrors}}}class BloqueNotFoundError extends BloqueAPIError{resourceType;resourceId;constructor(e,r){super(e,{...r,status:404}),this.name="BloqueNotFoundError",this.resourceType=r?.resourceType,this.resourceId=r?.resourceId,Object.setPrototypeOf(this,BloqueNotFoundError.prototype)}toJSON(){return{...super.toJSON(),resourceType:this.resourceType,resourceId:this.resourceId}}}class BloqueInsufficientFundsError extends BloqueAPIError{requestedAmount;availableBalance;currency;constructor(e,r){super(e,r),this.name="BloqueInsufficientFundsError",this.requestedAmount=r?.requestedAmount,this.availableBalance=r?.availableBalance,this.currency=r?.currency,Object.setPrototypeOf(this,BloqueInsufficientFundsError.prototype)}toJSON(){return{...super.toJSON(),requestedAmount:this.requestedAmount,availableBalance:this.availableBalance,currency:this.currency}}}class BloqueNetworkError extends BloqueAPIError{constructor(e,r){super(e,{...r,code:r?.code??"NETWORK_ERROR"}),this.name="BloqueNetworkError",Object.setPrototypeOf(this,BloqueNetworkError.prototype)}}class BloqueTimeoutError extends BloqueAPIError{timeoutMs;constructor(e,r){super(e,{...r,code:"TIMEOUT_ERROR"}),this.name="BloqueTimeoutError",this.timeoutMs=r?.timeoutMs??0,Object.setPrototypeOf(this,BloqueTimeoutError.prototype)}toJSON(){return{...super.toJSON(),timeoutMs:this.timeoutMs}}}class BloqueConfigError extends Error{constructor(e){super(e),this.name="BloqueConfigError",Object.setPrototypeOf(this,BloqueConfigError.prototype)}}const ERROR_CODE_MAP={INSUFFICIENT_FUNDS:BloqueInsufficientFundsError,INSUFFICIENT_BALANCE:BloqueInsufficientFundsError};function createBloqueError(e,r){let{status:t,code:o}=r??{};if(o&&ERROR_CODE_MAP[o])return new ERROR_CODE_MAP[o](e,r);switch(t){case 400:return new BloqueValidationError(e,r);case 401:case 403:return new BloqueAuthenticationError(e,r);case 404:return new BloqueNotFoundError(e,r);case 429:return new BloqueRateLimitError(e,r);default:return new BloqueAPIError(e,r)}}const isFrontendPlatform=e=>"browser"===e||"react-native"===e,createLocalStorageAdapter=()=>("u">typeof console&&console.warn&&console.warn("[Bloque SDK Security Warning] Using localStorage for token storage. localStorage is vulnerable to XSS attacks. For production use, provide a custom tokenStorage with httpOnly cookies or secure storage. See: https://owasp.org/www-community/attacks/xss/"),{get:()=>"u"<typeof localStorage?null:localStorage.getItem("access_token"),set:e=>{"u">typeof localStorage&&localStorage.setItem("access_token",e)},clear:()=>{"u">typeof localStorage&&localStorage.removeItem("access_token")}});class HttpClient{_config;baseUrl;publicRoutes=["/api/aliases","/api/origins/*/assert","/api/origins/*/connect","/api/origins"];constructor(e){const r={...e};this.validateConfig(r),this._config=r,this.baseUrl=r.baseUrl??API_BASE_URLS[r.mode??"production"]}get origin(){return this._config.origin}get auth(){return this._config.auth}get urn(){return this._config.urn}setAccessToken(e){this._config.accessToken=e}setJwtToken(e){if("jwt"!==this._config.auth.type)throw new BloqueConfigError("JWT token can only be set for JWT auth");this._config.tokenStorage?.set(e),this._config.accessToken=e}getJwtToken(){if("jwt"!==this._config.auth.type)throw new BloqueConfigError("JWT token is only available for JWT auth");return this._config.tokenStorage?.get()??null}setUrn(e){this._config.urn=e}setOrigin(e){this._config.origin=e}validateConfig(e){if(e.mode??="production",e.platform??="node",e.timeout??=3e4,e.retry??={},e.retry.enabled??=!0,e.retry.maxRetries??=3,e.retry.initialDelay??=1e3,e.retry.maxDelay??=3e4,!["sandbox","production"].includes(e.mode))throw new BloqueConfigError('Mode must be either "sandbox" or "production"');if(void 0!==e.timeout&&e.timeout<0)throw new BloqueConfigError("Timeout must be a non-negative number");if(void 0!==e.retry.maxRetries&&e.retry.maxRetries<0)throw new BloqueConfigError("maxRetries must be a non-negative number");if(void 0!==e.retry.initialDelay&&e.retry.initialDelay<0)throw new BloqueConfigError("initialDelay must be a non-negative number");if(void 0!==e.retry.maxDelay&&e.retry.maxDelay<0)throw new BloqueConfigError("maxDelay must be a non-negative number");if("apiKey"===e.auth.type){if(!e.auth.apiKey?.trim())throw new BloqueConfigError("API key is required for apiKey authentication");if(!e.origin?.trim())throw new BloqueConfigError("Origin is required for apiKey authentication");if(isFrontendPlatform(e.platform))throw new BloqueConfigError("API key authentication is not allowed in frontend platforms")}if("jwt"===e.auth.type&&!e.tokenStorage)if("browser"===e.platform)e.tokenStorage=createLocalStorageAdapter();else throw new BloqueConfigError("tokenStorage must be provided when using JWT authentication")}isPublicRoute(e){let r=e.split("?")[0];return this.publicRoutes.some(e=>{let t=e.replace(/\*/g,"[^/]+");return RegExp(`^${t}$`).test(r)})}buildAuthHeaders(e){if(this.isPublicRoute(e))return{};if("apiKey"===this._config.auth.type)return this._config.accessToken?{Authorization:`Bearer ${this._config.accessToken}`}:{Authorization:this._config.auth.apiKey};if("jwt"===this._config.auth.type){let e=this._config.tokenStorage?.get();if(!e)throw new BloqueConfigError("Authentication token is missing");return{Authorization:`Bearer ${e}`}}return{}}isRetryableError(e){return e instanceof BloqueRateLimitError||e instanceof BloqueNetworkError||e instanceof BloqueTimeoutError||e instanceof Error&&"status"in e&&503===e.status}calculateRetryDelay(e,r){let{initialDelay:t=1e3,maxDelay:o=3e4}=this._config.retry??{};if(r){let e=Number.parseInt(r,10);if(!Number.isNaN(e))return Math.min(1e3*e,o);let t=new Date(r);if(!Number.isNaN(t.getTime()))return Math.min(Math.max(t.getTime()-Date.now(),0),o)}let i=t*2**e,s=.25*i*(2*Math.random()-1);return Math.min(i+s,o)}sleep(e){return new Promise(r=>setTimeout(r,e))}async request(e){let r,{method:t,path:o,body:i,headers:s={},timeout:n}=e,a=`${this.baseUrl}${o}`,u={...DEFAULT_HEADERS,...this.buildAuthHeaders(o),...s},l=void 0!==n?n:this._config.timeout??3e4,{enabled:c=!0,maxRetries:_=3}=this._config.retry??{},p=0;for(;p<=(c?_:0);){let e,o=new AbortController;l>0&&(e=setTimeout(()=>{o.abort()},l));try{let s=await fetch(a,{method:t,headers:u,body:i?JSON.stringify(i):void 0,signal:o.signal});void 0!==e&&clearTimeout(e);let n=await s.json().catch(()=>({}));if(!s.ok){let e=s.headers.get("X-Request-ID")??s.headers.get("Request-ID")??void 0,t=s.headers.get("Retry-After"),o=429===s.status?new BloqueRateLimitError(n.message||"Rate limit exceeded",{status:s.status,code:n.code,requestId:e,response:n,retryAfter:t?Number.parseInt(t,10):void 0}):createBloqueError(n.message||`HTTP ${s.status}: ${s.statusText}`,{status:s.status,code:n.code,requestId:e,response:n});if(c&&p<_&&this.isRetryableError(o)){r=o;let e=this.calculateRetryDelay(p,t??void 0);await this.sleep(e),p++;continue}throw o}return n}catch(o){let t;if(void 0!==e&&clearTimeout(e),o&&"object"==typeof o&&"name"in o&&"string"==typeof o.name&&o.name.startsWith("Bloque")&&!this.isRetryableError(o))throw o;if(t=o instanceof Error&&"AbortError"===o.name?new BloqueTimeoutError(`Request timeout after ${l}ms`,{timeoutMs:l,cause:o}):o instanceof Error?new BloqueNetworkError(`Request failed: ${o.message}`,{cause:o}):createBloqueError("Unknown error occurred",{code:"UNKNOWN_ERROR"}),c&&p<_&&this.isRetryableError(t)){r=t;let e=this.calculateRetryDelay(p);await this.sleep(e),p++;continue}throw t}}throw r||createBloqueError("Request failed after retries",{code:"MAX_RETRIES_EXCEEDED"})}}for(var __rspack_i in exports.API_BASE_URLS=__webpack_exports__.API_BASE_URLS,exports.BaseClient=__webpack_exports__.BaseClient,exports.BloqueAPIError=__webpack_exports__.BloqueAPIError,exports.BloqueAuthenticationError=__webpack_exports__.BloqueAuthenticationError,exports.BloqueConfigError=__webpack_exports__.BloqueConfigError,exports.BloqueInsufficientFundsError=__webpack_exports__.BloqueInsufficientFundsError,exports.BloqueNetworkError=__webpack_exports__.BloqueNetworkError,exports.BloqueNotFoundError=__webpack_exports__.BloqueNotFoundError,exports.BloqueRateLimitError=__webpack_exports__.BloqueRateLimitError,exports.BloqueTimeoutError=__webpack_exports__.BloqueTimeoutError,exports.BloqueValidationError=__webpack_exports__.BloqueValidationError,exports.DEFAULT_HEADERS=__webpack_exports__.DEFAULT_HEADERS,exports.HttpClient=__webpack_exports__.HttpClient,exports.SUPPORTED_ASSETS=__webpack_exports__.SUPPORTED_ASSETS,exports.createBloqueError=__webpack_exports__.createBloqueError,exports.isSupportedAsset=__webpack_exports__.isSupportedAsset,__webpack_exports__)-1===["API_BASE_URLS","BaseClient","BloqueAPIError","BloqueAuthenticationError","BloqueConfigError","BloqueInsufficientFundsError","BloqueNetworkError","BloqueNotFoundError","BloqueRateLimitError","BloqueTimeoutError","BloqueValidationError","DEFAULT_HEADERS","HttpClient","SUPPORTED_ASSETS","createBloqueError","isSupportedAsset"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
1
+ "use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,r)=>{for(var t in r)__webpack_require__.o(r,t)&&!__webpack_require__.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},__webpack_require__.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{BloqueInsufficientFundsError:()=>BloqueInsufficientFundsError,API_BASE_URLS:()=>API_BASE_URLS,BloqueNetworkError:()=>BloqueNetworkError,createBloqueError:()=>createBloqueError,BloqueConfigError:()=>BloqueConfigError,BaseClient:()=>BaseClient,BloqueNotFoundError:()=>BloqueNotFoundError,HttpClient:()=>HttpClient,SUPPORTED_ASSETS:()=>SUPPORTED_ASSETS,BloqueAuthenticationError:()=>BloqueAuthenticationError,BloqueRateLimitError:()=>BloqueRateLimitError,DEFAULT_HEADERS:()=>DEFAULT_HEADERS,BloqueAPIError:()=>BloqueAPIError,BloqueValidationError:()=>BloqueValidationError,isSupportedAsset:()=>isSupportedAsset,BloqueTimeoutError:()=>BloqueTimeoutError});class BaseClient{httpClient;constructor(e){this.httpClient=e}}const API_BASE_URLS={sandbox:"https://dev.bloque.app",production:"https://api.bloque.app"},DEFAULT_HEADERS={"Content-Type":"application/json"},SUPPORTED_ASSETS=["DUSD/6","COPB/6","COPM/2","KSM/12"];function isSupportedAsset(e){return SUPPORTED_ASSETS.includes(e)}class BloqueAPIError extends Error{status;code;requestId;timestamp;response;cause;constructor(e,r){super(e),this.name="BloqueAPIError",this.status=r?.status,this.code=r?.code,this.requestId=r?.requestId,this.response=r?.response,this.cause=r?.cause,this.timestamp=new Date,Object.setPrototypeOf(this,BloqueAPIError.prototype)}toJSON(){return{name:this.name,message:this.message,status:this.status,code:this.code,requestId:this.requestId,timestamp:this.timestamp.toISOString(),response:this.response,stack:this.stack}}}class BloqueRateLimitError extends BloqueAPIError{retryAfter;constructor(e,r){super(e,{...r,status:429}),this.name="BloqueRateLimitError",this.retryAfter=r?.retryAfter,Object.setPrototypeOf(this,BloqueRateLimitError.prototype)}toJSON(){return{...super.toJSON(),retryAfter:this.retryAfter}}}class BloqueAuthenticationError extends BloqueAPIError{constructor(e,r){super(e,r),this.name="BloqueAuthenticationError",Object.setPrototypeOf(this,BloqueAuthenticationError.prototype)}}class BloqueValidationError extends BloqueAPIError{validationErrors;constructor(e,r){super(e,{...r,status:400}),this.name="BloqueValidationError",this.validationErrors=r?.validationErrors,Object.setPrototypeOf(this,BloqueValidationError.prototype)}toJSON(){return{...super.toJSON(),validationErrors:this.validationErrors}}}class BloqueNotFoundError extends BloqueAPIError{resourceType;resourceId;constructor(e,r){super(e,{...r,status:404}),this.name="BloqueNotFoundError",this.resourceType=r?.resourceType,this.resourceId=r?.resourceId,Object.setPrototypeOf(this,BloqueNotFoundError.prototype)}toJSON(){return{...super.toJSON(),resourceType:this.resourceType,resourceId:this.resourceId}}}class BloqueInsufficientFundsError extends BloqueAPIError{requestedAmount;availableBalance;currency;constructor(e,r){super(e,r),this.name="BloqueInsufficientFundsError",this.requestedAmount=r?.requestedAmount,this.availableBalance=r?.availableBalance,this.currency=r?.currency,Object.setPrototypeOf(this,BloqueInsufficientFundsError.prototype)}toJSON(){return{...super.toJSON(),requestedAmount:this.requestedAmount,availableBalance:this.availableBalance,currency:this.currency}}}class BloqueNetworkError extends BloqueAPIError{constructor(e,r){super(e,{...r,code:r?.code??"NETWORK_ERROR"}),this.name="BloqueNetworkError",Object.setPrototypeOf(this,BloqueNetworkError.prototype)}}class BloqueTimeoutError extends BloqueAPIError{timeoutMs;constructor(e,r){super(e,{...r,code:"TIMEOUT_ERROR"}),this.name="BloqueTimeoutError",this.timeoutMs=r?.timeoutMs??0,Object.setPrototypeOf(this,BloqueTimeoutError.prototype)}toJSON(){return{...super.toJSON(),timeoutMs:this.timeoutMs}}}class BloqueConfigError extends Error{constructor(e){super(e),this.name="BloqueConfigError",Object.setPrototypeOf(this,BloqueConfigError.prototype)}}const ERROR_CODE_MAP={INSUFFICIENT_FUNDS:BloqueInsufficientFundsError,INSUFFICIENT_BALANCE:BloqueInsufficientFundsError};function createBloqueError(e,r){let{status:t,code:o}=r??{};if(o&&ERROR_CODE_MAP[o])return new ERROR_CODE_MAP[o](e,r);switch(t){case 400:return new BloqueValidationError(e,r);case 401:case 403:return new BloqueAuthenticationError(e,r);case 404:return new BloqueNotFoundError(e,r);case 429:return new BloqueRateLimitError(e,r);default:return new BloqueAPIError(e,r)}}const isFrontendPlatform=e=>"browser"===e||"react-native"===e;class HttpClient{_config;baseUrl;publicRoutes=["/api/aliases","/api/origins/*/assert","/api/origins/*/connect","/api/origins"];constructor(e){const r={...e};this.validateConfig(r),this._config=r,this.baseUrl=r.baseUrl??API_BASE_URLS[r.mode??"production"]}get origin(){return this._config.origin}get auth(){return this._config.auth}get urn(){return this._config.urn}setAccessToken(e){this._config.accessToken=e}setJwtToken(e){if("jwt"!==this._config.auth.type)throw new BloqueConfigError("JWT token can only be set for JWT auth");this._config.tokenStorage?.set(e),this._config.accessToken=e}getJwtToken(){if("jwt"!==this._config.auth.type)throw new BloqueConfigError("JWT token is only available for JWT auth");return this._config.tokenStorage?.get()??null}setUrn(e){this._config.urn=e}setOrigin(e){this._config.origin=e}validateConfig(e){if(e.mode??="production",e.platform??="node",e.timeout??=3e4,e.retry??={},e.retry.enabled??=!0,e.retry.maxRetries??=3,e.retry.initialDelay??=1e3,e.retry.maxDelay??=3e4,!["sandbox","production"].includes(e.mode))throw new BloqueConfigError('Mode must be either "sandbox" or "production"');if(void 0!==e.timeout&&e.timeout<0)throw new BloqueConfigError("Timeout must be a non-negative number");if(void 0!==e.retry.maxRetries&&e.retry.maxRetries<0)throw new BloqueConfigError("maxRetries must be a non-negative number");if(void 0!==e.retry.initialDelay&&e.retry.initialDelay<0)throw new BloqueConfigError("initialDelay must be a non-negative number");if(void 0!==e.retry.maxDelay&&e.retry.maxDelay<0)throw new BloqueConfigError("maxDelay must be a non-negative number");if("apiKey"===e.auth.type){if(!e.auth.apiKey?.trim())throw new BloqueConfigError("API key is required for apiKey authentication");if(!e.origin?.trim())throw new BloqueConfigError("Origin is required for apiKey authentication");if(isFrontendPlatform(e.platform))throw new BloqueConfigError("API key authentication is not allowed in frontend platforms")}if("jwt"===e.auth.type&&"browser"!==e.platform&&!e.tokenStorage)throw new BloqueConfigError("tokenStorage must be provided when using JWT authentication outside browser platform")}isPublicRoute(e){let r=e.split("?")[0];return this.publicRoutes.some(e=>{let t=e.replace(/\*/g,"[^/]+");return RegExp(`^${t}$`).test(r)})}buildAuthHeaders(e){if(this.isPublicRoute(e))return{};if("apiKey"===this._config.auth.type)return this._config.accessToken?{Authorization:`Bearer ${this._config.accessToken}`}:{Authorization:this._config.auth.apiKey};if("jwt"===this._config.auth.type){if("browser"===this._config.platform)return{};let e=this._config.tokenStorage?.get();if(!e)throw new BloqueConfigError("Authentication token is missing");return{Authorization:`Bearer ${e}`}}return{}}isRetryableError(e){return e instanceof BloqueRateLimitError||e instanceof BloqueNetworkError||e instanceof BloqueTimeoutError||e instanceof Error&&"status"in e&&503===e.status}calculateRetryDelay(e,r){let{initialDelay:t=1e3,maxDelay:o=3e4}=this._config.retry??{};if(r){let e=Number.parseInt(r,10);if(!Number.isNaN(e))return Math.min(1e3*e,o);let t=new Date(r);if(!Number.isNaN(t.getTime()))return Math.min(Math.max(t.getTime()-Date.now(),0),o)}let i=t*2**e,s=.25*i*(2*Math.random()-1);return Math.min(i+s,o)}sleep(e){return new Promise(r=>setTimeout(r,e))}async request(e){let r,{method:t,path:o,body:i,headers:s={},timeout:n}=e,u=`${this.baseUrl}${o}`,a={...DEFAULT_HEADERS,...this.buildAuthHeaders(o),...s},l=void 0!==n?n:this._config.timeout??3e4,{enabled:c=!0,maxRetries:_=3}=this._config.retry??{},p=0;for(;p<=(c?_:0);){let e,o=new AbortController;l>0&&(e=setTimeout(()=>{o.abort()},l));try{let s=await fetch(u,{method:t,headers:a,body:i?JSON.stringify(i):void 0,credentials:"jwt"===this._config.auth.type&&"browser"===this._config.platform?"include":void 0,signal:o.signal});void 0!==e&&clearTimeout(e);let n=await s.json().catch(()=>({}));if(!s.ok){let e=s.headers.get("X-Request-ID")??s.headers.get("Request-ID")??void 0,t=s.headers.get("Retry-After"),o=429===s.status?new BloqueRateLimitError(n.message||"Rate limit exceeded",{status:s.status,code:n.code,requestId:e,response:n,retryAfter:t?Number.parseInt(t,10):void 0}):createBloqueError(n.message||`HTTP ${s.status}: ${s.statusText}`,{status:s.status,code:n.code,requestId:e,response:n});if(c&&p<_&&this.isRetryableError(o)){r=o;let e=this.calculateRetryDelay(p,t??void 0);await this.sleep(e),p++;continue}throw o}return n}catch(o){let t;if(void 0!==e&&clearTimeout(e),o&&"object"==typeof o&&"name"in o&&"string"==typeof o.name&&o.name.startsWith("Bloque")&&!this.isRetryableError(o))throw o;if(t=o instanceof Error&&"AbortError"===o.name?new BloqueTimeoutError(`Request timeout after ${l}ms`,{timeoutMs:l,cause:o}):o instanceof Error?new BloqueNetworkError(`Request failed: ${o.message}`,{cause:o}):createBloqueError("Unknown error occurred",{code:"UNKNOWN_ERROR"}),c&&p<_&&this.isRetryableError(t)){r=t;let e=this.calculateRetryDelay(p);await this.sleep(e),p++;continue}throw t}}throw r||createBloqueError("Request failed after retries",{code:"MAX_RETRIES_EXCEEDED"})}}for(var __rspack_i in exports.API_BASE_URLS=__webpack_exports__.API_BASE_URLS,exports.BaseClient=__webpack_exports__.BaseClient,exports.BloqueAPIError=__webpack_exports__.BloqueAPIError,exports.BloqueAuthenticationError=__webpack_exports__.BloqueAuthenticationError,exports.BloqueConfigError=__webpack_exports__.BloqueConfigError,exports.BloqueInsufficientFundsError=__webpack_exports__.BloqueInsufficientFundsError,exports.BloqueNetworkError=__webpack_exports__.BloqueNetworkError,exports.BloqueNotFoundError=__webpack_exports__.BloqueNotFoundError,exports.BloqueRateLimitError=__webpack_exports__.BloqueRateLimitError,exports.BloqueTimeoutError=__webpack_exports__.BloqueTimeoutError,exports.BloqueValidationError=__webpack_exports__.BloqueValidationError,exports.DEFAULT_HEADERS=__webpack_exports__.DEFAULT_HEADERS,exports.HttpClient=__webpack_exports__.HttpClient,exports.SUPPORTED_ASSETS=__webpack_exports__.SUPPORTED_ASSETS,exports.createBloqueError=__webpack_exports__.createBloqueError,exports.isSupportedAsset=__webpack_exports__.isSupportedAsset,__webpack_exports__)-1===["API_BASE_URLS","BaseClient","BloqueAPIError","BloqueAuthenticationError","BloqueConfigError","BloqueInsufficientFundsError","BloqueNetworkError","BloqueNotFoundError","BloqueRateLimitError","BloqueTimeoutError","BloqueValidationError","DEFAULT_HEADERS","HttpClient","SUPPORTED_ASSETS","createBloqueError","isSupportedAsset"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- class e{httpClient;constructor(e){this.httpClient=e}}let t={sandbox:"https://dev.bloque.app",production:"https://api.bloque.app"},r={"Content-Type":"application/json"},o=["DUSD/6","COPB/6","COPM/2","KSM/12"];function s(e){return o.includes(e)}class i extends Error{status;code;requestId;timestamp;response;cause;constructor(e,t){super(e),this.name="BloqueAPIError",this.status=t?.status,this.code=t?.code,this.requestId=t?.requestId,this.response=t?.response,this.cause=t?.cause,this.timestamp=new Date,Object.setPrototypeOf(this,i.prototype)}toJSON(){return{name:this.name,message:this.message,status:this.status,code:this.code,requestId:this.requestId,timestamp:this.timestamp.toISOString(),response:this.response,stack:this.stack}}}class a extends i{retryAfter;constructor(e,t){super(e,{...t,status:429}),this.name="BloqueRateLimitError",this.retryAfter=t?.retryAfter,Object.setPrototypeOf(this,a.prototype)}toJSON(){return{...super.toJSON(),retryAfter:this.retryAfter}}}class n extends i{constructor(e,t){super(e,t),this.name="BloqueAuthenticationError",Object.setPrototypeOf(this,n.prototype)}}class u extends i{validationErrors;constructor(e,t){super(e,{...t,status:400}),this.name="BloqueValidationError",this.validationErrors=t?.validationErrors,Object.setPrototypeOf(this,u.prototype)}toJSON(){return{...super.toJSON(),validationErrors:this.validationErrors}}}class c extends i{resourceType;resourceId;constructor(e,t){super(e,{...t,status:404}),this.name="BloqueNotFoundError",this.resourceType=t?.resourceType,this.resourceId=t?.resourceId,Object.setPrototypeOf(this,c.prototype)}toJSON(){return{...super.toJSON(),resourceType:this.resourceType,resourceId:this.resourceId}}}class l extends i{requestedAmount;availableBalance;currency;constructor(e,t){super(e,t),this.name="BloqueInsufficientFundsError",this.requestedAmount=t?.requestedAmount,this.availableBalance=t?.availableBalance,this.currency=t?.currency,Object.setPrototypeOf(this,l.prototype)}toJSON(){return{...super.toJSON(),requestedAmount:this.requestedAmount,availableBalance:this.availableBalance,currency:this.currency}}}class h extends i{constructor(e,t){super(e,{...t,code:t?.code??"NETWORK_ERROR"}),this.name="BloqueNetworkError",Object.setPrototypeOf(this,h.prototype)}}class p extends i{timeoutMs;constructor(e,t){super(e,{...t,code:"TIMEOUT_ERROR"}),this.name="BloqueTimeoutError",this.timeoutMs=t?.timeoutMs??0,Object.setPrototypeOf(this,p.prototype)}toJSON(){return{...super.toJSON(),timeoutMs:this.timeoutMs}}}class d extends Error{constructor(e){super(e),this.name="BloqueConfigError",Object.setPrototypeOf(this,d.prototype)}}let f={INSUFFICIENT_FUNDS:l,INSUFFICIENT_BALANCE:l};function m(e,t){let{status:r,code:o}=t??{};if(o&&f[o])return new f[o](e,t);switch(r){case 400:return new u(e,t);case 401:case 403:return new n(e,t);case 404:return new c(e,t);case 429:return new a(e,t);default:return new i(e,t)}}class y{_config;baseUrl;publicRoutes=["/api/aliases","/api/origins/*/assert","/api/origins/*/connect","/api/origins"];constructor(e){let r={...e};this.validateConfig(r),this._config=r,this.baseUrl=r.baseUrl??t[r.mode??"production"]}get origin(){return this._config.origin}get auth(){return this._config.auth}get urn(){return this._config.urn}setAccessToken(e){this._config.accessToken=e}setJwtToken(e){if("jwt"!==this._config.auth.type)throw new d("JWT token can only be set for JWT auth");this._config.tokenStorage?.set(e),this._config.accessToken=e}getJwtToken(){if("jwt"!==this._config.auth.type)throw new d("JWT token is only available for JWT auth");return this._config.tokenStorage?.get()??null}setUrn(e){this._config.urn=e}setOrigin(e){this._config.origin=e}validateConfig(e){if(e.mode??="production",e.platform??="node",e.timeout??=3e4,e.retry??={},e.retry.enabled??=!0,e.retry.maxRetries??=3,e.retry.initialDelay??=1e3,e.retry.maxDelay??=3e4,!["sandbox","production"].includes(e.mode))throw new d('Mode must be either "sandbox" or "production"');if(void 0!==e.timeout&&e.timeout<0)throw new d("Timeout must be a non-negative number");if(void 0!==e.retry.maxRetries&&e.retry.maxRetries<0)throw new d("maxRetries must be a non-negative number");if(void 0!==e.retry.initialDelay&&e.retry.initialDelay<0)throw new d("initialDelay must be a non-negative number");if(void 0!==e.retry.maxDelay&&e.retry.maxDelay<0)throw new d("maxDelay must be a non-negative number");if("apiKey"===e.auth.type){let t;if(!e.auth.apiKey?.trim())throw new d("API key is required for apiKey authentication");if(!e.origin?.trim())throw new d("Origin is required for apiKey authentication");if("browser"===(t=e.platform)||"react-native"===t)throw new d("API key authentication is not allowed in frontend platforms")}if("jwt"===e.auth.type&&!e.tokenStorage)if("browser"===e.platform)"u">typeof console&&console.warn&&console.warn("[Bloque SDK Security Warning] Using localStorage for token storage. localStorage is vulnerable to XSS attacks. For production use, provide a custom tokenStorage with httpOnly cookies or secure storage. See: https://owasp.org/www-community/attacks/xss/"),e.tokenStorage={get:()=>"u"<typeof localStorage?null:localStorage.getItem("access_token"),set:e=>{"u">typeof localStorage&&localStorage.setItem("access_token",e)},clear:()=>{"u">typeof localStorage&&localStorage.removeItem("access_token")}};else throw new d("tokenStorage must be provided when using JWT authentication")}isPublicRoute(e){let t=e.split("?")[0];return this.publicRoutes.some(e=>{let r=e.replace(/\*/g,"[^/]+");return RegExp(`^${r}$`).test(t)})}buildAuthHeaders(e){if(this.isPublicRoute(e))return{};if("apiKey"===this._config.auth.type)return this._config.accessToken?{Authorization:`Bearer ${this._config.accessToken}`}:{Authorization:this._config.auth.apiKey};if("jwt"===this._config.auth.type){let e=this._config.tokenStorage?.get();if(!e)throw new d("Authentication token is missing");return{Authorization:`Bearer ${e}`}}return{}}isRetryableError(e){return e instanceof a||e instanceof h||e instanceof p||e instanceof Error&&"status"in e&&503===e.status}calculateRetryDelay(e,t){let{initialDelay:r=1e3,maxDelay:o=3e4}=this._config.retry??{};if(t){let e=Number.parseInt(t,10);if(!Number.isNaN(e))return Math.min(1e3*e,o);let r=new Date(t);if(!Number.isNaN(r.getTime()))return Math.min(Math.max(r.getTime()-Date.now(),0),o)}let s=r*2**e,i=.25*s*(2*Math.random()-1);return Math.min(s+i,o)}sleep(e){return new Promise(t=>setTimeout(t,e))}async request(e){let t,{method:o,path:s,body:i,headers:n={},timeout:u}=e,c=`${this.baseUrl}${s}`,l={...r,...this.buildAuthHeaders(s),...n},d=void 0!==u?u:this._config.timeout??3e4,{enabled:f=!0,maxRetries:y=3}=this._config.retry??{},g=0;for(;g<=(f?y:0);){let e,r=new AbortController;d>0&&(e=setTimeout(()=>{r.abort()},d));try{let s=await fetch(c,{method:o,headers:l,body:i?JSON.stringify(i):void 0,signal:r.signal});void 0!==e&&clearTimeout(e);let n=await s.json().catch(()=>({}));if(!s.ok){let e=s.headers.get("X-Request-ID")??s.headers.get("Request-ID")??void 0,r=s.headers.get("Retry-After"),o=429===s.status?new a(n.message||"Rate limit exceeded",{status:s.status,code:n.code,requestId:e,response:n,retryAfter:r?Number.parseInt(r,10):void 0}):m(n.message||`HTTP ${s.status}: ${s.statusText}`,{status:s.status,code:n.code,requestId:e,response:n});if(f&&g<y&&this.isRetryableError(o)){t=o;let e=this.calculateRetryDelay(g,r??void 0);await this.sleep(e),g++;continue}throw o}return n}catch(o){let r;if(void 0!==e&&clearTimeout(e),o&&"object"==typeof o&&"name"in o&&"string"==typeof o.name&&o.name.startsWith("Bloque")&&!this.isRetryableError(o))throw o;if(r=o instanceof Error&&"AbortError"===o.name?new p(`Request timeout after ${d}ms`,{timeoutMs:d,cause:o}):o instanceof Error?new h(`Request failed: ${o.message}`,{cause:o}):m("Unknown error occurred",{code:"UNKNOWN_ERROR"}),f&&g<y&&this.isRetryableError(r)){t=r;let e=this.calculateRetryDelay(g);await this.sleep(e),g++;continue}throw r}}throw t||m("Request failed after retries",{code:"MAX_RETRIES_EXCEEDED"})}}export{t as API_BASE_URLS,e as BaseClient,i as BloqueAPIError,n as BloqueAuthenticationError,d as BloqueConfigError,l as BloqueInsufficientFundsError,h as BloqueNetworkError,c as BloqueNotFoundError,a as BloqueRateLimitError,p as BloqueTimeoutError,u as BloqueValidationError,r as DEFAULT_HEADERS,y as HttpClient,o as SUPPORTED_ASSETS,m as createBloqueError,s as isSupportedAsset};
1
+ class e{httpClient;constructor(e){this.httpClient=e}}let t={sandbox:"https://dev.bloque.app",production:"https://api.bloque.app"},r={"Content-Type":"application/json"},o=["DUSD/6","COPB/6","COPM/2","KSM/12"];function s(e){return o.includes(e)}class i extends Error{status;code;requestId;timestamp;response;cause;constructor(e,t){super(e),this.name="BloqueAPIError",this.status=t?.status,this.code=t?.code,this.requestId=t?.requestId,this.response=t?.response,this.cause=t?.cause,this.timestamp=new Date,Object.setPrototypeOf(this,i.prototype)}toJSON(){return{name:this.name,message:this.message,status:this.status,code:this.code,requestId:this.requestId,timestamp:this.timestamp.toISOString(),response:this.response,stack:this.stack}}}class n extends i{retryAfter;constructor(e,t){super(e,{...t,status:429}),this.name="BloqueRateLimitError",this.retryAfter=t?.retryAfter,Object.setPrototypeOf(this,n.prototype)}toJSON(){return{...super.toJSON(),retryAfter:this.retryAfter}}}class a extends i{constructor(e,t){super(e,t),this.name="BloqueAuthenticationError",Object.setPrototypeOf(this,a.prototype)}}class u extends i{validationErrors;constructor(e,t){super(e,{...t,status:400}),this.name="BloqueValidationError",this.validationErrors=t?.validationErrors,Object.setPrototypeOf(this,u.prototype)}toJSON(){return{...super.toJSON(),validationErrors:this.validationErrors}}}class c extends i{resourceType;resourceId;constructor(e,t){super(e,{...t,status:404}),this.name="BloqueNotFoundError",this.resourceType=t?.resourceType,this.resourceId=t?.resourceId,Object.setPrototypeOf(this,c.prototype)}toJSON(){return{...super.toJSON(),resourceType:this.resourceType,resourceId:this.resourceId}}}class l extends i{requestedAmount;availableBalance;currency;constructor(e,t){super(e,t),this.name="BloqueInsufficientFundsError",this.requestedAmount=t?.requestedAmount,this.availableBalance=t?.availableBalance,this.currency=t?.currency,Object.setPrototypeOf(this,l.prototype)}toJSON(){return{...super.toJSON(),requestedAmount:this.requestedAmount,availableBalance:this.availableBalance,currency:this.currency}}}class h extends i{constructor(e,t){super(e,{...t,code:t?.code??"NETWORK_ERROR"}),this.name="BloqueNetworkError",Object.setPrototypeOf(this,h.prototype)}}class p extends i{timeoutMs;constructor(e,t){super(e,{...t,code:"TIMEOUT_ERROR"}),this.name="BloqueTimeoutError",this.timeoutMs=t?.timeoutMs??0,Object.setPrototypeOf(this,p.prototype)}toJSON(){return{...super.toJSON(),timeoutMs:this.timeoutMs}}}class d extends Error{constructor(e){super(e),this.name="BloqueConfigError",Object.setPrototypeOf(this,d.prototype)}}let f={INSUFFICIENT_FUNDS:l,INSUFFICIENT_BALANCE:l};function m(e,t){let{status:r,code:o}=t??{};if(o&&f[o])return new f[o](e,t);switch(r){case 400:return new u(e,t);case 401:case 403:return new a(e,t);case 404:return new c(e,t);case 429:return new n(e,t);default:return new i(e,t)}}class y{_config;baseUrl;publicRoutes=["/api/aliases","/api/origins/*/assert","/api/origins/*/connect","/api/origins"];constructor(e){let r={...e};this.validateConfig(r),this._config=r,this.baseUrl=r.baseUrl??t[r.mode??"production"]}get origin(){return this._config.origin}get auth(){return this._config.auth}get urn(){return this._config.urn}setAccessToken(e){this._config.accessToken=e}setJwtToken(e){if("jwt"!==this._config.auth.type)throw new d("JWT token can only be set for JWT auth");this._config.tokenStorage?.set(e),this._config.accessToken=e}getJwtToken(){if("jwt"!==this._config.auth.type)throw new d("JWT token is only available for JWT auth");return this._config.tokenStorage?.get()??null}setUrn(e){this._config.urn=e}setOrigin(e){this._config.origin=e}validateConfig(e){if(e.mode??="production",e.platform??="node",e.timeout??=3e4,e.retry??={},e.retry.enabled??=!0,e.retry.maxRetries??=3,e.retry.initialDelay??=1e3,e.retry.maxDelay??=3e4,!["sandbox","production"].includes(e.mode))throw new d('Mode must be either "sandbox" or "production"');if(void 0!==e.timeout&&e.timeout<0)throw new d("Timeout must be a non-negative number");if(void 0!==e.retry.maxRetries&&e.retry.maxRetries<0)throw new d("maxRetries must be a non-negative number");if(void 0!==e.retry.initialDelay&&e.retry.initialDelay<0)throw new d("initialDelay must be a non-negative number");if(void 0!==e.retry.maxDelay&&e.retry.maxDelay<0)throw new d("maxDelay must be a non-negative number");if("apiKey"===e.auth.type){let t;if(!e.auth.apiKey?.trim())throw new d("API key is required for apiKey authentication");if(!e.origin?.trim())throw new d("Origin is required for apiKey authentication");if("browser"===(t=e.platform)||"react-native"===t)throw new d("API key authentication is not allowed in frontend platforms")}if("jwt"===e.auth.type&&"browser"!==e.platform&&!e.tokenStorage)throw new d("tokenStorage must be provided when using JWT authentication outside browser platform")}isPublicRoute(e){let t=e.split("?")[0];return this.publicRoutes.some(e=>{let r=e.replace(/\*/g,"[^/]+");return RegExp(`^${r}$`).test(t)})}buildAuthHeaders(e){if(this.isPublicRoute(e))return{};if("apiKey"===this._config.auth.type)return this._config.accessToken?{Authorization:`Bearer ${this._config.accessToken}`}:{Authorization:this._config.auth.apiKey};if("jwt"===this._config.auth.type){if("browser"===this._config.platform)return{};let e=this._config.tokenStorage?.get();if(!e)throw new d("Authentication token is missing");return{Authorization:`Bearer ${e}`}}return{}}isRetryableError(e){return e instanceof n||e instanceof h||e instanceof p||e instanceof Error&&"status"in e&&503===e.status}calculateRetryDelay(e,t){let{initialDelay:r=1e3,maxDelay:o=3e4}=this._config.retry??{};if(t){let e=Number.parseInt(t,10);if(!Number.isNaN(e))return Math.min(1e3*e,o);let r=new Date(t);if(!Number.isNaN(r.getTime()))return Math.min(Math.max(r.getTime()-Date.now(),0),o)}let s=r*2**e,i=.25*s*(2*Math.random()-1);return Math.min(s+i,o)}sleep(e){return new Promise(t=>setTimeout(t,e))}async request(e){let t,{method:o,path:s,body:i,headers:a={},timeout:u}=e,c=`${this.baseUrl}${s}`,l={...r,...this.buildAuthHeaders(s),...a},d=void 0!==u?u:this._config.timeout??3e4,{enabled:f=!0,maxRetries:y=3}=this._config.retry??{},g=0;for(;g<=(f?y:0);){let e,r=new AbortController;d>0&&(e=setTimeout(()=>{r.abort()},d));try{let s=await fetch(c,{method:o,headers:l,body:i?JSON.stringify(i):void 0,credentials:"jwt"===this._config.auth.type&&"browser"===this._config.platform?"include":void 0,signal:r.signal});void 0!==e&&clearTimeout(e);let a=await s.json().catch(()=>({}));if(!s.ok){let e=s.headers.get("X-Request-ID")??s.headers.get("Request-ID")??void 0,r=s.headers.get("Retry-After"),o=429===s.status?new n(a.message||"Rate limit exceeded",{status:s.status,code:a.code,requestId:e,response:a,retryAfter:r?Number.parseInt(r,10):void 0}):m(a.message||`HTTP ${s.status}: ${s.statusText}`,{status:s.status,code:a.code,requestId:e,response:a});if(f&&g<y&&this.isRetryableError(o)){t=o;let e=this.calculateRetryDelay(g,r??void 0);await this.sleep(e),g++;continue}throw o}return a}catch(o){let r;if(void 0!==e&&clearTimeout(e),o&&"object"==typeof o&&"name"in o&&"string"==typeof o.name&&o.name.startsWith("Bloque")&&!this.isRetryableError(o))throw o;if(r=o instanceof Error&&"AbortError"===o.name?new p(`Request timeout after ${d}ms`,{timeoutMs:d,cause:o}):o instanceof Error?new h(`Request failed: ${o.message}`,{cause:o}):m("Unknown error occurred",{code:"UNKNOWN_ERROR"}),f&&g<y&&this.isRetryableError(r)){t=r;let e=this.calculateRetryDelay(g);await this.sleep(e),g++;continue}throw r}}throw t||m("Request failed after retries",{code:"MAX_RETRIES_EXCEEDED"})}}export{t as API_BASE_URLS,e as BaseClient,i as BloqueAPIError,a as BloqueAuthenticationError,d as BloqueConfigError,l as BloqueInsufficientFundsError,h as BloqueNetworkError,c as BloqueNotFoundError,n as BloqueRateLimitError,p as BloqueTimeoutError,u as BloqueValidationError,r as DEFAULT_HEADERS,y as HttpClient,o as SUPPORTED_ASSETS,m as createBloqueError,s as isSupportedAsset};
package/dist/types.d.ts CHANGED
@@ -58,8 +58,8 @@ export type Platform =
58
58
  * Characteristics:
59
59
  * - No access to private API keys
60
60
  * - Authentication is performed via JWT
61
- * - Token persistence must be explicitly configured
62
- * (e.g. localStorage, sessionStorage, in-memory)
61
+ * - Requests include credentials (`credentials: 'include'`) to support httpOnly cookies
62
+ * - `tokenStorage` is optional
63
63
  */
64
64
  | 'browser'
65
65
  /**
@@ -70,8 +70,7 @@ export type Platform =
70
70
  * Characteristics:
71
71
  * - No access to private API keys
72
72
  * - Authentication is performed via JWT
73
- * - Token persistence must be provided by the consumer
74
- * (e.g. AsyncStorage, secure storage, in-memory)
73
+ * - `tokenStorage` is required to provide/store the JWT token
75
74
  */
76
75
  | 'react-native';
77
76
  /**
@@ -213,15 +212,19 @@ type BaseSDKConfig = {
213
212
  /**
214
213
  * JWT token storage strategy.
215
214
  *
216
- * Only applies when `platform` is set to `browser` or `react-native`.
215
+ * Used by JWT authentication.
217
216
  *
218
- * **Default behavior (browser only)**:
219
- * - The SDK uses `localStorage` by default for browser platform
220
- * - ⚠️ localStorage is INSECURE and vulnerable to XSS attacks
221
- * - A security warning will be logged to the console
217
+ * **Browser (`platform: 'browser'`)**:
218
+ * - Optional
219
+ * - JWT requests use `credentials: 'include'` to send cookies
220
+ * - No localStorage persistence is configured by default
222
221
  *
223
- * **For production applications**, provide a custom `tokenStorage` using:
224
- * - httpOnly cookies (recommended - immune to XSS)
222
+ * **React Native and non-browser platforms**:
223
+ * - Required for JWT auth
224
+ * - The SDK reads the JWT from `tokenStorage` and sends it as `Authorization: Bearer <token>`
225
+ *
226
+ * If you need explicit client-side token persistence, provide a custom `tokenStorage`:
227
+ * - httpOnly cookies are still recommended (managed by the server, not by `tokenStorage`)
225
228
  * - Secure storage libraries (for React Native)
226
229
  * - sessionStorage (slightly better than localStorage, but still vulnerable)
227
230
  * - In-memory storage (most secure, but lost on refresh)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloque/sdk-core",
3
- "version": "0.0.42",
3
+ "version": "0.0.43",
4
4
  "description": "Core utilities and types for Bloque SDK.",
5
5
  "type": "module",
6
6
  "keywords": [