palbase 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) 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/{BKGX3AZA.js → 2235YZCU.js} +2 -2
  8. package/dist/chunks/{7QFBZLAK.js → 2IQO655S.js} +1 -1
  9. package/dist/chunks/{PPK2UEAY.js → 3AWINO2F.js} +2 -2
  10. package/dist/chunks/{4S4ODZVM.js → 5RT5MMQZ.js} +2 -2
  11. package/dist/chunks/{VQXYHAU4.js → 6KQLUU3H.js} +2 -2
  12. package/dist/chunks/{XF3JEDIQ.js → B34MLQR7.js} +1 -1
  13. package/dist/chunks/{ART5HP5M.js → BAI274LR.js} +2 -2
  14. package/dist/chunks/{T2O6XEQO.js → BDXJNCHK.js} +1 -1
  15. package/dist/chunks/{KRQZOF2L.js → D6EZT4FT.js} +2 -2
  16. package/dist/chunks/{JKA2W4E5.js → EFLH3KG7.js} +2 -2
  17. package/dist/chunks/{6IMY2J5W.js → HVZBXN5X.js} +1 -1
  18. package/dist/chunks/{4HFD24QY.js → I3Z7F2Q7.js} +1 -1
  19. package/dist/chunks/{PMQOJ7FF.js → KK6V5EI4.js} +2 -2
  20. package/dist/chunks/{3GWBIPGH.js → LJP3LHLO.js} +2 -2
  21. package/dist/chunks/{BW5DFI3C.js → NTAJM7WR.js} +1 -1
  22. package/dist/chunks/{7R4WTDHI.js → PTZ7ZIVR.js} +1 -1
  23. package/dist/chunks/{FT7G3QQ4.js → RH4K3QBY.js} +2 -2
  24. package/dist/chunks/RNDZZL4L.js +2 -0
  25. package/dist/chunks/{EVBWED24.js → S7MGNDUF.js} +3 -3
  26. package/dist/chunks/{OC32TP3L.js → TQFLWOSE.js} +2 -2
  27. package/dist/chunks/{CAZYHE64.js → W6N2DVBO.js} +2 -2
  28. package/dist/chunks/WJ6WXWYV.js +21 -0
  29. package/dist/chunks/{XHNZDLR4.js → XW2UNA5Y.js} +2 -2
  30. package/dist/cli.js +117 -117
  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/stores.d.ts +166 -0
  50. package/types/web/src/auth.d.ts +11 -1
  51. package/dist/chunks/32XY6IBN.js +0 -21
  52. 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.1 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/ai is for servers: it speaks with the project secret key, which never goes into a browser or a mobile app \u2014 call your backend, and let it ask the model");
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.1 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/backend is a server framework: it runs on your backend, never in a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs)");
@@ -1,2 +1,2 @@
1
- /*! palbase 0.18.0 — Palbase SDK License (see LICENSE) */
1
+ /*! palbase 0.18.1 — Palbase SDK License (see LICENSE) */
2
2
  throw new Error("palbase/server is for servers: its secret key never goes into a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs) with the publishable key");
