palbase 0.14.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/ai/index.js +2 -2
  2. package/dist/backend/engine.js +2 -2
  3. package/dist/backend/env.js +1 -1
  4. package/dist/backend/index.js +3 -3
  5. package/dist/backend/stack.js +1 -1
  6. package/dist/backend/test.js +2 -2
  7. package/dist/chunks/{427AGWP3.js → 2JBRAHJV.js} +2 -2
  8. package/dist/chunks/{7DQ76T2V.js → 5W7IKTRI.js} +2 -2
  9. package/dist/chunks/{6NC5RYCS.js → 7HYPHYX5.js} +1 -1
  10. package/dist/chunks/{44ULNVPP.js → A4YMCQOP.js} +1 -1
  11. package/dist/chunks/{PRJZTG2I.js → C5PO7C6L.js} +1 -1
  12. package/dist/chunks/{4UQ4J7RV.js → CFGQWDV5.js} +3 -3
  13. package/dist/chunks/CXZ6WKOI.js +18 -0
  14. package/dist/chunks/{JKWWY2LJ.js → EHWHP4MD.js} +2 -2
  15. package/dist/chunks/{WXNFMEW7.js → EJHB65XA.js} +2 -2
  16. package/dist/chunks/{LUFWGH2V.js → HVC5H5HY.js} +2 -2
  17. package/dist/chunks/{CUL5OL4P.js → IA4LTPBJ.js} +2 -2
  18. package/dist/chunks/{RD5JFDGQ.js → JOWAWH33.js} +2 -2
  19. package/dist/chunks/L73SEFXF.js +21 -0
  20. package/dist/chunks/LY7D5Q3R.js +2 -0
  21. package/dist/chunks/NQNE5PZW.js +13 -0
  22. package/dist/chunks/{W3OCV3QH.js → QN5WMSP7.js} +2 -2
  23. package/dist/chunks/{SBUC7GHR.js → S7WYS4NC.js} +2 -2
  24. package/dist/chunks/TGVFGW5G.js +2 -0
  25. package/dist/chunks/{HHZSOYPP.js → TIC3NMUT.js} +1 -1
  26. package/dist/chunks/{DIOZGDFQ.js → VNLECYBD.js} +1 -1
  27. package/dist/chunks/{ZZNGA77G.js → VTUZYTKZ.js} +1 -1
  28. package/dist/chunks/{A46IASZE.js → WCTVLG4W.js} +2 -2
  29. package/dist/chunks/{P67I4TNQ.js → YUBOQ3NU.js} +1 -1
  30. package/dist/cli.js +127 -127
  31. package/dist/refuse/ai.js +1 -1
  32. package/dist/refuse/backend.js +1 -1
  33. package/dist/refuse/server.js +1 -1
  34. package/dist/server/index.js +2 -2
  35. package/dist/server/testing.js +2 -2
  36. package/dist/web/index.js +2 -2
  37. package/dist/web/message.js +2 -2
  38. package/dist/web/palbe.js +2 -2
  39. package/dist/web/paywall.js +2 -2
  40. package/dist/web/push-sw.js +1 -1
  41. package/dist/web/ssr.js +2 -2
  42. package/dist/web/vite.js +2 -2
  43. package/package.json +2 -2
  44. package/types/ai/src/ai.d.ts +18 -1
  45. package/types/ai/src/chats.d.ts +13 -2
  46. package/types/ai/src/index.d.ts +1 -1
  47. package/types/backend/src/decorators.d.ts +20 -0
  48. package/types/backend/src/engine.d.ts +9 -0
  49. package/types/backend/src/openapi.d.ts +3 -0
  50. package/types/backend/src/router.d.ts +2 -0
  51. package/types/internal/src/modules/ai.d.ts +67 -2
  52. package/types/internal/src/modules/analytics.d.ts +6 -2
  53. package/types/internal/src/modules/auth.d.ts +33 -14
  54. package/types/internal/src/modules/journeys.d.ts +45 -0
  55. package/types/web/src/backend-error.d.ts +6 -1
  56. package/types/web/src/inapp.d.ts +2 -0
  57. package/dist/chunks/3AENUHVO.js +0 -2
  58. package/dist/chunks/5H7UNNH6.js +0 -13
  59. package/dist/chunks/BRHGS5AI.js +0 -18
  60. package/dist/chunks/OMK2YEDZ.js +0 -2
  61. package/dist/chunks/QZH6GPCR.js +0 -21
