palbase 0.3.1 → 0.3.3
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/LICENSE +11 -5
- package/dist/ai/index.js +2 -2
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +3 -3
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/{NTMO2LFH.js → 47V66C2X.js} +2 -2
- package/dist/chunks/{L6GKX3XI.js → 4AQYBTIN.js} +2 -2
- package/dist/chunks/{XNRYSI7A.js → 4YD2XCGF.js} +1 -1
- package/dist/chunks/{XOGEEZNP.js → CJCMQ73A.js} +2 -2
- package/dist/chunks/{INXQWVHU.js → CZQ7KIRM.js} +2 -2
- package/dist/chunks/{TV7W53F2.js → IXHR57QC.js} +2 -2
- package/dist/chunks/{4UPL27ED.js → M5B52IE6.js} +1 -1
- package/dist/chunks/{6FQGUDBD.js → NK54UVDI.js} +2 -2
- package/dist/chunks/{4MOCDBZP.js → OKZJIY6F.js} +1 -1
- package/dist/chunks/{JF7KZUPL.js → P5JIZEPB.js} +2 -2
- package/dist/chunks/PB7UKHCY.js +2 -0
- package/dist/chunks/{VTNEPJRV.js → PRM2UXWG.js} +1 -1
- package/dist/chunks/TJ5SQTW5.js +92 -0
- package/dist/chunks/{MJPUCGXY.js → UXRIXHHY.js} +2 -2
- package/dist/chunks/{4K4MKD2J.js → YWOS5WH2.js} +2 -2
- package/dist/cli.js +153 -132
- package/dist/refuse/ai.js +1 -1
- package/dist/refuse/backend.js +1 -1
- package/dist/refuse/server.js +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/testing.js +2 -2
- package/dist/web/index.js +2 -2
- package/dist/web/palbe.js +2 -2
- package/dist/web/paywall.js +2 -2
- package/dist/web/vite.js +2 -2
- package/package.json +6 -6
- package/types/internal/src/modules/purchases.d.ts +77 -4
- package/types/internal/src/modules/storage.d.ts +3 -2
- package/types/server/src/auth/jwt.d.ts +4 -1
- package/dist/chunks/2YUVLZLK.js +0 -87
- package/dist/chunks/FVIHTHHV.js +0 -2
package/dist/refuse/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
2
|
throw new Error("palbase/ai is for servers: it speaks with the project secret key, which never goes into a browser or a mobile app \u2014 call your backend, and let it ask the model");
|
package/dist/refuse/backend.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
2
|
throw new Error("palbase/backend is a server framework: it runs on your backend, never in a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs)");
|
package/dist/refuse/server.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
2
|
throw new Error("palbase/server is for servers: its secret key never goes into a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs) with the publishable key");
|
package/dist/server/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import{a as c,b as d,c as e,d as f,e as g,f as h,g as i,h as j,i as k,j as l,k as m,l as n,m as o,n as p,o as q,p as r,q as s,r as t}from"../chunks/
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a as c,b as d,c as e,d as f,e as g,f as h,g as i,h as j,i as k,j as l,k as m,l as n,m as o,n as p,o as q,p as r,q as s,r as t}from"../chunks/PB7UKHCY.js";import"../chunks/4YD2XCGF.js";import{m as b}from"../chunks/NK54UVDI.js";import"../chunks/IXHR57QC.js";import{b as a}from"../chunks/UXRIXHHY.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";export{j as AuthUnavailable,b as EVENT_TYPES,a as PalbaseError,o as ReservationSettled,i as TokenError,l as TokenVerifier,d as WebhookSignatureError,c as createServer,n as isEntitled,t as loadSecrets,q as pages,s as platformOwn,r as processOwn,m as requestAddress,k as sessionStanding,g as signatureHeader,f as verifySignature,e as verifyWebhook,h as verifyWebhookRequest,p as withReservation};
|
package/dist/server/testing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import{a,b,c,d}from"../chunks/
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a,b,c,d}from"../chunks/YWOS5WH2.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";export{a as TestApiError,d as api,b as createTestApi,c as testRun};
|
package/dist/web/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import{a as Z,b as ee,e as te,f as F,g as B}from"../chunks/L6GKX3XI.js";import{u as $}from"../chunks/2YUVLZLK.js";import{b as M,c as y,h as D}from"../chunks/6FQGUDBD.js";import{a as q,b as P}from"../chunks/TV7W53F2.js";import{b as S,d as k}from"../chunks/MJPUCGXY.js";import"../chunks/4MOCDBZP.js";import"../chunks/VTNEPJRV.js";var T=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,r){this.api=y.client(e),this.open=y.client(t),this.session=s,this.credentials=r;let i=this.api,a=this.open;this.mfa={challenge:async(o,c,l)=>this.signedIn((await a.mfaChallenge({body:{mfa_token:o,type:c,code:l}})).data),recovery:async(o,c)=>this.signedIn((await a.mfaRecovery({body:{mfa_token:o,code:c}})).data),sendSmsCode:async o=>{await a.mfaSmsChallenge({body:{mfa_token:o}})},sendEmailCode:async o=>{await a.mfaEmailChallenge({body:{mfa_token:o}})},enrollTotp:async()=>{let o=(await i.mfaEnroll({body:{type:"totp"}})).data;return{enrollmentId:o.enrollment_id,secret:o.secret,otpUrl:o.otp_url,qrCode:o.qr_code,recoveryCodes:o.recovery_codes}},verifyTotp:async o=>{await i.mfaVerifyEnrollment({body:{code:o}})},enrollSms:async o=>(await i.mfaSmsEnroll({body:{phone:o}})).data,verifySms:async o=>{await i.mfaSmsVerifyEnrollment({body:{code:o}})},enrollEmail:async()=>{await i.mfaEmailEnroll()},factors:async()=>(await i.mfaListFactors()).data,removeFactor:async(o,c)=>{await i.mfaRemoveFactor({path:{id:o},body:{current_password:c}})},regenerateRecoveryCodes:async()=>(await i.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async o=>{let c=(await i.webauthnRegisterBegin({body:{name:o}})).data,l=await this.authenticator().create({publicKey:H(c.options.publicKey)});return(await i.webauthnRegisterFinish({body:G(l)})).data},signIn:async(o={})=>{let c=(await a.webauthnLoginBegin({body:o.userId?{user_id:o.userId}:{}})).data,l=await this.authenticator().get({publicKey:V(c.options.publicKey)}),u=await a.webauthnLoginFinish({query:o.userId?{user_id:o.userId}:void 0,body:J(l)});return this.signedIn(u.data)},signUp:async(o,c)=>{let l=(await a.webauthnSignupBegin({body:{identifier:o,user_name:c}})).data,u=await this.authenticator().create({publicKey:H(l.options.publicKey)});await a.webauthnSignupFinish({query:{user_id:l.user_id},body:G(u)});let d=(await a.webauthnLoginBegin({body:{user_id:l.user_id}})).data,w=await this.authenticator().get({publicKey:V(d.options.publicKey)});return this.signedIn((await a.webauthnLoginFinish({query:{user_id:l.user_id},body:J(w)})).data)},list:async()=>(await i.webauthnListCredentials()).data,remove:async o=>{await i.webauthnDeleteCredential({path:{id:o}})}},this.magicLink={send:async o=>{await a.magicLinkRequest({body:{email:o}})},verify:async o=>this.signedIn((await a.magicLinkVerify({body:{token:o}})).data)},this.phone={sendCode:async o=>(await a.requestPhoneOtp({body:{phone:o,channel:"sms"}})).data,verifyCode:async(o,c)=>this.signInResult((await a.verifyPhoneOtp({body:{phone:o,token:c}})).data)},this.password={requestReset:async o=>{await a.passwordResetRequest({body:{email:o}})},confirmReset:async(o,c)=>{await a.passwordResetConfirm({body:{token:o,new_password:c}})},change:async o=>(await i.passwordChange({body:o})).data,set:async o=>(await i.setPassword({body:o})).data},this.email={verify:async o=>{await a.verifyEmail({body:o})},resendVerification:async o=>(await a.resendVerification({body:{email:o}})).data},this.sessions={list:async()=>(await i.listSessions()).data,revoke:async o=>{await i.revokeSession({path:{id:o}})},revokeAll:async()=>{await i.revokeAllSessions()}}}onAuthStateChange(e){return this.session.onChange(e)}currentSession(){return this.session.session()}async signUp(e){let t=(await this.open.signup({body:e})).data;return t.access_token&&t.refresh_token&&t.expires_in!==void 0&&await this.session.set({access_token:t.access_token,refresh_token:t.refresh_token,expires_in:t.expires_in},"SIGNED_IN",t.user),t}async signIn(e,t){return this.signInResult((await this.open.login({body:{email:e,password:t}})).data)}async signOut(){try{await this.session.session()&&await this.api.logout()}finally{await this.session.clear("SIGNED_OUT")}}async getUser(){let e=this.session.snapshot(),t=(await this.api.getMe()).data;return await this.session.setUser(t,e),t}async refreshSession(){return this.session.refresh()}async deleteAccount(e){await this.api.deleteAccount(e===void 0?void 0:{body:{password:e}}),await this.session.clear("SIGNED_OUT")}async signInResult(e){return"mfa_required"in e&&e.mfa_required?{mfaRequired:{mfaToken:e.mfa_token,factors:e.factors}}:{user:await this.signedIn(e)}}async setSession(e){return this.signedIn(e)}async signedIn(e){let t=await this.session.set({access_token:e.access_token,refresh_token:e.refresh_token,expires_in:e.expires_in},"SIGNED_IN",e.user);if(e.user)return e.user;let s=(await this.api.verifyTokenUser()).data;return await this.session.setUser(s,t),s}authenticator(){if(!this.credentials)throw new Error("passkeys need navigator.credentials (or createClient({ webauthn }))");return this.credentials}},R=n=>{let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},p=n=>{if(!n)return;let e=n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},W=n=>Array.isArray(n)?n.map(e=>({...e,id:R(String(e.id))})):void 0;function H(n){let e=n.user;return{...n,challenge:R(String(n.challenge)),user:{...e,id:R(String(e.id))},excludeCredentials:W(n.excludeCredentials)}}function V(n){return{...n,challenge:R(String(n.challenge)),allowCredentials:W(n.allowCredentials)}}function G(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),attestationObject:p(t.attestationObject),transports:t.getTransports?.()}}}function J(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),authenticatorData:p(t.authenticatorData),signature:p(t.signature),userHandle:p(t.userHandle)}}}var f=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function N(){let n=null;return{load:()=>n,save:e=>{n=e},clear:()=>{n=null},shared:!1}}function L(n){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let r=s()?.getItem(n);return r==null?t?null:e:JSON.parse(r)}catch{return e}},save(r){e=r;try{let i=s();if(!i)throw new Error("no storage");i.setItem(n,JSON.stringify(r)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(n)}catch{}},watch(r){let i=globalThis;if(typeof i.addEventListener!="function")return()=>{};let a=o=>{(o.key===n||o.key===null)&&r()};return i.addEventListener("storage",a),()=>i.removeEventListener?.("storage",a)}}}function se(n){try{let e=n.split(".")[1]??"",t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),s=JSON.parse(t).sub;return typeof s=="string"?s:""}catch{return""}}var ne=6e4,ie=15e3;function re(n,e,t){let s=n?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var E=class{current=null;loaded;inflight=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;constructor(e,t,s,r={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=r.now??Date.now,this.lockName=r.lockName??"palbase.session.refresh",this.refreshTimeoutMs=r.refreshTimeoutMs??ie,this.loaded=Promise.resolve(e.load()).then(i=>{this.current=i}),e.watch?.(()=>{this.reconcile()})}async session(){return await this.loaded,this.current}snapshot(){return this.current}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async set(e,t,s){await this.loaded;let r=t==="TOKEN_REFRESHED"?this.current:null,i={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:this.now()+e.expires_in*1e3,userId:s?.id??r?.userId??se(e.access_token),user:s??r?.user};return this.current=i,await this.store.save(i),this.emit(t,i),i}async setUser(e,t){await this.loaded,!(!this.current||!t||this.current.userId!==t.userId)&&(this.current={...this.current,user:e},await this.store.save(this.current),this.emit("USER_UPDATED",this.current))}async clear(e){await this.loaded;let t=this.current;this.current=null,this.inflight=null;let s=await this.store.load();(!s||!t||s.userId===t.userId)&&await this.store.clear(),t&&this.emit(e,null)}async accessToken(){await this.loaded;let e=this.current;if(!e)return;let t=e.expiresAt-this.now();return t>ne?e.accessToken:t>0?(this.refresh().catch(()=>{}),e.accessToken):(await this.refresh()).accessToken}refresh(){if(this.inflight)return this.inflight;let e=re(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new f("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let r=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new f("the session changed while it was refreshed");return await this.set(r,"TOKEN_REFRESHED")}catch(r){throw this.isRejected(r)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED"),r}});return this.inflight=e,e.finally(()=>{this.inflight===e&&(this.inflight=null)}).catch(()=>{}),e}async adoptStored(e){let t=await this.store.load();if(!t)throw this.current=null,this.emit("SIGNED_OUT",null),new f("signed out in another tab");if(t.userId!==e.userId)throw this.current=t,this.emit("SIGNED_OUT",null),this.emit("SIGNED_IN",t),new f("another user signed in in another tab");if(t.refreshToken!==e.refreshToken&&t.expiresAt>=e.expiresAt)return this.current=t,this.emit("TOKEN_REFRESHED",t),t}async reconcile(){await this.loaded;let e=this.current,t=await this.store.load();if(!e){t&&(this.current=t,this.emit("SIGNED_IN",t));return}await this.adoptStored(e).catch(()=>{})}withTimeout(e){let t,s=new Promise((r,i)=>{t=setTimeout(()=>i(new Error(`the refresh did not answer within ${this.refreshTimeoutMs/1e3} s`)),this.refreshTimeoutMs)});return Promise.race([e,s]).finally(()=>clearTimeout(t))}emit(e,t){for(let s of this.listeners)try{s(e,t)}catch{}}};var _=class{state="closed";refusal;joinRef=null;listeners=new Map;closers=new Set;joinWaiters=[];name;socket;constructor(e,t){this.name=e,this.socket=t}get topic(){return`realtime:${this.name}`}join(){if(this.state==="joined")return Promise.resolve();let e=new Promise((t,s)=>this.joinWaiters.push({resolve:t,reject:s}));return this.state!=="joining"&&this.socket.join(this),e}leave(){this.socket.leave(this)}push(e,t){return this.socket.request(this,e,t)}on(e,t){let s=this.listeners.get(e);return s||this.listeners.set(e,s=new Set),s.add(t),()=>s.delete(t)}onClosed(e){return this.closers.add(e),()=>this.closers.delete(e)}deliver(e,t){for(let s of this.listeners.get(e)??[])try{s(t)}catch{}}settled(e,t){this.state=e?"joined":"refused",this.refusal=e?void 0:t;let s=this.joinWaiters.splice(0);for(let r of s)e?r.resolve():r.reject(new Error(`join ${this.name} refused: ${JSON.stringify(t)}`))}closed(e){this.state="closed",this.joinRef=null;let t=this.joinWaiters.splice(0);for(let s of t)s.reject(new Error(`join ${this.name}: ${e}`));for(let s of[...this.closers])try{s()}catch{}}},m=class{ws=null;opening=null;ref=0;channels=new Map;replies=new Map;heartbeat=null;heartbeatRef=null;reconnectTimer=null;attempts=0;closedByUs=!1;reconnects=0;opts;constructor(e){this.opts=e}channel(e){let t=this.channels.get(e);return t||this.channels.set(e,t=new _(e,this)),t}disconnect(){this.closedByUs=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.stopHeartbeat();let e=this.ws;this.ws=null,this.opening=null,e?.close(1e3);for(let[,t]of this.replies)t("error",{reason:"socket closed"});this.replies.clear();for(let t of this.channels.values())t.closed("the socket was closed")}async tokenChanged(){if(!this.ws||this.ws.readyState!==1)return;let e=await this.opts.accessToken();if(e)for(let t of this.channels.values())t.state==="joined"&&this.push(t.joinRef,t.topic,"access_token",{access_token:e})}join(e){e.state="joining",this.open().then(()=>this.sendJoin(e)).catch(t=>e.settled(!1,{reason:t instanceof Error?t.message:String(t)}))}leave(e){e.state==="joined"&&this.ws?.readyState===1&&this.push(e.joinRef,e.topic,"phx_leave",{}),e.state="closed",this.channels.delete(e.name)}async request(e,t,s){let r=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||r?.readyState!==1)return{status:"error",response:{reason:"not joined"}};let i=this.nextRef(),a=JSON.stringify([e.joinRef,i,e.topic,t,s]),o=this.awaitReply(i);return r.send(a),o}open(){if(this.ws?.readyState===1)return Promise.resolve();if(this.opening)return this.opening;this.closedByUs=!1;let e=this.opts.webSocket??globalThis.WebSocket,t=`${this.opts.baseUrl.replace(/^http/,"ws")}/realtime/v1/websocket?vsn=2.0.0&apikey=${encodeURIComponent(this.opts.publishableKey)}`,s=new Promise((r,i)=>{let a=new e(t);this.ws=a,a.onopen=()=>{this.attempts=0,this.startHeartbeat(),r()},a.onmessage=o=>this.receive(String(o.data)),a.onerror=()=>i(new Error("the realtime socket could not be opened")),a.onclose=()=>this.dropped(a)});return this.opening=s,s.finally(()=>{this.opening===s&&(this.opening=null)}).catch(()=>{}),s}dropped(e){if(this.ws!==e)return;this.ws=null,this.stopHeartbeat();for(let[,r]of this.replies)r("error",{reason:"socket closed"});this.replies.clear();for(let r of this.channels.values())r.state==="joined"&&(r.state="joining");if(this.closedByUs||![...this.channels.values()].some(r=>r.state==="joining"))return;let t=this.opts.backoff??[500,1e3,2e3,5e3,1e4,3e4],s=t[Math.min(this.attempts,t.length-1)]*(.8+Math.random()*.4);this.attempts++,this.reconnectTimer=I(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let r=[...this.channels.values()].filter(i=>i.state==="joining");this.open().then(()=>Promise.all(r.map(i=>this.sendJoin(i)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let r=this.awaitReply(s);this.push(s,e.topic,"phx_join",{access_token:t,config:{broadcast:{self:!1}}},s);let{status:i,response:a}=await r;if(this.channels.get(e.name)!==e||e.state!=="joining"){i==="ok"&&this.ws?.readyState===1&&this.push(s,e.topic,"phx_leave",{});return}e.settled(i==="ok",a)}awaitReply(e){return new Promise(t=>{let s=I(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(r,i)=>{clearTimeout(s),this.replies.delete(e),t({status:r,response:i})})})}receive(e){let t;try{t=JSON.parse(e)}catch{return}if(!Array.isArray(t)||t.length!==5||typeof t[2]!="string"||typeof t[3]!="string")return;let[,s,r,i,a]=t,o=typeof a=="object"&&a!==null?a:{};if(i==="phx_reply"&&typeof s=="string"){if(s===this.heartbeatRef){this.heartbeatRef=null;return}this.replies.get(s)?.(String(o.status),o.response??{});return}let c=[...this.channels.values()].find(l=>l.topic===r);if(c){if(i==="phx_close"){c.state="closed";return}if(i==="phx_error"){c.state="joining",I(setTimeout(()=>this.channels.get(c.name)===c&&c.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(c),1e3));return}c.deliver(i,o)}}push(e,t,s,r,i=this.nextRef()){this.ws?.send(JSON.stringify([e,i,t,s,r]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=I(setInterval(()=>{if(this.heartbeatRef!==null){this.heartbeatRef=null,this.ws?.close(4e3);return}this.heartbeatRef=this.nextRef(),this.push(null,"phoenix","heartbeat",{},this.heartbeatRef)},this.opts.heartbeatMs??25e3))}stopHeartbeat(){this.heartbeat&&clearInterval(this.heartbeat),this.heartbeat=null,this.heartbeatRef=null}};function I(n){return n.unref?.(),n}var ae=30*6e4,X=1e3,le=100,ce=60*1024,C=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function x(){try{return globalThis.localStorage}catch{return}}var g=class{api;closingApi;flushMs;flushAt;now;anonKey;sessionKey;events=[];samples=[];timer;memoryAnon;memorySession;appVersion;stopAuto;session;identifyPending=!1;constructor(e,t,s,r={}){this.session=t,this.api=M.client(e),this.closingApi=M.client({send:i=>e.send({...i,keepalive:!0})}),this.flushMs=r.flushMs??5e3,this.flushAt=r.flushAt??20,this.now=r.now??Date.now,this.anonKey=`palbase.analytics.anonymous.${s}`,this.sessionKey=`palbase.analytics.session.${s}`,t.onChange(i=>{i==="SIGNED_IN"?(this.identifyPending=!0,this.soon()):i==="SIGNED_OUT"&&(this.identifyPending=!1,this.reset())})}capture(e,t){let s=this.now();this.hold({event:e,distinct_id:this.distinctId(),properties:t,timestamp:s,session_id:this.sessionId(s),...this.appVersion?{app_version:this.appVersion}:{}})}page(e={}){let t=globalThis.location,s=globalThis.document,r=e.url??(t?`${t.origin}${t.pathname}`:"");if(!r)return;let i=e.referrer??fe(s?.referrer);this.capture("$pageview",{...e.properties,url:r,...e.title??s?.title?{title:e.title??s?.title}:{},...i?{referrer:i}:{}})}async identify(e){this.identifyPending=!1;let t=this.session.snapshot()?.userId;t&&(await this.flush(),await this.sendIdentify(this.api,t,e))}async sendIdentify(e,t,s){try{await e.identify({body:{distinct_id:t,anonymous_id:this.anonymousId(),traits:s,timestamp:this.now(),sent_at:this.now()}})}catch{}}reset(){this.memoryAnon=void 0,this.memorySession=void 0;try{x()?.removeItem(this.anonKey),x()?.removeItem(this.sessionKey)}catch{}}async flush(e=!1){this.timer&&clearTimeout(this.timer),this.timer=void 0;let t=e?this.closingApi:this.api,s=this.now(),r=this.session.snapshot()?.userId;for(this.identifyPending&&r&&(this.identifyPending=!1,await this.sendIdentify(t,r));this.events.length>0;){let i=this.take(this.events,e);try{await t.batch({body:{events:i.map(a=>({...a,sent_at:s}))}})}catch{}}for(;this.samples.length>0;){let i=this.take(this.samples,e);try{await t.sendPerf({body:{items:i}})}catch{}}}start(e={}){this.stopAuto?.(),this.appVersion=e.appVersion;let t=globalThis;if(typeof t.addEventListener!="function"||typeof globalThis.document>"u")return()=>{};let s=[];e.pageViews!==!1&&s.push(this.watchPages(t)),e.webVitals!==!1&&s.push(de((a,o)=>this.sample("web_vital",a,o))),e.network!==!1&&s.push(this.watchFetch(t));let r=()=>{document.visibilityState==="hidden"&&this.flush(!0)},i=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",r),t.addEventListener("pagehide",i),s.push(()=>{document.removeEventListener("visibilitychange",r),t.removeEventListener("pagehide",i)}),this.stopAuto=()=>{for(let a of s.splice(0))a();this.stopAuto=void 0},this.stopAuto}hold(e){this.events.length>=X&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,r={}){this.samples.length>=X&&this.samples.shift(),this.samples.push({row_id:C(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),distinct_id:this.distinctId(),...r}),this.soon()}soon(){if(this.events.length+this.samples.length>=this.flushAt){this.flush();return}this.timer||(this.timer=setTimeout(()=>{this.flush()},this.flushMs),this.timer.unref?.())}take(e,t){let s=e.splice(0,le);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>ce;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=x();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${C()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${C()}`,this.memoryAnon}sessionId(e){let t=x(),s=this.memorySession;try{let i=t?.getItem(this.sessionKey);i&&(s=JSON.parse(i))}catch{}let r=s&&e-s.last<ae?{id:s.id,last:e}:{id:`ses_${C()}`,last:e};this.memorySession=r;try{t?.setItem(this.sessionKey,JSON.stringify(r))}catch{}return r.id}watchPages(e){let t="",s=()=>{let o=`${e.location.origin}${e.location.pathname}`;o!==t&&(t=o,setTimeout(()=>this.page({url:o}),0))},r=e.history,i=r.pushState.bind(r),a=r.replaceState.bind(r);return r.pushState=(...o)=>{i(...o),s()},r.replaceState=(...o)=>{a(...o),s()},e.addEventListener("popstate",s),s(),()=>{r.pushState=i,r.replaceState=a,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(r,i)=>{let a=performance.now(),o=r instanceof Request?r:void 0,c=(i?.method??o?.method??"GET").toUpperCase(),l;try{l=new URL(o?.url??String(r),e.location.href)}catch{l=void 0}let u=!!l&&l.pathname.startsWith("/analytics/")||pe(i?.headers??o?.headers);try{let d=await t(r,i);return l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:String(d.status)},...d.headers.get("x-request-id")?{request_id:d.headers.get("x-request-id")}:{}}),d}catch(d){throw l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:"0"}}),d}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}},ue=n=>n.entryType==="layout-shift"&&"value"in n&&"hadRecentInput"in n,he=n=>n.entryType==="event"||n.entryType==="first-input";function A(n,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:n,buffered:!0}),t}catch{return}}function de(n){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,r=[A("largest-contentful-paint",l=>{for(let u of l)e=Math.max(e,u.startTime)}),A("layout-shift",l=>{for(let u of l)ue(u)&&!u.hadRecentInput&&(t+=u.value)}),A("event",l=>{for(let u of l)he(u)&&(s=Math.max(s,u.duration))}),A("paint",l=>{for(let u of l)u.name==="first-contentful-paint"&&n("FCP",u.startTime)})],i=performance.getEntriesByType("navigation")[0];i&&i.responseStart>0&&n("TTFB",i.responseStart);let a=!1,o=()=>{a||(a=!0,e>0&&n("LCP",e),n("CLS",t),s>0&&n("INP",s))},c=()=>{document.visibilityState==="hidden"&&o()};return document.addEventListener("visibilitychange",c),()=>{o(),document.removeEventListener("visibilitychange",c);for(let l of r)l?.disconnect()}}function pe(n){if(!n)return!1;try{return new Headers(n).has("next-router-prefetch")}catch{return!1}}function fe(n){if(!n)return"";try{let e=new URL(n);return`${e.origin}${e.pathname}`}catch{return n.split(/[?#]/,1)[0]??""}}var v=class{api;session;socket;ref;fetch;appVersion;listeners=new Set;watch;following;last;constructor(e,t,s,r,i,a){this.api=D.client(e),this.session=t,this.socket=s,this.ref=r,this.fetch=i,this.appVersion=a}async me(){let e=this.session.snapshot()?.userId,t=(await this.api.getMyCustomerInfo()).data;return this.watch&&this.watch.userId===e&&this.offer(this.watch,t),t}async offerings(e="web"){return(await this.api.getOfferings({query:{channel:e}})).data}async paywall(e,t={}){return $(this.api,this.ref,e,s=>this.checkout(s),{signal:t.signal,fetch:this.fetch,attributes:t.attributes,locale:t.locale,appVersion:this.appVersion})}async checkout(e){let t={product:e.product,plan:e.plan,success_url:e.successUrl,cancel_url:e.cancelUrl};return(await this.api.createCheckout({body:t})).data.url}async portal(e){return(await this.api.createPortalSession({body:{return_url:e}})).data.url}async mergeGrant(){return(await this.api.createMergeGrant()).data}async merge(e){let t=this.session.snapshot()?.userId,s=(await this.api.mergeGuest({body:{grant:typeof e=="string"?e:e.grant}})).data;return this.watch&&this.watch.userId===t&&this.offer(this.watch,s),s}onCustomerInfo(e){if(this.listeners.add(e),this.listeners.size===1)this.start();else if(this.last!==void 0){let t=this.last;queueMicrotask(()=>this.listeners.has(e)&&Y(e,t))}return()=>{this.listeners.delete(e)&&this.listeners.size===0&&this.stop()}}start(){this.following=this.session.onChange((e,t)=>{(e==="SIGNED_IN"||e==="SIGNED_OUT"||e==="SESSION_EXPIRED")&&this.follow(t)}),this.session.session().then(e=>{this.following&&!this.watch&&this.last===void 0&&this.follow(e)})}stop(){this.following?.(),this.following=void 0,this.unfollow(),this.last=void 0}follow(e){if(this.unfollow(),!e){this.tell(null);return}let t=this.socket.channel(`purchases:${this.ref}:${e.userId}`),s={userId:e.userId,channel:t,off:()=>{},revision:-1,reading:!1,wanted:Number.NEGATIVE_INFINITY},r=[t.on("broadcast",i=>{i.event==="changed"&&this.changed(s,U(i.payload))}),t.on("state_snapshot",i=>this.held(s,U(z(i.entries)))),t.on("state_diff",i=>this.held(s,U(z(i.set))))];s.off=()=>r.forEach(i=>i()),this.watch=s,t.join().catch(()=>{}),this.read(s)}unfollow(){let e=this.watch;e&&(this.watch=void 0,e.off(),e.channel.leave())}changed(e,t){this.watch!==e||t!==void 0&&t<=e.revision||(e.reading?e.wanted=Math.max(e.wanted,t??Number.POSITIVE_INFINITY):this.read(e))}held(e,t){t!==void 0&&this.changed(e,t)}async read(e){e.reading=!0;try{for(;;){e.wanted=Number.NEGATIVE_INFINITY;try{let t=(await this.api.getMyCustomerInfo()).data;if(this.watch!==e)return;this.offer(e,t)}catch{}if(this.watch!==e||e.wanted<=e.revision)return}}finally{e.reading=!1}}offer(e,t){this.watch!==e||t.revision<=e.revision||(e.revision=t.revision,this.tell(t))}tell(e){if(!(this.last===null&&e===null)){this.last=e;for(let t of[...this.listeners])Y(t,e)}}};function Y(n,e){try{n(e)}catch{}}function z(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function U(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var ye=/^pb_[a-z0-9]+_s/,me=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),ge=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function ve(n){if(ye.test(n.publishableKey)||"secretKey"in n)throw new TypeError("a secret key never goes into a client app: palbase/web takes the publishable key (pb_<ref>_c\u2026); servers use palbase/server");let e=/^pb_([a-z0-9]+)_c/.exec(n.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");let t=new URL(n.url).origin,s=n.storage??(we()?L(`palbase.session.${t}`):N()),r=n.retry??q,i=P(k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey},fetch:n.fetch}),r),a=y.client(i),o=new E(s,async h=>(await a.refreshToken({body:{refresh_token:h}})).data,h=>h instanceof S&&h.status===401&&ge.has(h.code),{lockName:`palbase.session.refresh.${t}`}),c=k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey,accessToken:()=>o.accessToken()},fetch:n.fetch,xmlHttpRequest:n.xmlHttpRequest??(n.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),l=P(j(c,o),r),u=new m({baseUrl:n.url,publishableKey:n.publishableKey,accessToken:()=>o.accessToken(),webSocket:n.webSocket});o.onChange(h=>{h==="SIGNED_OUT"||h==="SESSION_EXPIRED"||h==="SIGNED_IN"?u.disconnect():h==="TOKEN_REFRESHED"&&u.tokenChanged()});let d=new g(j(c,o),o,t);n.analytics&&d.start(n.analytics===!0?{}:n.analytics);let w=new Map,Q=h=>{let O=new URL(h).origin,b=w.get(O);return b||(b=P(j(k({baseUrl:O,credentials:{accessToken:()=>o.accessToken()},fetch:n.fetch}),o),r),w.set(O,b)),b},K=Object.assign(Object.create(F),{auth:new T(l,i,o,n.webauthn??globalThis.navigator?.credentials),socket:u,transport:l,analytics:d,purchases:new v(l,o,u,e,n.fetch,n.appVersion)});return B(K,t,Q,l,u),K}function we(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function j(n,e){return{async send(t){let s=await e.session();try{return await n.send(t)}catch(r){let i=t.auth.some(a=>a.includes("userJWT"));if(!(r instanceof S)||r.status!==401||!me.has(r.code)||!i||!s)throw r;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw r}if(e.snapshot()?.userId!==s.userId)throw r;return n.send(t)}}}}export{g as Analytics,Z as BackendError,_ as Channel,S as PalbaseError,v as Purchases,m as RealtimeSocket,te as RoomError,f as SessionChangedError,ve as createClient,ee as isBackendError,L as localStore,N as memoryStore};
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a as Z,b as ee,e as te,f as F,g as B}from"../chunks/4AQYBTIN.js";import{u as $}from"../chunks/TJ5SQTW5.js";import{b as M,c as y,h as D}from"../chunks/NK54UVDI.js";import{a as q,b as P}from"../chunks/IXHR57QC.js";import{b as S,d as k}from"../chunks/UXRIXHHY.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";var T=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,r){this.api=y.client(e),this.open=y.client(t),this.session=s,this.credentials=r;let i=this.api,a=this.open;this.mfa={challenge:async(o,c,l)=>this.signedIn((await a.mfaChallenge({body:{mfa_token:o,type:c,code:l}})).data),recovery:async(o,c)=>this.signedIn((await a.mfaRecovery({body:{mfa_token:o,code:c}})).data),sendSmsCode:async o=>{await a.mfaSmsChallenge({body:{mfa_token:o}})},sendEmailCode:async o=>{await a.mfaEmailChallenge({body:{mfa_token:o}})},enrollTotp:async()=>{let o=(await i.mfaEnroll({body:{type:"totp"}})).data;return{enrollmentId:o.enrollment_id,secret:o.secret,otpUrl:o.otp_url,qrCode:o.qr_code,recoveryCodes:o.recovery_codes}},verifyTotp:async o=>{await i.mfaVerifyEnrollment({body:{code:o}})},enrollSms:async o=>(await i.mfaSmsEnroll({body:{phone:o}})).data,verifySms:async o=>{await i.mfaSmsVerifyEnrollment({body:{code:o}})},enrollEmail:async()=>{await i.mfaEmailEnroll()},factors:async()=>(await i.mfaListFactors()).data,removeFactor:async(o,c)=>{await i.mfaRemoveFactor({path:{id:o},body:{current_password:c}})},regenerateRecoveryCodes:async()=>(await i.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async o=>{let c=(await i.webauthnRegisterBegin({body:{name:o}})).data,l=await this.authenticator().create({publicKey:H(c.options.publicKey)});return(await i.webauthnRegisterFinish({body:G(l)})).data},signIn:async(o={})=>{let c=(await a.webauthnLoginBegin({body:o.userId?{user_id:o.userId}:{}})).data,l=await this.authenticator().get({publicKey:V(c.options.publicKey)}),u=await a.webauthnLoginFinish({query:o.userId?{user_id:o.userId}:void 0,body:J(l)});return this.signedIn(u.data)},signUp:async(o,c)=>{let l=(await a.webauthnSignupBegin({body:{identifier:o,user_name:c}})).data,u=await this.authenticator().create({publicKey:H(l.options.publicKey)});await a.webauthnSignupFinish({query:{user_id:l.user_id},body:G(u)});let d=(await a.webauthnLoginBegin({body:{user_id:l.user_id}})).data,w=await this.authenticator().get({publicKey:V(d.options.publicKey)});return this.signedIn((await a.webauthnLoginFinish({query:{user_id:l.user_id},body:J(w)})).data)},list:async()=>(await i.webauthnListCredentials()).data,remove:async o=>{await i.webauthnDeleteCredential({path:{id:o}})}},this.magicLink={send:async o=>{await a.magicLinkRequest({body:{email:o}})},verify:async o=>this.signedIn((await a.magicLinkVerify({body:{token:o}})).data)},this.phone={sendCode:async o=>(await a.requestPhoneOtp({body:{phone:o,channel:"sms"}})).data,verifyCode:async(o,c)=>this.signInResult((await a.verifyPhoneOtp({body:{phone:o,token:c}})).data)},this.password={requestReset:async o=>{await a.passwordResetRequest({body:{email:o}})},confirmReset:async(o,c)=>{await a.passwordResetConfirm({body:{token:o,new_password:c}})},change:async o=>(await i.passwordChange({body:o})).data,set:async o=>(await i.setPassword({body:o})).data},this.email={verify:async o=>{await a.verifyEmail({body:o})},resendVerification:async o=>(await a.resendVerification({body:{email:o}})).data},this.sessions={list:async()=>(await i.listSessions()).data,revoke:async o=>{await i.revokeSession({path:{id:o}})},revokeAll:async()=>{await i.revokeAllSessions()}}}onAuthStateChange(e){return this.session.onChange(e)}currentSession(){return this.session.session()}async signUp(e){let t=(await this.open.signup({body:e})).data;return t.access_token&&t.refresh_token&&t.expires_in!==void 0&&await this.session.set({access_token:t.access_token,refresh_token:t.refresh_token,expires_in:t.expires_in},"SIGNED_IN",t.user),t}async signIn(e,t){return this.signInResult((await this.open.login({body:{email:e,password:t}})).data)}async signOut(){try{await this.session.session()&&await this.api.logout()}finally{await this.session.clear("SIGNED_OUT")}}async getUser(){let e=this.session.snapshot(),t=(await this.api.getMe()).data;return await this.session.setUser(t,e),t}async refreshSession(){return this.session.refresh()}async deleteAccount(e){await this.api.deleteAccount(e===void 0?void 0:{body:{password:e}}),await this.session.clear("SIGNED_OUT")}async signInResult(e){return"mfa_required"in e&&e.mfa_required?{mfaRequired:{mfaToken:e.mfa_token,factors:e.factors}}:{user:await this.signedIn(e)}}async setSession(e){return this.signedIn(e)}async signedIn(e){let t=await this.session.set({access_token:e.access_token,refresh_token:e.refresh_token,expires_in:e.expires_in},"SIGNED_IN",e.user);if(e.user)return e.user;let s=(await this.api.verifyTokenUser()).data;return await this.session.setUser(s,t),s}authenticator(){if(!this.credentials)throw new Error("passkeys need navigator.credentials (or createClient({ webauthn }))");return this.credentials}},R=n=>{let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},p=n=>{if(!n)return;let e=n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},W=n=>Array.isArray(n)?n.map(e=>({...e,id:R(String(e.id))})):void 0;function H(n){let e=n.user;return{...n,challenge:R(String(n.challenge)),user:{...e,id:R(String(e.id))},excludeCredentials:W(n.excludeCredentials)}}function V(n){return{...n,challenge:R(String(n.challenge)),allowCredentials:W(n.allowCredentials)}}function G(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),attestationObject:p(t.attestationObject),transports:t.getTransports?.()}}}function J(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),authenticatorData:p(t.authenticatorData),signature:p(t.signature),userHandle:p(t.userHandle)}}}var f=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function N(){let n=null;return{load:()=>n,save:e=>{n=e},clear:()=>{n=null},shared:!1}}function L(n){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let r=s()?.getItem(n);return r==null?t?null:e:JSON.parse(r)}catch{return e}},save(r){e=r;try{let i=s();if(!i)throw new Error("no storage");i.setItem(n,JSON.stringify(r)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(n)}catch{}},watch(r){let i=globalThis;if(typeof i.addEventListener!="function")return()=>{};let a=o=>{(o.key===n||o.key===null)&&r()};return i.addEventListener("storage",a),()=>i.removeEventListener?.("storage",a)}}}function se(n){try{let e=n.split(".")[1]??"",t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),s=JSON.parse(t).sub;return typeof s=="string"?s:""}catch{return""}}var ne=6e4,ie=15e3;function re(n,e,t){let s=n?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var E=class{current=null;loaded;inflight=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;constructor(e,t,s,r={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=r.now??Date.now,this.lockName=r.lockName??"palbase.session.refresh",this.refreshTimeoutMs=r.refreshTimeoutMs??ie,this.loaded=Promise.resolve(e.load()).then(i=>{this.current=i}),e.watch?.(()=>{this.reconcile()})}async session(){return await this.loaded,this.current}snapshot(){return this.current}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async set(e,t,s){await this.loaded;let r=t==="TOKEN_REFRESHED"?this.current:null,i={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:this.now()+e.expires_in*1e3,userId:s?.id??r?.userId??se(e.access_token),user:s??r?.user};return this.current=i,await this.store.save(i),this.emit(t,i),i}async setUser(e,t){await this.loaded,!(!this.current||!t||this.current.userId!==t.userId)&&(this.current={...this.current,user:e},await this.store.save(this.current),this.emit("USER_UPDATED",this.current))}async clear(e){await this.loaded;let t=this.current;this.current=null,this.inflight=null;let s=await this.store.load();(!s||!t||s.userId===t.userId)&&await this.store.clear(),t&&this.emit(e,null)}async accessToken(){await this.loaded;let e=this.current;if(!e)return;let t=e.expiresAt-this.now();return t>ne?e.accessToken:t>0?(this.refresh().catch(()=>{}),e.accessToken):(await this.refresh()).accessToken}refresh(){if(this.inflight)return this.inflight;let e=re(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new f("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let r=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new f("the session changed while it was refreshed");return await this.set(r,"TOKEN_REFRESHED")}catch(r){throw this.isRejected(r)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED"),r}});return this.inflight=e,e.finally(()=>{this.inflight===e&&(this.inflight=null)}).catch(()=>{}),e}async adoptStored(e){let t=await this.store.load();if(!t)throw this.current=null,this.emit("SIGNED_OUT",null),new f("signed out in another tab");if(t.userId!==e.userId)throw this.current=t,this.emit("SIGNED_OUT",null),this.emit("SIGNED_IN",t),new f("another user signed in in another tab");if(t.refreshToken!==e.refreshToken&&t.expiresAt>=e.expiresAt)return this.current=t,this.emit("TOKEN_REFRESHED",t),t}async reconcile(){await this.loaded;let e=this.current,t=await this.store.load();if(!e){t&&(this.current=t,this.emit("SIGNED_IN",t));return}await this.adoptStored(e).catch(()=>{})}withTimeout(e){let t,s=new Promise((r,i)=>{t=setTimeout(()=>i(new Error(`the refresh did not answer within ${this.refreshTimeoutMs/1e3} s`)),this.refreshTimeoutMs)});return Promise.race([e,s]).finally(()=>clearTimeout(t))}emit(e,t){for(let s of this.listeners)try{s(e,t)}catch{}}};var _=class{state="closed";refusal;joinRef=null;listeners=new Map;closers=new Set;joinWaiters=[];name;socket;constructor(e,t){this.name=e,this.socket=t}get topic(){return`realtime:${this.name}`}join(){if(this.state==="joined")return Promise.resolve();let e=new Promise((t,s)=>this.joinWaiters.push({resolve:t,reject:s}));return this.state!=="joining"&&this.socket.join(this),e}leave(){this.socket.leave(this)}push(e,t){return this.socket.request(this,e,t)}on(e,t){let s=this.listeners.get(e);return s||this.listeners.set(e,s=new Set),s.add(t),()=>s.delete(t)}onClosed(e){return this.closers.add(e),()=>this.closers.delete(e)}deliver(e,t){for(let s of this.listeners.get(e)??[])try{s(t)}catch{}}settled(e,t){this.state=e?"joined":"refused",this.refusal=e?void 0:t;let s=this.joinWaiters.splice(0);for(let r of s)e?r.resolve():r.reject(new Error(`join ${this.name} refused: ${JSON.stringify(t)}`))}closed(e){this.state="closed",this.joinRef=null;let t=this.joinWaiters.splice(0);for(let s of t)s.reject(new Error(`join ${this.name}: ${e}`));for(let s of[...this.closers])try{s()}catch{}}},m=class{ws=null;opening=null;ref=0;channels=new Map;replies=new Map;heartbeat=null;heartbeatRef=null;reconnectTimer=null;attempts=0;closedByUs=!1;reconnects=0;opts;constructor(e){this.opts=e}channel(e){let t=this.channels.get(e);return t||this.channels.set(e,t=new _(e,this)),t}disconnect(){this.closedByUs=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.stopHeartbeat();let e=this.ws;this.ws=null,this.opening=null,e?.close(1e3);for(let[,t]of this.replies)t("error",{reason:"socket closed"});this.replies.clear();for(let t of this.channels.values())t.closed("the socket was closed")}async tokenChanged(){if(!this.ws||this.ws.readyState!==1)return;let e=await this.opts.accessToken();if(e)for(let t of this.channels.values())t.state==="joined"&&this.push(t.joinRef,t.topic,"access_token",{access_token:e})}join(e){e.state="joining",this.open().then(()=>this.sendJoin(e)).catch(t=>e.settled(!1,{reason:t instanceof Error?t.message:String(t)}))}leave(e){e.state==="joined"&&this.ws?.readyState===1&&this.push(e.joinRef,e.topic,"phx_leave",{}),e.state="closed",this.channels.delete(e.name)}async request(e,t,s){let r=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||r?.readyState!==1)return{status:"error",response:{reason:"not joined"}};let i=this.nextRef(),a=JSON.stringify([e.joinRef,i,e.topic,t,s]),o=this.awaitReply(i);return r.send(a),o}open(){if(this.ws?.readyState===1)return Promise.resolve();if(this.opening)return this.opening;this.closedByUs=!1;let e=this.opts.webSocket??globalThis.WebSocket,t=`${this.opts.baseUrl.replace(/^http/,"ws")}/realtime/v1/websocket?vsn=2.0.0&apikey=${encodeURIComponent(this.opts.publishableKey)}`,s=new Promise((r,i)=>{let a=new e(t);this.ws=a,a.onopen=()=>{this.attempts=0,this.startHeartbeat(),r()},a.onmessage=o=>this.receive(String(o.data)),a.onerror=()=>i(new Error("the realtime socket could not be opened")),a.onclose=()=>this.dropped(a)});return this.opening=s,s.finally(()=>{this.opening===s&&(this.opening=null)}).catch(()=>{}),s}dropped(e){if(this.ws!==e)return;this.ws=null,this.stopHeartbeat();for(let[,r]of this.replies)r("error",{reason:"socket closed"});this.replies.clear();for(let r of this.channels.values())r.state==="joined"&&(r.state="joining");if(this.closedByUs||![...this.channels.values()].some(r=>r.state==="joining"))return;let t=this.opts.backoff??[500,1e3,2e3,5e3,1e4,3e4],s=t[Math.min(this.attempts,t.length-1)]*(.8+Math.random()*.4);this.attempts++,this.reconnectTimer=I(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let r=[...this.channels.values()].filter(i=>i.state==="joining");this.open().then(()=>Promise.all(r.map(i=>this.sendJoin(i)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let r=this.awaitReply(s);this.push(s,e.topic,"phx_join",{access_token:t,config:{broadcast:{self:!1}}},s);let{status:i,response:a}=await r;if(this.channels.get(e.name)!==e||e.state!=="joining"){i==="ok"&&this.ws?.readyState===1&&this.push(s,e.topic,"phx_leave",{});return}e.settled(i==="ok",a)}awaitReply(e){return new Promise(t=>{let s=I(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(r,i)=>{clearTimeout(s),this.replies.delete(e),t({status:r,response:i})})})}receive(e){let t;try{t=JSON.parse(e)}catch{return}if(!Array.isArray(t)||t.length!==5||typeof t[2]!="string"||typeof t[3]!="string")return;let[,s,r,i,a]=t,o=typeof a=="object"&&a!==null?a:{};if(i==="phx_reply"&&typeof s=="string"){if(s===this.heartbeatRef){this.heartbeatRef=null;return}this.replies.get(s)?.(String(o.status),o.response??{});return}let c=[...this.channels.values()].find(l=>l.topic===r);if(c){if(i==="phx_close"){c.state="closed";return}if(i==="phx_error"){c.state="joining",I(setTimeout(()=>this.channels.get(c.name)===c&&c.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(c),1e3));return}c.deliver(i,o)}}push(e,t,s,r,i=this.nextRef()){this.ws?.send(JSON.stringify([e,i,t,s,r]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=I(setInterval(()=>{if(this.heartbeatRef!==null){this.heartbeatRef=null,this.ws?.close(4e3);return}this.heartbeatRef=this.nextRef(),this.push(null,"phoenix","heartbeat",{},this.heartbeatRef)},this.opts.heartbeatMs??25e3))}stopHeartbeat(){this.heartbeat&&clearInterval(this.heartbeat),this.heartbeat=null,this.heartbeatRef=null}};function I(n){return n.unref?.(),n}var ae=30*6e4,X=1e3,le=100,ce=60*1024,C=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function x(){try{return globalThis.localStorage}catch{return}}var g=class{api;closingApi;flushMs;flushAt;now;anonKey;sessionKey;events=[];samples=[];timer;memoryAnon;memorySession;appVersion;stopAuto;session;identifyPending=!1;constructor(e,t,s,r={}){this.session=t,this.api=M.client(e),this.closingApi=M.client({send:i=>e.send({...i,keepalive:!0})}),this.flushMs=r.flushMs??5e3,this.flushAt=r.flushAt??20,this.now=r.now??Date.now,this.anonKey=`palbase.analytics.anonymous.${s}`,this.sessionKey=`palbase.analytics.session.${s}`,t.onChange(i=>{i==="SIGNED_IN"?(this.identifyPending=!0,this.soon()):i==="SIGNED_OUT"&&(this.identifyPending=!1,this.reset())})}capture(e,t){let s=this.now();this.hold({event:e,distinct_id:this.distinctId(),properties:t,timestamp:s,session_id:this.sessionId(s),...this.appVersion?{app_version:this.appVersion}:{}})}page(e={}){let t=globalThis.location,s=globalThis.document,r=e.url??(t?`${t.origin}${t.pathname}`:"");if(!r)return;let i=e.referrer??fe(s?.referrer);this.capture("$pageview",{...e.properties,url:r,...e.title??s?.title?{title:e.title??s?.title}:{},...i?{referrer:i}:{}})}async identify(e){this.identifyPending=!1;let t=this.session.snapshot()?.userId;t&&(await this.flush(),await this.sendIdentify(this.api,t,e))}async sendIdentify(e,t,s){try{await e.identify({body:{distinct_id:t,anonymous_id:this.anonymousId(),traits:s,timestamp:this.now(),sent_at:this.now()}})}catch{}}reset(){this.memoryAnon=void 0,this.memorySession=void 0;try{x()?.removeItem(this.anonKey),x()?.removeItem(this.sessionKey)}catch{}}async flush(e=!1){this.timer&&clearTimeout(this.timer),this.timer=void 0;let t=e?this.closingApi:this.api,s=this.now(),r=this.session.snapshot()?.userId;for(this.identifyPending&&r&&(this.identifyPending=!1,await this.sendIdentify(t,r));this.events.length>0;){let i=this.take(this.events,e);try{await t.batch({body:{events:i.map(a=>({...a,sent_at:s}))}})}catch{}}for(;this.samples.length>0;){let i=this.take(this.samples,e);try{await t.sendPerf({body:{items:i}})}catch{}}}start(e={}){this.stopAuto?.(),this.appVersion=e.appVersion;let t=globalThis;if(typeof t.addEventListener!="function"||typeof globalThis.document>"u")return()=>{};let s=[];e.pageViews!==!1&&s.push(this.watchPages(t)),e.webVitals!==!1&&s.push(de((a,o)=>this.sample("web_vital",a,o))),e.network!==!1&&s.push(this.watchFetch(t));let r=()=>{document.visibilityState==="hidden"&&this.flush(!0)},i=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",r),t.addEventListener("pagehide",i),s.push(()=>{document.removeEventListener("visibilitychange",r),t.removeEventListener("pagehide",i)}),this.stopAuto=()=>{for(let a of s.splice(0))a();this.stopAuto=void 0},this.stopAuto}hold(e){this.events.length>=X&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,r={}){this.samples.length>=X&&this.samples.shift(),this.samples.push({row_id:C(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),distinct_id:this.distinctId(),...r}),this.soon()}soon(){if(this.events.length+this.samples.length>=this.flushAt){this.flush();return}this.timer||(this.timer=setTimeout(()=>{this.flush()},this.flushMs),this.timer.unref?.())}take(e,t){let s=e.splice(0,le);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>ce;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=x();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${C()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${C()}`,this.memoryAnon}sessionId(e){let t=x(),s=this.memorySession;try{let i=t?.getItem(this.sessionKey);i&&(s=JSON.parse(i))}catch{}let r=s&&e-s.last<ae?{id:s.id,last:e}:{id:`ses_${C()}`,last:e};this.memorySession=r;try{t?.setItem(this.sessionKey,JSON.stringify(r))}catch{}return r.id}watchPages(e){let t="",s=()=>{let o=`${e.location.origin}${e.location.pathname}`;o!==t&&(t=o,setTimeout(()=>this.page({url:o}),0))},r=e.history,i=r.pushState.bind(r),a=r.replaceState.bind(r);return r.pushState=(...o)=>{i(...o),s()},r.replaceState=(...o)=>{a(...o),s()},e.addEventListener("popstate",s),s(),()=>{r.pushState=i,r.replaceState=a,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(r,i)=>{let a=performance.now(),o=r instanceof Request?r:void 0,c=(i?.method??o?.method??"GET").toUpperCase(),l;try{l=new URL(o?.url??String(r),e.location.href)}catch{l=void 0}let u=!!l&&l.pathname.startsWith("/analytics/")||pe(i?.headers??o?.headers);try{let d=await t(r,i);return l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:String(d.status)},...d.headers.get("x-request-id")?{request_id:d.headers.get("x-request-id")}:{}}),d}catch(d){throw l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:"0"}}),d}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}},ue=n=>n.entryType==="layout-shift"&&"value"in n&&"hadRecentInput"in n,he=n=>n.entryType==="event"||n.entryType==="first-input";function A(n,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:n,buffered:!0}),t}catch{return}}function de(n){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,r=[A("largest-contentful-paint",l=>{for(let u of l)e=Math.max(e,u.startTime)}),A("layout-shift",l=>{for(let u of l)ue(u)&&!u.hadRecentInput&&(t+=u.value)}),A("event",l=>{for(let u of l)he(u)&&(s=Math.max(s,u.duration))}),A("paint",l=>{for(let u of l)u.name==="first-contentful-paint"&&n("FCP",u.startTime)})],i=performance.getEntriesByType("navigation")[0];i&&i.responseStart>0&&n("TTFB",i.responseStart);let a=!1,o=()=>{a||(a=!0,e>0&&n("LCP",e),n("CLS",t),s>0&&n("INP",s))},c=()=>{document.visibilityState==="hidden"&&o()};return document.addEventListener("visibilitychange",c),()=>{o(),document.removeEventListener("visibilitychange",c);for(let l of r)l?.disconnect()}}function pe(n){if(!n)return!1;try{return new Headers(n).has("next-router-prefetch")}catch{return!1}}function fe(n){if(!n)return"";try{let e=new URL(n);return`${e.origin}${e.pathname}`}catch{return n.split(/[?#]/,1)[0]??""}}var v=class{api;session;socket;ref;fetch;appVersion;listeners=new Set;watch;following;last;constructor(e,t,s,r,i,a){this.api=D.client(e),this.session=t,this.socket=s,this.ref=r,this.fetch=i,this.appVersion=a}async me(){let e=this.session.snapshot()?.userId,t=(await this.api.getMyCustomerInfo()).data;return this.watch&&this.watch.userId===e&&this.offer(this.watch,t),t}async offerings(e="web"){return(await this.api.getOfferings({query:{channel:e}})).data}async paywall(e,t={}){return $(this.api,this.ref,e,s=>this.checkout(s),{signal:t.signal,fetch:this.fetch,attributes:t.attributes,locale:t.locale,appVersion:this.appVersion})}async checkout(e){let t={product:e.product,plan:e.plan,success_url:e.successUrl,cancel_url:e.cancelUrl};return(await this.api.createCheckout({body:t})).data.url}async portal(e){return(await this.api.createPortalSession({body:{return_url:e}})).data.url}async mergeGrant(){return(await this.api.createMergeGrant()).data}async merge(e){let t=this.session.snapshot()?.userId,s=(await this.api.mergeGuest({body:{grant:typeof e=="string"?e:e.grant}})).data;return this.watch&&this.watch.userId===t&&this.offer(this.watch,s),s}onCustomerInfo(e){if(this.listeners.add(e),this.listeners.size===1)this.start();else if(this.last!==void 0){let t=this.last;queueMicrotask(()=>this.listeners.has(e)&&Y(e,t))}return()=>{this.listeners.delete(e)&&this.listeners.size===0&&this.stop()}}start(){this.following=this.session.onChange((e,t)=>{(e==="SIGNED_IN"||e==="SIGNED_OUT"||e==="SESSION_EXPIRED")&&this.follow(t)}),this.session.session().then(e=>{this.following&&!this.watch&&this.last===void 0&&this.follow(e)})}stop(){this.following?.(),this.following=void 0,this.unfollow(),this.last=void 0}follow(e){if(this.unfollow(),!e){this.tell(null);return}let t=this.socket.channel(`purchases:${this.ref}:${e.userId}`),s={userId:e.userId,channel:t,off:()=>{},revision:-1,reading:!1,wanted:Number.NEGATIVE_INFINITY},r=[t.on("broadcast",i=>{i.event==="changed"&&this.changed(s,U(i.payload))}),t.on("state_snapshot",i=>this.held(s,U(z(i.entries)))),t.on("state_diff",i=>this.held(s,U(z(i.set))))];s.off=()=>r.forEach(i=>i()),this.watch=s,t.join().catch(()=>{}),this.read(s)}unfollow(){let e=this.watch;e&&(this.watch=void 0,e.off(),e.channel.leave())}changed(e,t){this.watch!==e||t!==void 0&&t<=e.revision||(e.reading?e.wanted=Math.max(e.wanted,t??Number.POSITIVE_INFINITY):this.read(e))}held(e,t){t!==void 0&&this.changed(e,t)}async read(e){e.reading=!0;try{for(;;){e.wanted=Number.NEGATIVE_INFINITY;try{let t=(await this.api.getMyCustomerInfo()).data;if(this.watch!==e)return;this.offer(e,t)}catch{}if(this.watch!==e||e.wanted<=e.revision)return}}finally{e.reading=!1}}offer(e,t){this.watch!==e||t.revision<=e.revision||(e.revision=t.revision,this.tell(t))}tell(e){if(!(this.last===null&&e===null)){this.last=e;for(let t of[...this.listeners])Y(t,e)}}};function Y(n,e){try{n(e)}catch{}}function z(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function U(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var ye=/^pb_[a-z0-9]+_s/,me=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),ge=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function ve(n){if(ye.test(n.publishableKey)||"secretKey"in n)throw new TypeError("a secret key never goes into a client app: palbase/web takes the publishable key (pb_<ref>_c\u2026); servers use palbase/server");let e=/^pb_([a-z0-9]+)_c/.exec(n.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");let t=new URL(n.url).origin,s=n.storage??(we()?L(`palbase.session.${t}`):N()),r=n.retry??q,i=P(k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey},fetch:n.fetch}),r),a=y.client(i),o=new E(s,async h=>(await a.refreshToken({body:{refresh_token:h}})).data,h=>h instanceof S&&h.status===401&&ge.has(h.code),{lockName:`palbase.session.refresh.${t}`}),c=k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey,accessToken:()=>o.accessToken()},fetch:n.fetch,xmlHttpRequest:n.xmlHttpRequest??(n.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),l=P(j(c,o),r),u=new m({baseUrl:n.url,publishableKey:n.publishableKey,accessToken:()=>o.accessToken(),webSocket:n.webSocket});o.onChange(h=>{h==="SIGNED_OUT"||h==="SESSION_EXPIRED"||h==="SIGNED_IN"?u.disconnect():h==="TOKEN_REFRESHED"&&u.tokenChanged()});let d=new g(j(c,o),o,t);n.analytics&&d.start(n.analytics===!0?{}:n.analytics);let w=new Map,Q=h=>{let O=new URL(h).origin,b=w.get(O);return b||(b=P(j(k({baseUrl:O,credentials:{accessToken:()=>o.accessToken()},fetch:n.fetch}),o),r),w.set(O,b)),b},K=Object.assign(Object.create(F),{auth:new T(l,i,o,n.webauthn??globalThis.navigator?.credentials),socket:u,transport:l,analytics:d,purchases:new v(l,o,u,e,n.fetch,n.appVersion)});return B(K,t,Q,l,u),K}function we(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function j(n,e){return{async send(t){let s=await e.session();try{return await n.send(t)}catch(r){let i=t.auth.some(a=>a.includes("userJWT"));if(!(r instanceof S)||r.status!==401||!me.has(r.code)||!i||!s)throw r;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw r}if(e.snapshot()?.userId!==s.userId)throw r;return n.send(t)}}}}export{g as Analytics,Z as BackendError,_ as Channel,S as PalbaseError,v as Purchases,m as RealtimeSocket,te as RoomError,f as SessionChangedError,ve as createClient,ee as isBackendError,L as localStore,N as memoryStore};
|
package/dist/web/palbe.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import{c as e,d as r,h as t}from"../chunks/
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{c as e,d as r,h as t}from"../chunks/4AQYBTIN.js";import"../chunks/IXHR57QC.js";import"../chunks/UXRIXHHY.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";export{e as RESERVED_CLIENT_NAMES,t as __registerBackend,r as isClientName};
|
package/dist/web/paywall.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import{a as e,b as a,c as t,d as l,e as o,f as p,g as r,h as y,i as s,j as P,k as i,l as n,m as w,n as f,o as d,p as m,q as u,r as A,s as c,t as v}from"../chunks/
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a as e,b as a,c as t,d as l,e as o,f as p,g as r,h as y,i as s,j as P,k as i,l as n,m as w,n as f,o as d,p as m,q as u,r as A,s as c,t as v}from"../chunks/TJ5SQTW5.js";import"../chunks/UXRIXHHY.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";export{w as PAYWALL_COMPONENTS,i as PAYWALL_ICONS,n as PAYWALL_SCHEMA,c as Paywall,a as assetId,p as attributesHeader,f as countdownValues,v as defaultPaywall,e as fontFamily,s as formatPeriod,y as formatPrice,o as htmlDocument,P as packageValues,d as packagesOf,r as parseDuration,t as prepareAssets,A as renderPaywall,m as resolvePaywall,u as resolvePaywallWithPaths,l as unzip};
|
package/dist/web/vite.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/*! palbase 0.3.
|
|
2
|
-
import"../chunks/
|
|
1
|
+
/*! palbase 0.3.3 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import"../chunks/PRM2UXWG.js";import{execFile as $}from"node:child_process";import{existsSync as y,mkdtempSync as k,readFileSync as S,rmSync as x,writeFileSync as P}from"node:fs";import{createRequire as O}from"node:module";import{tmpdir as W}from"node:os";import{dirname as g,join as o,relative as u,resolve as v,sep as d}from"node:path";var E=/\.(?:ts|js|mts|mjs)$/;function F(n){if(!/^[a-z][a-z0-9-]*$/.test(n.app))throw new TypeError(`palbase({ app }): ${JSON.stringify(n.app)} is an app's slug (palbase apps:list)`);let c=process.cwd(),p="",i="",f=()=>v(c,n.dir??"palbase"),m=()=>{let e=n.environments[p];if(!e)throw new Error(`palbase: the mode "${p}" is not built against any environment \u2014 say which in vite.config: palbase({ environments: { ${JSON.stringify(p)}: '<environment slug>' } })`);return e};return{name:"palbase",enforce:"pre",config(e,s){p=s.mode,i=s.command??"";let r=e.build?.rollupOptions?.onwarn;return{build:{rollupOptions:{onwarn(t,a){let l=String(t.exporter??t.id??"");if(t.code==="MISSING_EXPORT"&&l.includes(`${d}environments${d}`))throw new Error(`palbase: ${t.message} \u2014 ${m()}'s backend has no such route (palbase apps:sync brings what it has)`);r?r(t,a):a(t)}}}}},configResolved(e){c=e.root,p=e.mode,i=e.command??i},async buildStart(){i!=="build"||n.typecheck===!1||await j(c,m(),n.tsconfig)},resolveId(e,s){if(!s)return null;let r=f();if(e==="palbase"||e.startsWith("palbase/")){let w=u(r,s);return w.startsWith("..")||w===""?null:this.resolve(e,o(c,"index.html"),{skipSelf:!0})}if(!(e.startsWith(".")||e.startsWith("/")))return null;let t=v(g(s),e);if(E.test(t)||(t+=".ts"),g(t)!==r&&g(t)!==o(r,"palbe"))return null;let a=u(r,t),l=`${n.app}.ts`;if(a!==l&&!a.startsWith(`palbe${d}`))return null;let h=m(),b=o(r,"environments",h,a===l?l:o("palbe",a.slice(`palbe${d}`.length)));if(!y(b))throw new Error(`palbase: ${u(c,b)} is not there \u2014 palbase apps:sync writes it (is ${n.app} set in ${h}, and has ${h} that machine?)`);return b}}}async function j(n,c,p){let i=p?v(n,p):["tsconfig.app.json","tsconfig.json"].map(e=>o(n,e)).find(y);if(!i)return;if(!y(i))throw new Error(`palbase({ tsconfig }): ${u(n,i)} is not there`);let f;try{let e=O(o(n,"package.json")).resolve("typescript/package.json"),s=JSON.parse(S(e,"utf8")).bin?.tsc;if(!s)throw new Error("no tsc");f=o(g(e),s)}catch{throw new Error("palbase: the build type-checks the app against its environment with the app's TypeScript, and the app has none (npm i -D typescript) \u2014 or say palbase({ typecheck: false })")}let m=k(o(W(),"palbase-typecheck-"));try{let e=o(m,"tsconfig.json");P(e,JSON.stringify({extends:i,compilerOptions:{noEmit:!0,composite:!1,incremental:!1,moduleSuffixes:[`.${c}`,""]}}));let s=await new Promise(r=>$(process.execPath,[f,"-p",e,"--pretty","false"],{cwd:n,maxBuffer:16<<20},(t,a,l)=>r({code:t?typeof t.code=="number"?t.code:1:0,text:`${a}${l}`.trim()})));if(s.code!==0)throw new Error(`palbase: the app does not type-check against ${c}, the environment this build is made for \u2014 a route its backend does not have, or a call that does not fit it:
|
|
3
3
|
${s.text}`)}finally{x(m,{recursive:!0,force:!0})}}export{F as palbase};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "palbase",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Palbase for JavaScript: the web client (palbase/web), the server SDK (palbase/server), the backend framework (palbase/backend), AI (palbase/ai) and the CLI (npx palbase).",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://palbase.studio",
|
|
7
|
-
"author": "
|
|
7
|
+
"author": "Pallasite OÜ",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=22"
|
|
@@ -105,9 +105,9 @@
|
|
|
105
105
|
"README.md"
|
|
106
106
|
],
|
|
107
107
|
"dependencies": {
|
|
108
|
-
"palgres": "0.3.
|
|
109
|
-
"reflect-metadata": "0.2.2",
|
|
110
|
-
"typescript": "6.0.3",
|
|
111
|
-
"zod": "4.6.5"
|
|
108
|
+
"palgres": "0.3.3",
|
|
109
|
+
"reflect-metadata": "^0.2.2",
|
|
110
|
+
"typescript": "~6.0.3",
|
|
111
|
+
"zod": "^4.6.5"
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -566,9 +566,9 @@ export type ConfidenceReason = {
|
|
|
566
566
|
*/
|
|
567
567
|
chance?: number;
|
|
568
568
|
/**
|
|
569
|
-
* no_viewers: no one saw a variant yet; too_few_viewers: a variant was seen by fewer than min_viewers (variant, viewers); leader_unsure: the leader's chance to win is under min_chance (variant, chance).
|
|
569
|
+
* no_viewers: no one saw a variant yet; too_few_viewers: a variant was seen by fewer than min_viewers (variant, viewers); no_leader: no variant leads yet — one no one saw, or the likeliest even with the next (no leader is named); leader_unsure: the leader's chance to win is under min_chance (variant, chance). A client says a code it does not know in the reason's message.
|
|
570
570
|
*/
|
|
571
|
-
code: "no_viewers" | "too_few_viewers" | "leader_unsure";
|
|
571
|
+
code: "no_viewers" | "too_few_viewers" | "no_leader" | "leader_unsure";
|
|
572
572
|
/**
|
|
573
573
|
* The reason in words ("variant b has 40 viewers (needs 100)").
|
|
574
574
|
*/
|
|
@@ -1217,7 +1217,7 @@ export type ExperimentResults = {
|
|
|
1217
1217
|
*/
|
|
1218
1218
|
experiment_id: string;
|
|
1219
1219
|
/**
|
|
1220
|
-
* The variant
|
|
1220
|
+
* The variant likeliest to convert best, once every variant was seen and it is ahead of the next; absent before that, and in a tie.
|
|
1221
1221
|
*/
|
|
1222
1222
|
leader?: string;
|
|
1223
1223
|
/**
|
|
@@ -2002,7 +2002,7 @@ export type PaywallCountdown = {
|
|
|
2002
2002
|
visible?: PaywallCondition;
|
|
2003
2003
|
};
|
|
2004
2004
|
/**
|
|
2005
|
-
* A decorative HTML block from an archive the project uploaded (an animation, a Lottie or Rive scene): drawn in a sandbox of an origin of its own: it reaches neither the page around it, nor the app, nor the purchase, and loads only what came in its archive (a content security policy) — it may still navigate its own frame away. It is told the selected package, the language and the appearance, and is hidden from screen readers. It cannot buy anything.
|
|
2005
|
+
* A decorative HTML block from an archive the project uploaded (an animation, a Lottie or Rive scene): drawn in a sandbox of an origin of its own: it reaches neither the page around it, nor the app, nor the purchase, and loads only what came in its archive (a content security policy) — it may still navigate its own frame away and open a WebRTC connection (a content security policy does not cover WebRTC). It is told the selected package, the language and the appearance, and is hidden from screen readers. It cannot buy anything.
|
|
2006
2006
|
*/
|
|
2007
2007
|
export type PaywallCustomHtml = {
|
|
2008
2008
|
animation?: PaywallAnimation;
|
|
@@ -2816,6 +2816,56 @@ export type PaywallTarget = {
|
|
|
2816
2816
|
*/
|
|
2817
2817
|
at?: string;
|
|
2818
2818
|
};
|
|
2819
|
+
/**
|
|
2820
|
+
* One of the module's designed paywalls: its definition — checked by the module as any other — and the template assets it names.
|
|
2821
|
+
*/
|
|
2822
|
+
export type PaywallTemplate = {
|
|
2823
|
+
assets: PaywallTemplateAsset[];
|
|
2824
|
+
definition: PaywallDefinition;
|
|
2825
|
+
/**
|
|
2826
|
+
* What it looks like, in a sentence.
|
|
2827
|
+
*/
|
|
2828
|
+
description: string;
|
|
2829
|
+
/**
|
|
2830
|
+
* Its key.
|
|
2831
|
+
*/
|
|
2832
|
+
key: string;
|
|
2833
|
+
/**
|
|
2834
|
+
* Its name.
|
|
2835
|
+
*/
|
|
2836
|
+
name: string;
|
|
2837
|
+
};
|
|
2838
|
+
/**
|
|
2839
|
+
* A template asset: what its bytes are. A client making a paywall from the template downloads them (…/templates/{key}/assets/{id}), checks the SHA-256, uploads them to the project's paywall-assets bucket, registers them (POST /purchases/paywalls/assets) and names the new asset in place of this id.
|
|
2840
|
+
*/
|
|
2841
|
+
export type PaywallTemplateAsset = {
|
|
2842
|
+
/**
|
|
2843
|
+
* Its media type, as its bytes are.
|
|
2844
|
+
*/
|
|
2845
|
+
content_type: string;
|
|
2846
|
+
/**
|
|
2847
|
+
* The id the definition names (asset:<id>).
|
|
2848
|
+
*/
|
|
2849
|
+
id: string;
|
|
2850
|
+
/**
|
|
2851
|
+
* What it is.
|
|
2852
|
+
*/
|
|
2853
|
+
kind: "image" | "video" | "font" | "html";
|
|
2854
|
+
/**
|
|
2855
|
+
* The SHA-256 of its bytes, hex.
|
|
2856
|
+
*/
|
|
2857
|
+
sha256: string;
|
|
2858
|
+
/**
|
|
2859
|
+
* Its size in bytes.
|
|
2860
|
+
*/
|
|
2861
|
+
size: number;
|
|
2862
|
+
};
|
|
2863
|
+
/**
|
|
2864
|
+
* The module's templates, in the order they are offered.
|
|
2865
|
+
*/
|
|
2866
|
+
export type PaywallTemplates = {
|
|
2867
|
+
templates: PaywallTemplate[];
|
|
2868
|
+
};
|
|
2819
2869
|
/**
|
|
2820
2870
|
* A text: one string, or spans — bold, italic, colored parts and links —, in a type style of the theme or its own.
|
|
2821
2871
|
*/
|
|
@@ -5101,6 +5151,29 @@ export declare function client(t: Transport): {
|
|
|
5101
5151
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
5102
5152
|
signal?: AbortSignal;
|
|
5103
5153
|
}): Promise<Reply<204, undefined>>;
|
|
5154
|
+
/**
|
|
5155
|
+
* List the paywall templates
|
|
5156
|
+
*
|
|
5157
|
+
* The module's designed paywalls, to make a paywall from — Studio's and the CLI's one source. A template sells the packages pro.monthly, pro.yearly, family.monthly, family.yearly and lifetime.once (each as it has them): the client names the catalog's in their place. Its pictures are template assets (asset:<id> with ids of their own), never an address outside the project: the client downloads each (…/templates/{key}/assets/{asset_id}), uploads it to the project's paywall-assets bucket, registers it and names the new asset in place of the template's id. The module creates no bucket and uploads nothing.
|
|
5158
|
+
*/
|
|
5159
|
+
listPaywallTemplates(input?: {
|
|
5160
|
+
signal?: AbortSignal;
|
|
5161
|
+
}): Promise<Reply<200, PaywallTemplates>>;
|
|
5162
|
+
/**
|
|
5163
|
+
* Download a template asset
|
|
5164
|
+
*
|
|
5165
|
+
* A template asset's bytes, of the media type its bytes are; the ETag is their SHA-256 (an unchanged one is 304 to If-None-Match).
|
|
5166
|
+
*/
|
|
5167
|
+
getPaywallTemplateAsset(input: {
|
|
5168
|
+
path: {
|
|
5169
|
+
key: string; /** The template asset's id. */
|
|
5170
|
+
asset_id: string;
|
|
5171
|
+
};
|
|
5172
|
+
headers?: {
|
|
5173
|
+
"If-None-Match"?: string;
|
|
5174
|
+
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
5175
|
+
signal?: AbortSignal;
|
|
5176
|
+
}): Promise<Reply<200, Response> | Reply<304, undefined>>;
|
|
5104
5177
|
/**
|
|
5105
5178
|
* Check a paywall
|
|
5106
5179
|
*
|
|
@@ -389,14 +389,15 @@ export declare function client(t: Transport): {
|
|
|
389
389
|
/**
|
|
390
390
|
* Declare a bucket
|
|
391
391
|
*
|
|
392
|
-
* Creates the bucket as declared, or makes it so: whether anyone may read it (public), the largest object it takes, the content types it takes (empty: any; image/* a family), and the renditions made of every picture put in it. A declaration a renderer cannot honour is refused here, not at the first upload.
|
|
392
|
+
* Creates the bucket as declared, or makes it so: whether anyone may read it (public), the largest object it takes, the content types it takes (empty: any; image/* a family), and the renditions made of every picture put in it. A declaration a renderer cannot honour is refused here, not at the first upload. With If-None-Match: * it only creates the bucket: two clients making the same bucket at once do not overwrite each other's declaration — the second is told (412) and the bucket stays as the first made it.
|
|
393
393
|
*/
|
|
394
394
|
putBucket(input: {
|
|
395
395
|
path: {
|
|
396
396
|
bucket: string;
|
|
397
397
|
};
|
|
398
398
|
headers?: {
|
|
399
|
-
"Idempotency-Key"?: string;
|
|
399
|
+
"Idempotency-Key"?: string; /** * alone: create the bucket only if it does not exist (412 `precondition_failed` when it does, the bucket as it was). Without it the declaration creates the bucket or makes it so. */
|
|
400
|
+
"If-None-Match"?: "*";
|
|
400
401
|
};
|
|
401
402
|
body: BucketWrite; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
402
403
|
signal?: AbortSignal;
|
|
@@ -62,8 +62,10 @@ export interface VerifierOptions {
|
|
|
62
62
|
fetchTimeoutMs?: number;
|
|
63
63
|
/** The platform's answer to "does this token's session stand" (bootstrap asks GET /auth/user). */
|
|
64
64
|
standing: SessionStanding;
|
|
65
|
-
/** How long a session's standing is kept, ms (default
|
|
65
|
+
/** How long a session's standing is kept, ms (default 1000): a session that ended is refused within it. */
|
|
66
66
|
standingTtlMs?: number;
|
|
67
|
+
/** How long a session's last standing stands in while the platform cannot be asked, ms (default 15000). */
|
|
68
|
+
standingStaleMs?: number;
|
|
67
69
|
}
|
|
68
70
|
export declare class TokenVerifier {
|
|
69
71
|
private readonly issuer;
|
|
@@ -75,6 +77,7 @@ export declare class TokenVerifier {
|
|
|
75
77
|
private readonly fetchTimeoutMs;
|
|
76
78
|
private readonly standing;
|
|
77
79
|
private readonly standingTtlMs;
|
|
80
|
+
private readonly standingStaleMs;
|
|
78
81
|
private standings;
|
|
79
82
|
private asking;
|
|
80
83
|
private keys;
|