palbase 0.4.0 → 0.5.1
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 -10
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +8 -8
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/{TRHIZOIS.js → 32RCJNOH.js} +3 -3
- package/dist/chunks/{BJL2FT5W.js → 3AUBDHV2.js} +1 -1
- package/dist/chunks/{IVDNNHII.js → 7BA7LGEM.js} +2 -2
- package/dist/chunks/A7EL6JKQ.js +20 -0
- package/dist/chunks/AWHTWL65.js +2 -0
- package/dist/chunks/{2AT72FFB.js → B45UFKBR.js} +2 -2
- package/dist/chunks/{ST2NZ4TZ.js → DNHDO6AJ.js} +1 -1
- package/dist/chunks/{BHT2IHBE.js → EHJKMDP3.js} +2 -2
- package/dist/chunks/{3OIKIBMG.js → FSXD7MN3.js} +2 -2
- package/dist/chunks/{SUNHFMDO.js → KSJ6AMCG.js} +2 -2
- package/dist/chunks/PALOWH6U.js +6 -0
- package/dist/chunks/{RKNVSAGY.js → PFSUOVTB.js} +1 -1
- package/dist/chunks/{6JO3UVPT.js → QIN2NQPN.js} +2 -2
- package/dist/chunks/{FS222NNP.js → R43DXJZE.js} +2 -2
- package/dist/chunks/{ODFLUINN.js → TTZRGQWF.js} +1 -1
- package/dist/chunks/{UNTTPATW.js → ZXYDN6NA.js} +1 -1
- package/dist/cli.js +133 -129
- 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 +20 -2
- package/types/ai/src/chats.d.ts +75 -1
- package/types/ai/src/index.d.ts +2 -2
- package/types/ai/src/tools.d.ts +35 -0
- package/types/backend/src/channels.d.ts +81 -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 +12 -4
- package/types/backend/src/env.d.ts +1 -1
- package/types/backend/src/index.d.ts +4 -2
- package/types/backend/src/openapi.d.ts +3 -0
- package/types/backend/src/rooms.d.ts +10 -0
- package/types/backend/src/tasks.d.ts +168 -0
- package/types/internal/src/chat.d.ts +17 -1
- package/types/internal/src/modules/ai.d.ts +314 -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 +32 -3
- package/types/web/src/ai.d.ts +25 -2
- package/types/web/src/client.d.ts +7 -0
- package/types/web/src/index.d.ts +1 -1
- package/types/web/src/paywall/placement.d.ts +2 -0
- package/types/web/src/purchases.d.ts +3 -1
- package/dist/chunks/CY6B75KF.js +0 -6
- package/dist/chunks/EGRDFD5C.js +0 -20
- package/dist/chunks/ZFX4BFQR.js +0 -2
package/dist/refuse/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! palbase 0.
|
|
1
|
+
/*! palbase 0.5.1 — 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.1 — 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.1 — 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.1 — 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/KSJ6AMCG.js";import"../chunks/ZXYDN6NA.js";import{m as b}from"../chunks/AWHTWL65.js";import"../chunks/FSXD7MN3.js";import{b as a}from"../chunks/B45UFKBR.js";import"../chunks/PFSUOVTB.js";import"../chunks/TTZRGQWF.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.1 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a,b,c,d}from"../chunks/QIN2NQPN.js";import"../chunks/PFSUOVTB.js";import"../chunks/TTZRGQWF.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.1 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{a as de,b as he,e as ue,f as Y,g as z}from"../chunks/7BA7LGEM.js";import{u as Q}from"../chunks/32RCJNOH.js";import{c as E,e as q,f as p,g as Z,h as K}from"../chunks/PALOWH6U.js";import{a as G,b as D,c as m,h as J}from"../chunks/AWHTWL65.js";import{a as W,b as P,c as X}from"../chunks/FSXD7MN3.js";import{b as f,d as _}from"../chunks/B45UFKBR.js";import"../chunks/PFSUOVTB.js";import"../chunks/TTZRGQWF.js";var I=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,c)=>this.signedIn((await o.mfaChallenge({body:{mfa_token:a,type:l,code:c}})).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,c=await this.authenticator().create({publicKey:ee(l.options.publicKey)});return(await r.webauthnRegisterFinish({body:se(c)})).data},signIn:async(a={})=>{let l=(await o.webauthnLoginBegin({body:a.userId?{user_id:a.userId}:{}})).data,c=await this.authenticator().get({publicKey:te(l.options.publicKey)}),d=await o.webauthnLoginFinish({query:a.userId?{user_id:a.userId}:void 0,body:ne(c)});return this.signedIn(d.data)},signUp:async(a,l)=>{let c=(await o.webauthnSignupBegin({body:{identifier:a,user_name:l}})).data,d=await this.authenticator().create({publicKey:ee(c.options.publicKey)});await o.webauthnSignupFinish({query:{user_id:c.user_id},body:se(d)});let u=(await o.webauthnLoginBegin({body:{user_id:c.user_id}})).data,k=await this.authenticator().get({publicKey:te(u.options.publicKey)});return this.signedIn((await o.webauthnLoginFinish({query:{user_id:c.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}},C=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:C(String(e.id))})):void 0;function ee(i){let e=i.user;return{...i,challenge:C(String(i.challenge)),user:{...e,id:C(String(e.id))},excludeCredentials:ie(i.excludeCredentials)}}function te(i){return{...i,challenge:C(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 V(){let i=null;return{load:()=>i,save:e=>{i=e},clear:()=>{i=null},shared:!1}}function F(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 R=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(c=>c.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(),c;try{c=new URL(a?.url??String(n),e.location.href)}catch{c=void 0}let d=!!c&&c.pathname.startsWith("/analytics/")||_e(r?.headers??a?.headers);try{let u=await t(n,r);return c&&!d&&this.sample("network",`${l} ${c.origin}${c.pathname}`,performance.now()-o,{attrs:{status:String(u.status)},...u.headers.get("x-request-id")?{request_id:u.headers.get("x-request-id")}:{}}),u}catch(u){throw c&&!d&&this.sample("network",`${l} ${c.origin}${c.pathname}`,performance.now()-o,{attrs:{status:"0"}}),u}};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",c=>{for(let d of c)e=Math.max(e,d.startTime)}),N("layout-shift",c=>{for(let d of c)Se(d)&&!d.hadRecentInput&&(t+=d.value)}),N("event",c=>{for(let d of c)ke(d)&&(s=Math.max(s,d.duration))}),N("paint",c=>{for(let d of c)d.name==="first-contentful-paint"&&i("FCP",d.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 c of n)c?.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 f)||s.status===429)throw q(s);let n=X(s,t,30);if(n===void 0)throw q(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;voiceParts=[];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 f?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:K(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 f&&r.status===409)return!1;throw this.answering.delete(e),r}}async approve(e,t){await p(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 p(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 p(this.api.stopChat({path:{chat_id:this.id}}))).data.stopped}async startVoice(e){let t=new RTCPeerConnection,s=e.audio??(typeof Audio=="function"?new Audio:void 0);s&&(s.autoplay=!0),t.ontrack=n=>{s&&(s.srcObject=n.streams[0]??new MediaStream([n.track]))};for(let n of e.stream.getAudioTracks())t.addTrack(n,e.stream);try{let n=await t.createOffer();await t.setLocalDescription(n);let r=e.voice===void 0?{sdp:n.sdp??""}:{sdp:n.sdp??"",voice:e.voice},o=(await p(this.api.startChatVoice({path:{chat_id:this.id},body:r}))).data;await t.setRemoteDescription({type:"answer",sdp:o.sdp??""}),this.follow();let a=o.id;return{id:a,peer:t,stop:async()=>(t.close(),(await p(this.api.closeChatVoice({path:{chat_id:this.id,voice_id:a}}))).data.seconds)}}catch(n){throw t.close(),n}}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,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"voice":this.voiceParts.push(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:K(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 f&&(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,Ee(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")},voice:[...this.voiceParts]}}};function Ee(i,e,t,s){let n=[...i.marks.values()].map((a,l)=>({m:a,i:l,at:E(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 p(s.createChat({body:r}))).data},async list(){return(await p(s.listChats({}))).data.chats},async get(n){return(await p(s.getChat({path:{chat_id:n}}))).data},async delete(n){await p(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 Ie=/^pb_[a-z0-9]+_s/,Ce=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Re=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){return i.status===400&&i.code==="invalid_request"}function Ae(i){if(Ie.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&&!Ce.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??(Oe()?F(`palbase.session.${t}`):V()),n=i.retry??W,r=P(_({baseUrl:i.url,credentials:{publishableKey:i.publishableKey},fetch:i.fetch}),n),o=m.client(r),a=new R(s,async h=>(await o.refreshToken({body:{refresh_token:h}})).data,h=>h instanceof f&&(h.status===401&&xe.has(h.code)||Me(h)),{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)}),c=P($(l,a),n),d=new v({baseUrl:i.url,publishableKey:i.publishableKey,accessToken:()=>a.accessToken(),webSocket:i.webSocket});a.onChange(h=>{h==="SIGNED_OUT"||h==="SESSION_EXPIRED"||h==="SIGNED_IN"?d.disconnect():h==="TOKEN_REFRESHED"&&d.tokenChanged()});let u=new w($(l,a),a,t);i.analytics&&u.start(i.analytics===!0?{}:i.analytics);let k=new Map,ce=h=>{let j=new URL(h).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 I(c,r,a,i.webauthn??globalThis.navigator?.credentials),socket:d,transport:c,analytics:u,purchases:new b(c,a,d,e,i.fetch,i.appVersion,i.appId),ai:new S(c,a)});return z(H,t,ce,c,d),H}function Oe(){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 f)||n.status!==401||!Re.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,de as BackendError,M as Channel,U as ChatSession,f as PalbaseError,b as Purchases,v as RealtimeSocket,ue as RoomError,y as SessionChangedError,Ae as createClient,he as isBackendError,F as localStore,V 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.1 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import{c as e,d as r,h as t}from"../chunks/7BA7LGEM.js";import"../chunks/FSXD7MN3.js";import"../chunks/B45UFKBR.js";import"../chunks/PFSUOVTB.js";import"../chunks/TTZRGQWF.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.1 — 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/32RCJNOH.js";import"../chunks/B45UFKBR.js";import"../chunks/PFSUOVTB.js";import"../chunks/TTZRGQWF.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.1 — Palbase SDK License (see LICENSE) */
|
|
2
|
+
import"../chunks/TTZRGQWF.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.1",
|
|
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.1",
|
|
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,8 +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
|
+
import { type Agents, type Chats, type Endpoints, type Repos, type Settings } from './chats.js';
|
|
6
|
+
import { type AgentContext, type BackendAgent, type BackendRepo, type BackendTool, type BackendToolOptions, type ClientTool, type ClientToolOptions, type HttpsToolRef, type McpToolRef, type TurnDefinition } from './tools.js';
|
|
7
7
|
type Module = ReturnType<typeof modules.ai.client>;
|
|
8
8
|
export type Response = Awaited<ReturnType<Module['getResponse']>>['data'];
|
|
9
9
|
export type Usage = Awaited<ReturnType<Module['listUsage']>>['data']['usage'][number];
|
|
@@ -225,6 +225,24 @@ export interface AI {
|
|
|
225
225
|
machine?: string;
|
|
226
226
|
clients?: boolean;
|
|
227
227
|
}): BackendAgent;
|
|
228
|
+
/**
|
|
229
|
+
* A GitHub repository a chat's workspace works in, whose tokens this
|
|
230
|
+
* backend gives (token, asked at each clone and each push): put it with
|
|
231
|
+
* ai.repos.put(repo). Made once, at a module's top level.
|
|
232
|
+
*/
|
|
233
|
+
repo(options: {
|
|
234
|
+
name: string;
|
|
235
|
+
repository: string;
|
|
236
|
+
defaultBranch?: string;
|
|
237
|
+
machine?: string;
|
|
238
|
+
token: (ctx: {
|
|
239
|
+
repo: string;
|
|
240
|
+
repository: string;
|
|
241
|
+
signal: AbortSignal;
|
|
242
|
+
}) => string | Promise<string>;
|
|
243
|
+
}): BackendRepo;
|
|
244
|
+
/** The project's repositories a chat's workspace works in (chats.create({ workspace })). */
|
|
245
|
+
readonly repos: Repos;
|
|
228
246
|
/** The generated client of the ai module, for what the methods above do not say. */
|
|
229
247
|
readonly module: Module;
|
|
230
248
|
}
|
package/types/ai/src/chats.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ChatStream, type FollowChatOptions } from '../../internal/src/chat.js';
|
|
2
2
|
import type * as modules from '../../internal/src/modules/index.js';
|
|
3
3
|
import { type ToolResult } from '../../internal/src/tool-output.js';
|
|
4
|
-
import { type AgentDefinitionInput, type BackendAgent } from './tools.js';
|
|
4
|
+
import { type AgentDefinitionInput, type BackendAgent, type BackendRepo } from './tools.js';
|
|
5
5
|
type Module = ReturnType<typeof modules.ai.client>;
|
|
6
6
|
export type Chat = modules.ai.Chat;
|
|
7
7
|
export type ChatMessage = modules.ai.ChatMessage;
|
|
@@ -48,8 +48,43 @@ export interface CreateChat {
|
|
|
48
48
|
metadata?: Record<string, string>;
|
|
49
49
|
/** Who reads it and writes to it (64 at most). */
|
|
50
50
|
members?: MemberInput[];
|
|
51
|
+
/**
|
|
52
|
+
* The project's repositories the chat works in (ai.repos.put), each at a
|
|
53
|
+
* branch (its default unless said): its turns run on a machine of the
|
|
54
|
+
* platform's with them checked out, and what its agent commits is pushed
|
|
55
|
+
* to that branch — with a token the backend gives at each push (ai.repo).
|
|
56
|
+
*/
|
|
57
|
+
workspace?: {
|
|
58
|
+
repos: {
|
|
59
|
+
repo: string | BackendRepo;
|
|
60
|
+
branch?: string;
|
|
61
|
+
}[];
|
|
62
|
+
/** The agent pushes its commits without a person's yes (the chat's members' messages then reach the repository); otherwise a push waits for a member's approval. */
|
|
63
|
+
autoPush?: boolean;
|
|
64
|
+
};
|
|
51
65
|
signal?: AbortSignal;
|
|
52
66
|
}
|
|
67
|
+
/** A repository the project's chats work in, as the module keeps it. */
|
|
68
|
+
export interface Repo {
|
|
69
|
+
name: string;
|
|
70
|
+
repository: string;
|
|
71
|
+
defaultBranch: string;
|
|
72
|
+
/** The project's machine that gives its tokens. */
|
|
73
|
+
backend: string;
|
|
74
|
+
createdAt: string;
|
|
75
|
+
}
|
|
76
|
+
export interface Repos {
|
|
77
|
+
/** Puts a backend's ai.repo (its tokens asked of that backend at each clone and push), or a repository by name. */
|
|
78
|
+
put(repo: BackendRepo): Promise<Repo>;
|
|
79
|
+
put(name: string, repo: {
|
|
80
|
+
repository: string;
|
|
81
|
+
defaultBranch?: string;
|
|
82
|
+
backend?: string;
|
|
83
|
+
}): Promise<Repo>;
|
|
84
|
+
list(): Promise<Repo[]>;
|
|
85
|
+
/** A chat's workspace checks it out no more. */
|
|
86
|
+
delete(name: string): Promise<void>;
|
|
87
|
+
}
|
|
53
88
|
export interface SendMessage {
|
|
54
89
|
text: string;
|
|
55
90
|
/** The writer's id for it: sent again — a retry — it is the same message, delivered once. Made here when not given. */
|
|
@@ -58,8 +93,34 @@ export interface SendMessage {
|
|
|
58
93
|
delivery?: 'next' | 'now';
|
|
59
94
|
/** The member the server writes as. */
|
|
60
95
|
as?: string;
|
|
96
|
+
/** What the turn this message starts may cost at most, in US dollars, its subagents' calls counted: past it the turn stops (budget_exceeded). A message into a running turn takes that turn's. */
|
|
97
|
+
budget?: {
|
|
98
|
+
maxCostUsd: number;
|
|
99
|
+
};
|
|
61
100
|
signal?: AbortSignal;
|
|
62
101
|
}
|
|
102
|
+
/** What one turn of a chat cost so far, its subagents' calls counted; final once nothing more of it can be settled. */
|
|
103
|
+
export interface TurnCost {
|
|
104
|
+
chatId: string;
|
|
105
|
+
responseId: string;
|
|
106
|
+
inputTokens: number;
|
|
107
|
+
outputTokens: number;
|
|
108
|
+
/** In billionths of a US dollar. */
|
|
109
|
+
costNanoUsd: number;
|
|
110
|
+
/** A model of the turn has no price: the cost is a lower bound. */
|
|
111
|
+
unpriced: boolean;
|
|
112
|
+
final: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** One artifact a turn's agent published: a build's product from the workspace's Mac, a screenshot, a report. */
|
|
115
|
+
export interface TurnArtifact {
|
|
116
|
+
id: string;
|
|
117
|
+
mediaType: string;
|
|
118
|
+
logicalType?: string;
|
|
119
|
+
sizeBytes: number;
|
|
120
|
+
/** sha256:<hex> of its bytes. */
|
|
121
|
+
checksum: string;
|
|
122
|
+
createdAt: string;
|
|
123
|
+
}
|
|
63
124
|
export interface Chats {
|
|
64
125
|
create(chat: CreateChat): Promise<Chat>;
|
|
65
126
|
get(id: string, options?: {
|
|
@@ -81,6 +142,18 @@ export interface Chats {
|
|
|
81
142
|
};
|
|
82
143
|
/** 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
144
|
send(id: string, message: SendMessage): Promise<ChatMessage>;
|
|
145
|
+
/** What a turn (a message's responseId, a turn event's) cost so far, its subagents' calls counted — while it runs too. */
|
|
146
|
+
turnCost(id: string, responseId: string, options?: {
|
|
147
|
+
signal?: AbortSignal;
|
|
148
|
+
}): Promise<TurnCost>;
|
|
149
|
+
/** What a turn (or a subagent's work in it) published as its output. */
|
|
150
|
+
artifacts(id: string, responseId: string, options?: {
|
|
151
|
+
signal?: AbortSignal;
|
|
152
|
+
}): Promise<TurnArtifact[]>;
|
|
153
|
+
/** One artifact of a turn, its bytes as the agent published them: read the Response as it comes. */
|
|
154
|
+
artifact(id: string, responseId: string, artifactId: string, options?: {
|
|
155
|
+
signal?: AbortSignal;
|
|
156
|
+
}): Promise<globalThis.Response>;
|
|
84
157
|
/** What its members and the server wrote, the newest first. */
|
|
85
158
|
messages(id: string, options?: {
|
|
86
159
|
limit?: number;
|
|
@@ -143,5 +216,6 @@ export declare function chatsOf(raw: Module): {
|
|
|
143
216
|
agents: Agents;
|
|
144
217
|
endpoints: Endpoints;
|
|
145
218
|
settings: Settings;
|
|
219
|
+
repos: Repos;
|
|
146
220
|
};
|
|
147
221
|
export {};
|
package/types/ai/src/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { AISchemaError, prepare } from './schema.js';
|
|
|
4
4
|
export { ToolError } from './tools.js';
|
|
5
5
|
export type { Infer, StandardSchema } from './schema.js';
|
|
6
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';
|
|
7
|
+
export type { AISettings, Agent, Agents, Chat, ChatMessage, Chats, CreateChat, Decision, Endpoint, EndpointInput, Endpoints, MemberInput, Repo, Repos, SendMessage, Settings, TurnArtifact, TurnCost } from './chats.js';
|
|
8
|
+
export type { AgentContext, AgentDefinitionInput, BackendAgent, BackendRepo, BackendTool, BackendToolOptions, ChatContext, ClientTool, ClientToolOptions, HttpsToolRef, McpToolRef, SubagentDefinition, Tool, ToolContext, TurnDefinition, } from './tools.js';
|
|
9
9
|
export type { AgentEvent, ChatEvent, ChatPosition, ChatStream, MessageEvent, ResetEvent, TextEvent, ToolEvent, ToolStatus, TurnEvent, TurnStatus, WaitingReason } from '../../internal/src/chat.js';
|
|
10
10
|
export type { ToolPart, ToolResult } from '../../internal/src/tool-output.js';
|
package/types/ai/src/tools.d.ts
CHANGED
|
@@ -135,10 +135,27 @@ export interface BackendAgent {
|
|
|
135
135
|
tools: BackendTool[];
|
|
136
136
|
}>;
|
|
137
137
|
}
|
|
138
|
+
/** A repository a chat's workspace works in, whose tokens the backend gives (ai.repo). */
|
|
139
|
+
export interface BackendRepo {
|
|
140
|
+
readonly kind: 'repo';
|
|
141
|
+
readonly name: string;
|
|
142
|
+
/** The GitHub repository, owner/name. */
|
|
143
|
+
readonly repository: string;
|
|
144
|
+
readonly defaultBranch: string;
|
|
145
|
+
/** The project's machine that gives its tokens (default backend). */
|
|
146
|
+
readonly machine?: string;
|
|
147
|
+
/** A token for one clone or one push of it: asked at each — a GitHub App's installation token, minted then. */
|
|
148
|
+
token(ctx: {
|
|
149
|
+
repo: string;
|
|
150
|
+
repository: string;
|
|
151
|
+
signal: AbortSignal;
|
|
152
|
+
}): Promise<string>;
|
|
153
|
+
}
|
|
138
154
|
/** What this process declared, for the framework to serve. */
|
|
139
155
|
export interface DeclaredAI {
|
|
140
156
|
tools: Map<string, BackendTool>;
|
|
141
157
|
agents: Map<string, BackendAgent>;
|
|
158
|
+
repos: Map<string, BackendRepo>;
|
|
142
159
|
/** Names declared twice (tool:<name>, agent:<name>): the framework refuses to start with one. */
|
|
143
160
|
twice: Set<string>;
|
|
144
161
|
}
|
|
@@ -156,6 +173,24 @@ export declare const AGENT_NAME: RegExp;
|
|
|
156
173
|
export declare function parametersOf(schema: StandardSchema | undefined, what: string): Record<string, unknown>;
|
|
157
174
|
export declare function backendTool<S extends StandardSchema>(o: BackendToolOptions<S>): BackendTool<S>;
|
|
158
175
|
export declare function clientTool<S extends StandardSchema>(o: ClientToolOptions<S>): ClientTool;
|
|
176
|
+
/**
|
|
177
|
+
* A repository a chat's workspace works in, whose tokens this backend gives:
|
|
178
|
+
* put it with ai.repos.put(repo), and each clone and each push of a chat's
|
|
179
|
+
* workspace asks this machine for a token then (token) — a GitHub App's
|
|
180
|
+
* installation token for that one repository, say — kept nowhere. Made once,
|
|
181
|
+
* at a module's top level.
|
|
182
|
+
*/
|
|
183
|
+
export declare function backendRepo(options: {
|
|
184
|
+
name: string;
|
|
185
|
+
repository: string;
|
|
186
|
+
defaultBranch?: string;
|
|
187
|
+
machine?: string;
|
|
188
|
+
token: (ctx: {
|
|
189
|
+
repo: string;
|
|
190
|
+
repository: string;
|
|
191
|
+
signal: AbortSignal;
|
|
192
|
+
}) => string | Promise<string>;
|
|
193
|
+
}): BackendRepo;
|
|
159
194
|
export declare function backendAgent(name: string, define: (ctx: AgentContext) => TurnDefinition | Promise<TurnDefinition>, options?: {
|
|
160
195
|
machine?: string;
|
|
161
196
|
clients?: boolean;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type RoomAuthorizeContext, type RoomDeclaration } from './rooms.js';
|
|
2
|
+
/** What an authorize function lets the user do on the channel: subscribe (hear), and publish (send) if said. */
|
|
3
|
+
export interface ChannelGrant {
|
|
4
|
+
subscribe: boolean;
|
|
5
|
+
publish?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* v2's presence/state rights. A channel an authorize function decides is
|
|
8
|
+
* a room, and a room's member hears and sends — it has no state of its
|
|
9
|
+
* own: a grant that names state is taken for subscribe and publish alone,
|
|
10
|
+
* and the app's log says so once.
|
|
11
|
+
*/
|
|
12
|
+
state?: {
|
|
13
|
+
read?: boolean;
|
|
14
|
+
write?: boolean;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** What an authorize function is given: the user who asks (signed in — realtime turns anyone else away first), and the pattern's parameters. */
|
|
18
|
+
export type ChannelAuthorizeCtx = RoomAuthorizeContext;
|
|
19
|
+
interface OwnerEntry {
|
|
20
|
+
kind: 'owner';
|
|
21
|
+
}
|
|
22
|
+
interface PublicEntry {
|
|
23
|
+
kind: 'public';
|
|
24
|
+
publish?: boolean;
|
|
25
|
+
state?: {
|
|
26
|
+
read?: boolean;
|
|
27
|
+
write?: boolean;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
interface CustomEntry {
|
|
31
|
+
authorize: (ctx: ChannelAuthorizeCtx) => ChannelGrant | null | undefined | Promise<ChannelGrant | null | undefined>;
|
|
32
|
+
}
|
|
33
|
+
export type ChannelEntry = OwnerEntry | PublicEntry | CustomEntry;
|
|
34
|
+
export type ChannelsInput = Record<string, ChannelEntry>;
|
|
35
|
+
/** One owner or public channel, as the build's contract carries it (x-palbase-channels): the rights are a public one's — an owner channel is its owner's whole. */
|
|
36
|
+
export interface ChannelRow {
|
|
37
|
+
pattern: string;
|
|
38
|
+
kind: 'owner' | 'public';
|
|
39
|
+
publish: boolean;
|
|
40
|
+
state_read: boolean;
|
|
41
|
+
state_write: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** The project's channels: the rows realtime decides, and the ones an authorize function does. */
|
|
44
|
+
export interface ChannelsDef {
|
|
45
|
+
rows: readonly ChannelRow[];
|
|
46
|
+
custom: readonly {
|
|
47
|
+
pattern: string;
|
|
48
|
+
authorize: CustomEntry['authorize'];
|
|
49
|
+
}[];
|
|
50
|
+
}
|
|
51
|
+
/** The whole channel is the user's whose id its one {param} is: realtime compares the two, asking the app nothing. */
|
|
52
|
+
export declare function ownerOnly(): OwnerEntry;
|
|
53
|
+
/** Any signed-in user subscribes; publishing and state are each the channel's only when said. */
|
|
54
|
+
export declare function publicChannel(opts?: {
|
|
55
|
+
publish?: boolean;
|
|
56
|
+
state?: {
|
|
57
|
+
read?: boolean;
|
|
58
|
+
write?: boolean;
|
|
59
|
+
};
|
|
60
|
+
}): PublicEntry;
|
|
61
|
+
/**
|
|
62
|
+
* The project's channels, by pattern ("user:{userId}"). ownerOnly() needs
|
|
63
|
+
* exactly one {param}; an entry with an authorize function is decided by it.
|
|
64
|
+
* A v2 handler (publishes taken over by the app) is a room's @OnMessage in
|
|
65
|
+
* v3: a channel the app answers is a @Room.
|
|
66
|
+
*/
|
|
67
|
+
export declare function defineChannels(map: ChannelsInput): ChannelsDef;
|
|
68
|
+
/** The process's channels, as defineChannels declared them by now; none when it was never called. */
|
|
69
|
+
export declare function declaredChannels(): ChannelsDef;
|
|
70
|
+
/**
|
|
71
|
+
* The rooms the channels an authorize function decides are: one per
|
|
72
|
+
* pattern, its one method that function, its grant a room's ({ read, write }
|
|
73
|
+
* from subscribe and publish).
|
|
74
|
+
*/
|
|
75
|
+
export declare function channelRooms(def: ChannelsDef): {
|
|
76
|
+
cls: Function;
|
|
77
|
+
instance: object;
|
|
78
|
+
}[];
|
|
79
|
+
/** Why the channels and the app's @Room classes cannot both be, or undefined: a shape is one or the other's. */
|
|
80
|
+
export declare function channelsClash(def: ChannelsDef, rooms: readonly RoomDeclaration[]): string | undefined;
|
|
81
|
+
export {};
|
|
@@ -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[]);
|