package/dist/refuse/ai.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/ai is for servers: it speaks with the project secret key, which never goes into a browser or a mobile app \u2014 call your backend, and let it ask the model");
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/backend is a server framework: it runs on your backend, never in a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs)");
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/server is for servers: its secret key never goes into a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs) with the publishable key");
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{a as e,b as f,c as g,d as h,e as i,f as j,g as k,h as l,i as m,j as n,k as o,l as p,m as q,n as r,o as s,p as t,q as u,r as v,s as w,t as x,u as y}from"../chunks/LUFWGH2V.js";import{a as c,b as d}from"../chunks/HHZSOYPP.js";import"../chunks/ZZNGA77G.js";import"../chunks/44ULNVPP.js";import{m as b}from"../chunks/OMK2YEDZ.js";import"../chunks/RD5JFDGQ.js";import{b as a}from"../chunks/JKWWY2LJ.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";export{o as AuthUnavailable,b as EVENT_TYPES,c as FieldError,d as Fields,a as PalbaseError,t as ReservationSettled,n as TokenError,q as TokenVerifier,f as Transit,e as TransitRefusal,g as TransitRequest,i as WebhookSignatureError,h as createServer,s as isEntitled,y as loadSecrets,v as pages,x as platformOwn,w as processOwn,r as requestAddress,p as sessionStanding,l as signatureHeader,k as verifySignature,j as verifyWebhook,m as verifyWebhookRequest,u as withReservation};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{a as e,b as f,c as g,d as h,e as i,f as j,g as k,h as l,i as m,j as n,k as o,l as p,m as q,n as r,o as s,p as t,q as u,r as v,s as w,t as x,u as y}from"../chunks/HVC5H5HY.js";import{a as c,b as d}from"../chunks/TIC3NMUT.js";import"../chunks/VTUZYTKZ.js";import"../chunks/A4YMCQOP.js";import{m as b}from"../chunks/LY7D5Q3R.js";import"../chunks/JOWAWH33.js";import{b as a}from"../chunks/EHWHP4MD.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";export{o as AuthUnavailable,b as EVENT_TYPES,c as FieldError,d as Fields,a as PalbaseError,t as ReservationSettled,n as TokenError,q as TokenVerifier,f as Transit,e as TransitRefusal,g as TransitRequest,i as WebhookSignatureError,h as createServer,s as isEntitled,y as loadSecrets,v as pages,x as platformOwn,w as processOwn,r as requestAddress,p as sessionStanding,l as signatureHeader,k as verifySignature,j as verifyWebhook,m as verifyWebhookRequest,u as withReservation};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{a,b,c,d,e}from"../chunks/WXNFMEW7.js";import"../chunks/HHZSOYPP.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";export{b as TestApiError,e as api,c as createTestApi,a as testFields,d as testRun};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{a,b,c,d,e}from"../chunks/EJHB65XA.js";import"../chunks/TIC3NMUT.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";export{b as TestApiError,e as api,c as createTestApi,a as testFields,d as testRun};
package/dist/web/index.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{a as M,b as j,c as q,d as G,e as N,f as U,g as D,h as H,i as J,j as B,k as F,l as K,m as W,n as X,o as Y,p as Z,q as ee}from"../chunks/4UQ4J7RV.js";import{a as _,b as Q,f as z}from"../chunks/5H7UNNH6.js";import"../chunks/7DQ76T2V.js";import"../chunks/W3OCV3QH.js";import"../chunks/PRJZTG2I.js";import{b as E,c as T,d as x,f as O,g as A,j as R,k as $,l as V,m as v,o as S}from"../chunks/ZZNGA77G.js";import"../chunks/3AENUHVO.js";import"../chunks/OMK2YEDZ.js";import"../chunks/RD5JFDGQ.js";import{b as L}from"../chunks/JKWWY2LJ.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";var te="oai-events";async function ne(e){if(typeof e?.start!="function")throw new TypeError("connectVoice: start(sdp) is the round trip to the app's backend, which starts the voice (chats.voice.start) and answers { id, sdp }");let r=e.rtc??se(),t=e.signal;t?.throwIfAborted();let f=e.audio??ae(),l=e.microphone===void 0,c=e.microphone??await r.getUserMedia({audio:!0});if(t?.aborted){if(l)for(let n of c.getTracks())n.stop();throw t.reason}let o=new r.RTCPeerConnection,s=!1,u=()=>{if(!s){if(s=!0,m.close(),o.close(),l)for(let n of c.getTracks())n.stop();f.srcObject!==null&&(f.srcObject=null)}};o.addEventListener("track",n=>{f.srcObject=n.streams[0]??new MediaStream([n.track]),f.play?.()?.catch?.(()=>{})}),o.addEventListener("connectionstatechange",()=>e.onState?.(o.connectionState));for(let n of c.getAudioTracks())o.addTrack(n,c);let m=o.createDataChannel(te);m.addEventListener("message",n=>{let p=oe(n.data);p!==void 0&&e.onError?.(p)});let d=()=>u();t?.addEventListener("abort",d,{once:!0});try{await o.setLocalDescription(await o.createOffer()),t?.throwIfAborted(),await re(o,e.iceTimeoutMs??1e4,t);let n=o.localDescription?.sdp;if(!n)throw new Error("connectVoice: the peer connection made no offer");let p=await e.start(n);if(t?.throwIfAborted(),typeof p?.id!="string"||p.id===""||typeof p.sdp!="string"||p.sdp==="")throw new TypeError("connectVoice: start answered no voice \u2014 it is { id, sdp }, chats.voice.start's answer as the backend got it");return await o.setRemoteDescription({type:"answer",sdp:p.sdp}),t?.removeEventListener("abort",d),{id:p.id,peer:o,audio:f,microphone:c,get muted(){return c.getAudioTracks().every(h=>!h.enabled)},mute(h){for(let w of c.getAudioTracks())w.enabled=!h},close:u}}catch(n){throw t?.removeEventListener("abort",d),u(),t?.aborted?t.reason:n}}function re(e,r,t){return e.iceGatheringState==="complete"?Promise.resolve():t?.aborted?Promise.reject(t.reason):new Promise((f,l)=>{let c=()=>{clearTimeout(u),e.removeEventListener("icegatheringstatechange",o),t?.removeEventListener("abort",s)},o=()=>{e.iceGatheringState==="complete"&&(c(),f())},s=()=>{c(),l(t?.reason)},u=setTimeout(()=>{c(),l(new Error(`connectVoice: the network candidates were not gathered in ${r} ms`))},r);e.addEventListener("icegatheringstatechange",o),t?.addEventListener("abort",s,{once:!0})})}function oe(e){if(typeof e=="string")try{let r=JSON.parse(e);return r.type!=="error"?void 0:typeof r.error?.message=="string"?r.error.message:typeof r.error?.code=="string"?r.error.code:"the voice failed"}catch{return}}function se(){let e=globalThis;if(typeof e.RTCPeerConnection!="function"||typeof e.navigator?.mediaDevices?.getUserMedia!="function")throw new TypeError("connectVoice: this runtime has no WebRTC (RTCPeerConnection, navigator.mediaDevices): a chat's voice is a browser's");let r=e.navigator.mediaDevices;return{RTCPeerConnection:e.RTCPeerConnection,getUserMedia:t=>r.getUserMedia(t)}}function ae(){let e=globalThis.document;if(!e)throw new TypeError("connectVoice: give audio \u2014 the element the voice plays in \u2014 where there is no document");let r=e.createElement("audio");return r.autoplay=!0,r}var i=e=>typeof e=="object"&&e!==null&&!Array.isArray(e)?e:void 0;function ie(e,r,t){let f=i(i(i(e)?.components)?.schemas)??{},l=(d,n)=>{let p=new Set,h=(C,g,y)=>{let a=i(C);if(!a)return;if(typeof a.$ref=="string"){if(y.has(a.$ref)||!a.$ref.startsWith("#/components/schemas/"))return;h(f[a.$ref.slice(21)],g,new Set(y).add(a.$ref));return}if(a[E]===!0){p.add(g);return}for(let b of["anyOf","oneOf","allOf"]){let k=a[b];if(Array.isArray(k))for(let I of k)h(I,g,y)}let P=i(a.properties);if(P)for(let[b,k]of Object.entries(P))h(k,`${g}/${v(b)}`,y);i(a.items)&&h(a.items,`${g}/*`,y);for(let b of["additionalProperties","patternProperties","prefixItems"])if(a[b]!==void 0&&w(a[b],new Set(y)))throw new Error(`${t}: an encrypted field is a named property \u2014 not every key of a record, nor a tuple's place`)},w=(C,g)=>{if(Array.isArray(C))return C.some(a=>w(a,g));let y=i(C);return y?y[E]===!0?!0:typeof y.$ref=="string"&&!g.has(y.$ref)&&y.$ref.startsWith("#/components/schemas/")?(g.add(y.$ref),w(f[y.$ref.slice(21)],g)):Object.values(y).some(a=>typeof a=="object"&&a!==null&&w(a,g)):!1};return h(d,n,new Set),[...p]},c=d=>i(i(i(d)?.["application/json"])?.schema),o=[];o.push(...l(c(i(r.requestBody)?.content),"/body"));for(let d of Array.isArray(r.parameters)?r.parameters:[]){let n=i(d);if(!n)continue;let p=l(n.schema,`/query/${v(String(n.name))}`);if(p.length!==0){if(n.in!=="query")throw new Error(`${t}: ${String(n.in)} parameter ${String(n.name)} is marked encrypted \u2014 a body's or a query's field is`);if(p.some(h=>h.split("/").length!==3))throw new Error(`${t}: an encrypted query field is one of the query's own names`);o.push(...p)}}let s=i(r.responses)??{},u=Object.keys(s).filter(d=>/^2\d\d$/.test(d)).sort((d,n)=>d==="200"?-1:n==="200"?1:d.localeCompare(n)),m=u.length>0?l(c(i(s[u[0]])?.content),"/response"):[];if(o.length+m.length!==0){if(r["x-palbase-sse"]!==void 0&&m.length>0)throw new Error(`${t}: a streamed answer carries no encrypted field`);if(r["x-palbase-upload"]!==void 0)throw new Error(`${t}: an upload goes through storage, which seals nothing \u2014 it carries no encrypted field`);return{request:o,response:m}}}async function ce(e){let r=`${e.method.toUpperCase()} ${e.path}`,t=i(i(i(i(e.contract)?.paths)?.[e.path])?.[e.method.toLowerCase()]),f=t?ie(e.contract,t,r):void 0;if(!f)return{body:e.body,query:e.query,open:async s=>s};let{key:l,header:c}=await A(e.key.kid,x(e.key.publicKey),O(e.projectId,e.method,e.path,e.params??[])),o=(s,u)=>s==null?s:S(s,u,f.request,(m,d)=>R(l,m,d));return{header:c,body:await o(e.body,"/body"),query:await o(e.query,"/query"),open:s=>s===void 0?Promise.resolve(s):S(s,"/response",f.response,async(u,m)=>{if(!$(m))throw new T("unopenable",`${r}: ${u} came plain where the contract says it is encrypted`);return V(l,u,m)})}}export{D as Analytics,_ as BackendError,G as Channel,H as Consent,Z as Flags,z as GatewayError,F as InApp,J as Inbox,U as Installation,W as Notify,L as PalbaseError,X as Purchases,N as RealtimeSocket,B as SESSION_START,M as SessionChangedError,K as WebPush,ne as connectVoice,ee as createClient,ce as encryptedCall,Q as isBackendError,q as localStore,j as memoryStore,Y as redemptionToken};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{a as M,b as j,c as q,d as G,e as N,f as U,g as D,h as H,i as J,j as B,k as F,l as K,m as W,n as X,o as Y,p as Z,q as ee}from"../chunks/CFGQWDV5.js";import{a as _,b as Q,f as z}from"../chunks/NQNE5PZW.js";import"../chunks/5W7IKTRI.js";import"../chunks/QN5WMSP7.js";import"../chunks/C5PO7C6L.js";import{b as E,c as T,d as x,f as O,g as A,j as R,k as $,l as V,m as v,o as S}from"../chunks/VTUZYTKZ.js";import"../chunks/TGVFGW5G.js";import"../chunks/LY7D5Q3R.js";import"../chunks/JOWAWH33.js";import{b as L}from"../chunks/EHWHP4MD.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";var te="oai-events";async function ne(e){if(typeof e?.start!="function")throw new TypeError("connectVoice: start(sdp) is the round trip to the app's backend, which starts the voice (chats.voice.start) and answers { id, sdp }");let r=e.rtc??se(),t=e.signal;t?.throwIfAborted();let f=e.audio??ae(),l=e.microphone===void 0,c=e.microphone??await r.getUserMedia({audio:!0});if(t?.aborted){if(l)for(let n of c.getTracks())n.stop();throw t.reason}let o=new r.RTCPeerConnection,s=!1,u=()=>{if(!s){if(s=!0,m.close(),o.close(),l)for(let n of c.getTracks())n.stop();f.srcObject!==null&&(f.srcObject=null)}};o.addEventListener("track",n=>{f.srcObject=n.streams[0]??new MediaStream([n.track]),f.play?.()?.catch?.(()=>{})}),o.addEventListener("connectionstatechange",()=>e.onState?.(o.connectionState));for(let n of c.getAudioTracks())o.addTrack(n,c);let m=o.createDataChannel(te);m.addEventListener("message",n=>{let p=oe(n.data);p!==void 0&&e.onError?.(p)});let d=()=>u();t?.addEventListener("abort",d,{once:!0});try{await o.setLocalDescription(await o.createOffer()),t?.throwIfAborted(),await re(o,e.iceTimeoutMs??1e4,t);let n=o.localDescription?.sdp;if(!n)throw new Error("connectVoice: the peer connection made no offer");let p=await e.start(n);if(t?.throwIfAborted(),typeof p?.id!="string"||p.id===""||typeof p.sdp!="string"||p.sdp==="")throw new TypeError("connectVoice: start answered no voice \u2014 it is { id, sdp }, chats.voice.start's answer as the backend got it");return await o.setRemoteDescription({type:"answer",sdp:p.sdp}),t?.removeEventListener("abort",d),{id:p.id,peer:o,audio:f,microphone:c,get muted(){return c.getAudioTracks().every(h=>!h.enabled)},mute(h){for(let w of c.getAudioTracks())w.enabled=!h},close:u}}catch(n){throw t?.removeEventListener("abort",d),u(),t?.aborted?t.reason:n}}function re(e,r,t){return e.iceGatheringState==="complete"?Promise.resolve():t?.aborted?Promise.reject(t.reason):new Promise((f,l)=>{let c=()=>{clearTimeout(u),e.removeEventListener("icegatheringstatechange",o),t?.removeEventListener("abort",s)},o=()=>{e.iceGatheringState==="complete"&&(c(),f())},s=()=>{c(),l(t?.reason)},u=setTimeout(()=>{c(),l(new Error(`connectVoice: the network candidates were not gathered in ${r} ms`))},r);e.addEventListener("icegatheringstatechange",o),t?.addEventListener("abort",s,{once:!0})})}function oe(e){if(typeof e=="string")try{let r=JSON.parse(e);return r.type!=="error"?void 0:typeof r.error?.message=="string"?r.error.message:typeof r.error?.code=="string"?r.error.code:"the voice failed"}catch{return}}function se(){let e=globalThis;if(typeof e.RTCPeerConnection!="function"||typeof e.navigator?.mediaDevices?.getUserMedia!="function")throw new TypeError("connectVoice: this runtime has no WebRTC (RTCPeerConnection, navigator.mediaDevices): a chat's voice is a browser's");let r=e.navigator.mediaDevices;return{RTCPeerConnection:e.RTCPeerConnection,getUserMedia:t=>r.getUserMedia(t)}}function ae(){let e=globalThis.document;if(!e)throw new TypeError("connectVoice: give audio \u2014 the element the voice plays in \u2014 where there is no document");let r=e.createElement("audio");return r.autoplay=!0,r}var i=e=>typeof e=="object"&&e!==null&&!Array.isArray(e)?e:void 0;function ie(e,r,t){let f=i(i(i(e)?.components)?.schemas)??{},l=(d,n)=>{let p=new Set,h=(C,g,y)=>{let a=i(C);if(!a)return;if(typeof a.$ref=="string"){if(y.has(a.$ref)||!a.$ref.startsWith("#/components/schemas/"))return;h(f[a.$ref.slice(21)],g,new Set(y).add(a.$ref));return}if(a[E]===!0){p.add(g);return}for(let b of["anyOf","oneOf","allOf"]){let k=a[b];if(Array.isArray(k))for(let I of k)h(I,g,y)}let P=i(a.properties);if(P)for(let[b,k]of Object.entries(P))h(k,`${g}/${v(b)}`,y);i(a.items)&&h(a.items,`${g}/*`,y);for(let b of["additionalProperties","patternProperties","prefixItems"])if(a[b]!==void 0&&w(a[b],new Set(y)))throw new Error(`${t}: an encrypted field is a named property \u2014 not every key of a record, nor a tuple's place`)},w=(C,g)=>{if(Array.isArray(C))return C.some(a=>w(a,g));let y=i(C);return y?y[E]===!0?!0:typeof y.$ref=="string"&&!g.has(y.$ref)&&y.$ref.startsWith("#/components/schemas/")?(g.add(y.$ref),w(f[y.$ref.slice(21)],g)):Object.values(y).some(a=>typeof a=="object"&&a!==null&&w(a,g)):!1};return h(d,n,new Set),[...p]},c=d=>i(i(i(d)?.["application/json"])?.schema),o=[];o.push(...l(c(i(r.requestBody)?.content),"/body"));for(let d of Array.isArray(r.parameters)?r.parameters:[]){let n=i(d);if(!n)continue;let p=l(n.schema,`/query/${v(String(n.name))}`);if(p.length!==0){if(n.in!=="query")throw new Error(`${t}: ${String(n.in)} parameter ${String(n.name)} is marked encrypted \u2014 a body's or a query's field is`);if(p.some(h=>h.split("/").length!==3))throw new Error(`${t}: an encrypted query field is one of the query's own names`);o.push(...p)}}let s=i(r.responses)??{},u=Object.keys(s).filter(d=>/^2\d\d$/.test(d)).sort((d,n)=>d==="200"?-1:n==="200"?1:d.localeCompare(n)),m=u.length>0?l(c(i(s[u[0]])?.content),"/response"):[];if(o.length+m.length!==0){if(r["x-palbase-sse"]!==void 0&&m.length>0)throw new Error(`${t}: a streamed answer carries no encrypted field`);if(r["x-palbase-upload"]!==void 0)throw new Error(`${t}: an upload goes through storage, which seals nothing \u2014 it carries no encrypted field`);return{request:o,response:m}}}async function ce(e){let r=`${e.method.toUpperCase()} ${e.path}`,t=i(i(i(i(e.contract)?.paths)?.[e.path])?.[e.method.toLowerCase()]),f=t?ie(e.contract,t,r):void 0;if(!f)return{body:e.body,query:e.query,open:async s=>s};let{key:l,header:c}=await A(e.key.kid,x(e.key.publicKey),O(e.projectId,e.method,e.path,e.params??[])),o=(s,u)=>s==null?s:S(s,u,f.request,(m,d)=>R(l,m,d));return{header:c,body:await o(e.body,"/body"),query:await o(e.query,"/query"),open:s=>s===void 0?Promise.resolve(s):S(s,"/response",f.response,async(u,m)=>{if(!$(m))throw new T("unopenable",`${r}: ${u} came plain where the contract says it is encrypted`);return V(l,u,m)})}}export{D as Analytics,_ as BackendError,G as Channel,H as Consent,Z as Flags,z as GatewayError,F as InApp,J as Inbox,U as Installation,W as Notify,L as PalbaseError,X as Purchases,N as RealtimeSocket,B as SESSION_START,M as SessionChangedError,K as WebPush,ne as connectVoice,ee as createClient,ce as encryptedCall,Q as isBackendError,q as localStore,j as memoryStore,Y as redemptionToken};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{a as i}from"../chunks/W3OCV3QH.js";import{a as e,b as s,c as t,d as p,e as o,f as a,h as r,j as n,k as y,p as M,q as l,t as g}from"../chunks/PRJZTG2I.js";import"../chunks/6NC5RYCS.js";export{n as MESSAGE_COMPONENTS,a as MESSAGE_ICONS,r as MESSAGE_SCHEMA,s as assetId,y as countdownValues,e as fontFamily,o as htmlDocument,t as prepareAssets,i as presentMessage,g as renderMessage,M as resolveMessage,l as resolveMessageWithPaths,p as unzip};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{a as i}from"../chunks/QN5WMSP7.js";import{a as e,b as s,c as t,d as p,e as o,f as a,h as r,j as n,k as y,p as M,q as l,t as g}from"../chunks/C5PO7C6L.js";import"../chunks/7HYPHYX5.js";export{n as MESSAGE_COMPONENTS,a as MESSAGE_ICONS,r as MESSAGE_SCHEMA,s as assetId,y as countdownValues,e as fontFamily,o as htmlDocument,t as prepareAssets,i as presentMessage,g as renderMessage,M as resolveMessage,l as resolveMessageWithPaths,p as unzip};
package/dist/web/palbe.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{c as e,d as r,i as t}from"../chunks/5H7UNNH6.js";import"../chunks/ZZNGA77G.js";import"../chunks/3AENUHVO.js";import"../chunks/RD5JFDGQ.js";import"../chunks/JKWWY2LJ.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";export{e as RESERVED_CLIENT_NAMES,t as __registerBackend,r as isClientName};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{c as e,d as r,i as t}from"../chunks/NQNE5PZW.js";import"../chunks/VTUZYTKZ.js";import"../chunks/TGVFGW5G.js";import"../chunks/JOWAWH33.js";import"../chunks/EHWHP4MD.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";export{e as RESERVED_CLIENT_NAMES,t as __registerBackend,r as isClientName};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{a as f,b as d,c as m,d as u,e as A,f as c,g as R}from"../chunks/7DQ76T2V.js";import{a as e,b as a,c as t,d as l,e as r,f as o,g as p,i as y,k as s,l as P,n,o as i,s as w}from"../chunks/PRJZTG2I.js";import"../chunks/JKWWY2LJ.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";export{y as PAYWALL_COMPONENTS,o as PAYWALL_ICONS,p as PAYWALL_SCHEMA,c as Paywall,a as assetId,f as attributesHeader,s as countdownValues,R as defaultPaywall,e as fontFamily,u as formatPeriod,m as formatPrice,r as htmlDocument,A as packageValues,P as packagesOf,d as parseDuration,t as prepareAssets,w as renderPaywall,n as resolvePaywall,i as resolvePaywallWithPaths,l as unzip};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{a as f,b as d,c as m,d as u,e as A,f as c,g as R}from"../chunks/5W7IKTRI.js";import{a as e,b as a,c as t,d as l,e as r,f as o,g as p,i as y,k as s,l as P,n,o as i,s as w}from"../chunks/C5PO7C6L.js";import"../chunks/EHWHP4MD.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";export{y as PAYWALL_COMPONENTS,o as PAYWALL_ICONS,p as PAYWALL_SCHEMA,c as Paywall,a as assetId,f as attributesHeader,s as countdownValues,R as defaultPaywall,e as fontFamily,u as formatPeriod,m as formatPrice,r as htmlDocument,A as packageValues,P as packagesOf,d as parseDuration,t as prepareAssets,w as renderPaywall,n as resolvePaywall,i as resolvePaywallWithPaths,l as unzip};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
2
  "use strict";(()=>{function f(e,s){if(e)try{let i=new URL(e,s);if(i.protocol==="https:"||i.protocol==="http:"&&(i.hostname==="localhost"||i.hostname==="127.0.0.1"))return i.href}catch{}}function g(e){let s=new URL(e.location.href).searchParams,i=s.get("url")??"",l=s.get("key")??"",r=(n,t)=>!n||!i?Promise.resolve():e.fetch(`${i.replace(/\/$/,"")}/notify/receipts`,{method:"POST",headers:{"content-type":"application/json",apikey:l},body:JSON.stringify({receipts:[{receipt:n,status:t}]}),keepalive:!0}).catch(()=>{}),a=async(n,t)=>{for(let o of await e.clients.matchAll({type:"window",includeUncontrolled:!0}))o.postMessage({type:"palbase.push",event:n,url:t.url,data:t.data})};e.addEventListener("push",(n=>{let t={};try{t=n.data?.json()??{}}catch{}let o={url:t.url,receipt:t.receipt,data:t.data};n.waitUntil(e.registration.showNotification(t.title??"",{body:t.body,image:t.image,tag:t.tag,data:o}).then(()=>Promise.all([r(t.receipt,"delivered"),a("received",o)])))})),e.addEventListener("notificationclick",(n=>{n.notification.close();let t=n.notification.data??{},o=f(t.url,e.location.origin),c=async()=>{if(!o)return;let d=(await e.clients.matchAll({type:"window",includeUncontrolled:!0})).find(u=>u.url===o);d?await d.focus():await e.clients.openWindow(o)};n.waitUntil(Promise.all([r(t.receipt,"opened"),c(),a("opened",t)]))})),e.addEventListener("notificationclose",(n=>{n.waitUntil(r(n.notification.data?.receipt,"dismissed"))}))}typeof self<"u"&&typeof self.registration=="object"&&!("document"in self)&&g(self);})();
