palbase 0.18.0 → 0.18.2

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 (55) 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 +11 -11
  5. package/dist/backend/stack.js +1 -1
  6. package/dist/backend/test.js +2 -2
  7. package/dist/chunks/{BW5DFI3C.js → 2MCXKESR.js} +1 -1
  8. package/dist/chunks/{6IMY2J5W.js → 34GIR5XI.js} +1 -1
  9. package/dist/chunks/6O7HI5DJ.js +2 -0
  10. package/dist/chunks/{7QFBZLAK.js → BZD6DTRS.js} +1 -1
  11. package/dist/chunks/{KRQZOF2L.js → DTILUE3A.js} +2 -2
  12. package/dist/chunks/{FT7G3QQ4.js → FWE2RQ74.js} +2 -2
  13. package/dist/chunks/{XF3JEDIQ.js → FYEDISVZ.js} +1 -1
  14. package/dist/chunks/{4S4ODZVM.js → J3GVOUKS.js} +2 -2
  15. package/dist/chunks/{OC32TP3L.js → J3SSWIXW.js} +2 -2
  16. package/dist/chunks/{BKGX3AZA.js → JK6Y5742.js} +2 -2
  17. package/dist/chunks/{XHNZDLR4.js → JWBOJ4DZ.js} +2 -2
  18. package/dist/chunks/{PMQOJ7FF.js → KPB7BB3F.js} +2 -2
  19. package/dist/chunks/N7TLZR3V.js +22 -0
  20. package/dist/chunks/{4HFD24QY.js → NWFZYTV4.js} +1 -1
  21. package/dist/chunks/{VQXYHAU4.js → PPIZUQG5.js} +2 -2
  22. package/dist/chunks/{ART5HP5M.js → PQU3TAPP.js} +2 -2
  23. package/dist/chunks/{7R4WTDHI.js → QEBQ452U.js} +1 -1
  24. package/dist/chunks/{3GWBIPGH.js → RFF725G4.js} +2 -2
  25. package/dist/chunks/{CAZYHE64.js → TAFRNPVE.js} +2 -2
  26. package/dist/chunks/{PPK2UEAY.js → TNSIU2CJ.js} +2 -2
  27. package/dist/chunks/{T2O6XEQO.js → X6FNTEXY.js} +1 -1
  28. package/dist/chunks/{JKA2W4E5.js → XQANDC54.js} +2 -2
  29. package/dist/chunks/ZFJ7245R.js +21 -0
  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/backend/src/attest.d.ts +59 -0
  45. package/types/backend/src/decorators.d.ts +10 -1
  46. package/types/backend/src/index.d.ts +1 -1
  47. package/types/internal/src/modules/auth.d.ts +8 -0
  48. package/types/internal/src/modules/events.d.ts +2 -2
  49. package/types/internal/src/modules/purchases.d.ts +197 -2
  50. package/types/internal/src/modules/stores.d.ts +166 -0
  51. package/types/web/src/auth.d.ts +11 -1
  52. package/types/web/src/purchases.d.ts +11 -0
  53. package/dist/chunks/32XY6IBN.js +0 -21
  54. package/dist/chunks/EVBWED24.js +0 -22
  55. package/dist/chunks/ZXV3ZKVM.js +0 -2
