@fanfare-io/fanfare-sdk-core 0.7.0 → 0.7.2

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.
@@ -48,6 +48,12 @@ export declare class DefaultHttpClient implements HttpClient {
48
48
  */
49
49
  private initializeFingerprint;
50
50
  private getClient;
51
+ /**
52
+ * Normalize any thrown HTTP/transport error into a `FanfareError`, preserving
53
+ * the server `code`/`status` from the response envelope. Used by every catcher
54
+ * (including the 401 path) so no raw transport error escapes the client.
55
+ */
56
+ private toFanfareError;
51
57
  /**
52
58
  * Internal request method that handles all HTTP verbs
53
59
  */
package/dist/core/http.js CHANGED
@@ -1 +1 @@
1
- import e from"wretch";import{retry as t}from"wretch/middlewares";import{getAdmissionKeyThumbprint as r,buildAdmissionProofHeaders as i}from"../security/admission-proof.js";import{generateFingerprint as n}from"../utils/fingerprint.module.js";import{FanfareError as o,ErrorCodes as s}from"./errors.js";import{getLogger as a}from"./logger.js";import{isStorageAvailable as c,generateId as l}from"./utils.js";class g{constructor(e,t){this.logger=a(),this.fingerprint=null,this.config=e,this.fingerprintingEnabled=!1!==t?.features?.fingerprinting;const r="fanfare_client_session_id";let i=null;if(c("localStorage"))try{i=window.localStorage.getItem(r)}catch{i=null}if(this.clientSessionId=i||l(),!i&&c("localStorage"))try{window.localStorage.setItem(r,this.clientSessionId)}catch{}this.fingerprintingEnabled?this.initializeFingerprint():this.logger.debug("Browser fingerprinting disabled by configuration")}async initializeFingerprint(){try{const e=await n();this.fingerprint=e.hash,this.logger.debug("Browser fingerprint generated successfully",{fingerprintHash:this.fingerprint})}catch(e){this.logger.debug("Failed to generate browser fingerprint",{error:e instanceof Error?e.message:"Unknown error"}),this.fingerprint=null}}getClient(r){const{retryConfig:i={}}=this.config,n={"Content-Type":"application/json","X-Client-Session-Id":this.clientSessionId,...this.config.headers};return this.fingerprint&&(n["X-Fingerprint"]=this.fingerprint),e(this.config.baseUrl).polyfills({fetch:(e,t)=>globalThis.fetch(e,t)}).options({credentials:this.config.credentials??"include",mode:"cors"}).headers(n).middlewares([t({delayTimer:i.delayTimer||1e3,maxAttempts:i.maxRetries||3,until:(e,t)=>e?!!e.ok||e.status>=400&&e.status<500&&429!==e.status:(t&&i.retryOnNetworkError,!1),onRetry:e=>{this.logger.debug("Retrying request",{status:e.response?.status,error:e.error?.message,retryAfter:e.response?.headers?.get("Retry-After")??void 0})}})]).catcher(401,async e=>{throw!r?.skipUnauthorizedHandler&&this.config.onUnauthorized&&(this.logger.debug("Received 401, triggering re-authentication"),await this.config.onUnauthorized()),e}).catcherFallback(async e=>{if(e&&"object"==typeof e&&"response"in e&&e.response instanceof Response){const t=await e.response.text().catch(()=>null)||("function"==typeof e.text?await e.text().catch(()=>null):null);let r=null;if(t)try{r=JSON.parse(t)}catch{r={message:t}}else"function"==typeof e.json&&(r=await e.json().catch(()=>null));const i=("correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0)||void 0;throw o.fromResponse(e.response,r,i)}if(e&&"object"==typeof e&&"name"in e&&"AbortError"===e.name)throw new o("Request timed out",s.TIMEOUT,void 0,void 0,"correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0);throw new o(e&&"object"==typeof e&&"message"in e&&"string"==typeof e.message?e.message:"Network error occurred",s.NETWORK_ERROR,void 0,{originalError:e},e&&"object"==typeof e&&"correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0)})}async request(e,t,n,a){const c=l(),g=l(),p=this.config.timeout||3e4,h=await r(),d=function(e){return/^\/(queues|draws)\/[^/]+\/enter$/.test(e)}(t),u=new URL(t,this.config.baseUrl).toString(),f=new AbortController,m=setTimeout(()=>f.abort(),p);try{const r={"X-Correlation-Id":c,"X-Request-Id":g,...a?.headers};if(d&&!h&&!r["X-Admission-Key-Thumbprint"])throw new o("Admission proof requires persistent browser crypto support",s.ADMISSION_PROOF_UNAVAILABLE,void 0,{path:t});if(d){const n=await i({url:u,method:e.toUpperCase()});if(!n)throw new o("Admission proof requires persistent browser crypto support",s.ADMISSION_PROOF_UNAVAILABLE,void 0,{path:t});Object.assign(r,n)}h&&!r["X-Admission-Key-Thumbprint"]&&(r["X-Admission-Key-Thumbprint"]=h);const l=this.getClient(a).url(t).headers(r).options({signal:a?.signal||f.signal});let p;switch(e){case"get":p=await l.get().json();break;case"post":p=await l.post(n).json();break;case"put":p=await l.put(n).json();break;case"delete":p=await l.delete().json();break;case"patch":p=await l.patch(n).json();break;default:throw new Error(`Unsupported HTTP method: ${e}`)}return p}finally{clearTimeout(m)}}async get(e,t){return this.request("get",e,void 0,t)}async post(e,t,r){return this.request("post",e,t,r)}async put(e,t,r){return this.request("put",e,t,r)}async delete(e,t){return this.request("delete",e,void 0,t)}async patch(e,t,r){return this.request("patch",e,t,r)}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}}function p(e,t){return new g(e,t)}export{g as DefaultHttpClient,p as createHttpClient};
1
+ import e from"wretch";import{retry as t}from"wretch/middlewares";import{getAdmissionKeyThumbprint as r,buildAdmissionProofHeaders as i}from"../security/admission-proof.js";import{generateFingerprint as s}from"../utils/fingerprint.module.js";import{FanfareError as o,ErrorCodes as n}from"./errors.js";import{getLogger as a}from"./logger.js";import{isStorageAvailable as c,generateId as l}from"./utils.js";class g{constructor(e,t){this.logger=a(),this.fingerprint=null,this.config=e,this.fingerprintingEnabled=!1!==t?.features?.fingerprinting;const r="fanfare_client_session_id";let i=null;if(c("localStorage"))try{i=window.localStorage.getItem(r)}catch{i=null}if(this.clientSessionId=i||l(),!i&&c("localStorage"))try{window.localStorage.setItem(r,this.clientSessionId)}catch{}this.fingerprintingEnabled?this.initializeFingerprint():this.logger.debug("Browser fingerprinting disabled by configuration")}async initializeFingerprint(){try{const e=await s();this.fingerprint=e.hash,this.logger.debug("Browser fingerprint generated successfully",{fingerprintHash:this.fingerprint})}catch(e){this.logger.debug("Failed to generate browser fingerprint",{error:e instanceof Error?e.message:"Unknown error"}),this.fingerprint=null}}getClient(r){const{retryConfig:i={}}=this.config,s={"Content-Type":"application/json","X-Client-Session-Id":this.clientSessionId,...this.config.headers};return this.fingerprint&&(s["X-Fingerprint"]=this.fingerprint),e(this.config.baseUrl).polyfills({fetch:(e,t)=>globalThis.fetch(e,t)}).options({credentials:this.config.credentials??"include",mode:"cors"}).headers(s).middlewares([t({delayTimer:i.delayTimer||1e3,maxAttempts:i.maxRetries||3,until:(e,t)=>e?!!e.ok||e.status>=400&&e.status<500&&429!==e.status:(t&&i.retryOnNetworkError,!1),onRetry:e=>{this.logger.debug("Retrying request",{status:e.response?.status,error:e.error?.message,retryAfter:e.response?.headers?.get("Retry-After")??void 0})}})]).catcher(401,async e=>{throw!r?.skipUnauthorizedHandler&&this.config.onUnauthorized&&(this.logger.debug("Received 401, triggering re-authentication"),await this.config.onUnauthorized()),await this.toFanfareError(e)}).catcherFallback(async e=>{throw await this.toFanfareError(e)})}async toFanfareError(e){if(e&&"object"==typeof e&&"response"in e&&e.response instanceof Response){let t=null;const r=await e.response.text().catch(()=>null),i=e;if(r)try{t=JSON.parse(r)}catch{t={message:r}}else if(null!==i.json&&void 0!==i.json&&"object"==typeof i.json)t=i.json;else if("string"==typeof i.text&&i.text.length>0)try{t=JSON.parse(i.text)}catch{t={message:i.text}}const s=("correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0)||void 0;return o.fromResponse(e.response,t,s)}return e&&"object"==typeof e&&"name"in e&&"AbortError"===e.name?new o("Request timed out",n.TIMEOUT,void 0,void 0,"correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0):new o(e&&"object"==typeof e&&"message"in e&&"string"==typeof e.message?e.message:"Network error occurred",n.NETWORK_ERROR,void 0,{originalError:e},e&&"object"==typeof e&&"correlationId"in e&&"string"==typeof e.correlationId?e.correlationId:void 0)}async request(e,t,s,a){const c=l(),g=l(),p=this.config.timeout||3e4,d=await r(),h=function(e){return/^\/(queues|draws)\/[^/]+\/enter$/.test(e)}(t),f=new URL(t,this.config.baseUrl).toString(),u=new AbortController,m=setTimeout(()=>u.abort(),p);try{const r={"X-Correlation-Id":c,"X-Request-Id":g,...a?.headers};if(h&&!d&&!r["X-Admission-Key-Thumbprint"])throw new o("Admission proof requires persistent browser crypto support",n.ADMISSION_PROOF_UNAVAILABLE,void 0,{path:t});if(h){const s=await i({url:f,method:e.toUpperCase()});if(!s)throw new o("Admission proof requires persistent browser crypto support",n.ADMISSION_PROOF_UNAVAILABLE,void 0,{path:t});Object.assign(r,s)}d&&!r["X-Admission-Key-Thumbprint"]&&(r["X-Admission-Key-Thumbprint"]=d);const l=this.getClient(a).url(t).headers(r).options({signal:a?.signal||u.signal});let p;switch(e){case"get":p=await l.get().json();break;case"post":p=await l.post(s).json();break;case"put":p=await l.put(s).json();break;case"delete":p=await l.delete().json();break;case"patch":p=await l.patch(s).json();break;default:throw new Error(`Unsupported HTTP method: ${e}`)}return p}finally{clearTimeout(m)}}async get(e,t){return this.request("get",e,void 0,t)}async post(e,t,r){return this.request("post",e,t,r)}async put(e,t,r){return this.request("put",e,t,r)}async delete(e,t){return this.request("delete",e,void 0,t)}async patch(e,t,r){return this.request("patch",e,t,r)}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}}function p(e,t){return new g(e,t)}export{g as DefaultHttpClient,p as createHttpClient};
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Handoff module exports
3
3
  */
4
+ export { buildAdmissionProofHeaders, canonicalizeAdmissionProofUrl } from '../security/admission-proof';
4
5
  export { HandoffModule } from './handoff.module';
5
6
  export type { AdmissionProofHeaders, BuildAdmissionProofHeadersParams, BuildHandoffUrlParams, CreateHandoffTokenParams, HandoffModuleOptions, } from './handoff.module';
@@ -1 +1 @@
1
- import{HandoffModule as o}from"./handoff.module.js";export{o as HandoffModule};
1
+ import{buildAdmissionProofHeaders as o,canonicalizeAdmissionProofUrl as r}from"../security/admission-proof.js";import{HandoffModule as m}from"./handoff.module.js";export{m as HandoffModule,o as buildAdmissionProofHeaders,r as canonicalizeAdmissionProofUrl};
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * SDK version
3
3
  * This is automatically updated during the build process
4
4
  */
5
- export declare const version = "0.7.0";
5
+ export declare const version = "0.7.2";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.7.0";export{o as version};
1
+ const o="0.7.2";export{o as version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanfare-io/fanfare-sdk-core",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Official Fanfare Browser SDK for queue, draw, auction, and appointment experiences",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -122,7 +122,7 @@
122
122
  "uuid": "^14.0.0",
123
123
  "wretch": "^2.11.0",
124
124
  "zustand": "^5.0.6",
125
- "@fanfare-io/fanfare-sdk-contracts": "0.7.0"
125
+ "@fanfare-io/fanfare-sdk-contracts": "0.7.2"
126
126
  },
127
127
  "peerDependencies": {
128
128
  "valibot": "^1.1.0",
@@ -165,7 +165,7 @@
165
165
  "vite-plugin-dts": "^4.5.4",
166
166
  "vite-tsconfig-paths": "^5.1.4",
167
167
  "vitest": "^3.2.4",
168
- "@fanfare-io/shared-models": "0.7.0"
168
+ "@fanfare-io/shared-models": "0.7.2"
169
169
  },
170
170
  "sideEffects": false,
171
171
  "keywords": [