palbase 0.3.3 → 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 +10 -13
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +11 -11
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/{4AQYBTIN.js → 2GGJKIKT.js} +2 -2
- package/dist/chunks/2S5VK2PA.js +2 -0
- package/dist/chunks/{NK54UVDI.js → 6SXSYK4S.js} +2 -2
- package/dist/chunks/{IXHR57QC.js → 73WBTWOK.js} +2 -2
- package/dist/chunks/{4YD2XCGF.js → ABBUC5HE.js} +1 -1
- package/dist/chunks/{PB7UKHCY.js → C627JALV.js} +2 -2
- package/dist/chunks/{YWOS5WH2.js → CC36MKWZ.js} +2 -2
- package/dist/chunks/{TJ5SQTW5.js → COCND66P.js} +3 -3
- package/dist/chunks/{PRM2UXWG.js → FEHN6AHI.js} +1 -1
- package/dist/chunks/{P5JIZEPB.js → GUR3A4M7.js} +2 -2
- package/dist/chunks/HNMC2RJ7.js +20 -0
- package/dist/chunks/{OKZJIY6F.js → IOIQM4QO.js} +1 -1
- package/dist/chunks/OROMWNJD.js +6 -0
- package/dist/chunks/{47V66C2X.js → R5BCF2YW.js} +2 -2
- package/dist/chunks/RBUTW6OM.js +4 -0
- package/dist/chunks/{UXRIXHHY.js → RQFK2F3Q.js} +2 -2
- package/dist/cli.js +132 -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/ai/src/ai.d.ts +63 -2
- package/types/ai/src/chats.d.ts +147 -0
- package/types/ai/src/index.d.ts +6 -1
- package/types/ai/src/tools.d.ts +167 -0
- 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 +21 -5
- package/types/backend/src/env.d.ts +1 -1
- package/types/backend/src/i18n.d.ts +8 -7
- package/types/backend/src/index.d.ts +2 -1
- package/types/backend/src/strings-files.d.ts +28 -1
- package/types/backend/src/tasks.d.ts +168 -0
- package/types/internal/src/chat.d.ts +117 -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/internal/src/tool-output.d.ts +20 -0
- package/types/web/src/ai.d.ts +201 -0
- package/types/web/src/client.d.ts +10 -0
- package/types/web/src/index.d.ts +1 -0
- package/types/web/src/paywall/placement.d.ts +2 -0
- package/types/web/src/purchases.d.ts +3 -1
- package/dist/chunks/CJCMQ73A.js +0 -20
- package/dist/chunks/CZQ7KIRM.js +0 -2
- package/dist/chunks/M5B52IE6.js +0 -4
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 Z,b as ee,e as te,f as F,g as B}from"../chunks/4AQYBTIN.js";import{u as $}from"../chunks/TJ5SQTW5.js";import{b as M,c as y,h as D}from"../chunks/NK54UVDI.js";import{a as q,b as P}from"../chunks/IXHR57QC.js";import{b as S,d as k}from"../chunks/UXRIXHHY.js";import"../chunks/OKZJIY6F.js";import"../chunks/PRM2UXWG.js";var T=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,r){this.api=y.client(e),this.open=y.client(t),this.session=s,this.credentials=r;let i=this.api,a=this.open;this.mfa={challenge:async(o,c,l)=>this.signedIn((await a.mfaChallenge({body:{mfa_token:o,type:c,code:l}})).data),recovery:async(o,c)=>this.signedIn((await a.mfaRecovery({body:{mfa_token:o,code:c}})).data),sendSmsCode:async o=>{await a.mfaSmsChallenge({body:{mfa_token:o}})},sendEmailCode:async o=>{await a.mfaEmailChallenge({body:{mfa_token:o}})},enrollTotp:async()=>{let o=(await i.mfaEnroll({body:{type:"totp"}})).data;return{enrollmentId:o.enrollment_id,secret:o.secret,otpUrl:o.otp_url,qrCode:o.qr_code,recoveryCodes:o.recovery_codes}},verifyTotp:async o=>{await i.mfaVerifyEnrollment({body:{code:o}})},enrollSms:async o=>(await i.mfaSmsEnroll({body:{phone:o}})).data,verifySms:async o=>{await i.mfaSmsVerifyEnrollment({body:{code:o}})},enrollEmail:async()=>{await i.mfaEmailEnroll()},factors:async()=>(await i.mfaListFactors()).data,removeFactor:async(o,c)=>{await i.mfaRemoveFactor({path:{id:o},body:{current_password:c}})},regenerateRecoveryCodes:async()=>(await i.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async o=>{let c=(await i.webauthnRegisterBegin({body:{name:o}})).data,l=await this.authenticator().create({publicKey:H(c.options.publicKey)});return(await i.webauthnRegisterFinish({body:G(l)})).data},signIn:async(o={})=>{let c=(await a.webauthnLoginBegin({body:o.userId?{user_id:o.userId}:{}})).data,l=await this.authenticator().get({publicKey:V(c.options.publicKey)}),u=await a.webauthnLoginFinish({query:o.userId?{user_id:o.userId}:void 0,body:J(l)});return this.signedIn(u.data)},signUp:async(o,c)=>{let l=(await a.webauthnSignupBegin({body:{identifier:o,user_name:c}})).data,u=await this.authenticator().create({publicKey:H(l.options.publicKey)});await a.webauthnSignupFinish({query:{user_id:l.user_id},body:G(u)});let d=(await a.webauthnLoginBegin({body:{user_id:l.user_id}})).data,w=await this.authenticator().get({publicKey:V(d.options.publicKey)});return this.signedIn((await a.webauthnLoginFinish({query:{user_id:l.user_id},body:J(w)})).data)},list:async()=>(await i.webauthnListCredentials()).data,remove:async o=>{await i.webauthnDeleteCredential({path:{id:o}})}},this.magicLink={send:async o=>{await a.magicLinkRequest({body:{email:o}})},verify:async o=>this.signedIn((await a.magicLinkVerify({body:{token:o}})).data)},this.phone={sendCode:async o=>(await a.requestPhoneOtp({body:{phone:o,channel:"sms"}})).data,verifyCode:async(o,c)=>this.signInResult((await a.verifyPhoneOtp({body:{phone:o,token:c}})).data)},this.password={requestReset:async o=>{await a.passwordResetRequest({body:{email:o}})},confirmReset:async(o,c)=>{await a.passwordResetConfirm({body:{token:o,new_password:c}})},change:async o=>(await i.passwordChange({body:o})).data,set:async o=>(await i.setPassword({body:o})).data},this.email={verify:async o=>{await a.verifyEmail({body:o})},resendVerification:async o=>(await a.resendVerification({body:{email:o}})).data},this.sessions={list:async()=>(await i.listSessions()).data,revoke:async o=>{await i.revokeSession({path:{id:o}})},revokeAll:async()=>{await i.revokeAllSessions()}}}onAuthStateChange(e){return this.session.onChange(e)}currentSession(){return this.session.session()}async signUp(e){let t=(await this.open.signup({body:e})).data;return t.access_token&&t.refresh_token&&t.expires_in!==void 0&&await this.session.set({access_token:t.access_token,refresh_token:t.refresh_token,expires_in:t.expires_in},"SIGNED_IN",t.user),t}async signIn(e,t){return this.signInResult((await this.open.login({body:{email:e,password:t}})).data)}async signOut(){try{await this.session.session()&&await this.api.logout()}finally{await this.session.clear("SIGNED_OUT")}}async getUser(){let e=this.session.snapshot(),t=(await this.api.getMe()).data;return await this.session.setUser(t,e),t}async refreshSession(){return this.session.refresh()}async deleteAccount(e){await this.api.deleteAccount(e===void 0?void 0:{body:{password:e}}),await this.session.clear("SIGNED_OUT")}async signInResult(e){return"mfa_required"in e&&e.mfa_required?{mfaRequired:{mfaToken:e.mfa_token,factors:e.factors}}:{user:await this.signedIn(e)}}async setSession(e){return this.signedIn(e)}async signedIn(e){let t=await this.session.set({access_token:e.access_token,refresh_token:e.refresh_token,expires_in:e.expires_in},"SIGNED_IN",e.user);if(e.user)return e.user;let s=(await this.api.verifyTokenUser()).data;return await this.session.setUser(s,t),s}authenticator(){if(!this.credentials)throw new Error("passkeys need navigator.credentials (or createClient({ webauthn }))");return this.credentials}},R=n=>{let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},p=n=>{if(!n)return;let e=n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},W=n=>Array.isArray(n)?n.map(e=>({...e,id:R(String(e.id))})):void 0;function H(n){let e=n.user;return{...n,challenge:R(String(n.challenge)),user:{...e,id:R(String(e.id))},excludeCredentials:W(n.excludeCredentials)}}function V(n){return{...n,challenge:R(String(n.challenge)),allowCredentials:W(n.allowCredentials)}}function G(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),attestationObject:p(t.attestationObject),transports:t.getTransports?.()}}}function J(n){let e=n,t=e.response;return{id:e.id,rawId:p(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:p(t.clientDataJSON),authenticatorData:p(t.authenticatorData),signature:p(t.signature),userHandle:p(t.userHandle)}}}var f=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function N(){let n=null;return{load:()=>n,save:e=>{n=e},clear:()=>{n=null},shared:!1}}function L(n){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let r=s()?.getItem(n);return r==null?t?null:e:JSON.parse(r)}catch{return e}},save(r){e=r;try{let i=s();if(!i)throw new Error("no storage");i.setItem(n,JSON.stringify(r)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(n)}catch{}},watch(r){let i=globalThis;if(typeof i.addEventListener!="function")return()=>{};let a=o=>{(o.key===n||o.key===null)&&r()};return i.addEventListener("storage",a),()=>i.removeEventListener?.("storage",a)}}}function se(n){try{let e=n.split(".")[1]??"",t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),s=JSON.parse(t).sub;return typeof s=="string"?s:""}catch{return""}}var ne=6e4,ie=15e3;function re(n,e,t){let s=n?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var E=class{current=null;loaded;inflight=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;constructor(e,t,s,r={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=r.now??Date.now,this.lockName=r.lockName??"palbase.session.refresh",this.refreshTimeoutMs=r.refreshTimeoutMs??ie,this.loaded=Promise.resolve(e.load()).then(i=>{this.current=i}),e.watch?.(()=>{this.reconcile()})}async session(){return await this.loaded,this.current}snapshot(){return this.current}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async set(e,t,s){await this.loaded;let r=t==="TOKEN_REFRESHED"?this.current:null,i={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:this.now()+e.expires_in*1e3,userId:s?.id??r?.userId??se(e.access_token),user:s??r?.user};return this.current=i,await this.store.save(i),this.emit(t,i),i}async setUser(e,t){await this.loaded,!(!this.current||!t||this.current.userId!==t.userId)&&(this.current={...this.current,user:e},await this.store.save(this.current),this.emit("USER_UPDATED",this.current))}async clear(e){await this.loaded;let t=this.current;this.current=null,this.inflight=null;let s=await this.store.load();(!s||!t||s.userId===t.userId)&&await this.store.clear(),t&&this.emit(e,null)}async accessToken(){await this.loaded;let e=this.current;if(!e)return;let t=e.expiresAt-this.now();return t>ne?e.accessToken:t>0?(this.refresh().catch(()=>{}),e.accessToken):(await this.refresh()).accessToken}refresh(){if(this.inflight)return this.inflight;let e=re(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new f("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let r=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new f("the session changed while it was refreshed");return await this.set(r,"TOKEN_REFRESHED")}catch(r){throw this.isRejected(r)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED"),r}});return this.inflight=e,e.finally(()=>{this.inflight===e&&(this.inflight=null)}).catch(()=>{}),e}async adoptStored(e){let t=await this.store.load();if(!t)throw this.current=null,this.emit("SIGNED_OUT",null),new f("signed out in another tab");if(t.userId!==e.userId)throw this.current=t,this.emit("SIGNED_OUT",null),this.emit("SIGNED_IN",t),new f("another user signed in in another tab");if(t.refreshToken!==e.refreshToken&&t.expiresAt>=e.expiresAt)return this.current=t,this.emit("TOKEN_REFRESHED",t),t}async reconcile(){await this.loaded;let e=this.current,t=await this.store.load();if(!e){t&&(this.current=t,this.emit("SIGNED_IN",t));return}await this.adoptStored(e).catch(()=>{})}withTimeout(e){let t,s=new Promise((r,i)=>{t=setTimeout(()=>i(new Error(`the refresh did not answer within ${this.refreshTimeoutMs/1e3} s`)),this.refreshTimeoutMs)});return Promise.race([e,s]).finally(()=>clearTimeout(t))}emit(e,t){for(let s of this.listeners)try{s(e,t)}catch{}}};var _=class{state="closed";refusal;joinRef=null;listeners=new Map;closers=new Set;joinWaiters=[];name;socket;constructor(e,t){this.name=e,this.socket=t}get topic(){return`realtime:${this.name}`}join(){if(this.state==="joined")return Promise.resolve();let e=new Promise((t,s)=>this.joinWaiters.push({resolve:t,reject:s}));return this.state!=="joining"&&this.socket.join(this),e}leave(){this.socket.leave(this)}push(e,t){return this.socket.request(this,e,t)}on(e,t){let s=this.listeners.get(e);return s||this.listeners.set(e,s=new Set),s.add(t),()=>s.delete(t)}onClosed(e){return this.closers.add(e),()=>this.closers.delete(e)}deliver(e,t){for(let s of this.listeners.get(e)??[])try{s(t)}catch{}}settled(e,t){this.state=e?"joined":"refused",this.refusal=e?void 0:t;let s=this.joinWaiters.splice(0);for(let r of s)e?r.resolve():r.reject(new Error(`join ${this.name} refused: ${JSON.stringify(t)}`))}closed(e){this.state="closed",this.joinRef=null;let t=this.joinWaiters.splice(0);for(let s of t)s.reject(new Error(`join ${this.name}: ${e}`));for(let s of[...this.closers])try{s()}catch{}}},m=class{ws=null;opening=null;ref=0;channels=new Map;replies=new Map;heartbeat=null;heartbeatRef=null;reconnectTimer=null;attempts=0;closedByUs=!1;reconnects=0;opts;constructor(e){this.opts=e}channel(e){let t=this.channels.get(e);return t||this.channels.set(e,t=new _(e,this)),t}disconnect(){this.closedByUs=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.stopHeartbeat();let e=this.ws;this.ws=null,this.opening=null,e?.close(1e3);for(let[,t]of this.replies)t("error",{reason:"socket closed"});this.replies.clear();for(let t of this.channels.values())t.closed("the socket was closed")}async tokenChanged(){if(!this.ws||this.ws.readyState!==1)return;let e=await this.opts.accessToken();if(e)for(let t of this.channels.values())t.state==="joined"&&this.push(t.joinRef,t.topic,"access_token",{access_token:e})}join(e){e.state="joining",this.open().then(()=>this.sendJoin(e)).catch(t=>e.settled(!1,{reason:t instanceof Error?t.message:String(t)}))}leave(e){e.state==="joined"&&this.ws?.readyState===1&&this.push(e.joinRef,e.topic,"phx_leave",{}),e.state="closed",this.channels.delete(e.name)}async request(e,t,s){let r=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||r?.readyState!==1)return{status:"error",response:{reason:"not joined"}};let i=this.nextRef(),a=JSON.stringify([e.joinRef,i,e.topic,t,s]),o=this.awaitReply(i);return r.send(a),o}open(){if(this.ws?.readyState===1)return Promise.resolve();if(this.opening)return this.opening;this.closedByUs=!1;let e=this.opts.webSocket??globalThis.WebSocket,t=`${this.opts.baseUrl.replace(/^http/,"ws")}/realtime/v1/websocket?vsn=2.0.0&apikey=${encodeURIComponent(this.opts.publishableKey)}`,s=new Promise((r,i)=>{let a=new e(t);this.ws=a,a.onopen=()=>{this.attempts=0,this.startHeartbeat(),r()},a.onmessage=o=>this.receive(String(o.data)),a.onerror=()=>i(new Error("the realtime socket could not be opened")),a.onclose=()=>this.dropped(a)});return this.opening=s,s.finally(()=>{this.opening===s&&(this.opening=null)}).catch(()=>{}),s}dropped(e){if(this.ws!==e)return;this.ws=null,this.stopHeartbeat();for(let[,r]of this.replies)r("error",{reason:"socket closed"});this.replies.clear();for(let r of this.channels.values())r.state==="joined"&&(r.state="joining");if(this.closedByUs||![...this.channels.values()].some(r=>r.state==="joining"))return;let t=this.opts.backoff??[500,1e3,2e3,5e3,1e4,3e4],s=t[Math.min(this.attempts,t.length-1)]*(.8+Math.random()*.4);this.attempts++,this.reconnectTimer=I(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let r=[...this.channels.values()].filter(i=>i.state==="joining");this.open().then(()=>Promise.all(r.map(i=>this.sendJoin(i)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let r=this.awaitReply(s);this.push(s,e.topic,"phx_join",{access_token:t,config:{broadcast:{self:!1}}},s);let{status:i,response:a}=await r;if(this.channels.get(e.name)!==e||e.state!=="joining"){i==="ok"&&this.ws?.readyState===1&&this.push(s,e.topic,"phx_leave",{});return}e.settled(i==="ok",a)}awaitReply(e){return new Promise(t=>{let s=I(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(r,i)=>{clearTimeout(s),this.replies.delete(e),t({status:r,response:i})})})}receive(e){let t;try{t=JSON.parse(e)}catch{return}if(!Array.isArray(t)||t.length!==5||typeof t[2]!="string"||typeof t[3]!="string")return;let[,s,r,i,a]=t,o=typeof a=="object"&&a!==null?a:{};if(i==="phx_reply"&&typeof s=="string"){if(s===this.heartbeatRef){this.heartbeatRef=null;return}this.replies.get(s)?.(String(o.status),o.response??{});return}let c=[...this.channels.values()].find(l=>l.topic===r);if(c){if(i==="phx_close"){c.state="closed";return}if(i==="phx_error"){c.state="joining",I(setTimeout(()=>this.channels.get(c.name)===c&&c.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(c),1e3));return}c.deliver(i,o)}}push(e,t,s,r,i=this.nextRef()){this.ws?.send(JSON.stringify([e,i,t,s,r]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=I(setInterval(()=>{if(this.heartbeatRef!==null){this.heartbeatRef=null,this.ws?.close(4e3);return}this.heartbeatRef=this.nextRef(),this.push(null,"phoenix","heartbeat",{},this.heartbeatRef)},this.opts.heartbeatMs??25e3))}stopHeartbeat(){this.heartbeat&&clearInterval(this.heartbeat),this.heartbeat=null,this.heartbeatRef=null}};function I(n){return n.unref?.(),n}var ae=30*6e4,X=1e3,le=100,ce=60*1024,C=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function x(){try{return globalThis.localStorage}catch{return}}var g=class{api;closingApi;flushMs;flushAt;now;anonKey;sessionKey;events=[];samples=[];timer;memoryAnon;memorySession;appVersion;stopAuto;session;identifyPending=!1;constructor(e,t,s,r={}){this.session=t,this.api=M.client(e),this.closingApi=M.client({send:i=>e.send({...i,keepalive:!0})}),this.flushMs=r.flushMs??5e3,this.flushAt=r.flushAt??20,this.now=r.now??Date.now,this.anonKey=`palbase.analytics.anonymous.${s}`,this.sessionKey=`palbase.analytics.session.${s}`,t.onChange(i=>{i==="SIGNED_IN"?(this.identifyPending=!0,this.soon()):i==="SIGNED_OUT"&&(this.identifyPending=!1,this.reset())})}capture(e,t){let s=this.now();this.hold({event:e,distinct_id:this.distinctId(),properties:t,timestamp:s,session_id:this.sessionId(s),...this.appVersion?{app_version:this.appVersion}:{}})}page(e={}){let t=globalThis.location,s=globalThis.document,r=e.url??(t?`${t.origin}${t.pathname}`:"");if(!r)return;let i=e.referrer??fe(s?.referrer);this.capture("$pageview",{...e.properties,url:r,...e.title??s?.title?{title:e.title??s?.title}:{},...i?{referrer:i}:{}})}async identify(e){this.identifyPending=!1;let t=this.session.snapshot()?.userId;t&&(await this.flush(),await this.sendIdentify(this.api,t,e))}async sendIdentify(e,t,s){try{await e.identify({body:{distinct_id:t,anonymous_id:this.anonymousId(),traits:s,timestamp:this.now(),sent_at:this.now()}})}catch{}}reset(){this.memoryAnon=void 0,this.memorySession=void 0;try{x()?.removeItem(this.anonKey),x()?.removeItem(this.sessionKey)}catch{}}async flush(e=!1){this.timer&&clearTimeout(this.timer),this.timer=void 0;let t=e?this.closingApi:this.api,s=this.now(),r=this.session.snapshot()?.userId;for(this.identifyPending&&r&&(this.identifyPending=!1,await this.sendIdentify(t,r));this.events.length>0;){let i=this.take(this.events,e);try{await t.batch({body:{events:i.map(a=>({...a,sent_at:s}))}})}catch{}}for(;this.samples.length>0;){let i=this.take(this.samples,e);try{await t.sendPerf({body:{items:i}})}catch{}}}start(e={}){this.stopAuto?.(),this.appVersion=e.appVersion;let t=globalThis;if(typeof t.addEventListener!="function"||typeof globalThis.document>"u")return()=>{};let s=[];e.pageViews!==!1&&s.push(this.watchPages(t)),e.webVitals!==!1&&s.push(de((a,o)=>this.sample("web_vital",a,o))),e.network!==!1&&s.push(this.watchFetch(t));let r=()=>{document.visibilityState==="hidden"&&this.flush(!0)},i=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",r),t.addEventListener("pagehide",i),s.push(()=>{document.removeEventListener("visibilitychange",r),t.removeEventListener("pagehide",i)}),this.stopAuto=()=>{for(let a of s.splice(0))a();this.stopAuto=void 0},this.stopAuto}hold(e){this.events.length>=X&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,r={}){this.samples.length>=X&&this.samples.shift(),this.samples.push({row_id:C(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),distinct_id:this.distinctId(),...r}),this.soon()}soon(){if(this.events.length+this.samples.length>=this.flushAt){this.flush();return}this.timer||(this.timer=setTimeout(()=>{this.flush()},this.flushMs),this.timer.unref?.())}take(e,t){let s=e.splice(0,le);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>ce;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=x();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${C()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${C()}`,this.memoryAnon}sessionId(e){let t=x(),s=this.memorySession;try{let i=t?.getItem(this.sessionKey);i&&(s=JSON.parse(i))}catch{}let r=s&&e-s.last<ae?{id:s.id,last:e}:{id:`ses_${C()}`,last:e};this.memorySession=r;try{t?.setItem(this.sessionKey,JSON.stringify(r))}catch{}return r.id}watchPages(e){let t="",s=()=>{let o=`${e.location.origin}${e.location.pathname}`;o!==t&&(t=o,setTimeout(()=>this.page({url:o}),0))},r=e.history,i=r.pushState.bind(r),a=r.replaceState.bind(r);return r.pushState=(...o)=>{i(...o),s()},r.replaceState=(...o)=>{a(...o),s()},e.addEventListener("popstate",s),s(),()=>{r.pushState=i,r.replaceState=a,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(r,i)=>{let a=performance.now(),o=r instanceof Request?r:void 0,c=(i?.method??o?.method??"GET").toUpperCase(),l;try{l=new URL(o?.url??String(r),e.location.href)}catch{l=void 0}let u=!!l&&l.pathname.startsWith("/analytics/")||pe(i?.headers??o?.headers);try{let d=await t(r,i);return l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:String(d.status)},...d.headers.get("x-request-id")?{request_id:d.headers.get("x-request-id")}:{}}),d}catch(d){throw l&&!u&&this.sample("network",`${c} ${l.origin}${l.pathname}`,performance.now()-a,{attrs:{status:"0"}}),d}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}},ue=n=>n.entryType==="layout-shift"&&"value"in n&&"hadRecentInput"in n,he=n=>n.entryType==="event"||n.entryType==="first-input";function A(n,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:n,buffered:!0}),t}catch{return}}function de(n){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,r=[A("largest-contentful-paint",l=>{for(let u of l)e=Math.max(e,u.startTime)}),A("layout-shift",l=>{for(let u of l)ue(u)&&!u.hadRecentInput&&(t+=u.value)}),A("event",l=>{for(let u of l)he(u)&&(s=Math.max(s,u.duration))}),A("paint",l=>{for(let u of l)u.name==="first-contentful-paint"&&n("FCP",u.startTime)})],i=performance.getEntriesByType("navigation")[0];i&&i.responseStart>0&&n("TTFB",i.responseStart);let a=!1,o=()=>{a||(a=!0,e>0&&n("LCP",e),n("CLS",t),s>0&&n("INP",s))},c=()=>{document.visibilityState==="hidden"&&o()};return document.addEventListener("visibilitychange",c),()=>{o(),document.removeEventListener("visibilitychange",c);for(let l of r)l?.disconnect()}}function pe(n){if(!n)return!1;try{return new Headers(n).has("next-router-prefetch")}catch{return!1}}function fe(n){if(!n)return"";try{let e=new URL(n);return`${e.origin}${e.pathname}`}catch{return n.split(/[?#]/,1)[0]??""}}var v=class{api;session;socket;ref;fetch;appVersion;listeners=new Set;watch;following;last;constructor(e,t,s,r,i,a){this.api=D.client(e),this.session=t,this.socket=s,this.ref=r,this.fetch=i,this.appVersion=a}async me(){let e=this.session.snapshot()?.userId,t=(await this.api.getMyCustomerInfo()).data;return this.watch&&this.watch.userId===e&&this.offer(this.watch,t),t}async offerings(e="web"){return(await this.api.getOfferings({query:{channel:e}})).data}async paywall(e,t={}){return $(this.api,this.ref,e,s=>this.checkout(s),{signal:t.signal,fetch:this.fetch,attributes:t.attributes,locale:t.locale,appVersion:this.appVersion})}async checkout(e){let t={product:e.product,plan:e.plan,success_url:e.successUrl,cancel_url:e.cancelUrl};return(await this.api.createCheckout({body:t})).data.url}async portal(e){return(await this.api.createPortalSession({body:{return_url:e}})).data.url}async mergeGrant(){return(await this.api.createMergeGrant()).data}async merge(e){let t=this.session.snapshot()?.userId,s=(await this.api.mergeGuest({body:{grant:typeof e=="string"?e:e.grant}})).data;return this.watch&&this.watch.userId===t&&this.offer(this.watch,s),s}onCustomerInfo(e){if(this.listeners.add(e),this.listeners.size===1)this.start();else if(this.last!==void 0){let t=this.last;queueMicrotask(()=>this.listeners.has(e)&&Y(e,t))}return()=>{this.listeners.delete(e)&&this.listeners.size===0&&this.stop()}}start(){this.following=this.session.onChange((e,t)=>{(e==="SIGNED_IN"||e==="SIGNED_OUT"||e==="SESSION_EXPIRED")&&this.follow(t)}),this.session.session().then(e=>{this.following&&!this.watch&&this.last===void 0&&this.follow(e)})}stop(){this.following?.(),this.following=void 0,this.unfollow(),this.last=void 0}follow(e){if(this.unfollow(),!e){this.tell(null);return}let t=this.socket.channel(`purchases:${this.ref}:${e.userId}`),s={userId:e.userId,channel:t,off:()=>{},revision:-1,reading:!1,wanted:Number.NEGATIVE_INFINITY},r=[t.on("broadcast",i=>{i.event==="changed"&&this.changed(s,U(i.payload))}),t.on("state_snapshot",i=>this.held(s,U(z(i.entries)))),t.on("state_diff",i=>this.held(s,U(z(i.set))))];s.off=()=>r.forEach(i=>i()),this.watch=s,t.join().catch(()=>{}),this.read(s)}unfollow(){let e=this.watch;e&&(this.watch=void 0,e.off(),e.channel.leave())}changed(e,t){this.watch!==e||t!==void 0&&t<=e.revision||(e.reading?e.wanted=Math.max(e.wanted,t??Number.POSITIVE_INFINITY):this.read(e))}held(e,t){t!==void 0&&this.changed(e,t)}async read(e){e.reading=!0;try{for(;;){e.wanted=Number.NEGATIVE_INFINITY;try{let t=(await this.api.getMyCustomerInfo()).data;if(this.watch!==e)return;this.offer(e,t)}catch{}if(this.watch!==e||e.wanted<=e.revision)return}}finally{e.reading=!1}}offer(e,t){this.watch!==e||t.revision<=e.revision||(e.revision=t.revision,this.tell(t))}tell(e){if(!(this.last===null&&e===null)){this.last=e;for(let t of[...this.listeners])Y(t,e)}}};function Y(n,e){try{n(e)}catch{}}function z(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function U(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var ye=/^pb_[a-z0-9]+_s/,me=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),ge=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function ve(n){if(ye.test(n.publishableKey)||"secretKey"in n)throw new TypeError("a secret key never goes into a client app: palbase/web takes the publishable key (pb_<ref>_c\u2026); servers use palbase/server");let e=/^pb_([a-z0-9]+)_c/.exec(n.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");let t=new URL(n.url).origin,s=n.storage??(we()?L(`palbase.session.${t}`):N()),r=n.retry??q,i=P(k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey},fetch:n.fetch}),r),a=y.client(i),o=new E(s,async h=>(await a.refreshToken({body:{refresh_token:h}})).data,h=>h instanceof S&&h.status===401&&ge.has(h.code),{lockName:`palbase.session.refresh.${t}`}),c=k({baseUrl:n.url,credentials:{publishableKey:n.publishableKey,accessToken:()=>o.accessToken()},fetch:n.fetch,xmlHttpRequest:n.xmlHttpRequest??(n.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),l=P(j(c,o),r),u=new m({baseUrl:n.url,publishableKey:n.publishableKey,accessToken:()=>o.accessToken(),webSocket:n.webSocket});o.onChange(h=>{h==="SIGNED_OUT"||h==="SESSION_EXPIRED"||h==="SIGNED_IN"?u.disconnect():h==="TOKEN_REFRESHED"&&u.tokenChanged()});let d=new g(j(c,o),o,t);n.analytics&&d.start(n.analytics===!0?{}:n.analytics);let w=new Map,Q=h=>{let O=new URL(h).origin,b=w.get(O);return b||(b=P(j(k({baseUrl:O,credentials:{accessToken:()=>o.accessToken()},fetch:n.fetch}),o),r),w.set(O,b)),b},K=Object.assign(Object.create(F),{auth:new T(l,i,o,n.webauthn??globalThis.navigator?.credentials),socket:u,transport:l,analytics:d,purchases:new v(l,o,u,e,n.fetch,n.appVersion)});return B(K,t,Q,l,u),K}function we(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function j(n,e){return{async send(t){let s=await e.session();try{return await n.send(t)}catch(r){let i=t.auth.some(a=>a.includes("userJWT"));if(!(r instanceof S)||r.status!==401||!me.has(r.code)||!i||!s)throw r;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw r}if(e.snapshot()?.userId!==s.userId)throw r;return n.send(t)}}}}export{g as Analytics,Z as BackendError,_ as Channel,S as PalbaseError,v as Purchases,m as RealtimeSocket,te as RoomError,f as SessionChangedError,ve as createClient,ee as isBackendError,L as localStore,N as memoryStore};
|
|
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"
|
package/types/ai/src/ai.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { type Fetch } from '../../internal/src/transport.js';
|
|
|
2
2
|
import { type RetryPolicy } from '../../internal/src/retry.js';
|
|
3
3
|
import * as modules from '../../internal/src/modules/index.js';
|
|
4
4
|
import { type Infer, type PreparedSchema, type StandardSchema } from './schema.js';
|
|
5
|
+
import { type Agents, type Chats, type Endpoints, type Settings } from './chats.js';
|
|
6
|
+
import { type AgentContext, type BackendAgent, type BackendTool, type BackendToolOptions, type ClientTool, type ClientToolOptions, type HttpsToolRef, type McpToolRef, type TurnDefinition } from './tools.js';
|
|
5
7
|
type Module = ReturnType<typeof modules.ai.client>;
|
|
6
8
|
export type Response = Awaited<ReturnType<Module['getResponse']>>['data'];
|
|
7
9
|
export type Usage = Awaited<ReturnType<Module['listUsage']>>['data']['usage'][number];
|
|
@@ -14,6 +16,12 @@ export interface AIOptions {
|
|
|
14
16
|
retry?: RetryPolicy;
|
|
15
17
|
/** How long a stream that was cut is followed again before the caller is told (default 2 minutes). */
|
|
16
18
|
resumeFor?: number;
|
|
19
|
+
/**
|
|
20
|
+
* The project's machine this code runs on: an ai.tool given to a one-shot
|
|
21
|
+
* answer (ask, generate, stream, start) runs there unless it names its own.
|
|
22
|
+
* Left out, the platform calls the machine named backend.
|
|
23
|
+
*/
|
|
24
|
+
machine?: string;
|
|
17
25
|
/**
|
|
18
26
|
* A server client whose ai module the calls go through, in place of url and
|
|
19
27
|
* secretKey — a backend's `Palbase`: the address, key and retries are that
|
|
@@ -29,12 +37,38 @@ export interface Message {
|
|
|
29
37
|
role: 'user' | 'assistant';
|
|
30
38
|
content: string;
|
|
31
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* A picture a question is about: a file of the project's own storage, or an
|
|
42
|
+
* https address. Upload a photo to the project's storage first
|
|
43
|
+
* (storage.from(bucket).upload(path, file)), then give its bucket and path:
|
|
44
|
+
* the model reads it through a link signed for the while it answers, and
|
|
45
|
+
* the platform keeps no copy of it.
|
|
46
|
+
*
|
|
47
|
+
* Do not take bucket and path from the end user as they send them: the
|
|
48
|
+
* question is asked with the project's secret key, and the model can be
|
|
49
|
+
* shown any file of the project's. Check the file is the user's own (its
|
|
50
|
+
* path is under their id, a row of yours says it is theirs) before asking.
|
|
51
|
+
*/
|
|
52
|
+
export type AskImage = {
|
|
53
|
+
bucket: string;
|
|
54
|
+
path: string;
|
|
55
|
+
} | {
|
|
56
|
+
url: string;
|
|
57
|
+
};
|
|
58
|
+
/** What a one-shot answer may call: the backend's ai.tool, the project's HTTPS tools and MCP servers — never an app's client tool. */
|
|
59
|
+
export type AskTool = BackendTool<StandardSchema> | HttpsToolRef | McpToolRef;
|
|
32
60
|
export interface Ask {
|
|
33
61
|
/** The question; or `messages`, the conversation so far. */
|
|
34
62
|
prompt?: string;
|
|
35
63
|
messages?: Message[];
|
|
36
64
|
instructions?: string;
|
|
37
65
|
model?: Model;
|
|
66
|
+
/** Pictures the question is about (4 at most), in the project's storage ({ bucket, path }) or at an https address ({ url }) — a user's own file, checked by you (AskImage). */
|
|
67
|
+
images?: AskImage[];
|
|
68
|
+
/** What the model may call to answer: an ai.tool runs on the backend's machine; an app's client tool is a chat's alone. */
|
|
69
|
+
tools?: AskTool[];
|
|
70
|
+
/** How many tool calls the answer makes at most (1–200): past it the model is told it has no tools left, and answers. */
|
|
71
|
+
maxToolCalls?: number;
|
|
38
72
|
/** The caller's own labels: returned with the response and its event. */
|
|
39
73
|
metadata?: Record<string, string>;
|
|
40
74
|
signal?: AbortSignal;
|
|
@@ -65,8 +99,9 @@ export interface TextStream {
|
|
|
65
99
|
readonly response: Promise<Response>;
|
|
66
100
|
/**
|
|
67
101
|
* The stream as an HTTP answer a backend route returns to a browser:
|
|
68
|
-
* server-sent events `data: {"text": "<fragment>"}
|
|
69
|
-
* `
|
|
102
|
+
* server-sent events `data: {"text": "<fragment>"}`, an `event: reset`
|
|
103
|
+
* `{"offset": n}` when the model went back (keep the answer's first n
|
|
104
|
+
* characters), and a last `event: done` with the answer.
|
|
70
105
|
*/
|
|
71
106
|
toResponse(init?: ResponseInit): globalThis.Response;
|
|
72
107
|
}
|
|
@@ -164,6 +199,32 @@ export interface AI {
|
|
|
164
199
|
verified: boolean;
|
|
165
200
|
}>;
|
|
166
201
|
disconnectProvider(provider: string): Promise<void>;
|
|
202
|
+
/** The project's chats: started, written to, followed as typed parts, stopped; a tool call approved or answered. */
|
|
203
|
+
readonly chats: Chats;
|
|
204
|
+
/** The project's named agents: a chat started from the app, or by name from the server, talks to one. */
|
|
205
|
+
readonly agents: Agents;
|
|
206
|
+
/** The project's HTTPS tools and MCP servers, which an agent may be given by name. */
|
|
207
|
+
readonly endpoints: Endpoints;
|
|
208
|
+
/** Whether the app's users talk to the agents themselves, how often, and how much history is kept. */
|
|
209
|
+
readonly settings: Settings;
|
|
210
|
+
/**
|
|
211
|
+
* A tool of the project's backend: run on its machine when an agent calls
|
|
212
|
+
* it (the framework serves it), its input checked against the schema.
|
|
213
|
+
* Made once, at a module's top level.
|
|
214
|
+
*/
|
|
215
|
+
tool<S extends StandardSchema>(tool: BackendToolOptions<S>): BackendTool<S>;
|
|
216
|
+
/** A tool the app's code answers (pb.ai.chat(id).tools({ name: fn })): the turn waits for it. */
|
|
217
|
+
clientTool<S extends StandardSchema>(tool: ClientToolOptions<S>): ClientTool;
|
|
218
|
+
/**
|
|
219
|
+
* An agent the backend defines at each turn's start, from the turn's
|
|
220
|
+
* context: put it with ai.agents.put(agent), and its chats' turns ask the
|
|
221
|
+
* machine for it — clients: true, and the app's users start chats with it
|
|
222
|
+
* themselves. Made once, at a module's top level.
|
|
223
|
+
*/
|
|
224
|
+
agent(name: string, define: (ctx: AgentContext) => TurnDefinition | Promise<TurnDefinition>, options?: {
|
|
225
|
+
machine?: string;
|
|
226
|
+
clients?: boolean;
|
|
227
|
+
}): BackendAgent;
|
|
167
228
|
/** The generated client of the ai module, for what the methods above do not say. */
|
|
168
229
|
readonly module: Module;
|
|
169
230
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type ChatStream, type FollowChatOptions } from '../../internal/src/chat.js';
|
|
2
|
+
import type * as modules from '../../internal/src/modules/index.js';
|
|
3
|
+
import { type ToolResult } from '../../internal/src/tool-output.js';
|
|
4
|
+
import { type AgentDefinitionInput, type BackendAgent } from './tools.js';
|
|
5
|
+
type Module = ReturnType<typeof modules.ai.client>;
|
|
6
|
+
export type Chat = modules.ai.Chat;
|
|
7
|
+
export type ChatMessage = modules.ai.ChatMessage;
|
|
8
|
+
export type Agent = modules.ai.Agent;
|
|
9
|
+
export type Endpoint = modules.ai.Endpoint;
|
|
10
|
+
export type Decision = modules.ai.Decision;
|
|
11
|
+
/** What the project allows its chats. */
|
|
12
|
+
export interface AISettings {
|
|
13
|
+
/** The app's users talk to the project's agents with their own session: start a chat with a named agent, write to the chats they are in. */
|
|
14
|
+
clients: boolean;
|
|
15
|
+
/** How many messages one user sends a minute. */
|
|
16
|
+
userMessagesPerMinute: number;
|
|
17
|
+
/** How much chat history the project keeps; a message past it is refused (409 history_full) until chats are deleted. */
|
|
18
|
+
historyLimitBytes: number;
|
|
19
|
+
/** How much it keeps now. */
|
|
20
|
+
historyBytes: number;
|
|
21
|
+
}
|
|
22
|
+
export interface EndpointInput {
|
|
23
|
+
/** https: a tool at that address, called with a signed POST; mcp: an MCP server (streamable HTTP). */
|
|
24
|
+
kind: 'https' | 'mcp';
|
|
25
|
+
/** An https:// address on the public internet. */
|
|
26
|
+
url: string;
|
|
27
|
+
/** What an https tool does (an MCP server says its own). */
|
|
28
|
+
description?: string;
|
|
29
|
+
/** A JSON Schema of type object: what an https tool takes. */
|
|
30
|
+
parameters?: Record<string, unknown>;
|
|
31
|
+
/** Every call waits for a person's yes. */
|
|
32
|
+
approval?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface MemberInput {
|
|
35
|
+
userId: string;
|
|
36
|
+
/** How the agent and the others are told who wrote. */
|
|
37
|
+
name?: string;
|
|
38
|
+
/** The owner deletes the chat. */
|
|
39
|
+
owner?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface CreateChat {
|
|
42
|
+
/** A named agent of the project (or a backend's ai.agent, put); with a definition, the chat's name for it (default assistant). */
|
|
43
|
+
agent?: string | BackendAgent;
|
|
44
|
+
/** A definition of the chat's own, in place of a named agent. */
|
|
45
|
+
definition?: AgentDefinitionInput;
|
|
46
|
+
title?: string;
|
|
47
|
+
/** The caller's own labels (16 at most, snake_case keys). */
|
|
48
|
+
metadata?: Record<string, string>;
|
|
49
|
+
/** Who reads it and writes to it (64 at most). */
|
|
50
|
+
members?: MemberInput[];
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}
|
|
53
|
+
export interface SendMessage {
|
|
54
|
+
text: string;
|
|
55
|
+
/** The writer's id for it: sent again — a retry — it is the same message, delivered once. Made here when not given. */
|
|
56
|
+
clientId?: string;
|
|
57
|
+
/** While the agent works on a turn: next (the default) gives it the message at its next step, now cuts the step it is in. */
|
|
58
|
+
delivery?: 'next' | 'now';
|
|
59
|
+
/** The member the server writes as. */
|
|
60
|
+
as?: string;
|
|
61
|
+
signal?: AbortSignal;
|
|
62
|
+
}
|
|
63
|
+
export interface Chats {
|
|
64
|
+
create(chat: CreateChat): Promise<Chat>;
|
|
65
|
+
get(id: string, options?: {
|
|
66
|
+
signal?: AbortSignal;
|
|
67
|
+
}): Promise<Chat>;
|
|
68
|
+
/** Every chat (the newest first, 100 at most), or a member's. */
|
|
69
|
+
list(options?: {
|
|
70
|
+
member?: string;
|
|
71
|
+
signal?: AbortSignal;
|
|
72
|
+
}): Promise<Chat[]>;
|
|
73
|
+
/** A turn still running is stopped; its history no longer counts. */
|
|
74
|
+
delete(id: string): Promise<void>;
|
|
75
|
+
members: {
|
|
76
|
+
put(id: string, userId: string, member: {
|
|
77
|
+
name?: string;
|
|
78
|
+
owner?: boolean;
|
|
79
|
+
}): Promise<Chat>;
|
|
80
|
+
delete(id: string, userId: string): Promise<void>;
|
|
81
|
+
};
|
|
82
|
+
/** A message for the agent: a turn of its own when none runs. A transient refusal is sent again with the same clientId — the same message. */
|
|
83
|
+
send(id: string, message: SendMessage): Promise<ChatMessage>;
|
|
84
|
+
/** What its members and the server wrote, the newest first. */
|
|
85
|
+
messages(id: string, options?: {
|
|
86
|
+
limit?: number;
|
|
87
|
+
cursor?: string;
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
}): Promise<{
|
|
90
|
+
messages: ChatMessage[];
|
|
91
|
+
nextCursor?: string;
|
|
92
|
+
}>;
|
|
93
|
+
/** What happens in the chat as typed parts, as it happens, followed again after a cut from where the reader is: read with for await, stopped with break or signal. */
|
|
94
|
+
stream(id: string, options?: FollowChatOptions): ChatStream;
|
|
95
|
+
/** Stops the turn it is working on: what it wrote stays. Its response's id, or null when none ran. */
|
|
96
|
+
stop(id: string): Promise<string | null>;
|
|
97
|
+
/** A tool call that waits for a person's yes (a tool event's approval_id): made. */
|
|
98
|
+
approve(id: string, approvalId: string, reason?: string): Promise<Decision>;
|
|
99
|
+
/** Not made: the agent is told, with the reason, and goes on. */
|
|
100
|
+
deny(id: string, approvalId: string, reason?: string): Promise<Decision>;
|
|
101
|
+
/** The answer of a client tool's call (a tool event's call_id): true when it is the one taken, false when another came first. */
|
|
102
|
+
answer(id: string, callId: string, output: ToolResult, options?: {
|
|
103
|
+
isError?: boolean;
|
|
104
|
+
}): Promise<boolean>;
|
|
105
|
+
/** A message for one of the agent's subagents at work (an agent event's run_id), at its next step. */
|
|
106
|
+
sendToSubagent(id: string, runId: string, text: string, options?: {
|
|
107
|
+
clientId?: string;
|
|
108
|
+
}): Promise<{
|
|
109
|
+
runId: string;
|
|
110
|
+
clientId: string;
|
|
111
|
+
}>;
|
|
112
|
+
}
|
|
113
|
+
export interface Agents {
|
|
114
|
+
/** Names an agent: its definition, or a backend's ai.agent (its chats' turns ask the backend's machine); clients: true lets the app's users start chats with it. */
|
|
115
|
+
put(name: string, definition: AgentDefinitionInput | BackendAgent): Promise<Agent>;
|
|
116
|
+
put(agent: BackendAgent): Promise<Agent>;
|
|
117
|
+
list(): Promise<Agent[]>;
|
|
118
|
+
/** Its chats stay; a message to one is refused (agent_not_found) until it is put again. */
|
|
119
|
+
delete(name: string): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
export interface Endpoints {
|
|
122
|
+
/** An HTTPS tool or an MCP server; the answer says an https tool's signing secret, this once (putting it again makes a new one). */
|
|
123
|
+
put(name: string, endpoint: EndpointInput): Promise<Endpoint>;
|
|
124
|
+
list(): Promise<Endpoint[]>;
|
|
125
|
+
delete(name: string): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
export interface Settings {
|
|
128
|
+
get(): Promise<AISettings>;
|
|
129
|
+
/** A field left out is left as it is; the history kept may be lowered, not raised past the plan's. */
|
|
130
|
+
put(change: {
|
|
131
|
+
clients?: boolean;
|
|
132
|
+
userMessagesPerMinute?: number;
|
|
133
|
+
historyLimitBytes?: number;
|
|
134
|
+
}): Promise<AISettings>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A write the contract does not key but whose id makes it one message
|
|
138
|
+
* (client_id): sent again, while the answer says "not now", with the same id.
|
|
139
|
+
*/
|
|
140
|
+
export declare function withSameId<T>(send: () => Promise<T>, signal?: AbortSignal, attempts?: number): Promise<T>;
|
|
141
|
+
export declare function chatsOf(raw: Module): {
|
|
142
|
+
chats: Chats;
|
|
143
|
+
agents: Agents;
|
|
144
|
+
endpoints: Endpoints;
|
|
145
|
+
settings: Settings;
|
|
146
|
+
};
|
|
147
|
+
export {};
|
package/types/ai/src/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export { createAI, AIResponseError } from './ai.js';
|
|
2
|
-
export type { AI, AIOptions, Ask, DeepPartial, Embed, Generate, ImageRequest, Images, Job, Message, Model, ObjectStream, Picture, Response, Schema, TextStream, Uploader, Usage, } from './ai.js';
|
|
2
|
+
export type { AI, AIOptions, Ask, AskImage, AskTool, DeepPartial, Embed, Generate, ImageRequest, Images, Job, Message, Model, ObjectStream, Picture, Response, Schema, TextStream, Uploader, Usage, } from './ai.js';
|
|
3
3
|
export { AISchemaError, prepare } from './schema.js';
|
|
4
|
+
export { ToolError } from './tools.js';
|
|
4
5
|
export type { Infer, StandardSchema } from './schema.js';
|
|
5
6
|
export { partial } from './partial.js';
|
|
7
|
+
export type { AISettings, Agent, Agents, Chat, ChatMessage, Chats, CreateChat, Decision, Endpoint, EndpointInput, Endpoints, MemberInput, SendMessage, Settings } from './chats.js';
|
|
8
|
+
export type { AgentContext, AgentDefinitionInput, BackendAgent, BackendTool, BackendToolOptions, ChatContext, ClientTool, ClientToolOptions, HttpsToolRef, McpToolRef, SubagentDefinition, Tool, ToolContext, TurnDefinition, } from './tools.js';
|
|
9
|
+
export type { AgentEvent, ChatEvent, ChatPosition, ChatStream, MessageEvent, ResetEvent, TextEvent, ToolEvent, ToolStatus, TurnEvent, TurnStatus, WaitingReason } from '../../internal/src/chat.js';
|
|
10
|
+
export type { ToolPart, ToolResult } from '../../internal/src/tool-output.js';
|