@dismissible/react-client 1.0.0-canary.4.a9fb4a5 → 2.0.0-canary.5.88c27fb

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.
@@ -1 +1 @@
1
- (function(c,d){typeof exports=="object"&&typeof module!="undefined"?d(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],d):(c=typeof globalThis!="undefined"?globalThis:c||self,d(c.DismissibleClient={},c.React.jsxRuntime,c.React))})(this,(function(c,d,o){"use strict";var je=Object.defineProperty,$e=Object.defineProperties;var Te=Object.getOwnPropertyDescriptors;var Q=Object.getOwnPropertySymbols;var me=Object.prototype.hasOwnProperty,ye=Object.prototype.propertyIsEnumerable;var he=(c,d,o)=>d in c?je(c,d,{enumerable:!0,configurable:!0,writable:!0,value:o}):c[d]=o,g=(c,d)=>{for(var o in d||(d={}))me.call(d,o)&&he(c,o,d[o]);if(Q)for(var o of Q(d))ye.call(d,o)&&he(c,o,d[o]);return c},x=(c,d)=>$e(c,Te(d));var te=(c,d)=>{var o={};for(var R in c)me.call(c,R)&&d.indexOf(R)<0&&(o[R]=c[R]);if(c!=null&&Q)for(var R of Q(c))d.indexOf(R)<0&&ye.call(c,R)&&(o[R]=c[R]);return o};var q=(c,d,o)=>new Promise((R,J)=>{var V=j=>{try{H(o.next(j))}catch(F){J(F)}},X=j=>{try{H(o.throw(j))}catch(F){J(F)}},H=j=>j.done?R(j.value):Promise.resolve(j.value).then(V,X);H((o=o.apply(c,d)).next())});const R=/\{[^{}]+\}/g,J=()=>{var e,r;return typeof process=="object"&&Number.parseInt((r=(e=process==null?void 0:process.versions)==null?void 0:e.node)==null?void 0:r.substring(0,2))>=18&&process.versions.undici};function V(){return Math.random().toString(36).slice(2,11)}function X(e){let I=g({},e),{baseUrl:r="",Request:t=globalThis.Request,fetch:n=globalThis.fetch,querySerializer:i,bodySerializer:s,headers:a,requestInitExt:h=void 0}=I,b=te(I,["baseUrl","Request","fetch","querySerializer","bodySerializer","headers","requestInitExt"]);h=J()?h:void 0,r=ne(r);const m=[];function C(u,l){return q(this,null,function*(){var de;const fe=l||{},{baseUrl:A,fetch:$=n,Request:L=t,headers:D,params:S={},parseAs:U="json",querySerializer:T,bodySerializer:W=s!=null?s:we,body:_,middleware:f=[]}=fe,p=te(fe,["baseUrl","fetch","Request","headers","params","parseAs","querySerializer","bodySerializer","body","middleware"]);let y=r;A&&(y=(de=ne(A))!=null?de:r);let k=typeof i=="function"?i:re(i);T&&(k=typeof T=="function"?T:re(g(g({},typeof i=="object"?i:{}),T)));const N=_===void 0?void 0:W(_,se(a,D,S.header)),Ae=se(N===void 0||N instanceof FormData?{}:{"Content-Type":"application/json"},a,D,S.header),P=[...m,...f],De=x(g(g({redirect:"follow"},b),p),{body:N,headers:Ae});let B,G,O=new L(pe(u,{baseUrl:y,params:S,querySerializer:k}),De),w;for(const E in p)E in O||(O[E]=p[E]);if(P.length){B=V(),G=Object.freeze({baseUrl:y,fetch:$,parseAs:U,querySerializer:k,bodySerializer:W});for(const E of P)if(E&&typeof E=="object"&&typeof E.onRequest=="function"){const v=yield E.onRequest({request:O,schemaPath:u,params:S,options:G,id:B});if(v)if(v instanceof L)O=v;else if(v instanceof Response){w=v;break}else throw new Error("onRequest: must return new Request() or Response() when modifying the request")}}if(!w){try{w=yield $(O,h)}catch(E){let v=E;if(P.length)for(let z=P.length-1;z>=0;z--){const K=P[z];if(K&&typeof K=="object"&&typeof K.onError=="function"){const M=yield K.onError({request:O,error:v,schemaPath:u,params:S,options:G,id:B});if(M){if(M instanceof Response){v=void 0,w=M;break}if(M instanceof Error){v=M;continue}throw new Error("onError: must return new Response() or instance of Error")}}}if(v)throw v}if(P.length)for(let E=P.length-1;E>=0;E--){const v=P[E];if(v&&typeof v=="object"&&typeof v.onResponse=="function"){const z=yield v.onResponse({request:O,response:w,schemaPath:u,params:S,options:G,id:B});if(z){if(!(z instanceof Response))throw new Error("onResponse: must return new Response() when modifying the response");w=z}}}}if(w.status===204||O.method==="HEAD"||w.headers.get("Content-Length")==="0")return w.ok?{data:void 0,response:w}:{error:void 0,response:w};if(w.ok)return U==="stream"?{data:w.body,response:w}:{data:yield w[U](),response:w};let ee=yield w.text();try{ee=JSON.parse(ee)}catch(E){}return{error:ee,response:w}})}return{request(u,l,A){return C(l,x(g({},A),{method:u.toUpperCase()}))},GET(u,l){return C(u,x(g({},l),{method:"GET"}))},PUT(u,l){return C(u,x(g({},l),{method:"PUT"}))},POST(u,l){return C(u,x(g({},l),{method:"POST"}))},DELETE(u,l){return C(u,x(g({},l),{method:"DELETE"}))},OPTIONS(u,l){return C(u,x(g({},l),{method:"OPTIONS"}))},HEAD(u,l){return C(u,x(g({},l),{method:"HEAD"}))},PATCH(u,l){return C(u,x(g({},l),{method:"PATCH"}))},TRACE(u,l){return C(u,x(g({},l),{method:"TRACE"}))},use(...u){for(const l of u)if(l){if(typeof l!="object"||!("onRequest"in l||"onResponse"in l||"onError"in l))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");m.push(l)}},eject(...u){for(const l of u){const A=m.indexOf(l);A!==-1&&m.splice(A,1)}}}}function H(e,r,t){if(r==null)return"";if(typeof r=="object")throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${e}=${(t==null?void 0:t.allowReserved)===!0?r:encodeURIComponent(r)}`}function j(e,r,t){if(!r||typeof r!="object")return"";const n=[],i={simple:",",label:".",matrix:";"}[t.style]||"&";if(t.style!=="deepObject"&&t.explode===!1){for(const h in r)n.push(h,t.allowReserved===!0?r[h]:encodeURIComponent(r[h]));const a=n.join(",");switch(t.style){case"form":return`${e}=${a}`;case"label":return`.${a}`;case"matrix":return`;${e}=${a}`;default:return a}}for(const a in r){const h=t.style==="deepObject"?`${e}[${a}]`:a;n.push(H(h,r[a],t))}const s=n.join(i);return t.style==="label"||t.style==="matrix"?`${i}${s}`:s}function F(e,r,t){if(!Array.isArray(r))return"";if(t.explode===!1){const s={form:",",spaceDelimited:"%20",pipeDelimited:"|"}[t.style]||",",a=(t.allowReserved===!0?r:r.map(h=>encodeURIComponent(h))).join(s);switch(t.style){case"simple":return a;case"label":return`.${a}`;case"matrix":return`;${e}=${a}`;default:return`${e}=${a}`}}const n={simple:",",label:".",matrix:";"}[t.style]||"&",i=[];for(const s of r)t.style==="simple"||t.style==="label"?i.push(t.allowReserved===!0?s:encodeURIComponent(s)):i.push(H(e,s,t));return t.style==="label"||t.style==="matrix"?`${n}${i.join(n)}`:i.join(n)}function re(e){return function(t){const n=[];if(t&&typeof t=="object")for(const i in t){const s=t[i];if(s!=null){if(Array.isArray(s)){if(s.length===0)continue;n.push(F(i,s,x(g({style:"form",explode:!0},e==null?void 0:e.array),{allowReserved:(e==null?void 0:e.allowReserved)||!1})));continue}if(typeof s=="object"){n.push(j(i,s,x(g({style:"deepObject",explode:!0},e==null?void 0:e.object),{allowReserved:(e==null?void 0:e.allowReserved)||!1})));continue}n.push(H(i,s,e))}}return n.join("&")}}function be(e,r){var n;let t=e;for(const i of(n=e.match(R))!=null?n:[]){let s=i.substring(1,i.length-1),a=!1,h="simple";if(s.endsWith("*")&&(a=!0,s=s.substring(0,s.length-1)),s.startsWith(".")?(h="label",s=s.substring(1)):s.startsWith(";")&&(h="matrix",s=s.substring(1)),!r||r[s]===void 0||r[s]===null)continue;const b=r[s];if(Array.isArray(b)){t=t.replace(i,F(s,b,{style:h,explode:a}));continue}if(typeof b=="object"){t=t.replace(i,j(s,b,{style:h,explode:a}));continue}if(h==="matrix"){t=t.replace(i,`;${H(s,b)}`);continue}t=t.replace(i,h==="label"?`.${encodeURIComponent(b)}`:encodeURIComponent(b))}return t}function we(e,r){var t,n;return e instanceof FormData?e:r&&(r.get instanceof Function?(t=r.get("Content-Type"))!=null?t:r.get("content-type"):(n=r["Content-Type"])!=null?n:r["content-type"])==="application/x-www-form-urlencoded"?new URLSearchParams(e).toString():JSON.stringify(e)}function pe(e,r){var i,s;let t=`${r.baseUrl}${e}`;(i=r.params)!=null&&i.path&&(t=be(t,r.params.path));let n=r.querySerializer((s=r.params.query)!=null?s:{});return n.startsWith("?")&&(n=n.substring(1)),n&&(t+=`?${n}`),t}function se(...e){const r=new Headers;for(const t of e){if(!t||typeof t!="object")continue;const n=t instanceof Headers?t.entries():Object.entries(t);for(const[i,s]of n)if(s===null)r.delete(i);else if(Array.isArray(s))for(const a of s)r.append(i,a);else s!==void 0&&r.set(i,s)}return r}function ne(e){return e.endsWith("/")?e.substring(0,e.length-1):e}const ie=(e,r,t)=>{try{const n=`${r}_${e}`,i=localStorage.getItem(n);if(!i)return null;const{data:s,timestamp:a}=JSON.parse(i);return t&&Date.now()-a>t?(localStorage.removeItem(n),null):s}catch(n){return null}},Y=(e,r,t)=>{try{const n=`${t}_${e}`,i={data:r,timestamp:Date.now()};localStorage.setItem(n,JSON.stringify(i))}catch(n){console.warn("Failed to cache dismissible item:",n)}},oe=(e,r)=>{try{const t=`${r}_${e}`;localStorage.removeItem(t)}catch(t){console.warn("Failed to remove cached dismissible item:",t)}},Z=o.createContext(null),ae=()=>{const e=o.useContext(Z);if(!e)throw new Error("useDismissibleContext must be used within a DismissibleProvider");return e},ge="dismissible",ce=(e,r={})=>{const{initialData:t,enableCache:n=!0,cachePrefix:i=ge,cacheExpiration:s}=r,a=ae(),{userId:h}=a,b=o.useMemo(()=>X({baseUrl:a.baseUrl,headers:{}}),[a.baseUrl]),m=o.useMemo(()=>`${h}-${e}`,[h,e]),C=o.useRef({enableCache:n,cachePrefix:i,cacheExpiration:s}),I=o.useRef(e),u=o.useRef(m),l=o.useRef(null),[A,$]=o.useState(!1),[L,D]=o.useState(),[S,U]=o.useState(()=>{if(t)return t;if(n){const f=ie(m,i,s);if(f)return f}}),T=o.useCallback(()=>q(null,null,function*(){var p;if(n){const y=ie(m,i,s);if(y!=null&&y.dismissedAt){U(y),$(!1);return}}(p=l.current)==null||p.abort();const f=new AbortController;l.current=f,$(!0),D(void 0);try{const y=yield a.getAuthHeaders(),{data:k,error:N}=yield b.GET("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:h,itemId:e}},headers:y,signal:f.signal});if(N||!k)throw new Error("Failed to fetch dismissible item");U(k.data),n&&Y(m,k.data,i)}catch(y){if(y instanceof Error&&y.name==="AbortError")return;D(y instanceof Error?y:new Error("Unknown error occurred"))}finally{$(!1)}}),[e,h,m,n,i,s,b,a]);o.useEffect(()=>{const f=I.current!==e,p=u.current!==m;f||p?(I.current=e,u.current=m,T()):t||T()},[e,m,t,T]),o.useEffect(()=>()=>{var f;(f=l.current)==null||f.abort()},[]),o.useEffect(()=>{const f=C.current;(f.enableCache!==n||f.cachePrefix!==i||f.cacheExpiration!==s)&&(f.cachePrefix!==i&&oe(m,f.cachePrefix),!n&&f.enableCache&&oe(m,f.cachePrefix),C.current={enableCache:n,cachePrefix:i,cacheExpiration:s},T())},[n,i,s,m,T]);const W=o.useCallback(()=>q(null,null,function*(){D(void 0);try{const f=yield a.getAuthHeaders(),{data:p,error:y}=yield b.DELETE("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:h,itemId:e}},headers:f});if(y||!p)throw new Error("Failed to dismiss item");U(p.data),n&&Y(m,p.data,i)}catch(f){throw D(f instanceof Error?f:new Error("Failed to dismiss item")),f}}),[e,h,m,n,i,b,a]),_=o.useCallback(()=>q(null,null,function*(){D(void 0);try{const f=yield a.getAuthHeaders(),{data:p,error:y}=yield b.POST("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:h,itemId:e}},headers:f});if(y||!p)throw new Error("Failed to restore item");U(p.data),n&&Y(m,p.data,i)}catch(f){throw D(f instanceof Error?f:new Error("Failed to restore item")),f}}),[e,h,m,n,i,b,a]);return{dismissedAt:S==null?void 0:S.dismissedAt,dismiss:W,restore:_,isLoading:A,error:L,item:S}},ve=()=>d.jsx("div",{className:"dismissible-loading","aria-live":"polite",children:"Loading..."}),Ee=()=>d.jsx("div",{className:"dismissible-error",role:"alert",children:"Unable to load content. Please try again later."}),Ce=({onDismiss:e,ariaLabel:r})=>d.jsx("button",{className:"dismissible-button",onClick:e,"aria-label":r,type:"button",children:"×"}),Re=({itemId:e,children:r,onDismiss:t,LoadingComponent:n=ve,ErrorComponent:i=Ee,DismissButtonComponent:s=Ce,enableCache:a,cachePrefix:h,cacheExpiration:b,ignoreErrors:m=!1})=>{const{dismissedAt:C,isLoading:I,error:u,dismiss:l}=ce(e,{enableCache:a,cachePrefix:h,cacheExpiration:b}),[A,$]=o.useState(!1),[L,D]=o.useState(e);e!==L&&(D(e),$(!1));const S=()=>q(null,null,function*(){$(!0);try{yield l(),t==null||t()}catch(U){$(!1)}});return I&&n?d.jsx(n,{itemId:e}):I&&!n?null:u&&i&&!m?d.jsx(i,{itemId:e,error:u}):C||A?null:d.jsxs("div",{className:"dismissible-container",children:[d.jsx("div",{className:"dismissible-content",children:r}),s?d.jsx(s,{onDismiss:S,ariaLabel:`Dismiss ${e}`}):null]})},le=e=>q(null,null,function*(){if(typeof e=="function")try{const r=e();return yield Promise.resolve(r)}catch(r){console.warn("Failed to resolve JWT from function:",r);return}return e}),ue=e=>q(null,null,function*(){const r=yield le(e);return r?{Authorization:`Bearer ${r}`}:{}}),Se=e=>{try{const r=new URL(e),t=r.hostname==="localhost"||r.hostname==="127.0.0.1"||r.hostname==="[::1]",n=r.protocol==="https:";return{isSecure:n||t,isLocalhost:t,isHttps:n}}catch(r){return{isSecure:!1,isLocalhost:!1,isHttps:!1}}},xe=({userId:e,jwt:r,baseUrl:t,children:n})=>{const{isSecure:i}=Se(t);i||console.warn(`[dismissible] Insecure baseUrl "${t}". Use https:// in production (or localhost for development). JWT tokens may be exposed over insecure connections.`);const s=o.useMemo(()=>({userId:e,jwt:r,baseUrl:t,getAuthHeaders:()=>q(null,null,function*(){return yield ue(r)})}),[e,r,t]);return d.jsx(Z.Provider,{value:s,children:n})};c.Dismissible=Re,c.DismissibleContext=Z,c.DismissibleProvider=xe,c.getAuthHeaders=ue,c.resolveJwt=le,c.useDismissibleContext=ae,c.useDismissibleItem=ce,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(l,h){typeof exports=="object"&&typeof module!="undefined"?h(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],h):(l=typeof globalThis!="undefined"?globalThis:l||self,h(l.DismissibleClient={},l.React.jsxRuntime,l.React))})(this,(function(l,h,a){"use strict";var $e=Object.defineProperty,Te=Object.defineProperties;var Ie=Object.getOwnPropertyDescriptors;var X=Object.getOwnPropertySymbols;var de=Object.prototype.hasOwnProperty,he=Object.prototype.propertyIsEnumerable;var fe=(l,h,a)=>h in l?$e(l,h,{enumerable:!0,configurable:!0,writable:!0,value:a}):l[h]=a,w=(l,h)=>{for(var a in h||(h={}))de.call(h,a)&&fe(l,a,h[a]);if(X)for(var a of X(h))he.call(h,a)&&fe(l,a,h[a]);return l},A=(l,h)=>Te(l,Ie(h));var ee=(l,h)=>{var a={};for(var R in l)de.call(l,R)&&h.indexOf(R)<0&&(a[R]=l[R]);if(l!=null&&X)for(var R of X(l))h.indexOf(R)<0&&he.call(l,R)&&(a[R]=l[R]);return a};var j=(l,h,a)=>new Promise((R,z)=>{var _=x=>{try{F(a.next(x))}catch(L){z(L)}},J=x=>{try{F(a.throw(x))}catch(L){z(L)}},F=x=>x.done?R(x.value):Promise.resolve(x.value).then(_,J);F((a=a.apply(l,h)).next())});const R=(t,r,e)=>{try{const s=`${r}_${t}`,i=localStorage.getItem(s);if(!i)return null;const{data:n,timestamp:o}=JSON.parse(i);return e&&Date.now()-o>e?(localStorage.removeItem(s),null):n}catch(s){return null}},z=(t,r,e)=>{try{const s=`${e}_${t}`,i={data:r,timestamp:Date.now()};localStorage.setItem(s,JSON.stringify(i))}catch(s){console.warn("Failed to cache dismissible item:",s)}},_=(t,r)=>{try{const e=`${r}_${t}`;localStorage.removeItem(e)}catch(e){console.warn("Failed to remove cached dismissible item:",e)}},J=a.createContext(null),F=()=>{const t=a.useContext(J);if(!t)throw new Error("useDismissibleContext must be used within a DismissibleProvider");return t},x="dismissible",L=(t,r={})=>{const{initialData:e,enableCache:s=!0,cachePrefix:i=x,cacheExpiration:n}=r,o=F(),{userId:c,client:y,baseUrl:S}=o,m=`${c}-${t}`,I=a.useRef({enableCache:s,cachePrefix:i,cacheExpiration:n}),d=a.useRef(t),f=a.useRef(m),D=a.useRef(null),[H,q]=a.useState(!1),[N,v]=a.useState(),[$,T]=a.useState(()=>{if(e)return e;if(s){const u=R(m,i,n);if(u)return u}}),U=a.useCallback(()=>j(null,null,function*(){var C;if(s){const p=R(m,i,n);if(p!=null&&p.dismissedAt){T(p),q(!1);return}}(C=D.current)==null||C.abort();const u=new AbortController;D.current=u,q(!0),v(void 0);try{const p=yield o.getAuthHeaders(),M=yield y.getOrCreate({userId:c,itemId:t,baseUrl:S,authHeaders:p,signal:u.signal});T(M),s&&z(m,M,i)}catch(p){if(p instanceof Error&&p.name==="AbortError")return;v(p instanceof Error?p:new Error("Unknown error occurred"))}finally{q(!1)}}),[t,c,m,s,i,n,y,S,o]);a.useEffect(()=>{const u=d.current!==t,C=f.current!==m;u||C?(d.current=t,f.current=m,U()):e||U()},[t,m,e,U]),a.useEffect(()=>()=>{var u;(u=D.current)==null||u.abort()},[]),a.useEffect(()=>{const u=I.current;(u.enableCache!==s||u.cachePrefix!==i||u.cacheExpiration!==n)&&(u.cachePrefix!==i&&_(m,u.cachePrefix),!s&&u.enableCache&&_(m,u.cachePrefix),I.current={enableCache:s,cachePrefix:i,cacheExpiration:n},U())},[s,i,n,m,U]);const G=a.useCallback(()=>j(null,null,function*(){v(void 0);try{const u=yield o.getAuthHeaders(),C=yield y.dismiss({userId:c,itemId:t,baseUrl:S,authHeaders:u});T(C),s&&z(m,C,i)}catch(u){throw v(u instanceof Error?u:new Error("Failed to dismiss item")),u}}),[t,c,m,s,i,y,S,o]),Y=a.useCallback(()=>j(null,null,function*(){v(void 0);try{const u=yield o.getAuthHeaders(),C=yield y.restore({userId:c,itemId:t,baseUrl:S,authHeaders:u});T(C),s&&z(m,C,i)}catch(u){throw v(u instanceof Error?u:new Error("Failed to restore item")),u}}),[t,c,m,s,i,y,S,o]);return{dismissedAt:$==null?void 0:$.dismissedAt,dismiss:G,restore:Y,isLoading:H,error:N,item:$}},me=()=>h.jsx("div",{className:"dismissible-loading","aria-live":"polite",children:"Loading..."}),ye=()=>h.jsx("div",{className:"dismissible-error",role:"alert",children:"Unable to load content. Please try again later."}),be=({onDismiss:t,ariaLabel:r})=>h.jsx("button",{className:"dismissible-button",onClick:t,"aria-label":r,type:"button",children:"×"}),we=({itemId:t,children:r,onDismiss:e,LoadingComponent:s=me,ErrorComponent:i=ye,DismissButtonComponent:n=be,enableCache:o,cachePrefix:c,cacheExpiration:y,ignoreErrors:S=!1})=>{const{dismissedAt:m,isLoading:I,error:d,dismiss:f}=L(t,{enableCache:o,cachePrefix:c,cacheExpiration:y}),[D,H]=a.useState(!1),[q,N]=a.useState(t);t!==q&&(N(t),H(!1));const v=()=>j(null,null,function*(){H(!0);try{yield f(),e==null||e()}catch($){H(!1)}});return I&&s?h.jsx(s,{itemId:t}):I&&!s?null:d&&i&&!S?h.jsx(i,{itemId:t,error:d}):m||D?null:h.jsxs("div",{className:"dismissible-container",children:[h.jsx("div",{className:"dismissible-content",children:r}),n?h.jsx(n,{onDismiss:v,ariaLabel:`Dismiss ${t}`}):null]})},te=t=>j(null,null,function*(){if(typeof t=="function")try{const r=t();return yield Promise.resolve(r)}catch(r){console.warn("Failed to resolve JWT from function:",r);return}return t}),re=t=>j(null,null,function*(){const r=yield te(t);return r?{Authorization:`Bearer ${r}`}:{}}),pe=/\{[^{}]+\}/g,ge=()=>{var t,r;return typeof process=="object"&&Number.parseInt((r=(t=process==null?void 0:process.versions)==null?void 0:t.node)==null?void 0:r.substring(0,2))>=18&&process.versions.undici};function ve(){return Math.random().toString(36).slice(2,11)}function Ce(t){let I=w({},t),{baseUrl:r="",Request:e=globalThis.Request,fetch:s=globalThis.fetch,querySerializer:i,bodySerializer:n,headers:o,requestInitExt:c=void 0}=I,y=ee(I,["baseUrl","Request","fetch","querySerializer","bodySerializer","headers","requestInitExt"]);c=ge()?c:void 0,r=ae(r);const S=[];function m(d,f){return j(this,null,function*(){var ue;const le=f||{},{baseUrl:D,fetch:H=s,Request:q=e,headers:N,params:v={},parseAs:$="json",querySerializer:T,bodySerializer:U=n!=null?n:Re,body:G,middleware:Y=[]}=le,u=ee(le,["baseUrl","fetch","Request","headers","params","parseAs","querySerializer","bodySerializer","body","middleware"]);let C=r;D&&(C=(ue=ae(D))!=null?ue:r);let p=typeof i=="function"?i:ie(i);T&&(p=typeof T=="function"?T:ie(w(w({},typeof i=="object"?i:{}),T)));const M=G===void 0?void 0:U(G,oe(o,N,v.header)),je=oe(M===void 0||M instanceof FormData?{}:{"Content-Type":"application/json"},o,N,v.header),P=[...S,...Y],xe=A(w(w({redirect:"follow"},y),u),{body:M,headers:je});let K,Q,O=new q(Se(d,{baseUrl:C,params:v,querySerializer:p}),xe),b;for(const E in u)E in O||(O[E]=u[E]);if(P.length){K=ve(),Q=Object.freeze({baseUrl:C,fetch:H,parseAs:$,querySerializer:p,bodySerializer:U});for(const E of P)if(E&&typeof E=="object"&&typeof E.onRequest=="function"){const g=yield E.onRequest({request:O,schemaPath:d,params:v,options:Q,id:K});if(g)if(g instanceof q)O=g;else if(g instanceof Response){b=g;break}else throw new Error("onRequest: must return new Request() or Response() when modifying the request")}}if(!b){try{b=yield H(O,c)}catch(E){let g=E;if(P.length)for(let k=P.length-1;k>=0;k--){const V=P[k];if(V&&typeof V=="object"&&typeof V.onError=="function"){const W=yield V.onError({request:O,error:g,schemaPath:d,params:v,options:Q,id:K});if(W){if(W instanceof Response){g=void 0,b=W;break}if(W instanceof Error){g=W;continue}throw new Error("onError: must return new Response() or instance of Error")}}}if(g)throw g}if(P.length)for(let E=P.length-1;E>=0;E--){const g=P[E];if(g&&typeof g=="object"&&typeof g.onResponse=="function"){const k=yield g.onResponse({request:O,response:b,schemaPath:d,params:v,options:Q,id:K});if(k){if(!(k instanceof Response))throw new Error("onResponse: must return new Response() when modifying the response");b=k}}}}if(b.status===204||O.method==="HEAD"||b.headers.get("Content-Length")==="0")return b.ok?{data:void 0,response:b}:{error:void 0,response:b};if(b.ok)return $==="stream"?{data:b.body,response:b}:{data:yield b[$](),response:b};let Z=yield b.text();try{Z=JSON.parse(Z)}catch(E){}return{error:Z,response:b}})}return{request(d,f,D){return m(f,A(w({},D),{method:d.toUpperCase()}))},GET(d,f){return m(d,A(w({},f),{method:"GET"}))},PUT(d,f){return m(d,A(w({},f),{method:"PUT"}))},POST(d,f){return m(d,A(w({},f),{method:"POST"}))},DELETE(d,f){return m(d,A(w({},f),{method:"DELETE"}))},OPTIONS(d,f){return m(d,A(w({},f),{method:"OPTIONS"}))},HEAD(d,f){return m(d,A(w({},f),{method:"HEAD"}))},PATCH(d,f){return m(d,A(w({},f),{method:"PATCH"}))},TRACE(d,f){return m(d,A(w({},f),{method:"TRACE"}))},use(...d){for(const f of d)if(f){if(typeof f!="object"||!("onRequest"in f||"onResponse"in f||"onError"in f))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");S.push(f)}},eject(...d){for(const f of d){const D=S.indexOf(f);D!==-1&&S.splice(D,1)}}}}function B(t,r,e){if(r==null)return"";if(typeof r=="object")throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${t}=${(e==null?void 0:e.allowReserved)===!0?r:encodeURIComponent(r)}`}function se(t,r,e){if(!r||typeof r!="object")return"";const s=[],i={simple:",",label:".",matrix:";"}[e.style]||"&";if(e.style!=="deepObject"&&e.explode===!1){for(const c in r)s.push(c,e.allowReserved===!0?r[c]:encodeURIComponent(r[c]));const o=s.join(",");switch(e.style){case"form":return`${t}=${o}`;case"label":return`.${o}`;case"matrix":return`;${t}=${o}`;default:return o}}for(const o in r){const c=e.style==="deepObject"?`${t}[${o}]`:o;s.push(B(c,r[o],e))}const n=s.join(i);return e.style==="label"||e.style==="matrix"?`${i}${n}`:n}function ne(t,r,e){if(!Array.isArray(r))return"";if(e.explode===!1){const n={form:",",spaceDelimited:"%20",pipeDelimited:"|"}[e.style]||",",o=(e.allowReserved===!0?r:r.map(c=>encodeURIComponent(c))).join(n);switch(e.style){case"simple":return o;case"label":return`.${o}`;case"matrix":return`;${t}=${o}`;default:return`${t}=${o}`}}const s={simple:",",label:".",matrix:";"}[e.style]||"&",i=[];for(const n of r)e.style==="simple"||e.style==="label"?i.push(e.allowReserved===!0?n:encodeURIComponent(n)):i.push(B(t,n,e));return e.style==="label"||e.style==="matrix"?`${s}${i.join(s)}`:i.join(s)}function ie(t){return function(e){const s=[];if(e&&typeof e=="object")for(const i in e){const n=e[i];if(n!=null){if(Array.isArray(n)){if(n.length===0)continue;s.push(ne(i,n,A(w({style:"form",explode:!0},t==null?void 0:t.array),{allowReserved:(t==null?void 0:t.allowReserved)||!1})));continue}if(typeof n=="object"){s.push(se(i,n,A(w({style:"deepObject",explode:!0},t==null?void 0:t.object),{allowReserved:(t==null?void 0:t.allowReserved)||!1})));continue}s.push(B(i,n,t))}}return s.join("&")}}function Ee(t,r){var s;let e=t;for(const i of(s=t.match(pe))!=null?s:[]){let n=i.substring(1,i.length-1),o=!1,c="simple";if(n.endsWith("*")&&(o=!0,n=n.substring(0,n.length-1)),n.startsWith(".")?(c="label",n=n.substring(1)):n.startsWith(";")&&(c="matrix",n=n.substring(1)),!r||r[n]===void 0||r[n]===null)continue;const y=r[n];if(Array.isArray(y)){e=e.replace(i,ne(n,y,{style:c,explode:o}));continue}if(typeof y=="object"){e=e.replace(i,se(n,y,{style:c,explode:o}));continue}if(c==="matrix"){e=e.replace(i,`;${B(n,y)}`);continue}e=e.replace(i,c==="label"?`.${encodeURIComponent(y)}`:encodeURIComponent(y))}return e}function Re(t,r){var e,s;return t instanceof FormData?t:r&&(r.get instanceof Function?(e=r.get("Content-Type"))!=null?e:r.get("content-type"):(s=r["Content-Type"])!=null?s:r["content-type"])==="application/x-www-form-urlencoded"?new URLSearchParams(t).toString():JSON.stringify(t)}function Se(t,r){var i,n;let e=`${r.baseUrl}${t}`;(i=r.params)!=null&&i.path&&(e=Ee(e,r.params.path));let s=r.querySerializer((n=r.params.query)!=null?n:{});return s.startsWith("?")&&(s=s.substring(1)),s&&(e+=`?${s}`),e}function oe(...t){const r=new Headers;for(const e of t){if(!e||typeof e!="object")continue;const s=e instanceof Headers?e.entries():Object.entries(e);for(const[i,n]of s)if(n===null)r.delete(i);else if(Array.isArray(n))for(const o of n)r.append(i,o);else n!==void 0&&r.set(i,n)}return r}function ae(t){return t.endsWith("/")?t.substring(0,t.length-1):t}const ce=t=>{const r=Ce({baseUrl:t,headers:{}});return{getOrCreate:e=>j(null,null,function*(){const{userId:s,itemId:i,authHeaders:n,signal:o}=e,{data:c,error:y}=yield r.GET("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:s,itemId:i}},headers:n,signal:o});if(y||!c)throw new Error("Failed to fetch dismissible item");return c.data}),dismiss:e=>j(null,null,function*(){const{userId:s,itemId:i,authHeaders:n}=e,{data:o,error:c}=yield r.DELETE("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:s,itemId:i}},headers:n});if(c||!o)throw new Error("Failed to dismiss item");return o.data}),restore:e=>j(null,null,function*(){const{userId:s,itemId:i,authHeaders:n}=e,{data:o,error:c}=yield r.POST("/v1/users/{userId}/items/{itemId}",{params:{path:{userId:s,itemId:i}},headers:n});if(c||!o)throw new Error("Failed to restore item");return o.data})}},De=t=>{try{const r=new URL(t),e=r.hostname==="localhost"||r.hostname==="127.0.0.1"||r.hostname==="[::1]",s=r.protocol==="https:";return{isSecure:s||e,isLocalhost:e,isHttps:s}}catch(r){return{isSecure:!1,isLocalhost:!1,isHttps:!1}}},Ae=({userId:t,jwt:r,baseUrl:e,client:s,children:i})=>{const{isSecure:n}=De(e);n||console.warn(`[dismissible] Insecure baseUrl "${e}". Use https:// in production (or localhost for development). JWT tokens may be exposed over insecure connections.`);const o=a.useMemo(()=>s!=null?s:ce(e),[s,e]),c=a.useMemo(()=>({userId:t,jwt:r,baseUrl:e,getAuthHeaders:()=>j(null,null,function*(){return yield re(r)}),client:o}),[t,r,e,o]);return h.jsx(J.Provider,{value:c,children:i})};l.Dismissible=we,l.DismissibleContext=J,l.DismissibleProvider=Ae,l.createDefaultClient=ce,l.getAuthHeaders=re,l.resolveJwt=te,l.useDismissibleContext=F,l.useDismissibleItem=L,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
@@ -1,5 +1,4 @@
1
- import { components } from '../generated/contract';
2
- type DismissibleItem = components["schemas"]["DismissibleItemResponseDto"];
1
+ import { DismissibleItem } from '../types/dismissible.types';
3
2
  export type IDismissibleItem = DismissibleItem;
4
3
  export interface UseDismissibleItemOptions {
5
4
  /** Initial data for the dismissible item */
@@ -32,4 +31,3 @@ export interface UseDismissibleItemResponse {
32
31
  * @returns Object with dismissedAt, dismiss and restore functions
33
32
  */
34
33
  export declare const useDismissibleItem: (itemId: string, options?: UseDismissibleItemOptions) => UseDismissibleItemResponse;
35
- export {};
package/dist/root.d.ts CHANGED
@@ -4,3 +4,4 @@ export * from './contexts/DismissibleContext';
4
4
  export * from './contexts/DismissibleProvider';
5
5
  export * from './types/dismissible.types';
6
6
  export * from './utils/auth.utils';
7
+ export * from './clients/defaultClient';
@@ -5,6 +5,83 @@
5
5
  * JWT token can be either a static string, a function that returns a string, or an async function that returns a string
6
6
  */
7
7
  export type JwtToken = string | (() => string) | (() => Promise<string>);
8
+ /**
9
+ * Authentication headers type
10
+ */
11
+ export interface AuthHeaders {
12
+ Authorization?: string;
13
+ [key: string]: string | undefined;
14
+ }
15
+ /**
16
+ * Dismissible item data returned from the API
17
+ */
18
+ export interface DismissibleItem {
19
+ /** Unique identifier for the item */
20
+ itemId: string;
21
+ /** User identifier who created the item */
22
+ userId: string;
23
+ /** When the item was created (ISO 8601) */
24
+ createdAt: string;
25
+ /** When the item was dismissed (ISO 8601), undefined if not dismissed */
26
+ dismissedAt?: string;
27
+ }
28
+ /**
29
+ * Base parameters shared by all client methods
30
+ */
31
+ export interface BaseDismissibleClientParams {
32
+ /** User ID for the current user */
33
+ userId: string;
34
+ /** The dismissible item ID */
35
+ itemId: string;
36
+ /** Base URL for API requests */
37
+ baseUrl: string;
38
+ /** Authentication headers */
39
+ authHeaders: AuthHeaders;
40
+ }
41
+ /**
42
+ * Parameters for the getOrCreate client method
43
+ */
44
+ export interface GetOrCreateClientParams extends BaseDismissibleClientParams {
45
+ /** AbortSignal for request cancellation */
46
+ signal?: AbortSignal;
47
+ }
48
+ /**
49
+ * Parameters for the dismiss client method
50
+ */
51
+ export type DismissClientParams = BaseDismissibleClientParams;
52
+ /**
53
+ * Parameters for the restore client method
54
+ */
55
+ export type RestoreClientParams = BaseDismissibleClientParams;
56
+ /**
57
+ * Interface for custom HTTP clients
58
+ *
59
+ * Users can implement this interface to provide their own HTTP client
60
+ * with custom headers, tracking, interceptors, etc.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const myClient: DismissibleClient = {
65
+ * getOrCreate: async ({ userId, itemId, baseUrl, authHeaders, signal }) => {
66
+ * const res = await axios.get(`${baseUrl}/v1/users/${userId}/items/${itemId}`, {
67
+ * headers: { ...authHeaders, 'X-Correlation-ID': uuid() },
68
+ * signal
69
+ * });
70
+ * return res.data.data;
71
+ * },
72
+ * dismiss: async ({ userId, itemId, baseUrl, authHeaders }) => { ... },
73
+ * restore: async ({ userId, itemId, baseUrl, authHeaders }) => { ... },
74
+ * };
75
+ * ```
76
+ */
77
+ export interface DismissibleClient {
78
+ /** Get or create a dismissible item */
79
+ getOrCreate: (params: GetOrCreateClientParams) => Promise<DismissibleItem>;
80
+ /** Dismiss an item */
81
+ dismiss: (params: DismissClientParams) => Promise<DismissibleItem>;
82
+ /** Restore a dismissed item */
83
+ restore: (params: RestoreClientParams) => Promise<DismissibleItem>;
84
+ }
8
85
  /**
9
86
  * Configuration options for the DismissibleProvider
10
87
  */
@@ -15,6 +92,8 @@ export interface DismissibleProviderProps {
15
92
  jwt?: JwtToken;
16
93
  /** Base URL for API requests */
17
94
  baseUrl: string;
95
+ /** Custom HTTP client implementation (optional - uses default if not provided) */
96
+ client?: DismissibleClient;
18
97
  /** Child components */
19
98
  children: React.ReactNode;
20
99
  }
@@ -30,11 +109,6 @@ export interface DismissibleContextValue {
30
109
  baseUrl: string;
31
110
  /** Helper function to get authentication headers */
32
111
  getAuthHeaders: () => Promise<AuthHeaders>;
33
- }
34
- /**
35
- * Authentication headers type
36
- */
37
- export interface AuthHeaders {
38
- Authorization?: string;
39
- [key: string]: string | undefined;
112
+ /** The HTTP client to use for API requests */
113
+ client: DismissibleClient;
40
114
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Checks if a URL uses secure transport (https or localhost)
3
+ * @returns Object with isSecure flag and parsed URL info
4
+ */
5
+ export declare const checkUrlSecurity: (url: string) => {
6
+ isSecure: boolean;
7
+ isLocalhost: boolean;
8
+ isHttps: boolean;
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dismissible/react-client",
3
- "version": "1.0.0-canary.4.a9fb4a5",
3
+ "version": "2.0.0-canary.5.88c27fb",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",