@@ -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.1 — 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/BAI274LR.js";import{a as c,b as d}from"../chunks/I3Z7F2Q7.js";import"../chunks/PTZ7ZIVR.js";import"../chunks/2IQO655S.js";import{n as b}from"../chunks/RNDZZL4L.js";import"../chunks/RH4K3QBY.js";import{b as a}from"../chunks/6KQLUU3H.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — Palbase SDK License (see LICENSE) */
2
+ import{a,b,c,d,e}from"../chunks/2235YZCU.js";import"../chunks/I3Z7F2Q7.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — 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/S7MGNDUF.js";import{a as _,b as Q,f as z}from"../chunks/TQFLWOSE.js";import"../chunks/W6N2DVBO.js";import"../chunks/3AWINO2F.js";import"../chunks/B34MLQR7.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/PTZ7ZIVR.js";import"../chunks/XW2UNA5Y.js";import"../chunks/RNDZZL4L.js";import"../chunks/RH4K3QBY.js";import{b as I}from"../chunks/6KQLUU3H.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — Palbase SDK License (see LICENSE) */
2
+ import{a as i}from"../chunks/3AWINO2F.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/B34MLQR7.js";import"../chunks/BDXJNCHK.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.1 — Palbase SDK License (see LICENSE) */
2
+ import{c as e,d as r,i as t}from"../chunks/TQFLWOSE.js";import"../chunks/PTZ7ZIVR.js";import"../chunks/XW2UNA5Y.js";import"../chunks/RH4K3QBY.js";import"../chunks/6KQLUU3H.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — 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/W6N2DVBO.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/B34MLQR7.js";import"../chunks/6KQLUU3H.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — 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.1 — Palbase SDK License (see LICENSE) */
2
+ import{w as f}from"../chunks/S7MGNDUF.js";import"../chunks/TQFLWOSE.js";import"../chunks/W6N2DVBO.js";import"../chunks/3AWINO2F.js";import"../chunks/B34MLQR7.js";import"../chunks/PTZ7ZIVR.js";import"../chunks/XW2UNA5Y.js";import"../chunks/RNDZZL4L.js";import"../chunks/RH4K3QBY.js";import"../chunks/6KQLUU3H.js";import"../chunks/HVZBXN5X.js";import"../chunks/BDXJNCHK.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.1 — Palbase SDK License (see LICENSE) */
2
+ import"../chunks/BDXJNCHK.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.1",
4
4
  "description": "Palbase for JavaScript: the web client (palbase/web), the server SDK (palbase/server), the backend framework (palbase/backend), AI (palbase/ai) and the CLI (npx palbase).",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://palbase.studio",
@@ -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.1",
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">;
@@ -467,6 +467,10 @@ export type AppleChangedEvent = {
467
467
  * What Apple said of the key (connected, checked).
468
468
  */
469
469
  status?: "active" | "agreement" | "refused";
470
+ /**
471
+ * The key was made at Apple by Palbase, with the environment's Apple ID session (connected).
472
+ */
473
+ made?: boolean;
470
474
  };
471
475
  /**
472
476
  * A one-time grant to connect an Apple key: the key goes from the person's browser (connect_url) or terminal (POST /stores/connect with the grant) straight to the module.
@@ -2532,6 +2536,7 @@ export type AppleSession = {
2532
2536
  */
2533
2537
  status?: "active" | "expired";
2534
2538
  team?: AppleTeam;
2539
+ shared_from?: SharedEnvironment;
2535
2540
  };
2536
2541
  /**
2537
2542
  * stores.apple.session.changed: an Apple ID was signed in for the project, or disconnected. Never the session.
@@ -2885,6 +2890,125 @@ export type AppleSessionEndedEvent = {
2885
2890
  */
2886
2891
  connected_by: string;
2887
2892
  };
