palbase 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.js +2 -2
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +10 -10
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/{IVDNNHII.js → 2GGJKIKT.js} +2 -2
- package/dist/chunks/{BJL2FT5W.js → 2S5VK2PA.js} +1 -1
- package/dist/chunks/{ZFX4BFQR.js → 6SXSYK4S.js} +2 -2
- package/dist/chunks/{3OIKIBMG.js → 73WBTWOK.js} +2 -2
- package/dist/chunks/{UNTTPATW.js → ABBUC5HE.js} +1 -1
- package/dist/chunks/{SUNHFMDO.js → C627JALV.js} +2 -2
- package/dist/chunks/{6JO3UVPT.js → CC36MKWZ.js} +2 -2
- package/dist/chunks/{TRHIZOIS.js → COCND66P.js} +3 -3
- package/dist/chunks/{ODFLUINN.js → FEHN6AHI.js} +1 -1
- package/dist/chunks/{BHT2IHBE.js → GUR3A4M7.js} +2 -2
- package/dist/chunks/HNMC2RJ7.js +20 -0
- package/dist/chunks/{RKNVSAGY.js → IOIQM4QO.js} +1 -1
- package/dist/chunks/{CY6B75KF.js → OROMWNJD.js} +2 -2
- package/dist/chunks/{FS222NNP.js → R5BCF2YW.js} +2 -2
- package/dist/chunks/{ST2NZ4TZ.js → RBUTW6OM.js} +1 -1
- package/dist/chunks/{2AT72FFB.js → RQFK2F3Q.js} +2 -2
- package/dist/cli.js +129 -125
- 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 +2 -2
- package/types/backend/src/container.d.ts +4 -2
- package/types/backend/src/decorators.d.ts +32 -17
- package/types/backend/src/engine.d.ts +9 -4
- package/types/backend/src/env.d.ts +1 -1
- package/types/backend/src/index.d.ts +2 -1
- package/types/backend/src/tasks.d.ts +168 -0
- package/types/internal/src/modules/auth.d.ts +64 -47
- package/types/internal/src/modules/machines.d.ts +320 -79
- package/types/internal/src/modules/notify.d.ts +3 -3
- package/types/internal/src/modules/purchases.d.ts +562 -3
- package/types/internal/src/modules/storage.d.ts +31 -2
- package/types/web/src/client.d.ts +7 -0
- package/types/web/src/paywall/placement.d.ts +2 -0
- package/types/web/src/purchases.d.ts +3 -1
- package/dist/chunks/EGRDFD5C.js +0 -20
package/dist/refuse/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.
|
|
1
|
+
/*! palbase 0.5.0 — 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.
|
|
1
|
+
/*! palbase 0.5.0 — 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.
|
|
1
|
+
/*! palbase 0.5.0 — 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.
|
|
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.5.0 — 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/C627JALV.js";import"../chunks/ABBUC5HE.js";import{m as b}from"../chunks/6SXSYK4S.js";import"../chunks/73WBTWOK.js";import{b as a}from"../chunks/RQFK2F3Q.js";import"../chunks/IOIQM4QO.js";import"../chunks/FEHN6AHI.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.
|
|
2
|
-
import{a,b,c,d}from"../chunks/
|
|
1
|
+
/*! palbase 0.5.0 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a,b,c,d}from"../chunks/CC36MKWZ.js";import"../chunks/IOIQM4QO.js";import"../chunks/FEHN6AHI.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.
|
|
2
|
-
import{a as ue,b as ce,e as de,f as Y,g as z}from"../chunks/IVDNNHII.js";import{u as Q}from"../chunks/TRHIZOIS.js";import{c as E,e as K,f,g as Z,h as q}from"../chunks/CY6B75KF.js";import{a as G,b as D,c as m,h as J}from"../chunks/ZFX4BFQR.js";import{a as W,b as P,c as X}from"../chunks/3OIKIBMG.js";import{b as p,d as _}from"../chunks/2AT72FFB.js";import"../chunks/RKNVSAGY.js";import"../chunks/ODFLUINN.js";var R=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,n){this.api=m.client(e),this.open=m.client(t),this.session=s,this.credentials=n;let i=this.api,a=this.open;this.mfa={challenge:async(o,l,h)=>this.signedIn((await a.mfaChallenge({body:{mfa_token:o,type:l,code:h}})).data),recovery:async(o,l)=>this.signedIn((await a.mfaRecovery({body:{mfa_token:o,code:l}})).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,l)=>{await i.mfaRemoveFactor({path:{id:o},body:{current_password:l}})},regenerateRecoveryCodes:async()=>(await i.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async o=>{let l=(await i.webauthnRegisterBegin({body:{name:o}})).data,h=await this.authenticator().create({publicKey:ee(l.options.publicKey)});return(await i.webauthnRegisterFinish({body:se(h)})).data},signIn:async(o={})=>{let l=(await a.webauthnLoginBegin({body:o.userId?{user_id:o.userId}:{}})).data,h=await this.authenticator().get({publicKey:te(l.options.publicKey)}),u=await a.webauthnLoginFinish({query:o.userId?{user_id:o.userId}:void 0,body:ne(h)});return this.signedIn(u.data)},signUp:async(o,l)=>{let h=(await a.webauthnSignupBegin({body:{identifier:o,user_name:l}})).data,u=await this.authenticator().create({publicKey:ee(h.options.publicKey)});await a.webauthnSignupFinish({query:{user_id:h.user_id},body:se(u)});let d=(await a.webauthnLoginBegin({body:{user_id:h.user_id}})).data,k=await this.authenticator().get({publicKey:te(d.options.publicKey)});return this.signedIn((await a.webauthnLoginFinish({query:{user_id:h.user_id},body:ne(k)})).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,l)=>this.signInResult((await a.verifyPhoneOtp({body:{phone:o,token:l}})).data)},this.password={requestReset:async o=>{await a.passwordResetRequest({body:{email:o}})},confirmReset:async(o,l)=>{await a.passwordResetConfirm({body:{token:o,new_password:l}})},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}},I=r=>{let e=atob(r.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(r.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},g=r=>{if(!r)return;let e=r instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},ie=r=>Array.isArray(r)?r.map(e=>({...e,id:I(String(e.id))})):void 0;function ee(r){let e=r.user;return{...r,challenge:I(String(r.challenge)),user:{...e,id:I(String(e.id))},excludeCredentials:ie(r.excludeCredentials)}}function te(r){return{...r,challenge:I(String(r.challenge)),allowCredentials:ie(r.allowCredentials)}}function se(r){let e=r,t=e.response;return{id:e.id,rawId:g(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:g(t.clientDataJSON),attestationObject:g(t.attestationObject),transports:t.getTransports?.()}}}function ne(r){let e=r,t=e.response;return{id:e.id,rawId:g(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:g(t.clientDataJSON),authenticatorData:g(t.authenticatorData),signature:g(t.signature),userHandle:g(t.userHandle)}}}var y=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function F(){let r=null;return{load:()=>r,save:e=>{r=e},clear:()=>{r=null},shared:!1}}function V(r){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let n=s()?.getItem(r);return n==null?t?null:e:JSON.parse(n)}catch{return e}},save(n){e=n;try{let i=s();if(!i)throw new Error("no storage");i.setItem(r,JSON.stringify(n)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(r)}catch{}},watch(n){let i=globalThis;if(typeof i.addEventListener!="function")return()=>{};let a=o=>{(o.key===r||o.key===null)&&n()};return i.addEventListener("storage",a),()=>i.removeEventListener?.("storage",a)}}}function pe(r){try{let e=r.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 fe=6e4,ge=15e3;function ye(r,e,t){let s=r?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var C=class{current=null;loaded;inflight=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;constructor(e,t,s,n={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=n.now??Date.now,this.lockName=n.lockName??"palbase.session.refresh",this.refreshTimeoutMs=n.refreshTimeoutMs??ge,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 n=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??n?.userId??pe(e.access_token),user:s??n?.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>fe?e.accessToken:t>0?(this.refresh().catch(()=>{}),e.accessToken):(await this.refresh()).accessToken}refresh(){if(this.inflight)return this.inflight;let e=ye(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new y("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let n=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new y("the session changed while it was refreshed");return await this.set(n,"TOKEN_REFRESHED")}catch(n){throw this.isRejected(n)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED"),n}});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 y("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 y("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((n,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 M=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 n of s)e?n.resolve():n.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{}}},v=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 M(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 n=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||n?.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 n.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((n,i)=>{let a=new e(t);this.ws=a,a.onopen=()=>{this.attempts=0,this.startHeartbeat(),n()},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[,n]of this.replies)n("error",{reason:"socket closed"});this.replies.clear();for(let n of this.channels.values())n.state==="joined"&&(n.state="joining");if(this.closedByUs||![...this.channels.values()].some(n=>n.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=x(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let n=[...this.channels.values()].filter(i=>i.state==="joining");this.open().then(()=>Promise.all(n.map(i=>this.sendJoin(i)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let n=this.awaitReply(s);this.push(s,e.topic,"phx_join",{access_token:t,config:{broadcast:{self:!1}}},s);let{status:i,response:a}=await n;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=x(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(n,i)=>{clearTimeout(s),this.replies.delete(e),t({status:n,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,n,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 l=[...this.channels.values()].find(h=>h.topic===n);if(l){if(i==="phx_close"){l.state="closed";return}if(i==="phx_error"){l.state="joining",x(setTimeout(()=>this.channels.get(l.name)===l&&l.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(l),1e3));return}l.deliver(i,o)}}push(e,t,s,n,i=this.nextRef()){this.ws?.send(JSON.stringify([e,i,t,s,n]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=x(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 x(r){return r.unref?.(),r}var ve=30*6e4,re=1e3,we=100,be=60*1024,A=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function O(){try{return globalThis.localStorage}catch{return}}var w=class{api;closingApi;flushMs;flushAt;now;anonKey;sessionKey;events=[];samples=[];timer;memoryAnon;memorySession;appVersion;stopAuto;session;identifyPending=!1;constructor(e,t,s,n={}){this.session=t,this.api=D.client(e),this.closingApi=D.client({send:i=>e.send({...i,keepalive:!0})}),this.flushMs=n.flushMs??5e3,this.flushAt=n.flushAt??20,this.now=n.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,n=e.url??(t?`${t.origin}${t.pathname}`:"");if(!n)return;let i=e.referrer??Pe(s?.referrer);this.capture("$pageview",{...e.properties,url:n,...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{O()?.removeItem(this.anonKey),O()?.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(),n=this.session.snapshot()?.userId;for(this.identifyPending&&n&&(this.identifyPending=!1,await this.sendIdentify(t,n));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(Te((a,o)=>this.sample("web_vital",a,o))),e.network!==!1&&s.push(this.watchFetch(t));let n=()=>{document.visibilityState==="hidden"&&this.flush(!0)},i=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",n),t.addEventListener("pagehide",i),s.push(()=>{document.removeEventListener("visibilitychange",n),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>=re&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,n={}){this.samples.length>=re&&this.samples.shift(),this.samples.push({row_id:A(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),distinct_id:this.distinctId(),...n}),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,we);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>be;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=O();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${A()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${A()}`,this.memoryAnon}sessionId(e){let t=O(),s=this.memorySession;try{let i=t?.getItem(this.sessionKey);i&&(s=JSON.parse(i))}catch{}let n=s&&e-s.last<ve?{id:s.id,last:e}:{id:`ses_${A()}`,last:e};this.memorySession=n;try{t?.setItem(this.sessionKey,JSON.stringify(n))}catch{}return n.id}watchPages(e){let t="",s=()=>{let o=`${e.location.origin}${e.location.pathname}`;o!==t&&(t=o,setTimeout(()=>this.page({url:o}),0))},n=e.history,i=n.pushState.bind(n),a=n.replaceState.bind(n);return n.pushState=(...o)=>{i(...o),s()},n.replaceState=(...o)=>{a(...o),s()},e.addEventListener("popstate",s),s(),()=>{n.pushState=i,n.replaceState=a,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(n,i)=>{let a=performance.now(),o=n instanceof Request?n:void 0,l=(i?.method??o?.method??"GET").toUpperCase(),h;try{h=new URL(o?.url??String(n),e.location.href)}catch{h=void 0}let u=!!h&&h.pathname.startsWith("/analytics/")||_e(i?.headers??o?.headers);try{let d=await t(n,i);return h&&!u&&this.sample("network",`${l} ${h.origin}${h.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 h&&!u&&this.sample("network",`${l} ${h.origin}${h.pathname}`,performance.now()-a,{attrs:{status:"0"}}),d}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}},Se=r=>r.entryType==="layout-shift"&&"value"in r&&"hadRecentInput"in r,ke=r=>r.entryType==="event"||r.entryType==="first-input";function N(r,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:r,buffered:!0}),t}catch{return}}function Te(r){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,n=[N("largest-contentful-paint",h=>{for(let u of h)e=Math.max(e,u.startTime)}),N("layout-shift",h=>{for(let u of h)Se(u)&&!u.hadRecentInput&&(t+=u.value)}),N("event",h=>{for(let u of h)ke(u)&&(s=Math.max(s,u.duration))}),N("paint",h=>{for(let u of h)u.name==="first-contentful-paint"&&r("FCP",u.startTime)})],i=performance.getEntriesByType("navigation")[0];i&&i.responseStart>0&&r("TTFB",i.responseStart);let a=!1,o=()=>{a||(a=!0,e>0&&r("LCP",e),r("CLS",t),s>0&&r("INP",s))},l=()=>{document.visibilityState==="hidden"&&o()};return document.addEventListener("visibilitychange",l),()=>{o(),document.removeEventListener("visibilitychange",l);for(let h of n)h?.disconnect()}}function _e(r){if(!r)return!1;try{return new Headers(r).has("next-router-prefetch")}catch{return!1}}function Pe(r){if(!r)return"";try{let e=new URL(r);return`${e.origin}${e.pathname}`}catch{return r.split(/[?#]/,1)[0]??""}}var b=class{api;session;socket;ref;fetch;appVersion;listeners=new Set;watch;following;last;constructor(e,t,s,n,i,a){this.api=J.client(e),this.session=t,this.socket=s,this.ref=n,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 Q(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)&&oe(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},n=[t.on("broadcast",i=>{i.event==="changed"&&this.changed(s,B(i.payload))}),t.on("state_snapshot",i=>this.held(s,B(ae(i.entries)))),t.on("state_diff",i=>this.held(s,B(ae(i.set))))];s.off=()=>n.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])oe(t,e)}}};function oe(r,e){try{r(e)}catch{}}function ae(r){let e=typeof r=="object"&&r!==null?r.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function B(r){let e=typeof r=="object"&&r!==null?r.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}function le(){return"cm_"+crypto.randomUUID()}async function L(r,e=4){for(let t=1;;t++)try{return await r()}catch(s){if(t>=e||!(s instanceof p)||s.status===429)throw K(s);let n=X(s,t,30);if(n===void 0)throw K(s);await new Promise(i=>setTimeout(i,n*1e3))}}var U=class{id;api;session;options;status="idle";error=null;messages=new Map;responses=new Map;order=[];turn=null;calls=new Map;handlers=new Map;answering=new Set;listeners=new Set;following;position;snapshot;told=!1;constructor(e,t,s={},n){this.api=e,this.id=t,this.options=s,this.session=n,this.position={after:s.after??0}}get state(){return this.snapshot??=this.build()}subscribe(e){return this.listeners.add(e),this.follow(),()=>{this.listeners.delete(e)}}async*[Symbol.asyncIterator](){let e,t,s=this.subscribe(()=>e?.());try{for(;;){let n=this.state;if(n!==t){t=n,yield n;continue}if(this.status==="closed"||this.status==="failed")return;await new Promise(i=>e=i)}}finally{s()}}async send(e,t={}){let s=t.clientId??le(),n=this.messages.get(s),i=n?{...n,status:"pending",error:null}:{clientId:s,id:null,text:e,author:this.session?.snapshot()?.userId??null,authorName:"",delivery:t.delivery??"next",status:"pending",error:null,responseId:null,createdAt:new Date().toISOString(),mine:!0};this.messages.set(s,i),n||this.order.push({type:"message",key:s}),this.changed(),this.follow();let a={client_id:s,text:i.text};t.delivery!==void 0&&(a.delivery=t.delivery);try{let o=await L(async()=>(await this.api.sendChatMessage({path:{chat_id:this.id},body:a})).data);this.heard(o,!0)}catch(o){let l=this.messages.get(s);throw l.status==="pending"&&(this.messages.set(s,{...l,status:"failed",error:o instanceof p?o.code:"send_failed"}),this.changed()),o}return this.messages.get(s)}tools(e){for(let[t,s]of Object.entries(e))this.handlers.set(t,s);this.follow();for(let t of this.calls.values())this.autoAnswer(t);return()=>{for(let[t,s]of Object.entries(e))this.handlers.get(t)===s&&this.handlers.delete(t)}}async answer(e,t,s={}){let n={output:q(t),is_error:s.isError===!0};this.answering.add(e);try{return await L(()=>this.api.answerChatToolCall({path:{chat_id:this.id,call_id:e},body:n})),!0}catch(i){if(i instanceof p&&i.status===409)return!1;throw this.answering.delete(e),i}}async approve(e,t){await f(this.api.decideChatApproval({path:{chat_id:this.id,approval_id:e},body:t===void 0?{approve:!0}:{approve:!0,reason:t}}))}async deny(e,t){await f(this.api.decideChatApproval({path:{chat_id:this.id,approval_id:e},body:t===void 0?{approve:!1}:{approve:!1,reason:t}}))}async stop(){return(await f(this.api.stopChat({path:{chat_id:this.id}}))).data.stopped}async sendToSubagent(e,t){let s={client_id:le(),text:t};await L(()=>this.api.sendSubagentMessage({path:{chat_id:this.id,run_id:e},body:s}))}close(){this.following?.abort(),this.following=void 0,this.status="closed",this.changed()}follow(){if(this.following||this.status==="closed")return;let e=new AbortController;this.following=e,this.status="connecting",this.error=null,this.changed();let t=Z(async(s,n)=>{this.status!=="connecting"&&(this.status="connecting",this.changed());let i=(await this.api.followChat({path:{chat_id:this.id},query:s,signal:n})).data;return this.status="live",this.changed(),i},{...this.position,resumeFor:this.options.resumeFor,signal:e.signal});(async()=>{try{for await(let s of t)this.take(s)}catch(s){if(this.position=t.position,e.signal.aborted)return;this.status="failed",this.error=s,this.following=void 0,this.changed()}})()}take(e){switch(e.type){case"message":this.heard(e.message,!1);return;case"turn":{let t=this.response(e.response_id);t.status=e.status,t.waiting=e.waiting,t.error=e.error,e.user_id!==void 0&&(t.startedBy=e.user_id),typeof e.solo=="boolean"&&(t.solo=e.solo),this.turn=e;for(let s of this.calls.values())s.response_id===e.response_id&&this.autoAnswer(s);break}case"text":{let t=this.response(e.response_id);t.text=t.text.slice(0,E(t.text,e.offset))+e.text;break}case"reset":{let t=this.response(e.response_id);t.text=t.text.slice(0,E(t.text,e.offset));break}case"tool":{this.response(typeof e.agent_response_id=="string"&&e.agent_response_id!==""?e.agent_response_id:e.response_id).marks.set(`tool:${e.call_id}`,e),this.calls.set(e.call_id,e),this.autoAnswer(e);break}case"agent":{if(this.response(e.parent_response_id).marks.set(e.run_id?`agent:${e.run_id}`:`agent:seq:${e.seq}`,e),!e.response_id)break;let t=this.response(e.response_id);if(t.runId=e.run_id,t.agent=e.name,t.parentId===null){t.parentId=e.parent_response_id;let s=this.order.findIndex(n=>n.type==="response"&&n.key===e.response_id);s>=0&&this.order.splice(s,1)}break}}this.changed()}heard(e,t){let s=this.messages.get(e.client_id),n=e.status==="delivered"||e.status==="failed"?e.status:"pending",i={clientId:e.client_id,id:e.id,text:e.text,author:e.author,authorName:e.author_name,delivery:e.delivery,status:s&&s.status==="delivered"&&t?"delivered":n,error:e.error,responseId:e.response_id??s?.responseId??null,createdAt:e.created_at,mine:s?.mine??!1};this.messages.set(e.client_id,i),s||this.order.push({type:"message",key:e.client_id}),this.changed()}response(e){let t=this.responses.get(e);return t||(t={id:e,status:null,waiting:null,error:null,text:"",marks:new Map,runId:null,agent:null,parentId:null,startedBy:void 0,solo:void 0},this.responses.set(e,t),this.order.push({type:"response",key:e})),t}autoAnswer(e){if(e.status!=="awaiting_output"||this.answering.has(e.call_id)||!this.mine(e.response_id)||this.responses.get(e.response_id)?.solo!==!0)return;let t=this.handlers.get(e.name);t&&(this.answering.add(e.call_id),(async()=>{let s;try{s={output:q(await t(e.input,e)),is_error:!1}}catch(n){s={output:[{type:"text",text:n instanceof Error?n.message||n.name:String(n)}],is_error:!0}}try{await L(()=>this.api.answerChatToolCall({path:{chat_id:this.id,call_id:e.call_id},body:s}))}catch(n){n instanceof p&&(n.status===409||n.status===403)||this.answering.delete(e.call_id)}})())}mine(e){let t=this.session?.snapshot()?.userId;return t!==void 0&&this.responses.get(e)?.startedBy===t}changed(){this.snapshot=void 0,!this.told&&(this.told=!0,queueMicrotask(()=>{this.told=!1;let e=this.state;for(let t of[...this.listeners])try{t(e)}catch{}}))}build(){let e=new Map;for(let n of this.responses.values()){let i=n.parentId!==null?this.responses.get(n.parentId)??n:n;e.set(n.id,Ee(n,i.startedBy??null,this.mine(i.id),i.solo??null))}let t=[];for(let n of this.order)n.type==="message"?t.push({type:"message",message:this.messages.get(n.key)}):this.responses.get(n.key).parentId===null&&t.push({type:"response",response:e.get(n.key)});let s=[...this.calls.values()].filter(n=>this.mine(n.response_id));return{status:this.status,error:this.error,items:t,messages:[...this.messages.values()],responses:[...e.values()],turn:this.turn,waiting:{approvals:s.filter(n=>n.status==="awaiting_approval"),outputs:s.filter(n=>n.status==="awaiting_output")}}}};function Ee(r,e,t,s){let n=[...r.marks.values()].map((o,l)=>({m:o,i:l,at:E(r.text,Math.max(0,Number(o.text_offset)||0))}));n.sort((o,l)=>o.at-l.at||o.i-l.i);let i=[],a=0;for(let{m:o,at:l}of n)l>a&&i.push({type:"text",text:r.text.slice(a,l)}),a=Math.max(a,l),i.push(o.type==="tool"?{type:"tool",tool:o}:{type:"agent",agent:o});return a<r.text.length&&i.push({type:"text",text:r.text.slice(a)}),{id:r.id,status:r.status,waiting:r.waiting,error:r.error,text:r.text,parts:i,runId:r.runId,agent:r.agent,parentId:r.parentId,startedBy:e,mine:t,solo:s}}var S=class{api;session;chats;constructor(e,t){let s=G.client(e);this.api=s,this.session=t,this.chats={async create(n){let i={agent:n.agent};return n.name!==void 0&&(i.name=n.name),n.title!==void 0&&(i.title=n.title),(await f(s.createChat({body:i}))).data},async list(){return(await f(s.listChats({}))).data.chats},async get(n){return(await f(s.getChat({path:{chat_id:n}}))).data},async delete(n){await f(s.deleteChat({path:{chat_id:n}}))}}}chat(e,t={}){if(typeof e!="string"||e==="")throw new TypeError("pb.ai.chat(id): id is the chat's");return new U(this.api,e,t,this.session)}};var Re=/^pb_[a-z0-9]+_s/,Ie=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),Ce=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function xe(r){if(Re.test(r.publishableKey)||"secretKey"in r)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(r.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");let t=new URL(r.url).origin,s=r.storage??(Me()?V(`palbase.session.${t}`):F()),n=r.retry??W,i=P(_({baseUrl:r.url,credentials:{publishableKey:r.publishableKey},fetch:r.fetch}),n),a=m.client(i),o=new C(s,async c=>(await a.refreshToken({body:{refresh_token:c}})).data,c=>c instanceof p&&c.status===401&&Ce.has(c.code),{lockName:`palbase.session.refresh.${t}`}),l=_({baseUrl:r.url,credentials:{publishableKey:r.publishableKey,accessToken:()=>o.accessToken()},fetch:r.fetch,xmlHttpRequest:r.xmlHttpRequest??(r.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),h=P($(l,o),n),u=new v({baseUrl:r.url,publishableKey:r.publishableKey,accessToken:()=>o.accessToken(),webSocket:r.webSocket});o.onChange(c=>{c==="SIGNED_OUT"||c==="SESSION_EXPIRED"||c==="SIGNED_IN"?u.disconnect():c==="TOKEN_REFRESHED"&&u.tokenChanged()});let d=new w($(l,o),o,t);r.analytics&&d.start(r.analytics===!0?{}:r.analytics);let k=new Map,he=c=>{let j=new URL(c).origin,T=k.get(j);return T||(T=P($(_({baseUrl:j,credentials:{accessToken:()=>o.accessToken()},fetch:r.fetch}),o),n),k.set(j,T)),T},H=Object.assign(Object.create(Y),{auth:new R(h,i,o,r.webauthn??globalThis.navigator?.credentials),socket:u,transport:h,analytics:d,purchases:new b(h,o,u,e,r.fetch,r.appVersion),ai:new S(h,o)});return z(H,t,he,h,u),H}function Me(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function $(r,e){return{async send(t){let s=await e.session();try{return await r.send(t)}catch(n){let i=t.auth.some(a=>a.includes("userJWT"));if(!(n instanceof p)||n.status!==401||!Ie.has(n.code)||!i||!s)throw n;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw n}if(e.snapshot()?.userId!==s.userId)throw n;return r.send(t)}}}}export{S as AI,w as Analytics,ue as BackendError,M as Channel,U as ChatSession,p as PalbaseError,b as Purchases,v as RealtimeSocket,de as RoomError,y as SessionChangedError,xe as createClient,ce as isBackendError,V as localStore,F as memoryStore};
|
|
1
|
+
/*! palbase 0.5.0 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a as ue,b as ce,e as de,f as Y,g as z}from"../chunks/2GGJKIKT.js";import{u as Q}from"../chunks/COCND66P.js";import{c as I,e as K,f,g as Z,h as q}from"../chunks/OROMWNJD.js";import{a as G,b as D,c as m,h as J}from"../chunks/6SXSYK4S.js";import{a as W,b as P,c as X}from"../chunks/73WBTWOK.js";import{b as p,d as _}from"../chunks/RQFK2F3Q.js";import"../chunks/IOIQM4QO.js";import"../chunks/FEHN6AHI.js";var E=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,n){this.api=m.client(e),this.open=m.client(t),this.session=s,this.credentials=n;let r=this.api,o=this.open;this.mfa={challenge:async(a,l,h)=>this.signedIn((await o.mfaChallenge({body:{mfa_token:a,type:l,code:h}})).data),recovery:async(a,l)=>this.signedIn((await o.mfaRecovery({body:{mfa_token:a,code:l}})).data),sendSmsCode:async a=>{await o.mfaSmsChallenge({body:{mfa_token:a}})},sendEmailCode:async a=>{await o.mfaEmailChallenge({body:{mfa_token:a}})},enrollTotp:async()=>{let a=(await r.mfaEnroll({body:{type:"totp"}})).data;return{enrollmentId:a.enrollment_id,secret:a.secret,otpUrl:a.otp_url,qrCode:a.qr_code,recoveryCodes:a.recovery_codes}},verifyTotp:async a=>{await r.mfaVerifyEnrollment({body:{code:a}})},enrollSms:async a=>(await r.mfaSmsEnroll({body:{phone:a}})).data,verifySms:async a=>{await r.mfaSmsVerifyEnrollment({body:{code:a}})},enrollEmail:async()=>{await r.mfaEmailEnroll()},factors:async()=>(await r.mfaListFactors()).data,removeFactor:async(a,l)=>{await r.mfaRemoveFactor({path:{id:a},body:{current_password:l}})},regenerateRecoveryCodes:async()=>(await r.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async a=>{let l=(await r.webauthnRegisterBegin({body:{name:a}})).data,h=await this.authenticator().create({publicKey:ee(l.options.publicKey)});return(await r.webauthnRegisterFinish({body:se(h)})).data},signIn:async(a={})=>{let l=(await o.webauthnLoginBegin({body:a.userId?{user_id:a.userId}:{}})).data,h=await this.authenticator().get({publicKey:te(l.options.publicKey)}),u=await o.webauthnLoginFinish({query:a.userId?{user_id:a.userId}:void 0,body:ne(h)});return this.signedIn(u.data)},signUp:async(a,l)=>{let h=(await o.webauthnSignupBegin({body:{identifier:a,user_name:l}})).data,u=await this.authenticator().create({publicKey:ee(h.options.publicKey)});await o.webauthnSignupFinish({query:{user_id:h.user_id},body:se(u)});let d=(await o.webauthnLoginBegin({body:{user_id:h.user_id}})).data,k=await this.authenticator().get({publicKey:te(d.options.publicKey)});return this.signedIn((await o.webauthnLoginFinish({query:{user_id:h.user_id},body:ne(k)})).data)},list:async()=>(await r.webauthnListCredentials()).data,remove:async a=>{await r.webauthnDeleteCredential({path:{id:a}})}},this.magicLink={send:async a=>{await o.magicLinkRequest({body:{email:a}})},verify:async a=>this.signedIn((await o.magicLinkVerify({body:{token:a}})).data)},this.phone={sendCode:async a=>(await o.requestPhoneOtp({body:{phone:a,channel:"sms"}})).data,verifyCode:async(a,l)=>this.signInResult((await o.verifyPhoneOtp({body:{phone:a,token:l}})).data)},this.password={requestReset:async a=>{await o.passwordResetRequest({body:{email:a}})},confirmReset:async(a,l)=>{await o.passwordResetConfirm({body:{token:a,new_password:l}})},change:async a=>(await r.passwordChange({body:a})).data,set:async a=>(await r.setPassword({body:a})).data},this.email={verify:async a=>{await o.verifyEmail({body:a})},resendVerification:async a=>(await o.resendVerification({body:{email:a}})).data},this.sessions={list:async()=>(await r.listSessions()).data,revoke:async a=>{await r.revokeSession({path:{id:a}})},revokeAll:async()=>{await r.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=i=>{let e=atob(i.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(i.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},g=i=>{if(!i)return;let e=i instanceof ArrayBuffer?new Uint8Array(i):new Uint8Array(i.buffer,i.byteOffset,i.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},ie=i=>Array.isArray(i)?i.map(e=>({...e,id:R(String(e.id))})):void 0;function ee(i){let e=i.user;return{...i,challenge:R(String(i.challenge)),user:{...e,id:R(String(e.id))},excludeCredentials:ie(i.excludeCredentials)}}function te(i){return{...i,challenge:R(String(i.challenge)),allowCredentials:ie(i.allowCredentials)}}function se(i){let e=i,t=e.response;return{id:e.id,rawId:g(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:g(t.clientDataJSON),attestationObject:g(t.attestationObject),transports:t.getTransports?.()}}}function ne(i){let e=i,t=e.response;return{id:e.id,rawId:g(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:g(t.clientDataJSON),authenticatorData:g(t.authenticatorData),signature:g(t.signature),userHandle:g(t.userHandle)}}}var y=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function F(){let i=null;return{load:()=>i,save:e=>{i=e},clear:()=>{i=null},shared:!1}}function V(i){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let n=s()?.getItem(i);return n==null?t?null:e:JSON.parse(n)}catch{return e}},save(n){e=n;try{let r=s();if(!r)throw new Error("no storage");r.setItem(i,JSON.stringify(n)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(i)}catch{}},watch(n){let r=globalThis;if(typeof r.addEventListener!="function")return()=>{};let o=a=>{(a.key===i||a.key===null)&&n()};return r.addEventListener("storage",o),()=>r.removeEventListener?.("storage",o)}}}function pe(i){try{let e=i.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 fe=6e4,ge=15e3;function ye(i,e,t){let s=i?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var C=class{current=null;loaded;inflight=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;constructor(e,t,s,n={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=n.now??Date.now,this.lockName=n.lockName??"palbase.session.refresh",this.refreshTimeoutMs=n.refreshTimeoutMs??ge,this.loaded=Promise.resolve(e.load()).then(r=>{this.current=r}),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 n=t==="TOKEN_REFRESHED"?this.current:null,r={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:this.now()+e.expires_in*1e3,userId:s?.id??n?.userId??pe(e.access_token),user:s??n?.user};return this.current=r,await this.store.save(r),this.emit(t,r),r}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>fe?e.accessToken:t>0?(this.refresh().catch(()=>{}),e.accessToken):(await this.refresh()).accessToken}refresh(){if(this.inflight)return this.inflight;let e=ye(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new y("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let n=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new y("the session changed while it was refreshed");return await this.set(n,"TOKEN_REFRESHED")}catch(n){throw this.isRejected(n)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED"),n}});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 y("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 y("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((n,r)=>{t=setTimeout(()=>r(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 M=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 n of s)e?n.resolve():n.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{}}},v=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 M(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 n=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||n?.readyState!==1)return{status:"error",response:{reason:"not joined"}};let r=this.nextRef(),o=JSON.stringify([e.joinRef,r,e.topic,t,s]),a=this.awaitReply(r);return n.send(o),a}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((n,r)=>{let o=new e(t);this.ws=o,o.onopen=()=>{this.attempts=0,this.startHeartbeat(),n()},o.onmessage=a=>this.receive(String(a.data)),o.onerror=()=>r(new Error("the realtime socket could not be opened")),o.onclose=()=>this.dropped(o)});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[,n]of this.replies)n("error",{reason:"socket closed"});this.replies.clear();for(let n of this.channels.values())n.state==="joined"&&(n.state="joining");if(this.closedByUs||![...this.channels.values()].some(n=>n.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=x(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let n=[...this.channels.values()].filter(r=>r.state==="joining");this.open().then(()=>Promise.all(n.map(r=>this.sendJoin(r)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let n=this.awaitReply(s);this.push(s,e.topic,"phx_join",{access_token:t,config:{broadcast:{self:!1}}},s);let{status:r,response:o}=await n;if(this.channels.get(e.name)!==e||e.state!=="joining"){r==="ok"&&this.ws?.readyState===1&&this.push(s,e.topic,"phx_leave",{});return}e.settled(r==="ok",o)}awaitReply(e){return new Promise(t=>{let s=x(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(n,r)=>{clearTimeout(s),this.replies.delete(e),t({status:n,response:r})})})}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,n,r,o]=t,a=typeof o=="object"&&o!==null?o:{};if(r==="phx_reply"&&typeof s=="string"){if(s===this.heartbeatRef){this.heartbeatRef=null;return}this.replies.get(s)?.(String(a.status),a.response??{});return}let l=[...this.channels.values()].find(h=>h.topic===n);if(l){if(r==="phx_close"){l.state="closed";return}if(r==="phx_error"){l.state="joining",x(setTimeout(()=>this.channels.get(l.name)===l&&l.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(l),1e3));return}l.deliver(r,a)}}push(e,t,s,n,r=this.nextRef()){this.ws?.send(JSON.stringify([e,r,t,s,n]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=x(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 x(i){return i.unref?.(),i}var ve=30*6e4,re=1e3,we=100,be=60*1024,A=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function O(){try{return globalThis.localStorage}catch{return}}var w=class{api;closingApi;flushMs;flushAt;now;anonKey;sessionKey;events=[];samples=[];timer;memoryAnon;memorySession;appVersion;stopAuto;session;identifyPending=!1;constructor(e,t,s,n={}){this.session=t,this.api=D.client(e),this.closingApi=D.client({send:r=>e.send({...r,keepalive:!0})}),this.flushMs=n.flushMs??5e3,this.flushAt=n.flushAt??20,this.now=n.now??Date.now,this.anonKey=`palbase.analytics.anonymous.${s}`,this.sessionKey=`palbase.analytics.session.${s}`,t.onChange(r=>{r==="SIGNED_IN"?(this.identifyPending=!0,this.soon()):r==="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,n=e.url??(t?`${t.origin}${t.pathname}`:"");if(!n)return;let r=e.referrer??Pe(s?.referrer);this.capture("$pageview",{...e.properties,url:n,...e.title??s?.title?{title:e.title??s?.title}:{},...r?{referrer:r}:{}})}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{O()?.removeItem(this.anonKey),O()?.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(),n=this.session.snapshot()?.userId;for(this.identifyPending&&n&&(this.identifyPending=!1,await this.sendIdentify(t,n));this.events.length>0;){let r=this.take(this.events,e);try{await t.batch({body:{events:r.map(o=>({...o,sent_at:s}))}})}catch{}}for(;this.samples.length>0;){let r=this.take(this.samples,e);try{await t.sendPerf({body:{items:r}})}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(Te((o,a)=>this.sample("web_vital",o,a))),e.network!==!1&&s.push(this.watchFetch(t));let n=()=>{document.visibilityState==="hidden"&&this.flush(!0)},r=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",n),t.addEventListener("pagehide",r),s.push(()=>{document.removeEventListener("visibilitychange",n),t.removeEventListener("pagehide",r)}),this.stopAuto=()=>{for(let o of s.splice(0))o();this.stopAuto=void 0},this.stopAuto}hold(e){this.events.length>=re&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,n={}){this.samples.length>=re&&this.samples.shift(),this.samples.push({row_id:A(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),distinct_id:this.distinctId(),...n}),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,we);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>be;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=O();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${A()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${A()}`,this.memoryAnon}sessionId(e){let t=O(),s=this.memorySession;try{let r=t?.getItem(this.sessionKey);r&&(s=JSON.parse(r))}catch{}let n=s&&e-s.last<ve?{id:s.id,last:e}:{id:`ses_${A()}`,last:e};this.memorySession=n;try{t?.setItem(this.sessionKey,JSON.stringify(n))}catch{}return n.id}watchPages(e){let t="",s=()=>{let a=`${e.location.origin}${e.location.pathname}`;a!==t&&(t=a,setTimeout(()=>this.page({url:a}),0))},n=e.history,r=n.pushState.bind(n),o=n.replaceState.bind(n);return n.pushState=(...a)=>{r(...a),s()},n.replaceState=(...a)=>{o(...a),s()},e.addEventListener("popstate",s),s(),()=>{n.pushState=r,n.replaceState=o,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(n,r)=>{let o=performance.now(),a=n instanceof Request?n:void 0,l=(r?.method??a?.method??"GET").toUpperCase(),h;try{h=new URL(a?.url??String(n),e.location.href)}catch{h=void 0}let u=!!h&&h.pathname.startsWith("/analytics/")||_e(r?.headers??a?.headers);try{let d=await t(n,r);return h&&!u&&this.sample("network",`${l} ${h.origin}${h.pathname}`,performance.now()-o,{attrs:{status:String(d.status)},...d.headers.get("x-request-id")?{request_id:d.headers.get("x-request-id")}:{}}),d}catch(d){throw h&&!u&&this.sample("network",`${l} ${h.origin}${h.pathname}`,performance.now()-o,{attrs:{status:"0"}}),d}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}},Se=i=>i.entryType==="layout-shift"&&"value"in i&&"hadRecentInput"in i,ke=i=>i.entryType==="event"||i.entryType==="first-input";function N(i,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:i,buffered:!0}),t}catch{return}}function Te(i){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,n=[N("largest-contentful-paint",h=>{for(let u of h)e=Math.max(e,u.startTime)}),N("layout-shift",h=>{for(let u of h)Se(u)&&!u.hadRecentInput&&(t+=u.value)}),N("event",h=>{for(let u of h)ke(u)&&(s=Math.max(s,u.duration))}),N("paint",h=>{for(let u of h)u.name==="first-contentful-paint"&&i("FCP",u.startTime)})],r=performance.getEntriesByType("navigation")[0];r&&r.responseStart>0&&i("TTFB",r.responseStart);let o=!1,a=()=>{o||(o=!0,e>0&&i("LCP",e),i("CLS",t),s>0&&i("INP",s))},l=()=>{document.visibilityState==="hidden"&&a()};return document.addEventListener("visibilitychange",l),()=>{a(),document.removeEventListener("visibilitychange",l);for(let h of n)h?.disconnect()}}function _e(i){if(!i)return!1;try{return new Headers(i).has("next-router-prefetch")}catch{return!1}}function Pe(i){if(!i)return"";try{let e=new URL(i);return`${e.origin}${e.pathname}`}catch{return i.split(/[?#]/,1)[0]??""}}var b=class{api;session;socket;ref;fetch;appVersion;app;listeners=new Set;watch;following;last;constructor(e,t,s,n,r,o,a){this.api=J.client(e),this.session=t,this.socket=s,this.ref=n,this.fetch=r,this.appVersion=o,this.app=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 Q(this.api,this.ref,e,s=>this.checkout(s),{signal:t.signal,fetch:this.fetch,attributes:t.attributes,locale:t.locale,appVersion:this.appVersion,app:this.app})}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)&&ae(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},n=[t.on("broadcast",r=>{r.event==="changed"&&this.changed(s,B(r.payload))}),t.on("state_snapshot",r=>this.held(s,B(oe(r.entries)))),t.on("state_diff",r=>this.held(s,B(oe(r.set))))];s.off=()=>n.forEach(r=>r()),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])ae(t,e)}}};function ae(i,e){try{i(e)}catch{}}function oe(i){let e=typeof i=="object"&&i!==null?i.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function B(i){let e=typeof i=="object"&&i!==null?i.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}function le(){return"cm_"+crypto.randomUUID()}async function L(i,e=4){for(let t=1;;t++)try{return await i()}catch(s){if(t>=e||!(s instanceof p)||s.status===429)throw K(s);let n=X(s,t,30);if(n===void 0)throw K(s);await new Promise(r=>setTimeout(r,n*1e3))}}var U=class{id;api;session;options;status="idle";error=null;messages=new Map;responses=new Map;order=[];turn=null;calls=new Map;handlers=new Map;answering=new Set;listeners=new Set;following;position;snapshot;told=!1;constructor(e,t,s={},n){this.api=e,this.id=t,this.options=s,this.session=n,this.position={after:s.after??0}}get state(){return this.snapshot??=this.build()}subscribe(e){return this.listeners.add(e),this.follow(),()=>{this.listeners.delete(e)}}async*[Symbol.asyncIterator](){let e,t,s=this.subscribe(()=>e?.());try{for(;;){let n=this.state;if(n!==t){t=n,yield n;continue}if(this.status==="closed"||this.status==="failed")return;await new Promise(r=>e=r)}}finally{s()}}async send(e,t={}){let s=t.clientId??le(),n=this.messages.get(s),r=n?{...n,status:"pending",error:null}:{clientId:s,id:null,text:e,author:this.session?.snapshot()?.userId??null,authorName:"",delivery:t.delivery??"next",status:"pending",error:null,responseId:null,createdAt:new Date().toISOString(),mine:!0};this.messages.set(s,r),n||this.order.push({type:"message",key:s}),this.changed(),this.follow();let o={client_id:s,text:r.text};t.delivery!==void 0&&(o.delivery=t.delivery);try{let a=await L(async()=>(await this.api.sendChatMessage({path:{chat_id:this.id},body:o})).data);this.heard(a,!0)}catch(a){let l=this.messages.get(s);throw l.status==="pending"&&(this.messages.set(s,{...l,status:"failed",error:a instanceof p?a.code:"send_failed"}),this.changed()),a}return this.messages.get(s)}tools(e){for(let[t,s]of Object.entries(e))this.handlers.set(t,s);this.follow();for(let t of this.calls.values())this.autoAnswer(t);return()=>{for(let[t,s]of Object.entries(e))this.handlers.get(t)===s&&this.handlers.delete(t)}}async answer(e,t,s={}){let n={output:q(t),is_error:s.isError===!0};this.answering.add(e);try{return await L(()=>this.api.answerChatToolCall({path:{chat_id:this.id,call_id:e},body:n})),!0}catch(r){if(r instanceof p&&r.status===409)return!1;throw this.answering.delete(e),r}}async approve(e,t){await f(this.api.decideChatApproval({path:{chat_id:this.id,approval_id:e},body:t===void 0?{approve:!0}:{approve:!0,reason:t}}))}async deny(e,t){await f(this.api.decideChatApproval({path:{chat_id:this.id,approval_id:e},body:t===void 0?{approve:!1}:{approve:!1,reason:t}}))}async stop(){return(await f(this.api.stopChat({path:{chat_id:this.id}}))).data.stopped}async sendToSubagent(e,t){let s={client_id:le(),text:t};await L(()=>this.api.sendSubagentMessage({path:{chat_id:this.id,run_id:e},body:s}))}close(){this.following?.abort(),this.following=void 0,this.status="closed",this.changed()}follow(){if(this.following||this.status==="closed")return;let e=new AbortController;this.following=e,this.status="connecting",this.error=null,this.changed();let t=Z(async(s,n)=>{this.status!=="connecting"&&(this.status="connecting",this.changed());let r=(await this.api.followChat({path:{chat_id:this.id},query:s,signal:n})).data;return this.status="live",this.changed(),r},{...this.position,resumeFor:this.options.resumeFor,signal:e.signal});(async()=>{try{for await(let s of t)this.take(s)}catch(s){if(this.position=t.position,e.signal.aborted)return;this.status="failed",this.error=s,this.following=void 0,this.changed()}})()}take(e){switch(e.type){case"message":this.heard(e.message,!1);return;case"turn":{let t=this.response(e.response_id);t.status=e.status,t.waiting=e.waiting,t.error=e.error,e.user_id!==void 0&&(t.startedBy=e.user_id),typeof e.solo=="boolean"&&(t.solo=e.solo),this.turn=e;for(let s of this.calls.values())s.response_id===e.response_id&&this.autoAnswer(s);break}case"text":{let t=this.response(e.response_id);t.text=t.text.slice(0,I(t.text,e.offset))+e.text;break}case"reset":{let t=this.response(e.response_id);t.text=t.text.slice(0,I(t.text,e.offset));break}case"tool":{this.response(typeof e.agent_response_id=="string"&&e.agent_response_id!==""?e.agent_response_id:e.response_id).marks.set(`tool:${e.call_id}`,e),this.calls.set(e.call_id,e),this.autoAnswer(e);break}case"agent":{if(this.response(e.parent_response_id).marks.set(e.run_id?`agent:${e.run_id}`:`agent:seq:${e.seq}`,e),!e.response_id)break;let t=this.response(e.response_id);if(t.runId=e.run_id,t.agent=e.name,t.parentId===null){t.parentId=e.parent_response_id;let s=this.order.findIndex(n=>n.type==="response"&&n.key===e.response_id);s>=0&&this.order.splice(s,1)}break}}this.changed()}heard(e,t){let s=this.messages.get(e.client_id),n=e.status==="delivered"||e.status==="failed"?e.status:"pending",r={clientId:e.client_id,id:e.id,text:e.text,author:e.author,authorName:e.author_name,delivery:e.delivery,status:s&&s.status==="delivered"&&t?"delivered":n,error:e.error,responseId:e.response_id??s?.responseId??null,createdAt:e.created_at,mine:s?.mine??!1};this.messages.set(e.client_id,r),s||this.order.push({type:"message",key:e.client_id}),this.changed()}response(e){let t=this.responses.get(e);return t||(t={id:e,status:null,waiting:null,error:null,text:"",marks:new Map,runId:null,agent:null,parentId:null,startedBy:void 0,solo:void 0},this.responses.set(e,t),this.order.push({type:"response",key:e})),t}autoAnswer(e){if(e.status!=="awaiting_output"||this.answering.has(e.call_id)||!this.mine(e.response_id)||this.responses.get(e.response_id)?.solo!==!0)return;let t=this.handlers.get(e.name);t&&(this.answering.add(e.call_id),(async()=>{let s;try{s={output:q(await t(e.input,e)),is_error:!1}}catch(n){s={output:[{type:"text",text:n instanceof Error?n.message||n.name:String(n)}],is_error:!0}}try{await L(()=>this.api.answerChatToolCall({path:{chat_id:this.id,call_id:e.call_id},body:s}))}catch(n){n instanceof p&&(n.status===409||n.status===403)||this.answering.delete(e.call_id)}})())}mine(e){let t=this.session?.snapshot()?.userId;return t!==void 0&&this.responses.get(e)?.startedBy===t}changed(){this.snapshot=void 0,!this.told&&(this.told=!0,queueMicrotask(()=>{this.told=!1;let e=this.state;for(let t of[...this.listeners])try{t(e)}catch{}}))}build(){let e=new Map;for(let n of this.responses.values()){let r=n.parentId!==null?this.responses.get(n.parentId)??n:n;e.set(n.id,Ie(n,r.startedBy??null,this.mine(r.id),r.solo??null))}let t=[];for(let n of this.order)n.type==="message"?t.push({type:"message",message:this.messages.get(n.key)}):this.responses.get(n.key).parentId===null&&t.push({type:"response",response:e.get(n.key)});let s=[...this.calls.values()].filter(n=>this.mine(n.response_id));return{status:this.status,error:this.error,items:t,messages:[...this.messages.values()],responses:[...e.values()],turn:this.turn,waiting:{approvals:s.filter(n=>n.status==="awaiting_approval"),outputs:s.filter(n=>n.status==="awaiting_output")}}}};function Ie(i,e,t,s){let n=[...i.marks.values()].map((a,l)=>({m:a,i:l,at:I(i.text,Math.max(0,Number(a.text_offset)||0))}));n.sort((a,l)=>a.at-l.at||a.i-l.i);let r=[],o=0;for(let{m:a,at:l}of n)l>o&&r.push({type:"text",text:i.text.slice(o,l)}),o=Math.max(o,l),r.push(a.type==="tool"?{type:"tool",tool:a}:{type:"agent",agent:a});return o<i.text.length&&r.push({type:"text",text:i.text.slice(o)}),{id:i.id,status:i.status,waiting:i.waiting,error:i.error,text:i.text,parts:r,runId:i.runId,agent:i.agent,parentId:i.parentId,startedBy:e,mine:t,solo:s}}var S=class{api;session;chats;constructor(e,t){let s=G.client(e);this.api=s,this.session=t,this.chats={async create(n){let r={agent:n.agent};return n.name!==void 0&&(r.name=n.name),n.title!==void 0&&(r.title=n.title),(await f(s.createChat({body:r}))).data},async list(){return(await f(s.listChats({}))).data.chats},async get(n){return(await f(s.getChat({path:{chat_id:n}}))).data},async delete(n){await f(s.deleteChat({path:{chat_id:n}}))}}}chat(e,t={}){if(typeof e!="string"||e==="")throw new TypeError("pb.ai.chat(id): id is the chat's");return new U(this.api,e,t,this.session)}};var Ee=/^pb_[a-z0-9]+_s/,Re=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Ce=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),xe=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function Me(i){if(Ee.test(i.publishableKey)||"secretKey"in i)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(i.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");if(i.appId!==void 0&&!Re.test(i.appId))throw new TypeError("appId is the registered app's id, a UUID (settings.appId of palbase apps:sync), not its slug");let t=new URL(i.url).origin,s=i.storage??(Ae()?V(`palbase.session.${t}`):F()),n=i.retry??W,r=P(_({baseUrl:i.url,credentials:{publishableKey:i.publishableKey},fetch:i.fetch}),n),o=m.client(r),a=new C(s,async c=>(await o.refreshToken({body:{refresh_token:c}})).data,c=>c instanceof p&&c.status===401&&xe.has(c.code),{lockName:`palbase.session.refresh.${t}`}),l=_({baseUrl:i.url,credentials:{publishableKey:i.publishableKey,accessToken:()=>a.accessToken()},fetch:i.fetch,xmlHttpRequest:i.xmlHttpRequest??(i.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),h=P($(l,a),n),u=new v({baseUrl:i.url,publishableKey:i.publishableKey,accessToken:()=>a.accessToken(),webSocket:i.webSocket});a.onChange(c=>{c==="SIGNED_OUT"||c==="SESSION_EXPIRED"||c==="SIGNED_IN"?u.disconnect():c==="TOKEN_REFRESHED"&&u.tokenChanged()});let d=new w($(l,a),a,t);i.analytics&&d.start(i.analytics===!0?{}:i.analytics);let k=new Map,he=c=>{let j=new URL(c).origin,T=k.get(j);return T||(T=P($(_({baseUrl:j,credentials:{accessToken:()=>a.accessToken()},fetch:i.fetch}),a),n),k.set(j,T)),T},H=Object.assign(Object.create(Y),{auth:new E(h,r,a,i.webauthn??globalThis.navigator?.credentials),socket:u,transport:h,analytics:d,purchases:new b(h,a,u,e,i.fetch,i.appVersion,i.appId),ai:new S(h,a)});return z(H,t,he,h,u),H}function Ae(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function $(i,e){return{async send(t){let s=await e.session();try{return await i.send(t)}catch(n){let r=t.auth.some(o=>o.includes("userJWT"));if(!(n instanceof p)||n.status!==401||!Ce.has(n.code)||!r||!s)throw n;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw n}if(e.snapshot()?.userId!==s.userId)throw n;return i.send(t)}}}}export{S as AI,w as Analytics,ue as BackendError,M as Channel,U as ChatSession,p as PalbaseError,b as Purchases,v as RealtimeSocket,de as RoomError,y as SessionChangedError,Me as createClient,ce as isBackendError,V as localStore,F as memoryStore};
|
package/dist/web/palbe.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.
|
|
2
|
-
import{c as e,d as r,h as t}from"../chunks/
|
|
1
|
+
/*! palbase 0.5.0 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{c as e,d as r,h as t}from"../chunks/2GGJKIKT.js";import"../chunks/73WBTWOK.js";import"../chunks/RQFK2F3Q.js";import"../chunks/IOIQM4QO.js";import"../chunks/FEHN6AHI.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.
|
|
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.5.0 — 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/COCND66P.js";import"../chunks/RQFK2F3Q.js";import"../chunks/IOIQM4QO.js";import"../chunks/FEHN6AHI.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.
|
|
2
|
-
import"../chunks/
|
|
1
|
+
/*! palbase 0.5.0 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import"../chunks/FEHN6AHI.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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "palbase",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"README.md"
|
|
106
106
|
],
|
|
107
107
|
"dependencies": {
|
|
108
|
-
"palgres": "0.
|
|
108
|
+
"palgres": "0.5.0",
|
|
109
109
|
"reflect-metadata": "^0.2.2",
|
|
110
110
|
"typescript": "~6.0.3",
|
|
111
111
|
"zod": "^4.6.5"
|
|
@@ -24,8 +24,10 @@ export declare class Container {
|
|
|
24
24
|
readonly eventProviders: Ctor[];
|
|
25
25
|
/** The providers that are @Webhook classes: their @On take a third party's. */
|
|
26
26
|
readonly webhooks: Ctor[];
|
|
27
|
-
/** The providers that are @
|
|
28
|
-
readonly
|
|
27
|
+
/** The providers that are @Cron classes: the platform runs them on their schedules. */
|
|
28
|
+
readonly cronProviders: Ctor[];
|
|
29
|
+
/** The providers that are @Task classes: the platform runs them as their tasks come due. */
|
|
30
|
+
readonly taskProviders: Ctor[];
|
|
29
31
|
/** The providers that are @Room classes. */
|
|
30
32
|
readonly rooms: Ctor[];
|
|
31
33
|
constructor(modules: Function[]);
|
|
@@ -83,7 +83,8 @@ export declare const INJECTABLE: unique symbol;
|
|
|
83
83
|
export declare const MODULE: unique symbol;
|
|
84
84
|
export declare const EVENTS: unique symbol;
|
|
85
85
|
export declare const WEBHOOK: unique symbol;
|
|
86
|
-
export declare const
|
|
86
|
+
export declare const CRONS: unique symbol;
|
|
87
|
+
export declare const TASKS: unique symbol;
|
|
87
88
|
export declare function declared(): Set<Function>;
|
|
88
89
|
export declare const RESERVED: Set<string>;
|
|
89
90
|
export declare function Controller(basePath: string, options?: ControllerOptions): ClassDecorator;
|
|
@@ -179,49 +180,63 @@ export declare const isFileEvent: (event: string) => boolean;
|
|
|
179
180
|
* offers, and each types its handler (EventHandler).
|
|
180
181
|
*/
|
|
181
182
|
export declare function On<E extends EventType | (string & {})>(event: E, options?: OnOptions): <F extends EventHandler<E>>(target: object, key: string | symbol, descriptor: TypedPropertyDescriptor<F>) => void;
|
|
182
|
-
export interface
|
|
183
|
+
export interface CronOptions {
|
|
183
184
|
/**
|
|
184
185
|
* What its runs are kept under (Studio, the CLI) and the platform calls it
|
|
185
186
|
* by: letters, digits, '.', '_' and '-', at most 64. Renaming it starts a
|
|
186
|
-
* new
|
|
187
|
+
* new cron.
|
|
187
188
|
*/
|
|
188
189
|
name: string;
|
|
189
|
-
/** Five fields of cron's — minute hour day-of-month month day-of-week —
|
|
190
|
+
/** Five fields of cron's — minute hour day-of-month month day-of-week — like "0 3 * * *", on the clocks of timeZone. */
|
|
190
191
|
schedule: string;
|
|
191
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* The time zone whose clocks the schedule is on, by its IANA name
|
|
194
|
+
* ("Europe/Istanbul", "America/New_York"): UTC when none. Where its clocks
|
|
195
|
+
* change, a time they skip is not run, and a time they show twice is run
|
|
196
|
+
* the first time only.
|
|
197
|
+
*/
|
|
198
|
+
timeZone?: string;
|
|
199
|
+
/** Seconds one run may take before it is a failed attempt: 1–900 (30). */
|
|
192
200
|
timeout?: number;
|
|
193
201
|
/** Attempts after a failed one, 10 s, 20 s, … five minutes apart: 0–10 (5). */
|
|
194
202
|
retry?: number;
|
|
195
203
|
}
|
|
196
|
-
export interface
|
|
204
|
+
export interface CronDeclaration {
|
|
197
205
|
name: string;
|
|
198
206
|
schedule: string;
|
|
207
|
+
timeZone: string;
|
|
199
208
|
timeout: number;
|
|
200
209
|
retries: number;
|
|
201
210
|
}
|
|
202
|
-
/** One run of a
|
|
203
|
-
export interface
|
|
211
|
+
/** One run of a cron, as the platform calls it: what its run(meta) is given. */
|
|
212
|
+
export interface CronMeta {
|
|
204
213
|
/** The app's environment variables, as it started (its keys left out). */
|
|
205
214
|
env: Record<string, string>;
|
|
206
215
|
/** The project the app belongs to (its id). */
|
|
207
216
|
environmentId: string;
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
/** The cron's name. */
|
|
218
|
+
cron: string;
|
|
219
|
+
/** The run's id: the same for each attempt of one run — what a cron keys its work on to do it once. */
|
|
210
220
|
runId: string;
|
|
211
|
-
/** The minute it was due. */
|
|
221
|
+
/** The minute it was due (or was asked to run now). */
|
|
212
222
|
scheduledAt: Date;
|
|
213
223
|
/** 1 for the first, then one more each time a failed attempt is made again. */
|
|
214
224
|
attempt: number;
|
|
215
225
|
}
|
|
226
|
+
export declare const PLATFORM_NAME: RegExp;
|
|
227
|
+
/** Why a time zone is not one the platform reads its clocks of, or undefined when it is. */
|
|
228
|
+
export declare function zoneProblem(zone: string): string | undefined;
|
|
216
229
|
/**
|
|
217
|
-
* A provider the platform runs on `schedule` — five fields of cron's,
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
230
|
+
* A provider the platform runs on `schedule` — five fields of cron's, on the
|
|
231
|
+
* clocks of its time zone (UTC unless it names one) — by calling its
|
|
232
|
+
* run(meta), on the machine: woken for it if asleep, one of its copies
|
|
233
|
+
* called, one run of a cron at a time. A throw is a failed attempt, made
|
|
234
|
+
* again; a return is done. It runs in a transaction of its own, as the
|
|
221
235
|
* service role: no one called it but the app. Off the platform nothing calls
|
|
222
|
-
* it. Its module lists it in its providers, as any other.
|
|
236
|
+
* it. Its module lists it in its providers, as any other. Studio and the CLI
|
|
237
|
+
* pause it, resume it and run it now.
|
|
223
238
|
*/
|
|
224
|
-
export declare function
|
|
239
|
+
export declare function Cron(options: CronOptions): ClassDecorator;
|
|
225
240
|
/** The senders whose signing scheme is known by name. */
|
|
226
241
|
export type WebhookProvider = 'stripe' | 'github' | 'twilio' | 'sendgrid' | 'slack' | 'discord' | 'livekit';
|
|
227
242
|
/** A signature scheme spelled out, for a sender with no preset: an HMAC of `signs`, in `header`. */
|
|
@@ -91,10 +91,15 @@ export interface AppOptions {
|
|
|
91
91
|
* missing_signature, malformed_signature, stale_timestamp or
|
|
92
92
|
* signature_mismatch. The factory gives it the machine's
|
|
93
93
|
* PALBASE_PLATFORM_SECRET; unset here, none is served (404). They are:
|
|
94
|
-
* - the app's @
|
|
95
|
-
* once a version is up), POST /_palbase/
|
|
96
|
-
* {
|
|
97
|
-
* and answers 204, or the failure the platform tries again;
|
|
94
|
+
* - the app's @Cron classes: GET /_palbase/crons lists them (the platform
|
|
95
|
+
* asks once a version is up), POST /_palbase/crons/<name> runs one — its
|
|
96
|
+
* body {cron, run_id, scheduled_at, attempt} is what the signature covers
|
|
97
|
+
* — and answers 204, or the failure the platform tries again;
|
|
98
|
+
* - its @Task classes: GET /_palbase/tasks lists them (asked with the
|
|
99
|
+
* crons), POST /_palbase/tasks/<name> runs one attempt of a task — {task,
|
|
100
|
+
* id, attempt, payload, created_at} — and answers 204, 422 for a task
|
|
101
|
+
* never to be done (TaskFailure, or a payload its schema refuses), or the
|
|
102
|
+
* failure the platform tries again;
|
|
98
103
|
* - its @Upload routes' two steps, from storage (upload.ts), and its
|
|
99
104
|
* @Room classes' joins, messages and moments, from realtime (rooms.ts):
|
|
100
105
|
* platform-calls.ts;
|
|
@@ -11,7 +11,7 @@ export interface PalbaseConnection {
|
|
|
11
11
|
* The key the platform signs its own calls to this machine with —
|
|
12
12
|
* PALBASE_PLATFORM_SECRET, which the platform starts every machine with.
|
|
13
13
|
* Off the platform there is none, and what only the platform calls (the
|
|
14
|
-
* app's
|
|
14
|
+
* app's crons and tasks, /_palbase/crons and /_palbase/tasks) is not served.
|
|
15
15
|
*/
|
|
16
16
|
platformSecret?: string;
|
|
17
17
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers,
|
|
2
|
+
export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Cron, Injectable, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type CronMeta, type CronOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
|
|
3
|
+
export { Task, TaskFailure, Tasks, type EnqueueOptions, type PayloadOf, type QueuedTask, type TaskClass, type TaskMeta, type TaskOptions, type TasksService } from './tasks.js';
|
|
3
4
|
export { Upload, UploadedObject, type UploadConfig } from './upload.js';
|
|
4
5
|
export { OnAuthorize, OnEmpty, OnFirst, OnJoin, OnLeave, OnMessage, Room, type RoomAuthorizeContext, type RoomContext, type RoomGrant, type RoomMessageContext, type RoomOptions, type RoomUser, } from './rooms.js';
|
|
5
6
|
export { getWebhookManifest, type WebhookEventHandler, type WebhookMeta } from './webhooks.js';
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { type StandardSchemaV1 } from './decorators.js';
|
|
2
|
+
export interface TaskOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The task's type: what its tasks are put on the queue under, kept under
|
|
5
|
+
* (Studio, the CLI) and called by — letters, digits, '.', '_' and '-', at
|
|
6
|
+
* most 64.
|
|
7
|
+
*/
|
|
8
|
+
name: string;
|
|
9
|
+
/** Seconds one attempt may take before it is a failed one: 1–900 (60). */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Attempts after a failed one, 10 s, 20 s, … an hour apart at most: 0–20 (5). */
|
|
12
|
+
retry?: number;
|
|
13
|
+
/** How many of its tasks the machine runs at once, however many copies it has: 1–50 (5). */
|
|
14
|
+
concurrency?: number;
|
|
15
|
+
/**
|
|
16
|
+
* What a task carries, checked before run() is called: a task that does
|
|
17
|
+
* not hold to it can never be done, and fails at once — it is not tried
|
|
18
|
+
* again. run() is given what the schema gives.
|
|
19
|
+
*/
|
|
20
|
+
payload?: StandardSchemaV1;
|
|
21
|
+
}
|
|
22
|
+
export interface TaskDeclaration {
|
|
23
|
+
name: string;
|
|
24
|
+
timeout: number;
|
|
25
|
+
retries: number;
|
|
26
|
+
concurrency: number;
|
|
27
|
+
payload?: StandardSchemaV1;
|
|
28
|
+
}
|
|
29
|
+
/** One attempt of a task, as the platform calls it: what its run(payload, meta) is given beside what it carries. */
|
|
30
|
+
export interface TaskMeta {
|
|
31
|
+
/** The app's environment variables, as it started (its keys left out). */
|
|
32
|
+
env: Record<string, string>;
|
|
33
|
+
/** The project the app belongs to (its id). */
|
|
34
|
+
environmentId: string;
|
|
35
|
+
/** The task's type. */
|
|
36
|
+
task: string;
|
|
37
|
+
/** The task's id: the same for each of its attempts — what it keys its work on to do it once. */
|
|
38
|
+
id: string;
|
|
39
|
+
/** 1 for the first, then one more each time a failed attempt is made again. */
|
|
40
|
+
attempt: number;
|
|
41
|
+
/** When it was put on the queue. */
|
|
42
|
+
createdAt: Date;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown by a task's run(): the task can never be done — what it carries is
|
|
46
|
+
* not what it needs, the thing it works on is gone — and fails now, not to
|
|
47
|
+
* be tried again. Any other throw is an attempt that failed, made again.
|
|
48
|
+
*/
|
|
49
|
+
export declare class TaskFailure extends Error {
|
|
50
|
+
constructor(message: string, options?: {
|
|
51
|
+
cause?: unknown;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A provider whose run(payload, meta) does tasks of its type: put on the
|
|
56
|
+
* queue with Tasks.enqueue(TheClass, payload), each run once its time
|
|
57
|
+
* comes — on the platform, which wakes the machine for it; off it, in this
|
|
58
|
+
* process. A return is done; a throw an attempt that failed, made again
|
|
59
|
+
* later (a TaskFailure: failed for good). It runs in a transaction of its
|
|
60
|
+
* own, as the service role: no one called it but the app. Its module lists
|
|
61
|
+
* it in its providers, as any other.
|
|
62
|
+
*/
|
|
63
|
+
export declare function Task(options: TaskOptions): ClassDecorator;
|
|
64
|
+
/** A @Task class: its constructor takes what it was written to take, its run() a payload and the meta. */
|
|
65
|
+
export type TaskClass = abstract new (...args: never[]) => {
|
|
66
|
+
run(payload: never, meta: TaskMeta): unknown;
|
|
67
|
+
};
|
|
68
|
+
/** What a @Task class's run() takes as its payload. */
|
|
69
|
+
export type PayloadOf<C> = C extends abstract new (...args: never[]) => {
|
|
70
|
+
run(payload: infer P, ...rest: never[]): unknown;
|
|
71
|
+
} ? P : never;
|
|
72
|
+
export interface EnqueueOptions {
|
|
73
|
+
/** Due this many seconds from now (30 days at most). */
|
|
74
|
+
delay?: number;
|
|
75
|
+
/** Due at this time (30 days from now at most; a time past is now). */
|
|
76
|
+
runAt?: Date;
|
|
77
|
+
/**
|
|
78
|
+
* Put once under this key: another task of its type under the same key,
|
|
79
|
+
* while the first is held — until a day after it is over — is not put,
|
|
80
|
+
* and the first is answered (duplicate: true).
|
|
81
|
+
*/
|
|
82
|
+
key?: string;
|
|
83
|
+
}
|
|
84
|
+
/** A task on the queue, as it was put. */
|
|
85
|
+
export interface QueuedTask {
|
|
86
|
+
id: string;
|
|
87
|
+
task: string;
|
|
88
|
+
state: 'waiting' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
89
|
+
attempt: number;
|
|
90
|
+
/** When it is due (RFC 3339): JSON as it is, so a handler can answer with the task. */
|
|
91
|
+
runAt: string;
|
|
92
|
+
key?: string;
|
|
93
|
+
reason?: string;
|
|
94
|
+
/** Put already under its key: this is that task, and nothing new was put. */
|
|
95
|
+
duplicate: boolean;
|
|
96
|
+
}
|
|
97
|
+
/** The queue the app puts its tasks on: the platform's, or its own off the platform. */
|
|
98
|
+
export interface TaskQueue {
|
|
99
|
+
enqueue(task: string, payload: unknown, options: EnqueueOptions & {
|
|
100
|
+
machine?: string;
|
|
101
|
+
}): Promise<QueuedTask>;
|
|
102
|
+
cancel(id: string, machine?: string): Promise<QueuedTask>;
|
|
103
|
+
get(id: string, machine?: string): Promise<QueuedTask>;
|
|
104
|
+
}
|
|
105
|
+
export interface TasksService {
|
|
106
|
+
/**
|
|
107
|
+
* Put a task of this @Task class on the machine's queue, carrying payload
|
|
108
|
+
* — what its run() takes, checked as it is written.
|
|
109
|
+
*/
|
|
110
|
+
enqueue<C extends TaskClass>(task: C, payload: PayloadOf<C>, options?: EnqueueOptions): Promise<QueuedTask>;
|
|
111
|
+
/** Put a task of a type by its name — of another of the project's machines, with machine. */
|
|
112
|
+
enqueue(task: string, payload?: unknown, options?: EnqueueOptions & {
|
|
113
|
+
machine?: string;
|
|
114
|
+
}): Promise<QueuedTask>;
|
|
115
|
+
/** Take a task that is waiting off the queue: it is not run. */
|
|
116
|
+
cancel(id: string, options?: {
|
|
117
|
+
machine?: string;
|
|
118
|
+
}): Promise<QueuedTask>;
|
|
119
|
+
/** A task on the queue, as it is now. */
|
|
120
|
+
get(id: string, options?: {
|
|
121
|
+
machine?: string;
|
|
122
|
+
}): Promise<QueuedTask>;
|
|
123
|
+
}
|
|
124
|
+
/** The machine's task queue. */
|
|
125
|
+
export declare const Tasks: TasksService;
|
|
126
|
+
/** The platform's queue of the machine this app runs on (PALBASE_MACHINE), or of another of the project's. */
|
|
127
|
+
export declare function platformQueue(machine: string | undefined): TaskQueue;
|
|
128
|
+
/** How the app does one attempt of a task: what the platform's call would answer. */
|
|
129
|
+
export type RunTask = (call: {
|
|
130
|
+
task: string;
|
|
131
|
+
id: string;
|
|
132
|
+
attempt: number;
|
|
133
|
+
payload: unknown;
|
|
134
|
+
createdAt: Date;
|
|
135
|
+
}, signal: AbortSignal) => Promise<{
|
|
136
|
+
status: number;
|
|
137
|
+
message?: string;
|
|
138
|
+
}>;
|
|
139
|
+
/**
|
|
140
|
+
* The app's own queue, off the platform: its tasks run in this process, as
|
|
141
|
+
* the platform would run them — when due, each type no more at once than its
|
|
142
|
+
* concurrency, an attempt that failed made again later, a key held a day
|
|
143
|
+
* after its task is over. Nothing of it outlives the process.
|
|
144
|
+
*/
|
|
145
|
+
export declare class LocalQueue implements TaskQueue {
|
|
146
|
+
private readonly types;
|
|
147
|
+
private readonly run;
|
|
148
|
+
private readonly now;
|
|
149
|
+
private readonly tasks;
|
|
150
|
+
private readonly running;
|
|
151
|
+
private readonly idle;
|
|
152
|
+
constructor(types: ReadonlyMap<string, TaskDeclaration>, run: RunTask, now?: () => number);
|
|
153
|
+
enqueue(task: string, payload: unknown, o: EnqueueOptions & {
|
|
154
|
+
machine?: string;
|
|
155
|
+
}): Promise<QueuedTask>;
|
|
156
|
+
cancel(id: string): Promise<QueuedTask>;
|
|
157
|
+
get(id: string): Promise<QueuedTask>;
|
|
158
|
+
/** Resolves once no task is waiting to run now, nor running: what a test waits for after putting one. */
|
|
159
|
+
settled(): Promise<void>;
|
|
160
|
+
private quiet;
|
|
161
|
+
private known;
|
|
162
|
+
private view;
|
|
163
|
+
private schedule;
|
|
164
|
+
private pump;
|
|
165
|
+
private attempt;
|
|
166
|
+
private finish;
|
|
167
|
+
private wake;
|
|
168
|
+
}
|