package/dist/web/ssr.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import{q as f}from"../chunks/4UQ4J7RV.js";import"../chunks/5H7UNNH6.js";import"../chunks/7DQ76T2V.js";import"../chunks/W3OCV3QH.js";import"../chunks/PRJZTG2I.js";import"../chunks/ZZNGA77G.js";import"../chunks/3AENUHVO.js";import"../chunks/OMK2YEDZ.js";import"../chunks/RD5JFDGQ.js";import"../chunks/JKWWY2LJ.js";import"../chunks/P67I4TNQ.js";import"../chunks/6NC5RYCS.js";var C=Object.freeze({"Cache-Control":"private, no-cache, no-store, must-revalidate, max-age=0",Expires:"0",Pragma:"no-cache"}),x={path:"/",sameSite:"lax",secure:!0,httpOnly:!1,maxAge:400*24*60*60},u=3180,k=5*6e4;function d(t){let e=/^pb_([a-z0-9]+)_c/.exec(t)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");return`pb-${e}-session`}var y=t=>{let e=new TextEncoder().encode(JSON.stringify(t)),o="";for(let s of e)o+=String.fromCharCode(s);return btoa(o).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},b=t=>{try{let e=atob(t.replace(/-/g,"+").replace(/_/g,"/")),o=JSON.parse(new TextDecoder().decode(Uint8Array.from(e,s=>s.charCodeAt(0))));return typeof o.accessToken!="string"||typeof o.refreshToken!="string"||typeof o.expiresAt!="number"||typeof o.userId!="string"?null:o}catch{return null}};function m(t,e,o={},s=!1){let c={...x,...o},g=async()=>new Map((await e.getAll()).map(n=>[n.name,n.value])),S=n=>n===t||n.startsWith(`${t}.`)&&/^\d+$/.test(n.slice(t.length+1)),h=async n=>{if(!e.setAll)return;let i=n===null?[]:n.length<=u?[[t,n]]:Array.from({length:Math.ceil(n.length/u)},(r,l)=>[`${t}.${l}`,n.slice(l*u,(l+1)*u)]),p=new Set(i.map(([r])=>r)),a=i.map(([r,l])=>({name:r,value:l,options:c}));for(let r of(await g()).keys())S(r)&&!p.has(r)&&a.push({name:r,value:"",options:{...c,maxAge:0}});a.length>0&&await e.setAll(a,{...C})};return{async load(){let n=await g(),i=n.get(t);if(i===void 0){let p="";for(let a=0;n.has(`${t}.${a}`);a++)p+=n.get(`${t}.${a}`);i=p}return i?b(i):null},save:n=>h(y(n)),clear:()=>h(null),shared:s}}function A(t){let{cookies:e,cookieOptions:o,...s}=t,c=t.refresh??(e.setAll?"before":"never");return f({...s,refresh:c,storage:m(d(t.publishableKey),e,o)})}function O(){let t=()=>{let e=globalThis.document;if(!e)throw new Error("documentCookies: there is no document here \u2014 a server gives its request's cookies to createServerClient");return e};return{getAll:()=>t().cookie.split(";").map(e=>e.trim()).filter(e=>e.includes("=")).map(e=>{let o=e.indexOf("=");return{name:e.slice(0,o),value:e.slice(o+1)}}),setAll(e){for(let o of e){let s=o.options,c=[`Path=${s.path??"/"}`,s.domain?`Domain=${s.domain}`:"",s.maxAge!==void 0?`Max-Age=${s.maxAge}`:"",s.expires?`Expires=${s.expires.toUTCString()}`:"",s.sameSite?`SameSite=${s.sameSite.charAt(0).toUpperCase()}${s.sameSite.slice(1)}`:"",s.secure?"Secure":""].filter(Boolean);t().cookie=[`${o.name}=${o.value}`,...c].join("; ")}}}}function $(t){let{cookieOptions:e,...o}=t,s=globalThis.location?.protocol==="https:";return f({...o,storage:m(d(t.publishableKey),O(),{secure:s,...e},!0)})}async function v(t){let e=await t.auth.currentSession();if(!e||(e.expiresAt-Date.now()<=k&&await t.auth.refreshSession().catch(()=>{}),!await t.auth.currentSession()))return null;try{return(await t.auth.api.verifyTokenUser()).data}catch(o){if(o.status===401)return null;throw o}}export{C as NO_STORE_HEADERS,x as SESSION_COOKIE_OPTIONS,m as cookieSessionStore,$ as createBrowserClient,A as createServerClient,O as documentCookies,v as keepSession,d as sessionCookieName};
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import{q as f}from"../chunks/CFGQWDV5.js";import"../chunks/NQNE5PZW.js";import"../chunks/5W7IKTRI.js";import"../chunks/QN5WMSP7.js";import"../chunks/C5PO7C6L.js";import"../chunks/VTUZYTKZ.js";import"../chunks/TGVFGW5G.js";import"../chunks/LY7D5Q3R.js";import"../chunks/JOWAWH33.js";import"../chunks/EHWHP4MD.js";import"../chunks/YUBOQ3NU.js";import"../chunks/7HYPHYX5.js";var C=Object.freeze({"Cache-Control":"private, no-cache, no-store, must-revalidate, max-age=0",Expires:"0",Pragma:"no-cache"}),x={path:"/",sameSite:"lax",secure:!0,httpOnly:!1,maxAge:400*24*60*60},u=3180,k=5*6e4;function d(t){let e=/^pb_([a-z0-9]+)_c/.exec(t)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");return`pb-${e}-session`}var y=t=>{let e=new TextEncoder().encode(JSON.stringify(t)),o="";for(let s of e)o+=String.fromCharCode(s);return btoa(o).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},b=t=>{try{let e=atob(t.replace(/-/g,"+").replace(/_/g,"/")),o=JSON.parse(new TextDecoder().decode(Uint8Array.from(e,s=>s.charCodeAt(0))));return typeof o.accessToken!="string"||typeof o.refreshToken!="string"||typeof o.expiresAt!="number"||typeof o.userId!="string"?null:o}catch{return null}};function m(t,e,o={},s=!1){let c={...x,...o},g=async()=>new Map((await e.getAll()).map(n=>[n.name,n.value])),S=n=>n===t||n.startsWith(`${t}.`)&&/^\d+$/.test(n.slice(t.length+1)),h=async n=>{if(!e.setAll)return;let i=n===null?[]:n.length<=u?[[t,n]]:Array.from({length:Math.ceil(n.length/u)},(r,l)=>[`${t}.${l}`,n.slice(l*u,(l+1)*u)]),p=new Set(i.map(([r])=>r)),a=i.map(([r,l])=>({name:r,value:l,options:c}));for(let r of(await g()).keys())S(r)&&!p.has(r)&&a.push({name:r,value:"",options:{...c,maxAge:0}});a.length>0&&await e.setAll(a,{...C})};return{async load(){let n=await g(),i=n.get(t);if(i===void 0){let p="";for(let a=0;n.has(`${t}.${a}`);a++)p+=n.get(`${t}.${a}`);i=p}return i?b(i):null},save:n=>h(y(n)),clear:()=>h(null),shared:s}}function A(t){let{cookies:e,cookieOptions:o,...s}=t,c=t.refresh??(e.setAll?"before":"never");return f({...s,refresh:c,storage:m(d(t.publishableKey),e,o)})}function O(){let t=()=>{let e=globalThis.document;if(!e)throw new Error("documentCookies: there is no document here \u2014 a server gives its request's cookies to createServerClient");return e};return{getAll:()=>t().cookie.split(";").map(e=>e.trim()).filter(e=>e.includes("=")).map(e=>{let o=e.indexOf("=");return{name:e.slice(0,o),value:e.slice(o+1)}}),setAll(e){for(let o of e){let s=o.options,c=[`Path=${s.path??"/"}`,s.domain?`Domain=${s.domain}`:"",s.maxAge!==void 0?`Max-Age=${s.maxAge}`:"",s.expires?`Expires=${s.expires.toUTCString()}`:"",s.sameSite?`SameSite=${s.sameSite.charAt(0).toUpperCase()}${s.sameSite.slice(1)}`:"",s.secure?"Secure":""].filter(Boolean);t().cookie=[`${o.name}=${o.value}`,...c].join("; ")}}}}function $(t){let{cookieOptions:e,...o}=t,s=globalThis.location?.protocol==="https:";return f({...o,storage:m(d(t.publishableKey),O(),{secure:s,...e},!0)})}async function v(t){let e=await t.auth.currentSession();if(!e||(e.expiresAt-Date.now()<=k&&await t.auth.refreshSession().catch(()=>{}),!await t.auth.currentSession()))return null;try{return(await t.auth.api.verifyTokenUser()).data}catch(o){if(o.status===401)return null;throw o}}export{C as NO_STORE_HEADERS,x as SESSION_COOKIE_OPTIONS,m as cookieSessionStore,$ as createBrowserClient,A as createServerClient,O as documentCookies,v as keepSession,d as sessionCookieName};
package/dist/web/vite.js CHANGED
@@ -1,3 +1,3 @@
1
- /*! palbase 0.14.2 — Palbase SDK License (see LICENSE) */
2
- import"../chunks/6NC5RYCS.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:
1
+ /*! palbase 0.16.0 — Palbase SDK License (see LICENSE) */
2
+ import"../chunks/7HYPHYX5.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.14.2",
3
+ "version": "0.16.0",
4
4
  "description": "Palbase for JavaScript: the web client (palbase/web), the server SDK (palbase/server), the backend framework (palbase/backend), AI (palbase/ai) and the CLI (npx palbase).",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://palbase.studio",
@@ -135,7 +135,7 @@
135
135
  "dependencies": {
136
136
  "@types/node": "26.6.4",
137
137
  "bun-types": "1.4.2",
138
- "palgres": "0.14.2",
138
+ "palgres": "0.16.0",
139
139
  "reflect-metadata": "^0.2.2",
140
140
  "typescript": "~6.0.3",
141
141
  "zod": "^4.6.5"
@@ -7,6 +7,12 @@ import { type AgentContext, type BackendAgent, type BackendAgentOptions, type Ba
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];
10
+ /**
11
+ * What the project's use of Palbase's models (the platform's provider keys) cost this month, and what it may still
12
+ * spend: the free dollar a month brings and what is left of it, the monthly budget, and whether they serve the
13
+ * project now — and if not, why (reason).
14
+ */
15
+ export type Spend = modules.ai.Spend;
10
16
  export type Models = modules.ai.Models;
11
17
  /** A text model a turn may name, as the engine's catalogue says it (ai.models().chat). */
12
18
  export type ChatModel = modules.ai.ChatModel;
@@ -224,7 +230,8 @@ export interface AI {
224
230
  /**
225
231
  * Uses of models and their cost, newest first. Each carries its labels (metadata): its caller's — and a chat's turn
226
232
  * the chat's labels and the chat (chat). With metadata, only the uses that carry every one of those labels: a
227
- * product's spend, a task's — a deleted chat's too.
233
+ * product's spend, a task's — a deleted chat's too. A use whose tokens are in part an estimate says so (estimated):
234
+ * a reasoning call cut before its answer, whose hidden thinking its provider never counted.
228
235
  */
229
236
  usage(options?: {
230
237
  kind?: 'text' | 'embedding' | 'image';
@@ -235,6 +242,16 @@ export interface AI {
235
242
  usage: Usage[];
236
243
  nextCursor?: string;
237
244
  }>;
245
+ /**
246
+ * The month's spend on Palbase's models (the platform's provider keys) at what it is billed, the free dollar a
247
+ * month brings and what is left of it (a Free project's), the monthly budget, and whether they serve the project
248
+ * now (platform_keys) — when not, why: its budget is spent (budget) or its free dollar is, with no balance to pay
249
+ * (payment). A call to them is then refused (402 ai_budget_reached, ai_payment_required) unless the project
250
+ * connected its own key for the model's provider (connectProvider), which its provider bills.
251
+ */
252
+ spend(options?: {
253
+ signal?: AbortSignal;
254
+ }): Promise<Spend>;
238
255
  /** Calls go out with the project's own provider key from now on. */
239
256
  connectProvider(provider: string, key: string): Promise<{
240
257
  name: string;
@@ -31,6 +31,14 @@ export interface AISettings {
31
31
  historyLimitBytes: number | null;
32
32
  /** How much it keeps now. */
33
33
  historyBytes: number;
34
+ /**
35
+ * The most the project spends a month on Palbase's models (the platform's provider keys), in US dollars at what it
36
+ * is billed; past it a call they would serve is refused (402 ai_budget_reached) until the month turns (UTC) or the
37
+ * budget is raised. null: none. Set by an owner or an admin of the organization, in Studio (AI › Settings) or with
38
+ * the CLI (palbase ai:settings:set --monthly-budget): what spends the money does not raise its own limit. The
39
+ * project's own provider keys are not counted: their provider bills them. ai.spend() says what is spent.
40
+ */
41
+ monthlyBudgetUsd: number | null;
34
42
  }
35
43
  export interface EndpointInput {
36
44
  /** https: a tool at that address, called with a signed POST; mcp: an MCP server (streamable HTTP). */
@@ -731,8 +739,11 @@ export interface Endpoints {
731
739
  }
732
740
  export interface Settings {
733
741
  get(): Promise<AISettings>;
734
- /** A field left out is left as it is; the history kept may be lowered, not raised past the plan's. */
735
- /** A field left out is left as it is; historyLimitBytes null clears the project's own limit (the plan's is kept). */
742
+ /**
743
+ * A field left out is left as it is; the history kept may be lowered, not raised past the plan's, and
744
+ * historyLimitBytes null clears the project's own limit (the plan's is kept). The monthly budget is not set here:
745
+ * the platform refuses a key's request naming it (403) — an owner or an admin sets it in Studio or with the CLI.
746
+ */
736
747
  put(change: {
737
748
  clients?: boolean;
738
749
  userMessagesPerMinute?: number;
@@ -1,5 +1,5 @@
1
1
  export { createAI, AIResponseError } from './ai.js';
2
- export type { AI, AIOptions, AgentGenerate, Ask, AskImage, AskTool, ChatModel, DeepPartial, Embed, Generate, ImageRequest, Images, Job, Message, Model, Models, ObjectStream, Picture, Response, Schema, TextStream, Uploader, Usage, } from './ai.js';
2
+ export type { AI, AIOptions, AgentGenerate, Ask, AskImage, AskTool, ChatModel, DeepPartial, Embed, Generate, ImageRequest, Images, Job, Message, Model, Models, ObjectStream, Picture, Response, Schema, Spend, TextStream, Uploader, Usage, } from './ai.js';
3
3
  export { AISchemaError, prepare } from './schema.js';
4
4
  export { ToolError } from './tools.js';
5
5
  export type { Infer, StandardSchema } from './schema.js';
@@ -28,6 +28,14 @@ export type StandardResult<Output> = {
28
28
  export interface AuthConfig {
29
29
  required: boolean;
30
30
  verifiedEmail?: boolean;
31
+ /**
32
+ * How the user signed in, at least: 'aal2' — with a second factor (a passkey
33
+ * that verifies its user, an authenticator code, a step-up). A token below it
34
+ * is refused with 401 insufficient_user_authentication and WWW-Authenticate's
35
+ * acr_values (RFC 9470): the app steps the user up and calls again. Implies
36
+ * a signed-in user.
37
+ */
38
+ aal?: 'aal1' | 'aal2' | 'aal3';
31
39
  /**
32
40
  * Palbase checks no role or permission: a route naming one is refused at
33
41
  * boot, so none runs believing it was checked — check the role in the service.
@@ -43,11 +51,23 @@ export interface RateLimitConfig {
43
51
  }
44
52
  export interface ControllerOptions {
45
53
  auth?: AuthSpec;
54
+ /** Every route of the controller asks for device attestation (RouteOptions.attest), unless a route says false. */
55
+ attest?: boolean;
46
56
  }
47
57
  export interface RouteOptions {
48
58
  auth?: AuthSpec;
49
59
  /** A limit for this route; false for none. */
50
60
  rateLimit?: RateLimitConfig | false;
61
+ /**
62
+ * Only the app's own build on a genuine device calls this route: App Attest
63
+ * on iOS, a Keystore key attested by Google on Android — Palbase's iOS and
64
+ * Android SDKs attach the proof by themselves. Whether it is asked is the
65
+ * environment's switch (Studio's Device trust, app_attest_mode): off,
66
+ * monitor (verified and counted, nobody refused) or enforce (a call without
67
+ * a proof that verifies is refused: 401 app_attest_required). A browser
68
+ * cannot attest: under enforce, a web app's calls to the route are refused.
69
+ */
70
+ attest?: boolean;
51
71
  }
52
72
  export type ParamKind = 'body' | 'query' | 'param' | 'user' | 'optionalUser' | 'headers' | 'req' | 'requestId' | 'client' | 'resolve' | 'uploadedObject';
53
73
  export interface ParamMeta {
@@ -14,6 +14,15 @@ export interface UserT {
14
14
  sessionId: string | null;
15
15
  /** A test user of the project (made with its secret key; the token says test: true). */
16
16
  test: boolean;
17
+ /**
18
+ * How the user signed in, as the token says (acr): 'aal1' a first factor alone, 'aal2' with a second one (a passkey that
19
+ * verified its user, an authenticator code, a step-up) — null where no token says it (a platform's call naming the user).
20
+ */
21
+ acr: 'aal1' | 'aal2' | 'aal3' | null;
22
+ /** The methods the sign-in used (amr: pwd, otp, hwk, …), as the token says; empty where none says it. */
23
+ amr: string[];
24
+ /** When the user signed in, in Unix seconds (auth_time) — a step-up moves it; null where no token says it. */
25
+ authTime: number | null;
17
26
  }
18
27
  export interface ClientInfo {
19
28
  sdkVersion: string | null;
@@ -9,9 +9,12 @@ export interface RouteFacts {
9
9
  auth: {
10
10
  required: boolean;
11
11
  verifiedEmail: boolean;
12
+ aal: 'aal1' | 'aal2' | 'aal3';
12
13
  };
13
14
  /** The limit the route spends, or false when it has none. */
14
15
  limit: RateLimitConfig | false;
16
+ /** The route asks for the device's attestation (when the environment's switch is on). */
17
+ attest: boolean;
15
18
  }
16
19
  export interface ContractOptions {
17
20
  /** The app's database runs each request as its caller's identity (or keeps its claims). */
@@ -11,6 +11,8 @@ export interface Route {
11
11
  params: ParamMeta[];
12
12
  meta: RouteMeta;
13
13
  controllerAuth: AuthSpec | undefined;
14
+ /** The controller's attest: true, which a route's own option overrides. */
15
+ controllerAttest: boolean | undefined;
14
16
  }
15
17
  export declare function routeTable(controllers: Function[]): Route[];
16
18
  export type Match = {
@@ -1775,6 +1775,10 @@ export type Settings = {
1775
1775
  * How much chat history the project keeps; a message past it is refused (history_full) until chats are deleted. A free project keeps 500 MiB at most; null: no fixed limit — a project with paid rights keeps all of it, paid by use, unless it says a limit of its own.
1776
1776
  */
1777
1777
  history_limit_bytes: number | null;
1778
+ /**
1779
+ * The most the project spends a month on Palbase's models (the platform's provider keys), in US dollars at what it is billed; past it a call they would serve is refused (402 ai_budget_reached) until the month turns (UTC) or the budget is raised, and the organization's owners are emailed once. null: none. The project's own provider keys are not counted: their provider bills them.
1780
+ */
1781
+ monthly_budget_usd: number | null;
1778
1782
  /**
1779
1783
  * How many messages one user sends a minute (default 20).
1780
1784
  */
@@ -1792,11 +1796,60 @@ export type SettingsRequest = {
1792
1796
  * A limit of the project's own: a free project at most the plan's 500 MiB (it may keep less, not more), a project with paid rights at most 1 TiB. null clears it: the plan's is kept (free: 500 MiB; with paid rights: none).
1793
1797
  */
1794
1798
  history_limit_bytes?: number | null;
1799
+ /**
1800
+ * A monthly budget for Palbase's models, in US dollars (cents at most): 0.01 to 1000000. null takes it away. Set by an owner or an admin of the project's organization, in Studio or with the CLI; a key's or a token's request naming it is refused (403): what spends the money does not raise its own limit.
1801
+ */
1802
+ monthly_budget_usd?: number | null;
1795
1803
  /**
1796
1804
  * 1 to 600.
1797
1805
  */
1798
1806
  user_messages_per_minute?: number;
1799
1807
  };
1808
+ /**
1809
+ * What the project's use of Palbase's models (the platform's provider keys) has cost this month, and what it may still spend. A month brings a dollar of it free: a Free project's own, a paying account's once for all its projects. Past it a Free project uses its own provider keys; a Pay as you go one pays from its balance, at the provider's price and 10%.
1810
+ */
1811
+ export type Spend = {
1812
+ /**
1813
+ * What is left of a Free project's free dollar this month; null on a paying one (its account's free dollar is its bill's).
1814
+ */
1815
+ free_left_usd: number | null;
1816
+ /**
1817
+ * Whose the free dollar is: the project's own (project) or its account's, all its projects together (account).
1818
+ */
1819
+ free_scope: "project" | "account";
1820
+ /**
1821
+ * The month's free use of Palbase's models, in US dollars.
1822
+ */
1823
+ free_usd: number;
1824
+ /**
1825
+ * The month (UTC, YYYY-MM).
1826
+ */
1827
+ month: string;
1828
+ /**
1829
+ * The budget the project's owners set (null: none).
1830
+ */
1831
+ monthly_budget_usd: number | null;
1832
+ /**
1833
+ * free (no paid rights: its free dollar, then its own keys), pay_as_you_go (its account's balance pays past the free dollar) or exempt (measured, not charged).
1834
+ */
1835
+ plan: "free" | "pay_as_you_go" | "exempt";
1836
+ /**
1837
+ * Whether Palbase's models serve the project now. When not, a call to them is refused (402) unless the project connected its own key for the model's provider.
1838
+ */
1839
+ platform_keys: boolean;
1840
+ /**
1841
+ * Why Palbase's models serve it no more this month: budget (its monthly budget is spent) or payment (its free dollar is spent and it has no payment account with a balance).
1842
+ */
1843
+ reason?: "budget" | "payment";
1844
+ /**
1845
+ * The day the month's free dollar and budget start again (UTC, YYYY-MM-DD).
1846
+ */
1847
+ resets_on: string;
1848
+ /**
1849
+ * The month's use of Palbase's models, in US dollars at what it is billed (the provider's price and 10%), before the free dollar is taken off.
1850
+ */
1851
+ spent_usd: number;
1852
+ };
1800
1853
  /**
1801
1854
  * The turn a stop stopped.
1802
1855
  */
@@ -2199,6 +2252,10 @@ export type Use = {
2199
2252
  * When.
2200
2253
  */
2201
2254
  created_at: string;
2255
+ /**
2256
+ * Its tokens are in part an estimate: a reasoning call cut before its answer, whose provider never said what its hidden thinking came to, billed as the time the model thought at its measured speed, rounded down.
2257
+ */
2258
+ estimated: boolean;
2202
2259
  /**
2203
2260
  * The use's id.
2204
2261
  */
@@ -2388,7 +2445,7 @@ export type VoiceSession = {
2388
2445
  */
2389
2446
  chat_id: string;
2390
2447
  /**
2391
- * Why it ended: close_requested, member_removed, chat_deleted, replaced (its member started another), lost (the engine no longer holds it), or the provider's word.
2448
+ * Why it ended: close_requested, member_removed, chat_deleted, replaced (its member started another), lost (the engine no longer holds it), ai_limit_reached (its project's free AI, monthly AI budget or what its account can pay is spent, and it ran on Palbase's models), or the provider's word.
2392
2449
  */
2393
2450
  close_reason?: string;
2394
2451
  /**
@@ -3302,12 +3359,20 @@ export declare function client(t: Transport): {
3302
3359
  /**
3303
3360
  * Change what the project allows its chats
3304
3361
  *
3305
- * A field left out is left as it is. The history kept may be lowered, not raised past the plan's.
3362
+ * A field left out is left as it is. The history kept may be lowered, not raised past the plan's. A monthly budget is kept by Palbase's billing: on a stack that bills no AI it is refused (409 no_billing).
3306
3363
  */
3307
3364
  putSettings(input: {
3308
3365
  body: SettingsRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
3309
3366
  signal?: AbortSignal;
3310
3367
  }): Promise<Reply<200, Settings>>;
3368
+ /**
3369
+ * What the project's AI on Palbase's models costs this month
3370
+ *
3371
+ * The month's spend on Palbase's models at what it is billed, the free dollar a month brings and what is left of it, the monthly budget, and whether Palbase's models serve the project now — and if not, why.
3372
+ */
3373
+ getSpend(input?: {
3374
+ signal?: AbortSignal;
3375
+ }): Promise<Reply<200, Spend>>;
3311
3376
  /**
3312
3377
  * The tools an agent may be given
3313
3378
  *
@@ -298,9 +298,9 @@ export type CaptureRequest = {
298
298
  */
299
299
  app_version?: string;
300
300
  /**
301
- * Who did it (256 characters at most). With a user's token, the user's id instead.
301
+ * Who did it (256 characters at most). With a user's token, the user's id instead; with user_id, the user's id. Required unless user_id names the user.
302
302
  */
303
- distinct_id: string;
303
+ distinct_id?: string;
304
304
  /**
305
305
  * The event's name: a letter or $, then letters, digits and _.:-$; 64 at most.
306
306
  */
@@ -323,6 +323,10 @@ export type CaptureRequest = {
323
323
  * Unix milliseconds on the device's clock.
324
324
  */
325
325
  timestamp?: number;
326
+ /**
327
+ * The user whose event it is: the project's server alone names one (its secret key) — their own event, as their app sends it signed in, on their timeline and acted on by their journeys. An app's event is its signed-in user's; one that names user_id is refused (invalid_user_id).
328
+ */
329
+ user_id?: string;
326
330
  };
327
331
  /**
328
332
  * Every event a project's timelines can hold: the platform modules', and those its apps and backend sent in the window.
@@ -790,7 +790,7 @@ export type AssetLinkTarget = {
790
790
  */
791
791
  export type AssetLinks = AssetLinkStatement[];
792
792
  /**
793
- * One request's App Attest evidence and the request it claims to be bound to.
793
+ * One request's device attestation evidence (App Attest on iOS, a Keystore signature on Android) and the request it claims to be bound to.
794
794
  */
795
795
  export type AttestAssertionCheck = {
796
796
  /**
@@ -812,11 +812,11 @@ export type AttestAssertionCheck = {
812
812
  */
813
813
  path?: string;
814
814
  /**
815
- * authenticatorData (37 bytes) followed by clientDataHash (32 bytes), base64.
815
+ * iOS: authenticatorData (37 bytes) followed by clientDataHash (32 bytes). Android: 0x01, the device's counter (8 bytes, big-endian) and clientDataHash (32 bytes). Base64.
816
816
  */
817
817
  payload?: string;
818
818
  /**
819
- * DER-encoded ECDSA signature, base64.
819
+ * DER-encoded ECDSA signature, base64: App Attest's on iOS; on Android, ECDSA-SHA256 over the payload by the enrolled key.
820
820
  */
821
821
  signature?: string;
822
822
  };
@@ -846,9 +846,17 @@ export type AttestObservationBatch = {
846
846
  incapable?: number;
847
847
  no_sdk?: number;
848
848
  unknown?: number;
849
+ /**
850
+ * Requests with evidence that verified: they pass under enforce.
851
+ */
852
+ verified?: number;
853
+ /**
854
+ * Requests with evidence that would be refused under enforce.
855
+ */
856
+ refused?: number;
849
857
  };
850
858
  /**
851
- * What the customer runtime saw in the window, by device capability, and the mode in force.
859
+ * What the customer runtime saw in the window: callers by device capability, what the evidence it verified came to, and the mode in force.
852
860
  */
853
861
  export type AttestObservationSummary = {
854
862
  capable: number;
@@ -856,6 +864,14 @@ export type AttestObservationSummary = {
856
864
  mode: "off" | "monitor" | "enforce";
857
865
  no_sdk: number;
858
866
  unknown: number;
867
+ /**
868
+ * Requests with evidence that verified: they pass under enforce.
869
+ */
870
+ verified: number;
871
+ /**
872
+ * Requests with evidence that would be refused under enforce.
873
+ */
874
+ refused: number;
859
875
  };
860
876
  export type AttestPolicy = {
861
877
  mode: "off" | "monitor" | "enforce";
@@ -1454,18 +1470,18 @@ export type Device = {
1454
1470
  trusted: boolean;
1455
1471
  };
1456
1472
  /**
1457
- * A Play Integrity verdict to enrol an Android device with.
1473
+ * An Android Keystore key's attestation to verify.
1458
1474
  */
1459
1475
  export type DeviceAttestAndroidRequest = {
1460
- device_name?: string;
1461
1476
  /**
1462
- * The app's package name, whose Play Console project issued the token.
1477
+ * The key's attestation certificate chain from `KeyStore.getCertificateChain`, leaf first, each certificate DER in base64.
1463
1478
  */
1464
- package_name: string;
1479
+ certificate_chain: string[];
1465
1480
  /**
1466
- * The Play Integrity token.
1481
+ * The challenge from `POST /auth/devices/challenge`, base64, exactly as received.
1467
1482
  */
1468
- verdict_token: string;
1483
+ challenge: string;
1484
+ device_name?: string;
1469
1485
  };
1470
1486
  /**
1471
1487
  * An App Attest attestation to verify.
@@ -4625,11 +4641,14 @@ export declare function client(t: Transport): {
4625
4641
  signal?: AbortSignal;
4626
4642
  }): Promise<Reply<200, DeviceList>>;
4627
4643
  /**
4628
- * Enrol an Android device with Play Integrity
4644
+ * Enrol an Android device with Key Attestation
4629
4645
  *
4630
- * Decodes a Play Integrity verdict token for the named package and, when the verdict passes, stores the device as verified under the signed-in user. A verdict that fails is refused with 403 and its reason (`emulator_detected`, `device_integrity_failed`) and stores nothing. A token this project cannot decode answers 400 `invalid_verdict_token`. 409 `play_integrity_not_configured`: this project has no Play Integrity integration. 503 `integrity_service_unavailable`: Google could not be reached; retry after `Retry-After`. The device has no key yet: bind the app's key with `POST /auth/devices/bind`.
4646
+ * Verifies an Android Keystore key's attestation and stores the key as a verified device, so the device can sign its requests to a backend route that requires attestation. The app generates an EC P-256 signing key in the Android Keystore with the challenge from `POST /auth/devices/challenge` as its attestation challenge and sends the key's certificate chain. The chain must end in one of Google's hardware attestation roots with no certificate on Google's revocation list; the key must be in the TEE or StrongBox and generated there; the device must be locked with a verified boot; and the attesting app's package and signing certificate must be those of an Android app registered with this environment. No session is required: with a valid user token the device is enrolled under that user, otherwise under the installation anchor in `X-Palbase-Installation-Anchor` (the anchor the challenge was issued for). A caller with neither is refused with 401. The challenge is spent by this call. 400: the request cannot be evaluated (`missing_fields`, `invalid_certificate_chain`, `invalid_challenge` — not issued for this anchor or already spent, `invalid_installation_anchor`). 403: the chain was evaluated and refused, the reason being the code (`untrusted_root`, `software_key` — an emulator or a software keystore, `device_not_locked`, `unverified_boot`, `package_mismatch`, `signature_mismatch`, `certificate_revoked`, `certificate_expired`, `challenge_mismatch`, `key_not_generated`, `invalid_key`). 409 `android_app_not_configured`: no Android app is registered with this environment. 503: the challenge store (`challenge_unavailable`) or Google's revocation list (`revocation_list_unavailable`) cannot be reached; retry after `Retry-After`. Rate limited per IP address.
4631
4647
  */
4632
4648
  attestAndroidDevice(input: {
4649
+ headers?: {
4650
+ "X-Palbase-Installation-Anchor"?: string;
4651
+ };
4633
4652
  body: DeviceAttestAndroidRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
4634
4653
  signal?: AbortSignal;
4635
4654
  }): Promise<Reply<200, Device>>;
@@ -4648,7 +4667,7 @@ export declare function client(t: Transport): {
4648
4667
  /**
4649
4668
  * Bind a public key to a device
4650
4669
  *
4651
- * Stores the signing key of one of the signed-in user's devices — once. The device must be `verified` and have no key yet: an Android device after `POST /auth/devices/attest/android`, whose Play Integrity verdict certifies no key. A device that already has a key (every App Attest device: attestation establishes its key) answers 409 `device_key_bound`; to use a new key, enrol a new device and delete the old one. A device that is not verified answers 400 `device_not_verified`. `public_key` must be a DER SubjectPublicKeyInfo holding an ECDSA key, or the call answers 400 `invalid_public_key`.
4670
+ * Stores the signing key of one of the signed-in user's devices — once. The device must be `verified` and have no key yet. A device that already has a key — every device enrolled with App Attest or Android Key Attestation: enrolment establishes its key — answers 409 `device_key_bound`; to use a new key, enrol a new device and delete the old one. A device that is not verified answers 400 `device_not_verified`. `public_key` must be a DER SubjectPublicKeyInfo holding an ECDSA key, or the call answers 400 `invalid_public_key`.
4652
4671
  */
4653
4672
  bindDeviceKey(input: {
4654
4673
  body: DeviceBindRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
@@ -4657,7 +4676,7 @@ export declare function client(t: Transport): {
4657
4676
  /**
4658
4677
  * Get a single-use enrolment challenge
4659
4678
  *
4660
- * Issues a single-use challenge, valid for 5 minutes, that the device embeds in its App Attest attestation and sends back to `POST /auth/devices/attest/ios`. No session is required. When a valid user token is sent, the challenge is scoped to that user; otherwise it is scoped to the installation anchor in `X-Palbase-Installation-Anchor`. A caller with neither gets a freshly minted anchor in `installation_anchor` and must send it back in `X-Palbase-Installation-Anchor` on the attest call. An anchor header that is not an issued `ins_…` anchor answers 400 `invalid_installation_anchor`. Rate limited per IP address. Takes no request body.
4679
+ * Issues a single-use challenge, valid for 5 minutes, that the device embeds in its attestation — App Attest's, or an Android Keystore key's — and sends back to `POST /auth/devices/attest/ios` or `POST /auth/devices/attest/android`. No session is required. When a valid user token is sent, the challenge is scoped to that user; otherwise it is scoped to the installation anchor in `X-Palbase-Installation-Anchor`. A caller with neither gets a freshly minted anchor in `installation_anchor` and must send it back in `X-Palbase-Installation-Anchor` on the attest call. An anchor header that is not an issued `ins_…` anchor answers 400 `invalid_installation_anchor`. Rate limited per IP address. Takes no request body.
4661
4680
  */
4662
4681
  createDeviceChallenge(input?: {
4663
4682
  headers?: {