2893
+ /**
2894
+ * A key Palbase made at Apple for the environment: never its .p8.
2895
+ */
2896
+ export type MadeKey = {
2897
+ /**
2898
+ * The apps it is for (APNs, In-App Purchase).
2899
+ */
2900
+ bundles?: string[];
2901
+ /**
2902
+ * An APNs key's environment.
2903
+ */
2904
+ environment?: "sandbox" | "prod";
2905
+ /**
2906
+ * The key's id at Apple.
2907
+ */
2908
+ key_id: string;
2909
+ /**
2910
+ * `asc` (App Store Connect API), `apns` or `iap` (In-App Purchase).
2911
+ */
2912
+ kind: "asc" | "apns" | "iap";
2913
+ /**
2914
+ * When it was made.
2915
+ */
2916
+ made_at: string;
2917
+ /**
2918
+ * Who asked for it: a developer's id, or the key's.
2919
+ */
2920
+ made_by: string;
2921
+ /**
2922
+ * The module it is for: notify (APNs), purchases (In-App Purchase).
2923
+ */
2924
+ module?: "notify" | "purchases";
2925
+ /**
2926
+ * What became of it, when it was not simply taken.
2927
+ */
2928
+ note?: string;
2929
+ /**
2930
+ * When its module took it, refused it, or it was revoked.
2931
+ */
2932
+ settled_at?: string;
2933
+ /**
2934
+ * `waiting` for its module to take it, `taken`, `refused` (its module keeps a key of its own and it could not be revoked at Apple), or `revoked`.
2935
+ */
2936
+ state: "waiting" | "taken" | "refused" | "revoked";
2937
+ };
2938
+ /**
2939
+ * Keys Palbase made at Apple for the environment.
2940
+ */
2941
+ export type MadeKeys = {
2942
+ keys: MadeKey[];
2943
+ };
2944
+ /**
2945
+ * The key to make at Apple.
2946
+ */
2947
+ export type MakeKeyRequest = {
2948
+ /**
2949
+ * The iOS app an In-App Purchase key is for; required when the environment has more than one.
2950
+ */
2951
+ bundle?: string;
2952
+ /**
2953
+ * `asc` (App Store Connect API), `apns` or `iap` (In-App Purchase).
2954
+ */
2955
+ kind: "asc" | "apns" | "iap";
2956
+ };
2957
+ /**
2958
+ * The environment of the organization whose Apple ID session the project uses, having none of its own: signed in to the project's App Store Connect team.
2959
+ */
2960
+ export type SharedEnvironment = {
2961
+ /**
2962
+ * Its project's name.
2963
+ */
2964
+ name?: string;
2965
+ /**
2966
+ * Its platform project's id.
2967
+ */
2968
+ project_id: string;
2969
+ /**
2970
+ * Its ref.
2971
+ */
2972
+ ref?: string;
2973
+ };
2974
+ /**
2975
+ * stores.apple.key.made: keys were made at Apple for another module of the environment (notify's APNs keys, purchases' In-App Purchase key), which takes them. Never a key.
2976
+ */
2977
+ export type AppleKeyMadeEvent = {
2978
+ /**
2979
+ * The keys' handover: what the module takes at once.
2980
+ */
2981
+ handover: string;
2982
+ /**
2983
+ * The keys' ids at Apple.
2984
+ */
2985
+ key_ids: string[];
2986
+ /**
2987
+ * `apns` or `iap`.
2988
+ */
2989
+ kind: "apns" | "iap";
2990
+ /**
2991
+ * The module the keys are for.
2992
+ */
2993
+ module: "notify" | "purchases";
2994
+ };
2995
+ /**
2996
+ * stores.apple.key.revoked: a key Palbase made at Apple for the environment was revoked there. Never the key.
2997
+ */
2998
+ export type AppleKeyRevokedEvent = {
2999
+ /**
3000
+ * The key's id at Apple.
3001
+ */
3002
+ key_id: string;
3003
+ /**
3004
+ * `apns` or `iap`.
3005
+ */
3006
+ kind: "asc" | "apns" | "iap";
3007
+ /**
3008
+ * The module it was for.
3009
+ */
3010
+ module?: string;
3011
+ };
2888
3012
  /** The events this module sends the project's webhooks (x-palbase-events), by type: each one's payload, the event's data. */
2889
3013
  export interface Events {
2890
3014
  /**
@@ -2971,6 +3095,14 @@ export interface Events {
2971
3095
  * stores.apple.session.ended: Palbase's own project's copy of an Apple ID session Apple ended in a customer's project, whose Studio mails the person who connected it.
2972
3096
  */
2973
3097
  "stores.apple.session.ended": AppleSessionEndedEvent;
3098
+ /**
3099
+ * stores.apple.key.made: keys were made at Apple for another module of the environment (notify's APNs keys, purchases' In-App Purchase key), which takes them. Never a key.
3100
+ */
3101
+ "stores.apple.key.made": AppleKeyMadeEvent;
3102
+ /**
3103
+ * stores.apple.key.revoked: a key Palbase made at Apple for the environment was revoked there. Never the key.
3104
+ */
3105
+ "stores.apple.key.revoked": AppleKeyRevokedEvent;
2974
3106
  }
2975
3107
  /** Palbase Stores */
2976
3108
  export declare function client(t: Transport): {
@@ -3914,5 +4046,39 @@ export declare function client(t: Transport): {
3914
4046
  }; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
3915
4047
  signal?: AbortSignal;
3916
4048
  }): Promise<Reply<204, undefined>>;