package/dist/refuse/ai.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.2 — 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.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.2 — 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.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.2 — 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.18.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/ART5HP5M.js";import{a as c,b as d}from"../chunks/4HFD24QY.js";import"../chunks/7R4WTDHI.js";import"../chunks/7QFBZLAK.js";import{n as b}from"../chunks/ZXV3ZKVM.js";import"../chunks/FT7G3QQ4.js";import{b as a}from"../chunks/VQXYHAU4.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.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.18.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/PQU3TAPP.js";import{a as c,b as d}from"../chunks/NWFZYTV4.js";import"../chunks/QEBQ452U.js";import"../chunks/BZD6DTRS.js";import{n as b}from"../chunks/6O7HI5DJ.js";import"../chunks/FWE2RQ74.js";import{b as a}from"../chunks/PPIZUQG5.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.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.18.0 — Palbase SDK License (see LICENSE) */
2
- import{a,b,c,d,e}from"../chunks/BKGX3AZA.js";import"../chunks/4HFD24QY.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.js";export{b as TestApiError,e as api,c as createTestApi,a as testFields,d as testRun};
1
+ /*! palbase 0.18.2 — Palbase SDK License (see LICENSE) */
2
+ import{a,b,c,d,e}from"../chunks/JK6Y5742.js";import"../chunks/NWFZYTV4.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.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.18.0 — Palbase SDK License (see LICENSE) */
2
- import{a as L,b as j,c as q,d as G,e as D,f as N,g as U,h as F,i as B,j as H,k as J,l as K,m as W,n as X,o as Y,p as Z,q as ee,r as te,s as ne,t as re,u as oe,v as se,w as ae}from"../chunks/EVBWED24.js";import{a as _,b as Q,f as z}from"../chunks/OC32TP3L.js";import"../chunks/CAZYHE64.js";import"../chunks/PPK2UEAY.js";import"../chunks/XF3JEDIQ.js";import{b as E,c as T,d as O,f as x,g as A,j as R,k as V,l as $,m as S,o as v}from"../chunks/7R4WTDHI.js";import"../chunks/XHNZDLR4.js";import"../chunks/ZXV3ZKVM.js";import"../chunks/FT7G3QQ4.js";import{b as I}from"../chunks/VQXYHAU4.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.js";var ie="oai-events";async function ce(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??ye(),t=e.signal;t?.throwIfAborted();let f=e.audio??fe(),u=e.microphone===void 0,c=e.microphone??await r.getUserMedia({audio:!0});if(t?.aborted){if(u)for(let n of c.getTracks())n.stop();throw t.reason}let o=new r.RTCPeerConnection,s=!1,l=()=>{if(!s){if(s=!0,m.close(),o.close(),u)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(ie);m.addEventListener("message",n=>{let p=pe(n.data);p!==void 0&&e.onError?.(p)});let d=()=>l();t?.addEventListener("abort",d,{once:!0});try{await o.setLocalDescription(await o.createOffer()),t?.throwIfAborted(),await de(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:l}}catch(n){throw t?.removeEventListener("abort",d),l(),t?.aborted?t.reason:n}}function de(e,r,t){return e.iceGatheringState==="complete"?Promise.resolve():t?.aborted?Promise.reject(t.reason):new Promise((f,u)=>{let c=()=>{clearTimeout(l),e.removeEventListener("icegatheringstatechange",o),t?.removeEventListener("abort",s)},o=()=>{e.iceGatheringState==="complete"&&(c(),f())},s=()=>{c(),u(t?.reason)},l=setTimeout(()=>{c(),u(new Error(`connectVoice: the network candidates were not gathered in ${r} ms`))},r);e.addEventListener("icegatheringstatechange",o),t?.addEventListener("abort",s,{once:!0})})}function pe(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 ye(){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 fe(){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 le(e,r,t){let f=i(i(i(e)?.components)?.schemas)??{},u=(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 M of k)h(M,g,y)}let P=i(a.properties);if(P)for(let[b,k]of Object.entries(P))h(k,`${g}/${S(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(...u(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=u(n.schema,`/query/${S(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)??{},l=Object.keys(s).filter(d=>/^2\d\d$/.test(d)).sort((d,n)=>d==="200"?-1:n==="200"?1:d.localeCompare(n)),m=l.length>0?u(c(i(s[l[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 ue(e){let r=`${e.method.toUpperCase()} ${e.path}`,t=i(i(i(i(e.contract)?.paths)?.[e.path])?.[e.method.toLowerCase()]),f=t?le(e.contract,t,r):void 0;if(!f)return{body:e.body,query:e.query,open:async s=>s};let{key:u,header:c}=await A(e.key.kid,O(e.key.publicKey),x(e.projectId,e.method,e.path,e.params??[])),o=(s,l)=>s==null?s:v(s,l,f.request,(m,d)=>R(u,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):v(s,"/response",f.response,async(l,m)=>{if(!V(m))throw new T("unopenable",`${r}: ${l} came plain where the contract says it is encrypted`);return $(u,l,m)})}}export{U as Analytics,_ as BackendError,G as Channel,F as Consent,ne as ConversationList,re as ConversationView,Z as Flags,z as GatewayError,J as InApp,B as Inbox,N as Installation,te as Messaging,W as Notify,I as PalbaseError,X as Purchases,D as RealtimeSocket,H as SESSION_START,se as ScheduledList,L as SessionChangedError,oe as ThreadView,K as WebPush,ce as connectVoice,ae as createClient,ue as encryptedCall,ee as indexedDBKeyValue,Q as isBackendError,q as localStore,j as memoryStore,Y as redemptionToken};
1
+ /*! palbase 0.18.2 — Palbase SDK License (see LICENSE) */
2
+ import{a as L,b as j,c as q,d as G,e as D,f as N,g as U,h as F,i as B,j as H,k as J,l as K,m as W,n as X,o as Y,p as Z,q as ee,r as te,s as ne,t as re,u as oe,v as se,w as ae}from"../chunks/N7TLZR3V.js";import{a as _,b as Q,f as z}from"../chunks/J3SSWIXW.js";import"../chunks/TAFRNPVE.js";import"../chunks/TNSIU2CJ.js";import"../chunks/FYEDISVZ.js";import{b as E,c as T,d as O,f as x,g as A,j as R,k as V,l as $,m as S,o as v}from"../chunks/QEBQ452U.js";import"../chunks/JWBOJ4DZ.js";import"../chunks/6O7HI5DJ.js";import"../chunks/FWE2RQ74.js";import{b as I}from"../chunks/PPIZUQG5.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.js";var ie="oai-events";async function ce(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??ye(),t=e.signal;t?.throwIfAborted();let f=e.audio??fe(),u=e.microphone===void 0,c=e.microphone??await r.getUserMedia({audio:!0});if(t?.aborted){if(u)for(let n of c.getTracks())n.stop();throw t.reason}let o=new r.RTCPeerConnection,s=!1,l=()=>{if(!s){if(s=!0,m.close(),o.close(),u)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(ie);m.addEventListener("message",n=>{let p=pe(n.data);p!==void 0&&e.onError?.(p)});let d=()=>l();t?.addEventListener("abort",d,{once:!0});try{await o.setLocalDescription(await o.createOffer()),t?.throwIfAborted(),await de(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:l}}catch(n){throw t?.removeEventListener("abort",d),l(),t?.aborted?t.reason:n}}function de(e,r,t){return e.iceGatheringState==="complete"?Promise.resolve():t?.aborted?Promise.reject(t.reason):new Promise((f,u)=>{let c=()=>{clearTimeout(l),e.removeEventListener("icegatheringstatechange",o),t?.removeEventListener("abort",s)},o=()=>{e.iceGatheringState==="complete"&&(c(),f())},s=()=>{c(),u(t?.reason)},l=setTimeout(()=>{c(),u(new Error(`connectVoice: the network candidates were not gathered in ${r} ms`))},r);e.addEventListener("icegatheringstatechange",o),t?.addEventListener("abort",s,{once:!0})})}function pe(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 ye(){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 fe(){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 le(e,r,t){let f=i(i(i(e)?.components)?.schemas)??{},u=(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 M of k)h(M,g,y)}let P=i(a.properties);if(P)for(let[b,k]of Object.entries(P))h(k,`${g}/${S(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(...u(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=u(n.schema,`/query/${S(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)??{},l=Object.keys(s).filter(d=>/^2\d\d$/.test(d)).sort((d,n)=>d==="200"?-1:n==="200"?1:d.localeCompare(n)),m=l.length>0?u(c(i(s[l[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 ue(e){let r=`${e.method.toUpperCase()} ${e.path}`,t=i(i(i(i(e.contract)?.paths)?.[e.path])?.[e.method.toLowerCase()]),f=t?le(e.contract,t,r):void 0;if(!f)return{body:e.body,query:e.query,open:async s=>s};let{key:u,header:c}=await A(e.key.kid,O(e.key.publicKey),x(e.projectId,e.method,e.path,e.params??[])),o=(s,l)=>s==null?s:v(s,l,f.request,(m,d)=>R(u,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):v(s,"/response",f.response,async(l,m)=>{if(!V(m))throw new T("unopenable",`${r}: ${l} came plain where the contract says it is encrypted`);return $(u,l,m)})}}export{U as Analytics,_ as BackendError,G as Channel,F as Consent,ne as ConversationList,re as ConversationView,Z as Flags,z as GatewayError,J as InApp,B as Inbox,N as Installation,te as Messaging,W as Notify,I as PalbaseError,X as Purchases,D as RealtimeSocket,H as SESSION_START,se as ScheduledList,L as SessionChangedError,oe as ThreadView,K as WebPush,ce as connectVoice,ae as createClient,ue as encryptedCall,ee as indexedDBKeyValue,Q as isBackendError,q as localStore,j as memoryStore,Y as redemptionToken};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.0 — Palbase SDK License (see LICENSE) */
2
- import{a as i}from"../chunks/PPK2UEAY.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/XF3JEDIQ.js";import"../chunks/T2O6XEQO.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.18.2 — Palbase SDK License (see LICENSE) */
2
+ import{a as i}from"../chunks/TNSIU2CJ.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/FYEDISVZ.js";import"../chunks/X6FNTEXY.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.18.0 — Palbase SDK License (see LICENSE) */
2
- import{c as e,d as r,i as t}from"../chunks/OC32TP3L.js";import"../chunks/7R4WTDHI.js";import"../chunks/XHNZDLR4.js";import"../chunks/FT7G3QQ4.js";import"../chunks/VQXYHAU4.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.js";export{e as RESERVED_CLIENT_NAMES,t as __registerBackend,r as isClientName};
1
+ /*! palbase 0.18.2 — Palbase SDK License (see LICENSE) */
2
+ import{c as e,d as r,i as t}from"../chunks/J3SSWIXW.js";import"../chunks/QEBQ452U.js";import"../chunks/JWBOJ4DZ.js";import"../chunks/FWE2RQ74.js";import"../chunks/PPIZUQG5.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.js";export{e as RESERVED_CLIENT_NAMES,t as __registerBackend,r as isClientName};
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.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/CAZYHE64.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/XF3JEDIQ.js";import"../chunks/VQXYHAU4.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.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.18.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/TAFRNPVE.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/FYEDISVZ.js";import"../chunks/PPIZUQG5.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.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.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.2 — Palbase SDK License (see LICENSE) */
2
2
  "use strict";(()=>{function g(n,s){if(n)try{let i=new URL(n,s);if(i.protocol==="https:"||i.protocol==="http:"&&(i.hostname==="localhost"||i.hostname==="127.0.0.1"))return i.href}catch{}}function p(n){let s=new URL(n.location.href).searchParams,i=s.get("url")??"",u=s.get("key")??"",a=(t,e)=>!t||!i?Promise.resolve():n.fetch(`${i.replace(/\/$/,"")}/notify/receipts`,{method:"POST",headers:{"content-type":"application/json",apikey:u},body:JSON.stringify({receipts:[{receipt:t,status:e}]}),keepalive:!0}).catch(()=>{}),l=async(t,e)=>{for(let o of await n.clients.matchAll({type:"window",includeUncontrolled:!0}))o.postMessage({type:"palbase.push",event:t,url:e.url,data:e.data})};n.addEventListener("push",(t=>{let e={};try{e=t.data?.json()??{}}catch{}let o={url:e.url,receipt:e.receipt,data:e.data},d=async()=>e.data?.type==="messaging.message"&&(await n.clients.matchAll({type:"window",includeUncontrolled:!0})).some(r=>r.focused===!0);t.waitUntil(d().then(r=>r?void 0:n.registration.showNotification(e.title??"",{body:e.body,image:e.image,tag:e.tag,data:o})).then(()=>Promise.all([a(e.receipt,"delivered"),l("received",o)])))})),n.addEventListener("notificationclick",(t=>{t.notification.close();let e=t.notification.data??{},o=g(e.url,n.location.origin),d=async()=>{if(!o)return;let c=(await n.clients.matchAll({type:"window",includeUncontrolled:!0})).find(f=>f.url===o);c?await c.focus():await n.clients.openWindow(o)};t.waitUntil(Promise.all([a(e.receipt,"opened"),d(),l("opened",e)]))})),n.addEventListener("notificationclose",(t=>{t.waitUntil(a(t.notification.data?.receipt,"dismissed"))}))}typeof self<"u"&&typeof self.registration=="object"&&!("document"in self)&&p(self);})();
package/dist/web/ssr.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.0 — Palbase SDK License (see LICENSE) */
2
- import{w as f}from"../chunks/EVBWED24.js";import"../chunks/OC32TP3L.js";import"../chunks/CAZYHE64.js";import"../chunks/PPK2UEAY.js";import"../chunks/XF3JEDIQ.js";import"../chunks/7R4WTDHI.js";import"../chunks/XHNZDLR4.js";import"../chunks/ZXV3ZKVM.js";import"../chunks/FT7G3QQ4.js";import"../chunks/VQXYHAU4.js";import"../chunks/6IMY2J5W.js";import"../chunks/T2O6XEQO.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.18.2 — Palbase SDK License (see LICENSE) */
2
+ import{w as f}from"../chunks/N7TLZR3V.js";import"../chunks/J3SSWIXW.js";import"../chunks/TAFRNPVE.js";import"../chunks/TNSIU2CJ.js";import"../chunks/FYEDISVZ.js";import"../chunks/QEBQ452U.js";import"../chunks/JWBOJ4DZ.js";import"../chunks/6O7HI5DJ.js";import"../chunks/FWE2RQ74.js";import"../chunks/PPIZUQG5.js";import"../chunks/34GIR5XI.js";import"../chunks/X6FNTEXY.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.18.0 — Palbase SDK License (see LICENSE) */
2
- import"../chunks/T2O6XEQO.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.18.2 — Palbase SDK License (see LICENSE) */
2
+ import"../chunks/X6FNTEXY.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.18.0",
3
+ "version": "0.18.2",
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.18.0",
138
+ "palgres": "0.18.2",
139
139
  "reflect-metadata": "^0.2.2",
140
140
  "typescript": "~6.0.3",
141
141
  "zod": "^4.6.5"
@@ -0,0 +1,59 @@
1
+ import type { PalbaseServer } from '../../server/src/index.js';
2
+ export type AttestMode = 'off' | 'monitor' | 'enforce';
3
+ export declare const ATTEST_HEADERS: {
4
+ readonly deviceId: 'x-palbase-device-id';
5
+ readonly anchor: 'x-palbase-installation-anchor';
6
+ readonly challenge: 'x-palbase-attest-challenge';
7
+ readonly payload: 'x-palbase-attest-payload';
8
+ readonly signature: 'x-palbase-attest-signature';
9
+ readonly capable: 'x-palbase-attest-capable';
10
+ readonly sdkVersion: 'x-palbase-sdk-version';
11
+ };
12
+ /** The reasons a refusal names (data.reason): the clients act on each. */
13
+ export type AttestReason = 'app_attest_required' | 'assertion_invalid' | 'assertion_stale' | 'device_unknown';
14
+ /**
15
+ * The device whose proof auth verified — what @AttestedDevice() gives a route.
16
+ * Auth names it (its id and platform), not the request's X-Palbase-Device-Id:
17
+ * that header is the client's word, and verified only when enforce refuses a
18
+ * request without evidence.
19
+ */
20
+ export type AttestedDevice = {
21
+ id: string;
22
+ platform: 'ios' | 'android';
23
+ };
24
+ export type AttestOutcome = {
25
+ pass: true;
26
+ challenge?: string;
27
+ device?: AttestedDevice;
28
+ } | {
29
+ pass: false;
30
+ reason: AttestReason;
31
+ challenge: string;
32
+ } | {
33
+ unavailable: true;
34
+ pass: false;
35
+ };
36
+ type Auth = Pick<PalbaseServer['auth'], 'adminGetAttestPolicy' | 'adminVerifyDeviceAssertion' | 'adminRecordAttestObservations'>;
37
+ export declare class AttestGate {
38
+ private readonly auth;
39
+ private readonly now;
40
+ private mode;
41
+ private readAt;
42
+ private reading;
43
+ private counts;
44
+ private timer;
45
+ private shipping;
46
+ constructor(auth: Auth, now?: () => number);
47
+ /** The mode in force: read again when 30 seconds old; the last one read while auth cannot answer. */
48
+ modeNow(): Promise<AttestMode | undefined>;
49
+ private readMode;
50
+ /** One request to a route marked attest: true. `raw` is the body's bytes as they came. */
51
+ check(request: Request, url: URL, raw: Uint8Array | undefined): Promise<AttestOutcome>;
52
+ private declared;
53
+ private outcome;
54
+ private schedule;
55
+ /** Ships the counts gathered since the last batch. A batch auth does not take is dropped: they are a forecast, not a bill. */
56
+ flush(): Promise<void>;
57
+ stop(): Promise<void>;
58
+ }
59
+ export {};
@@ -1,3 +1,4 @@
1
+ import type { AttestedDevice as AttestedDeviceOf } from './attest.js';
1
2
  import 'reflect-metadata';
2
3
  import type { EventType, PalbaseEvent } from '../../server/src/index.js';
3
4
  import type { UserT } from './engine.js';
@@ -69,7 +70,7 @@ export interface RouteOptions {
69
70
  */
70
71
  attest?: boolean;
71
72
  }
72
- export type ParamKind = 'body' | 'query' | 'param' | 'user' | 'optionalUser' | 'headers' | 'req' | 'requestId' | 'client' | 'resolve' | 'uploadedObject';
73
+ export type ParamKind = 'body' | 'query' | 'param' | 'user' | 'optionalUser' | 'headers' | 'req' | 'requestId' | 'client' | 'resolve' | 'uploadedObject' | 'attestedDevice';
73
74
  export interface ParamMeta {
74
75
  index: number;
75
76
  kind: ParamKind;
@@ -129,6 +130,14 @@ export declare const Req: () => ParameterDecorator;
129
130
  export declare const RequestId: () => ParameterDecorator;
130
131
  export declare const TraceId: () => ParameterDecorator;
131
132
  export declare const Client: () => ParameterDecorator;
133
+ /**
134
+ * The device whose proof auth verified for this call ({ id, platform }), on a
135
+ * route marked attest: true. Null unless the environment enforces App Attest:
136
+ * under off nothing is verified, under monitor nothing is refused.
137
+ */
138
+ export declare const AttestedDevice: () => ParameterDecorator;
139
+ /** What @AttestedDevice() gives: `@AttestedDevice() device: AttestedDevice | null`. */
140
+ export type AttestedDevice = AttestedDeviceOf;
132
141
  /** What a resolver is given of the request: what the route's own decorators read, before its body is. */
133
142
  export interface ResolveContext {
134
143
  /** The path's parameters, decoded: {ref} of /environments/{ref}. */
@@ -1,5 +1,5 @@
1
1
  import 'reflect-metadata';
2
- export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Cron, Injectable, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type CronMeta, type CronOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
2
+ export { AttestedDevice, Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Cron, Injectable, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type CronMeta, type CronOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
3
3
  export { Task, TaskFailure, Tasks, type EnqueueOptions, type PayloadOf, type QueuedTask, type TaskClass, type TaskMeta, type TaskOptions, type TasksService } from './tasks.js';
4
4
  export { TestUserTemplate, type TemplateMeta, type TemplateUser, type TestUserTemplateClass, type TestUserTemplateOptions } from './test-user-templates.js';
5
5
  export { Upload, UploadedObject, type UploadConfig } from './upload.js';
@@ -824,11 +824,19 @@ export type AttestAssertionCheck = {
824
824
  * The verdict on one request's evidence. Every refusal is a verdict, not an error status.
825
825
  */
826
826
  export type AttestAssertionVerdict = {
827
+ /**
828
+ * The device whose enrolled key verified this request, when ok; empty otherwise. A backend gives its route this device, not the request's X-Palbase-Device-Id header.
829
+ */
830
+ device_id: string;
827
831
  /**
828
832
  * A fresh challenge for the client's next assertion; empty when the server has no challenge secret.
829
833
  */
830
834
  next_challenge: string;
831
835
  ok: boolean;
836
+ /**
837
+ * The verified device's platform, when ok; empty otherwise.
838
+ */
839
+ platform: "" | "ios" | "android";
832
840
  /**
833
841
  * Empty when ok. app_attest_required: no evidence; device_unknown: no verified device with that id; assertion_invalid: the evidence does not verify or is bound to another request; assertion_stale: another request advanced the counter first (retry).
834
842
  */
@@ -15,11 +15,11 @@ export interface PlatformEvents extends AiEvents, AnalyticsEvents, AuthEvents, F
15
15
  /** A platform event's type: one a module's contract declares. */
16
16
  export type EventType = keyof PlatformEvents;
17
17
  /** Every platform event's type, as the contracts declare them. */
18
- export declare const EVENT_TYPES: readonly ["ai.goal.updated", "ai.response.completed", "ai.response.failed", "ai.response.started", "ai.voice.closed", "ai.voice.delegated", "ai.voice.started", "ai.workspace.published", "ai.workspace.pushed", "audience.entered", "audience.exited", "consent.changed", "device.revoked", "file.deleted", "file.moved", "file.uploaded", "flag.changed", "flag.override_changed", "journey.converted", "journey.ended", "journey.entered", "journey.event", "journey.step", "messaging.conversation.created", "messaging.conversation.deleted", "messaging.report.created", "notification.action", "notification.bounced", "notification.complained", "notification.delivered", "notification.dismissed", "notification.expired", "notification.failed", "notification.not_shown", "notification.opened", "notification.push_failing", "notification.read", "notification.received", "notification.rejected", "notification.sent", "notification.unconfirmed", "notification.undelivered", "notification.uninstalled", "purchases.catalog.applied", "purchases.catalog.changed", "purchases.coupon.redeemed", "purchases.credits.depleted", "purchases.credits.low", "purchases.customer.changed", "purchases.customer.erased", "purchases.customer.merged", "purchases.entitlement.changed", "purchases.offer.redeemed", "purchases.ownership.transferred", "purchases.paywall.published", "purchases.purchase.completed", "purchases.quota.exhausted", "purchases.quota.threshold", "purchases.refund.changed", "purchases.store.changed", "purchases.subscription.changed", "session.ended", "stores.action.changed", "stores.app.changed", "stores.apple.changed", "stores.apple.session.changed", "stores.apple.session.ended", "stores.apple.session.expired", "stores.beta_review.changed", "stores.build.changed", "stores.delivery.changed", "stores.delivery.requested", "stores.feedback.received", "stores.google.changed", "stores.group.changed", "stores.package.changed", "stores.play_release.changed", "stores.product.changed", "stores.review.message", "stores.version.changed", "stores.version.reviewed", "stores.vitals.changed", "stores.webhook.changed", "user.converted", "user.deleted", "user.locale_changed", "user.permissions_changed"];
18
+ export declare const EVENT_TYPES: readonly ["ai.goal.updated", "ai.response.completed", "ai.response.failed", "ai.response.started", "ai.voice.closed", "ai.voice.delegated", "ai.voice.started", "ai.workspace.published", "ai.workspace.pushed", "audience.entered", "audience.exited", "consent.changed", "device.revoked", "file.deleted", "file.moved", "file.uploaded", "flag.changed", "flag.override_changed", "journey.converted", "journey.ended", "journey.entered", "journey.event", "journey.step", "messaging.conversation.created", "messaging.conversation.deleted", "messaging.report.created", "notification.action", "notification.bounced", "notification.complained", "notification.delivered", "notification.dismissed", "notification.expired", "notification.failed", "notification.not_shown", "notification.opened", "notification.push_failing", "notification.read", "notification.received", "notification.rejected", "notification.sent", "notification.unconfirmed", "notification.undelivered", "notification.uninstalled", "purchases.catalog.applied", "purchases.catalog.changed", "purchases.coupon.redeemed", "purchases.credits.depleted", "purchases.credits.low", "purchases.customer.changed", "purchases.customer.erased", "purchases.customer.merged", "purchases.entitlement.changed", "purchases.offer.redeemed", "purchases.ownership.transferred", "purchases.paywall.published", "purchases.purchase.completed", "purchases.quota.exhausted", "purchases.quota.threshold", "purchases.refund.changed", "purchases.store.changed", "purchases.subscription.changed", "session.ended", "stores.action.changed", "stores.app.changed", "stores.apple.changed", "stores.apple.key.made", "stores.apple.key.revoked", "stores.apple.session.changed", "stores.apple.session.ended", "stores.apple.session.expired", "stores.beta_review.changed", "stores.build.changed", "stores.delivery.changed", "stores.delivery.requested", "stores.feedback.received", "stores.google.changed", "stores.group.changed", "stores.package.changed", "stores.play_release.changed", "stores.product.changed", "stores.review.message", "stores.version.changed", "stores.version.reviewed", "stores.vitals.changed", "stores.webhook.changed", "user.converted", "user.deleted", "user.locale_changed", "user.permissions_changed"];
19
19
  /**
20
20
  * A platform event as delivered: one member per type the contracts declare,
21
21
  * its data that type's payload, so a switch on its type narrows it. An
22
22
  * event of a type none of them declares (one a newer platform sends) is no
23
23
  * member: at run time it reaches the switch's default, which takes it.
24
24
  */
25
- export type PalbaseEvent = WebhookEvent<PlatformEvents["ai.goal.updated"], "ai.goal.updated"> | WebhookEvent<PlatformEvents["ai.response.completed"], "ai.response.completed"> | WebhookEvent<PlatformEvents["ai.response.failed"], "ai.response.failed"> | WebhookEvent<PlatformEvents["ai.response.started"], "ai.response.started"> | WebhookEvent<PlatformEvents["ai.voice.closed"], "ai.voice.closed"> | WebhookEvent<PlatformEvents["ai.voice.delegated"], "ai.voice.delegated"> | WebhookEvent<PlatformEvents["ai.voice.started"], "ai.voice.started"> | WebhookEvent<PlatformEvents["ai.workspace.published"], "ai.workspace.published"> | WebhookEvent<PlatformEvents["ai.workspace.pushed"], "ai.workspace.pushed"> | WebhookEvent<PlatformEvents["audience.entered"], "audience.entered"> | WebhookEvent<PlatformEvents["audience.exited"], "audience.exited"> | WebhookEvent<PlatformEvents["consent.changed"], "consent.changed"> | WebhookEvent<PlatformEvents["device.revoked"], "device.revoked"> | WebhookEvent<PlatformEvents["file.deleted"], "file.deleted"> | WebhookEvent<PlatformEvents["file.moved"], "file.moved"> | WebhookEvent<PlatformEvents["file.uploaded"], "file.uploaded"> | WebhookEvent<PlatformEvents["flag.changed"], "flag.changed"> | WebhookEvent<PlatformEvents["flag.override_changed"], "flag.override_changed"> | WebhookEvent<PlatformEvents["journey.converted"], "journey.converted"> | WebhookEvent<PlatformEvents["journey.ended"], "journey.ended"> | WebhookEvent<PlatformEvents["journey.entered"], "journey.entered"> | WebhookEvent<PlatformEvents["journey.event"], "journey.event"> | WebhookEvent<PlatformEvents["journey.step"], "journey.step"> | WebhookEvent<PlatformEvents["messaging.conversation.created"], "messaging.conversation.created"> | WebhookEvent<PlatformEvents["messaging.conversation.deleted"], "messaging.conversation.deleted"> | WebhookEvent<PlatformEvents["messaging.report.created"], "messaging.report.created"> | WebhookEvent<PlatformEvents["notification.action"], "notification.action"> | WebhookEvent<PlatformEvents["notification.bounced"], "notification.bounced"> | WebhookEvent<PlatformEvents["notification.complained"], "notification.complained"> | WebhookEvent<PlatformEvents["notification.delivered"], "notification.delivered"> | WebhookEvent<PlatformEvents["notification.dismissed"], "notification.dismissed"> | WebhookEvent<PlatformEvents["notification.expired"], "notification.expired"> | WebhookEvent<PlatformEvents["notification.failed"], "notification.failed"> | WebhookEvent<PlatformEvents["notification.not_shown"], "notification.not_shown"> | WebhookEvent<PlatformEvents["notification.opened"], "notification.opened"> | WebhookEvent<PlatformEvents["notification.push_failing"], "notification.push_failing"> | WebhookEvent<PlatformEvents["notification.read"], "notification.read"> | WebhookEvent<PlatformEvents["notification.received"], "notification.received"> | WebhookEvent<PlatformEvents["notification.rejected"], "notification.rejected"> | WebhookEvent<PlatformEvents["notification.sent"], "notification.sent"> | WebhookEvent<PlatformEvents["notification.unconfirmed"], "notification.unconfirmed"> | WebhookEvent<PlatformEvents["notification.undelivered"], "notification.undelivered"> | WebhookEvent<PlatformEvents["notification.uninstalled"], "notification.uninstalled"> | WebhookEvent<PlatformEvents["purchases.catalog.applied"], "purchases.catalog.applied"> | WebhookEvent<PlatformEvents["purchases.catalog.changed"], "purchases.catalog.changed"> | WebhookEvent<PlatformEvents["purchases.coupon.redeemed"], "purchases.coupon.redeemed"> | WebhookEvent<PlatformEvents["purchases.credits.depleted"], "purchases.credits.depleted"> | WebhookEvent<PlatformEvents["purchases.credits.low"], "purchases.credits.low"> | WebhookEvent<PlatformEvents["purchases.customer.changed"], "purchases.customer.changed"> | WebhookEvent<PlatformEvents["purchases.customer.erased"], "purchases.customer.erased"> | WebhookEvent<PlatformEvents["purchases.customer.merged"], "purchases.customer.merged"> | WebhookEvent<PlatformEvents["purchases.entitlement.changed"], "purchases.entitlement.changed"> | WebhookEvent<PlatformEvents["purchases.offer.redeemed"], "purchases.offer.redeemed"> | WebhookEvent<PlatformEvents["purchases.ownership.transferred"], "purchases.ownership.transferred"> | WebhookEvent<PlatformEvents["purchases.paywall.published"], "purchases.paywall.published"> | WebhookEvent<PlatformEvents["purchases.purchase.completed"], "purchases.purchase.completed"> | WebhookEvent<PlatformEvents["purchases.quota.exhausted"], "purchases.quota.exhausted"> | WebhookEvent<PlatformEvents["purchases.quota.threshold"], "purchases.quota.threshold"> | WebhookEvent<PlatformEvents["purchases.refund.changed"], "purchases.refund.changed"> | WebhookEvent<PlatformEvents["purchases.store.changed"], "purchases.store.changed"> | WebhookEvent<PlatformEvents["purchases.subscription.changed"], "purchases.subscription.changed"> | WebhookEvent<PlatformEvents["session.ended"], "session.ended"> | WebhookEvent<PlatformEvents["stores.action.changed"], "stores.action.changed"> | WebhookEvent<PlatformEvents["stores.app.changed"], "stores.app.changed"> | WebhookEvent<PlatformEvents["stores.apple.changed"], "stores.apple.changed"> | WebhookEvent<PlatformEvents["stores.apple.session.changed"], "stores.apple.session.changed"> | WebhookEvent<PlatformEvents["stores.apple.session.ended"], "stores.apple.session.ended"> | WebhookEvent<PlatformEvents["stores.apple.session.expired"], "stores.apple.session.expired"> | WebhookEvent<PlatformEvents["stores.beta_review.changed"], "stores.beta_review.changed"> | WebhookEvent<PlatformEvents["stores.build.changed"], "stores.build.changed"> | WebhookEvent<PlatformEvents["stores.delivery.changed"], "stores.delivery.changed"> | WebhookEvent<PlatformEvents["stores.delivery.requested"], "stores.delivery.requested"> | WebhookEvent<PlatformEvents["stores.feedback.received"], "stores.feedback.received"> | WebhookEvent<PlatformEvents["stores.google.changed"], "stores.google.changed"> | WebhookEvent<PlatformEvents["stores.group.changed"], "stores.group.changed"> | WebhookEvent<PlatformEvents["stores.package.changed"], "stores.package.changed"> | WebhookEvent<PlatformEvents["stores.play_release.changed"], "stores.play_release.changed"> | WebhookEvent<PlatformEvents["stores.product.changed"], "stores.product.changed"> | WebhookEvent<PlatformEvents["stores.review.message"], "stores.review.message"> | WebhookEvent<PlatformEvents["stores.version.changed"], "stores.version.changed"> | WebhookEvent<PlatformEvents["stores.version.reviewed"], "stores.version.reviewed"> | WebhookEvent<PlatformEvents["stores.vitals.changed"], "stores.vitals.changed"> | WebhookEvent<PlatformEvents["stores.webhook.changed"], "stores.webhook.changed"> | WebhookEvent<PlatformEvents["user.converted"], "user.converted"> | WebhookEvent<PlatformEvents["user.deleted"], "user.deleted"> | WebhookEvent<PlatformEvents["user.locale_changed"], "user.locale_changed"> | WebhookEvent<PlatformEvents["user.permissions_changed"], "user.permissions_changed">;
25
+ export type PalbaseEvent = WebhookEvent<PlatformEvents["ai.goal.updated"], "ai.goal.updated"> | WebhookEvent<PlatformEvents["ai.response.completed"], "ai.response.completed"> | WebhookEvent<PlatformEvents["ai.response.failed"], "ai.response.failed"> | WebhookEvent<PlatformEvents["ai.response.started"], "ai.response.started"> | WebhookEvent<PlatformEvents["ai.voice.closed"], "ai.voice.closed"> | WebhookEvent<PlatformEvents["ai.voice.delegated"], "ai.voice.delegated"> | WebhookEvent<PlatformEvents["ai.voice.started"], "ai.voice.started"> | WebhookEvent<PlatformEvents["ai.workspace.published"], "ai.workspace.published"> | WebhookEvent<PlatformEvents["ai.workspace.pushed"], "ai.workspace.pushed"> | WebhookEvent<PlatformEvents["audience.entered"], "audience.entered"> | WebhookEvent<PlatformEvents["audience.exited"], "audience.exited"> | WebhookEvent<PlatformEvents["consent.changed"], "consent.changed"> | WebhookEvent<PlatformEvents["device.revoked"], "device.revoked"> | WebhookEvent<PlatformEvents["file.deleted"], "file.deleted"> | WebhookEvent<PlatformEvents["file.moved"], "file.moved"> | WebhookEvent<PlatformEvents["file.uploaded"], "file.uploaded"> | WebhookEvent<PlatformEvents["flag.changed"], "flag.changed"> | WebhookEvent<PlatformEvents["flag.override_changed"], "flag.override_changed"> | WebhookEvent<PlatformEvents["journey.converted"], "journey.converted"> | WebhookEvent<PlatformEvents["journey.ended"], "journey.ended"> | WebhookEvent<PlatformEvents["journey.entered"], "journey.entered"> | WebhookEvent<PlatformEvents["journey.event"], "journey.event"> | WebhookEvent<PlatformEvents["journey.step"], "journey.step"> | WebhookEvent<PlatformEvents["messaging.conversation.created"], "messaging.conversation.created"> | WebhookEvent<PlatformEvents["messaging.conversation.deleted"], "messaging.conversation.deleted"> | WebhookEvent<PlatformEvents["messaging.report.created"], "messaging.report.created"> | WebhookEvent<PlatformEvents["notification.action"], "notification.action"> | WebhookEvent<PlatformEvents["notification.bounced"], "notification.bounced"> | WebhookEvent<PlatformEvents["notification.complained"], "notification.complained"> | WebhookEvent<PlatformEvents["notification.delivered"], "notification.delivered"> | WebhookEvent<PlatformEvents["notification.dismissed"], "notification.dismissed"> | WebhookEvent<PlatformEvents["notification.expired"], "notification.expired"> | WebhookEvent<PlatformEvents["notification.failed"], "notification.failed"> | WebhookEvent<PlatformEvents["notification.not_shown"], "notification.not_shown"> | WebhookEvent<PlatformEvents["notification.opened"], "notification.opened"> | WebhookEvent<PlatformEvents["notification.push_failing"], "notification.push_failing"> | WebhookEvent<PlatformEvents["notification.read"], "notification.read"> | WebhookEvent<PlatformEvents["notification.received"], "notification.received"> | WebhookEvent<PlatformEvents["notification.rejected"], "notification.rejected"> | WebhookEvent<PlatformEvents["notification.sent"], "notification.sent"> | WebhookEvent<PlatformEvents["notification.unconfirmed"], "notification.unconfirmed"> | WebhookEvent<PlatformEvents["notification.undelivered"], "notification.undelivered"> | WebhookEvent<PlatformEvents["notification.uninstalled"], "notification.uninstalled"> | WebhookEvent<PlatformEvents["purchases.catalog.applied"], "purchases.catalog.applied"> | WebhookEvent<PlatformEvents["purchases.catalog.changed"], "purchases.catalog.changed"> | WebhookEvent<PlatformEvents["purchases.coupon.redeemed"], "purchases.coupon.redeemed"> | WebhookEvent<PlatformEvents["purchases.credits.depleted"], "purchases.credits.depleted"> | WebhookEvent<PlatformEvents["purchases.credits.low"], "purchases.credits.low"> | WebhookEvent<PlatformEvents["purchases.customer.changed"], "purchases.customer.changed"> | WebhookEvent<PlatformEvents["purchases.customer.erased"], "purchases.customer.erased"> | WebhookEvent<PlatformEvents["purchases.customer.merged"], "purchases.customer.merged"> | WebhookEvent<PlatformEvents["purchases.entitlement.changed"], "purchases.entitlement.changed"> | WebhookEvent<PlatformEvents["purchases.offer.redeemed"], "purchases.offer.redeemed"> | WebhookEvent<PlatformEvents["purchases.ownership.transferred"], "purchases.ownership.transferred"> | WebhookEvent<PlatformEvents["purchases.paywall.published"], "purchases.paywall.published"> | WebhookEvent<PlatformEvents["purchases.purchase.completed"], "purchases.purchase.completed"> | WebhookEvent<PlatformEvents["purchases.quota.exhausted"], "purchases.quota.exhausted"> | WebhookEvent<PlatformEvents["purchases.quota.threshold"], "purchases.quota.threshold"> | WebhookEvent<PlatformEvents["purchases.refund.changed"], "purchases.refund.changed"> | WebhookEvent<PlatformEvents["purchases.store.changed"], "purchases.store.changed"> | WebhookEvent<PlatformEvents["purchases.subscription.changed"], "purchases.subscription.changed"> | WebhookEvent<PlatformEvents["session.ended"], "session.ended"> | WebhookEvent<PlatformEvents["stores.action.changed"], "stores.action.changed"> | WebhookEvent<PlatformEvents["stores.app.changed"], "stores.app.changed"> | WebhookEvent<PlatformEvents["stores.apple.changed"], "stores.apple.changed"> | WebhookEvent<PlatformEvents["stores.apple.key.made"], "stores.apple.key.made"> | WebhookEvent<PlatformEvents["stores.apple.key.revoked"], "stores.apple.key.revoked"> | WebhookEvent<PlatformEvents["stores.apple.session.changed"], "stores.apple.session.changed"> | WebhookEvent<PlatformEvents["stores.apple.session.ended"], "stores.apple.session.ended"> | WebhookEvent<PlatformEvents["stores.apple.session.expired"], "stores.apple.session.expired"> | WebhookEvent<PlatformEvents["stores.beta_review.changed"], "stores.beta_review.changed"> | WebhookEvent<PlatformEvents["stores.build.changed"], "stores.build.changed"> | WebhookEvent<PlatformEvents["stores.delivery.changed"], "stores.delivery.changed"> | WebhookEvent<PlatformEvents["stores.delivery.requested"], "stores.delivery.requested"> | WebhookEvent<PlatformEvents["stores.feedback.received"], "stores.feedback.received"> | WebhookEvent<PlatformEvents["stores.google.changed"], "stores.google.changed"> | WebhookEvent<PlatformEvents["stores.group.changed"], "stores.group.changed"> | WebhookEvent<PlatformEvents["stores.package.changed"], "stores.package.changed"> | WebhookEvent<PlatformEvents["stores.play_release.changed"], "stores.play_release.changed"> | WebhookEvent<PlatformEvents["stores.product.changed"], "stores.product.changed"> | WebhookEvent<PlatformEvents["stores.review.message"], "stores.review.message"> | WebhookEvent<PlatformEvents["stores.version.changed"], "stores.version.changed"> | WebhookEvent<PlatformEvents["stores.version.reviewed"], "stores.version.reviewed"> | WebhookEvent<PlatformEvents["stores.vitals.changed"], "stores.vitals.changed"> | WebhookEvent<PlatformEvents["stores.webhook.changed"], "stores.webhook.changed"> | WebhookEvent<PlatformEvents["user.converted"], "user.converted"> | WebhookEvent<PlatformEvents["user.deleted"], "user.deleted"> | WebhookEvent<PlatformEvents["user.locale_changed"], "user.locale_changed"> | WebhookEvent<PlatformEvents["user.permissions_changed"], "user.permissions_changed">;
@@ -1556,6 +1556,7 @@ export type CustomerRecord = {
1556
1556
  * The moves of their purchases to and from other customers, newest first (the latest 100): a restore, a new purchase made on a store account they share, a guest's merge into its account — as purchases.ownership.transferred told each.
1557
1557
  */
1558
1558
  transfers: OwnershipTransfer[];
1559
+ refund_data_consent?: RefundDataConsent;
1559
1560
  };
1560
1561
  /**
1561
1562
  * purchases.customer.merged: a guest's purchases, grants, credits and quota use went to the account it signed in to; the guest's id points to the account from then on.
@@ -6006,9 +6007,9 @@ export type CustomerEvent = {
6006
6007
  */
6007
6008
  at: string;
6008
6009
  /**
6009
- * What happened: a payment (`purchase`, `renewal`), a `refund`, a subscription's renewal turned off (`cancellation`) or back on (`resumption`), a failed charge (`billing_issue`), its end (`expiration`), a grant given (`grant`) or taken back (`grant_revoked`), credits moved (`credits`), a purchase moved to (`transfer_in`) or from (`transfer_out`) the customer.
6010
+ * What happened: a payment (`purchase`, `renewal`), a `refund`, a subscription's renewal turned off (`cancellation`) or back on (`resumption`), a failed charge (`billing_issue`), its end (`expiration`), a grant given (`grant`) or taken back (`grant_revoked`), credits moved (`credits`), a purchase moved to (`transfer_in`) or from (`transfer_out`) the customer. Support's own: a subscription extended (`extension`), refunded (`refund_issued`) or its renewal turned off (`cancel_requested`); and the customer asking the App Store for a refund (`refund_requested`).
6010
6011
  */
6011
- kind: "purchase" | "renewal" | "refund" | "cancellation" | "resumption" | "billing_issue" | "expiration" | "grant" | "grant_revoked" | "credits" | "transfer_in" | "transfer_out";
6012
+ kind: "purchase" | "renewal" | "refund" | "cancellation" | "resumption" | "billing_issue" | "expiration" | "grant" | "grant_revoked" | "credits" | "transfer_in" | "transfer_out" | "extension" | "refund_issued" | "cancel_requested" | "refund_requested";
6012
6013
  /**
6013
6014
  * The purchase's store.
6014
6015
  */
@@ -6066,6 +6067,26 @@ export type CustomerEvent = {
6066
6067
  * A transfer's other side: whom from, whom to (null: a purchase that was no one's).
6067
6068
  */
6068
6069
  other_customer_id?: string | null;
6070
+ /**
6071
+ * An extension's days.
6072
+ */
6073
+ days?: number;
6074
+ /**
6075
+ * An extension's (or a refund's, a cancellation's) expiry after: when the subscription ends now.
6076
+ */
6077
+ expires_at?: string;
6078
+ /**
6079
+ * A refund support issued: `full` or `prorated`.
6080
+ */
6081
+ refund_mode?: "full" | "prorated";
6082
+ /**
6083
+ * What support wrote of what it did.
6084
+ */
6085
+ note?: string;
6086
+ /**
6087
+ * What Palbase told the App Store of a refund the customer asked it for: `sent`, `pending`, `not_consented` (nothing sent: the customer did not consent) or `expired` (its 12 hours passed).
6088
+ */
6089
+ answer?: "sent" | "pending" | "not_consented" | "expired";
6069
6090
  };
6070
6091
  /**
6071
6092
  * What happened to a customer, the newest first, a page at a time.
@@ -6245,6 +6266,123 @@ export type SpendRefusal = {
6245
6266
  */
6246
6267
  upgrades?: LimitUpgrade[];
6247
6268
  };
6269
+ /**
6270
+ * A subscription's renewal moved later, for free.
6271
+ */
6272
+ export type ExtendSubscriptionRequest = {
6273
+ /**
6274
+ * How many days (1 to 90).
6275
+ */
6276
+ days: number;
6277
+ /**
6278
+ * Why, as the App Store asks it.
6279
+ */
6280
+ reason: "customer_satisfaction" | "service_issue" | "other";
6281
+ /**
6282
+ * What support writes of it (500 characters at most): the record.
6283
+ */
6284
+ note?: string;
6285
+ };
6286
+ /**
6287
+ * A subscription's latest payment refunded, and the subscription ended now.
6288
+ */
6289
+ export type RefundSubscriptionRequest = {
6290
+ /**
6291
+ * `full`: the latest payment; `prorated`: what is left of its period.
6292
+ */
6293
+ mode: "full" | "prorated";
6294
+ /**
6295
+ * What support writes of it (500 characters at most): the record.
6296
+ */
6297
+ note?: string;
6298
+ };
6299
+ /**
6300
+ * A subscription's renewal turned off: it ends at its period's end.
6301
+ */
6302
+ export type CancelSubscriptionRequest = {
6303
+ /**
6304
+ * What support writes of it (500 characters at most): the record.
6305
+ */
6306
+ note?: string;
6307
+ };
6308
+ /**
6309
+ * What support did to a subscription.
6310
+ */
6311
+ export type SupportAction = {
6312
+ /**
6313
+ * The action.
6314
+ */
6315
+ id: string;
6316
+ /**
6317
+ * The customer.
6318
+ */
6319
+ customer_id: string;
6320
+ /**
6321
+ * The subscription.
6322
+ */
6323
+ subscription_id: string;
6324
+ /**
6325
+ * What was done.
6326
+ */
6327
+ action: "extend" | "refund" | "cancel";
6328
+ /**
6329
+ * The subscription's store.
6330
+ */
6331
+ store: "app_store" | "play_store" | "stripe";
6332
+ /**
6333
+ * An extension's days.
6334
+ */
6335
+ days?: number;
6336
+ /**
6337
+ * An extension's reason.
6338
+ */
6339
+ reason?: string;
6340
+ /**
6341
+ * A refund's kind.
6342
+ */
6343
+ mode?: "full" | "prorated";
6344
+ /**
6345
+ * What support wrote of it.
6346
+ */
6347
+ note?: string;
6348
+ /**
6349
+ * Who did it: the developer whose Studio or CLI call it was (`developer:…`), or the key (`key:…`).
6350
+ */
6351
+ actor: string;
6352
+ /**
6353
+ * When.
6354
+ */
6355
+ at: string;
6356
+ };
6357
+ /**
6358
+ * What support did, and the subscription as its store holds it after.
6359
+ */
6360
+ export type SupportResult = {
6361
+ action: SupportAction;
6362
+ subscription: SubscriptionInfo;
6363
+ };
6364
+ /**
6365
+ * The customer's word, in the app, on the App Store being told of their use of a purchase they ask a refund of.
6366
+ */
6367
+ export type RefundDataConsent = {
6368
+ /**
6369
+ * What they said.
6370
+ */
6371
+ consented: boolean;
6372
+ /**
6373
+ * When they said it.
6374
+ */
6375
+ at: string | null;
6376
+ };
6377
+ /**
6378
+ * What the customer said, as the app asked them.
6379
+ */
6380
+ export type RefundDataConsentRequest = {
6381
+ /**
6382
+ * true: Palbase answers the App Store's question when they ask Apple for a refund; false: it never does.
6383
+ */
6384
+ consented: boolean;
6385
+ };
6248
6386
  /** The events this module sends the project's webhooks (x-palbase-events), by type: each one's payload, the event's data. */
6249
6387
  export interface Events {
6250
6388
  /**
@@ -7666,5 +7804,62 @@ export declare function client(t: Transport): {
7666
7804
  }; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
7667
7805
  signal?: AbortSignal;
7668
7806
  }): Promise<Reply<200, CatalogDoc>>;
7807
+ /**
7808
+ * Extend a subscription
7809
+ *
7810
+ * Moves the subscription's renewal days later, for free: the App Store's renewal-date extension (a paid, active subscription; at most 90 days, twice a year), Google Play's deferral, Stripe's next charge moved. The store is asked again after: the record answers the new expiry. Kept in the customer's history (`extension`) with who did it.
7811
+ */
7812
+ extendSubscription(input: {
7813
+ path: {
7814
+ customer_id: string; /** The subscription, by its id in the customer's record (subscriptions[].id). */
7815
+ subscription_id: string;
7816
+ };
7817
+ headers?: {
7818
+ "Idempotency-Key"?: string;
7819
+ };
7820
+ body: ExtendSubscriptionRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
7821
+ signal?: AbortSignal;
7822
+ }): Promise<Reply<200, SupportResult>>;
7823
+ /**
7824
+ * Refund a subscription
7825
+ *
7826
+ * Refunds the subscription's latest payment — all of it (`full`) or what is left of its period (`prorated`) — and ends it now: the customer's access ends as the call answers. Google Play and Stripe; the App Store decides its own refunds (`409 store_decides_refunds`: the customer asks Apple, which asks the app what they used — Palbase answers it when they consented). Kept in the history (`refund_issued`).
7827
+ */
7828
+ refundSubscription(input: {
7829
+ path: {
7830
+ customer_id: string; /** The subscription, by its id in the customer's record (subscriptions[].id). */
7831
+ subscription_id: string;
7832
+ };
7833
+ headers?: {
7834
+ "Idempotency-Key"?: string;
7835
+ };
7836
+ body: RefundSubscriptionRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
7837
+ signal?: AbortSignal;
7838
+ }): Promise<Reply<200, SupportResult>>;
7839
+ /**
7840
+ * Cancel a subscription's renewal
7841
+ *
7842
+ * Turns the subscription's renewal off: it ends at its period's end, the customer keeping what they paid for. Google Play and Stripe; an App Store subscription's renewal is the customer's to turn off (`409 customer_cancels`). Kept in the history (`cancel_requested`).
7843
+ */
7844
+ cancelSubscription(input: {
7845
+ path: {
7846
+ customer_id: string; /** The subscription, by its id in the customer's record (subscriptions[].id). */
7847
+ subscription_id: string;
7848
+ };
7849
+ headers?: {
7850
+ "Idempotency-Key"?: string;
7851
+ };
7852
+ body?: CancelSubscriptionRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
7853
+ signal?: AbortSignal;
7854
+ }): Promise<Reply<200, SupportResult>>;
7855
+ /**
7856
+ * Record the customer's consent to refund data
7857
+ *
7858
+ * What the signed-in customer said, as the app asked them: whether the App Store is told of their use of a purchase they ask Apple a refund of (Apple's CONSUMPTION_REQUEST). With it, Palbase answers Apple within its 12 hours — whether it gave what was bought, whether a free trial came first, how much of a pack of credits was spent — and states no preference of its own; without it, Apple is told nothing. The latest word counts.
7859
+ */
7860
+ setRefundDataConsent(input: {
7861
+ body: RefundDataConsentRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
7862
+ signal?: AbortSignal;
7863
+ }): Promise<Reply<200, RefundDataConsent>>;
7669
7864
  };
7670
7865
  export type Client = ReturnType<typeof client>;