4049
+ /**
4050
+ * Keys made at Apple
4051
+ *
4052
+ * The keys Palbase made at Apple for the environment with its Apple ID session (`POST /stores/apple/keys`), the newest first — never a key itself: its App Store Connect API key, its APNs keys (notify's) and its In-App Purchase key (purchases'), and where each stands.
4053
+ */
4054
+ listMadeAppleKeys(input?: {
4055
+ signal?: AbortSignal;
4056
+ }): Promise<Reply<200, MadeKeys>>;
4057
+ /**
4058
+ * Make a key at Apple
4059
+ *
4060
+ * Makes one key at Apple with the Apple ID session the environment uses, and connects it: no one downloads a .p8. `asc` — the environment's App Store Connect API key (Admin, every app), connected as `POST /stores/connect` connects one (409 `key_connected` when one is). `apns` — two APNs keys, one for each APNs environment (Apple makes a key scoped to apps for one environment), scoped to the environment's iOS apps, which the notify module takes as its APNs provider. `iap` — an In-App Purchase key for one of its iOS apps (`bundle`, required with more than one), which the purchases module connects. A module that keeps a key the environment connected itself refuses the one made, and it is revoked at Apple. One a request (each well inside the edge's time); 409 `key_made` for a kind Palbase made already. The Apple ID must be an Admin or the Account Holder (409 `apple_role_insufficient`). An owner's or an admin's, or the project's secret key's (403 `admin_required` for a member); never an environment's token's (403 `token_out_of_scope`): a key outlives it. Emits `stores.apple.changed` (asc) or `stores.apple.key.made` (apns, iap).
4061
+ */
4062
+ makeAppleKey(input: {
4063
+ headers?: {
4064
+ "Idempotency-Key"?: string;
4065
+ };
4066
+ body: MakeKeyRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
4067
+ signal?: AbortSignal;
4068
+ }): Promise<Reply<201, MadeKeys>>;
4069
+ /**
4070
+ * Revoke a key made at Apple
4071
+ *
4072
+ * Revokes at Apple an APNs or In-App Purchase key Palbase made for the environment: its module keeps it, and it no longer works. The App Store Connect key is revoked as it is disconnected (`DELETE /stores/apple`; 409 `key_connected` here). An owner's or an admin's, or the project's secret key's. Emits `stores.apple.key.revoked`.
4073
+ */
4074
+ revokeMadeAppleKey(input: {
4075
+ path: {
4076
+ key_id: string;
4077
+ };
4078
+ headers?: {
4079
+ "Idempotency-Key"?: string;
4080
+ }; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
4081
+ signal?: AbortSignal;
4082
+ }): Promise<Reply<200, MadeKey>>;
3917
4083
  };
3918
4084
  export type Client = ReturnType<typeof client>;
@@ -1,6 +1,6 @@
1
1
  import { auth as authModule } from '../../internal/src/modules/index.js';
2
2
  import type { Transport } from '../../internal/src/transport.js';
3
- import type { AuthEvent, Session, SessionEndReason, SessionManager } from './session.js';
3
+ import { type AuthEvent, type Session, type SessionEndReason, type SessionManager } from './session.js';
4
4
  type A = typeof authModule;
5
5
  export type User = authModule.User;
6
6
  export type SignupRequest = authModule.SignupRequest;
@@ -62,6 +62,13 @@ export declare class Auth {
62
62
  /** Removes a factor; the account's password confirms it. */
63
63
  removeFactor: (id: string, currentPassword: string) => Promise<void>;
64
64
  regenerateRecoveryCodes: () => Promise<authModule.MFARecoveryCodesResponse>;
65
+ /**
66
+ * Raises the signed-in session to aal2 with a code the authenticator app
67
+ * shows — what a route marked auth { aal: 'aal2' } asks for (401
68
+ * insufficient_user_authentication). The session holds the new token from
69
+ * here on; its refreshes stay at aal2.
70
+ */
71
+ stepUp: (code: string) => Promise<Session>;
65
72
  };
66
73
  readonly passkey: {
67
74
  /** Adds a passkey to the signed-in user. */
@@ -79,6 +86,8 @@ export declare class Auth {
79
86
  * it (the sign-up answers no tokens). The identifier is the user's email.
80
87
  */
81
88
  signUp: (identifier: string, userName?: string) => Promise<User>;
89
+ /** Raises the signed-in session to aal2 with one of the user's passkeys (as mfa.stepUp does with a code). */
90
+ stepUp: () => Promise<Session>;
82
91
  list: () => Promise<authModule.WebAuthnCredentialList>;
83
92
  remove: (id: string) => Promise<void>;
84
93
  };
@@ -156,6 +165,7 @@ export declare class Auth {
156
165
  }): Promise<User>;
157
166
  /** Starts the session from a token pair; the user is the answer's, or read once when it carries none. */
158
167
  private signedIn;
168
+ private steppedUp;
159
169
  private authenticator;
160
170
  }
161
171
  type Json = Record<string, unknown>;