@corbado/autocapture 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,8 @@ The package observes three kinds of signal:
13
13
 
14
14
  - **WebAuthn ceremonies** — the lifecycle of `navigator.credentials.get`/`create` passkey
15
15
  ceremonies, from invocation to settlement, including silent cancellations.
16
+ - **Federated identity (FedCM) requests** — `navigator.credentials.get({ identity })` calls such
17
+ as Google One Tap on Chromium: the providers requested, the account chosen, or why it failed.
16
18
  - **Network requests and exchanges** — request starts and their eventual outcomes over
17
19
  `XMLHttpRequest` and `fetch`, limited to URLs a caller-provided predicate selects. A page-local
18
20
  request ID correlates both callbacks.
@@ -35,12 +37,22 @@ Every observer follows the platform observer pattern (`MutationObserver`, `Resiz
35
37
  it with a callback, receive events, and call `disconnect()` when finished.
36
38
 
37
39
  ```ts
38
- import { captureWebAuthn, captureNetwork, captureNavigation, composedPath } from "@corbado/autocapture";
40
+ import {
41
+ captureFederatedIdentity,
42
+ captureWebAuthn,
43
+ captureNetwork,
44
+ captureNavigation,
45
+ composedPath,
46
+ } from "@corbado/autocapture";
39
47
 
40
48
  const webauthn = captureWebAuthn({
41
49
  onEvent: (event) => console.log(event.kind, event.mediation, event.phase, event.ceremonyId),
42
50
  });
43
51
 
52
+ const fedcm = captureFederatedIdentity({
53
+ onEvent: (event) => console.log(event.phase, event.requestId),
54
+ });
55
+
44
56
  const network = captureNetwork({
45
57
  match: (url) => url.origin === location.origin && url.pathname.startsWith("/auth-api/"),
46
58
  bodyCapture: {
@@ -70,6 +82,7 @@ document.addEventListener("click", (event) => {
70
82
 
71
83
  // when finished
72
84
  webauthn.disconnect();
85
+ fedcm.disconnect();
73
86
  network.disconnect();
74
87
  navigation.disconnect();
75
88
  ```
@@ -87,6 +100,14 @@ Autocapture deliberately does not infer product concepts such as conditional-UI
87
100
  known-identifier state, enrollment intent, or the user/system actor. Integrations map those facts in
88
101
  their own state context.
89
102
 
103
+ Federated identity events carry the requested providers (`configURL`, `clientId`), `context`,
104
+ `mode` and `mediation` on `started`; the chosen provider's `configURL` and `isAutoSelected` on
105
+ `completed`; `errorName` (plus an `IdentityCredentialError` `code`) on `failed`. Tokens, nonces,
106
+ provider parameters and login hints are never read. `captureWebAuthn` and `captureFederatedIdentity`
107
+ share one attachment to the credential methods and can start and stop in any order; a later capture
108
+ joins at the surface the first one attached to, so pass `attach: "container"` to whichever starts
109
+ first (see `src/federated-identity.contract.md`).
110
+
90
111
  ## Safety invariants
91
112
 
92
113
  The observers run inside application call paths, so their behaviour is defined by what they promise
@@ -106,10 +127,10 @@ never to disturb:
106
127
  still owned by the capture, and later wrappers are never overwritten. A buried wrapper becomes an
107
128
  inert pass-through after disconnect. Locked WebAuthn methods are never bypassed through a container
108
129
  proxy; the entire WebAuthn attachment is rolled back and reported as unavailable.
109
- - **Exactly-once reporting.** Each patched surface holds a single capture wrapper, so one
110
- application action passes through observation once. A later integration that overwrites a wrapped
111
- method without forwarding through it displaces capture for that surface: the application call
112
- still succeeds, telemetry is lost. A package wrapper hidden below an unknown third-party wrapper
130
+ - **Exactly-once reporting.** Each patched surface holds a single capture wrapper, shared by the
131
+ WebAuthn and federated identity captures, so one application action passes through observation
132
+ once. A later integration that overwrites a wrapped method without forwarding through it
133
+ displaces capture for that surface: the application call still succeeds, telemetry is lost. A package wrapper hidden below an unknown third-party wrapper
113
134
  cannot currently be detected by another copy.
114
135
  - **Conditional removal.** `disconnect()` stops delivery immediately, releases active listeners, and
115
136
  restores only slots still owned by the capture. If another integration sits above it, the inert
@@ -241,6 +262,47 @@ It does not activate automatically or collect field values/message text.
241
262
  See [the API and evidence contract](src/input-validation.contract.md), including the limits of
242
263
  asynchronous DOM inference and the `beginAttempt()`, `requestStarted()`, and `refresh()` methods.
243
264
 
265
+ ## Probe capture (`@corbado/autocapture/probe`)
266
+
267
+ A separate subpath (existing imports of `@corbado/autocapture` do not load it): a config-driven
268
+ diagnostic capture for Corbado autocapture bundles. A JSON config selects surfaces (`page`, `ui`,
269
+ `act`, `nav`, `res`, `store`, `net`, `form`, `err`, `console`, `dl`, `msg`, `glob`, `cev`, each
270
+ `off | inventory | shape | values`), redaction rules, actions (`snapshot`, `correlate`, `count`),
271
+ conditions and a flight-recorder trigger. Redacted items go to an injected sink, normally the
272
+ internal `tracker.probe()` of Observe ≥ 1.4 (no transport of its own).
273
+
274
+ ```ts
275
+ import { startProbes, validateProbeConfig } from "@corbado/autocapture/probe";
276
+
277
+ const handle = startProbes(config, {
278
+ sink: (item) => tracker.probe(item),
279
+ projectId,
280
+ network: { subscribe: (subscriber) => hub.subscribeNetwork(subscriber) }, // else captureNetwork
281
+ navigation: { subscribe: (listener) => hub.subscribeNavigation(listener) }, // else captureNavigation
282
+ webauthn: { subscribe: (listener) => hub.subscribeWebAuthn(listener) }, // taint feed only
283
+ context: () => ({ state, flowType, step }),
284
+ tags: () => flowTags,
285
+ sessionId: () => tracker.getSessionId(),
286
+ });
287
+ handle.signal("step-error"); // trigger / action events from the host
288
+ ```
289
+
290
+ Defaults are conservative: every value no rule names becomes its class (`<email>`, `<digits:6>`,
291
+ `<text:3w>`), free text keeps plain words and classes every other token, and `clear` happens only
292
+ through an explicit rule. Always-on guards that no config can loosen: field values are read through
293
+ one path (password, one-time-code and card fields, and inputs of WebAuthn-bound forms yield at most
294
+ their length), typed secrets, WebAuthn ceremony parts, cookie values and Authorization headers are
295
+ fingerprinted and replaced wherever they show up, a pattern pass removes JWT/JWE, card numbers,
296
+ WebAuthn client data, password/WebAuthn keys and high-entropy tokens, a failing guard drops the item,
297
+ and items are capped at 16 KB (large views are split into several items). One engine per page;
298
+ `startProbes` never throws. When injecting no sources, the engine installs `captureNetwork` /
299
+ `captureNavigation` itself, which then occupy those APIs for other captures on the page.
300
+
301
+ See [the probe contract](src/probe/probe.contract.md) for the config reference and an example
302
+ config. The guard conformance suite (`probeGuardFixtures`, `runProbeGuardFixture`, `applyGuards`) lives
303
+ in its own subpath, `@corbado/autocapture/probe/fixtures`, so bundles that import `/probe` never carry
304
+ its fake secrets. The package is marked `"sideEffects": false`.
305
+
244
306
  ## Local development
245
307
 
246
308
  Run `pnpm --filter @corbado/autocapture... build` from the workspace root before linting or
@@ -0,0 +1 @@
1
+ var pe={log:()=>{}};function _(e){return e?{log:(...r)=>{try{let n=e.log(...r);if(n&&(typeof n=="object"||typeof n=="function"))try{Promise.resolve(n).catch(()=>{})}catch{}}catch{}}}:pe}var re=Symbol.for("corbado.autocapture.installed");function U(e){try{return typeof e=="function"&&Object.prototype.hasOwnProperty.call(e,re)}catch{return!1}}function X(e,r){var o,a;let n=r;try{Object.defineProperty(e,re,{value:r,configurable:!0})}catch{}try{Object.defineProperty(e,"name",{value:(o=n.name)!=null?o:"",configurable:!0})}catch{}try{Object.defineProperty(e,"length",{value:(a=n.length)!=null?a:0,configurable:!0})}catch{}return e}function k(){return{mode:"unavailable",disconnect:()=>{}}}function Z(e,r){return!!e&&"value"in e&&"value"in r&&e.value===r.value&&e.writable===r.writable&&e.enumerable===r.enumerable&&e.configurable===r.configurable}function V(e,r,n,o,a,p=String(r)){try{let c=Object.getOwnPropertyDescriptor(e,r);Z(c,{...o,value:n})&&Object.defineProperty(e,r,o)}catch(c){a.log(`${p} restoration skipped`,c)}}function z(e,r,n){let o=_(e);return a=>{try{let p=n(a);if(p&&(typeof p=="object"||typeof p=="function"))try{Promise.resolve(p).catch(c=>o.log(`${r} listener failed`,c))}catch(c){o.log(`${r} listener failed`,c)}}catch(p){o.log(`${r} listener failed`,p)}}}var oe=0;function ae(){return oe+=1,`network-${oe}`}function fe(e,r){let n=e.responseType;if(n===""||n==="text")return r(e.responseText);if(n==="json"){let o=e.response;return o==null?void 0:r(o)}}var he=500,se=Symbol("body-read-timeout");function ie(e){return/event-stream|octet-stream/i.test(e)?!1:/json|text|urlencoded/i.test(e)}async function ue(e,r){let n=e.body;if(!n)return;let o=n.getReader(),a;try{let p=new Promise(m=>{a=setTimeout(()=>m(se),he)}),c=new TextDecoder,q=[];for(;;){let m=await Promise.race([o.read(),p]);if(m===se){r.log("body omitted: read timed out"),o.cancel().catch(()=>{});return}if(m.done)break;q.push(c.decode(m.value,{stream:!0}))}return q.push(c.decode()),q.join("")}catch{o.cancel().catch(()=>{});return}finally{a!==void 0&&clearTimeout(a)}}function ee(e){var r;(r=e==null?void 0:e.body)==null||r.cancel().catch(()=>{})}function ve(e){var w,P,te;let{onExchange:r,onRequest:n,match:o}=e;if(typeof r!="function"||typeof o!="function")throw new TypeError("captureNetwork requires onExchange and match callbacks");let a=_(e.logger),p=(w=e.transports)!=null?w:["xhr","fetch"],c=(P=e.bodyCapture)==null?void 0:P.request,q=(te=e.bodyCapture)==null?void 0:te.response,m=typeof c=="function",H=typeof q=="function",b=!1,L=z(a,"network",d=>{if(b)return r(d)}),$=z(a,"network request",d=>{if(b)return n==null?void 0:n(d)}),D=(d,h,g)=>{if(typeof g=="function")try{return g(d,h)}catch(y){a.log("body projection failed",y);return}},C=(d,h)=>{try{let g=typeof document!="undefined"?document.baseURI:void 0,y=new URL(String(d),g);return o(y,h)===!0?{url:y.href,path:y.pathname}:void 0}catch{return}},M=()=>{if(typeof XMLHttpRequest=="undefined")return a.log("xhr capture unavailable: XMLHttpRequest missing"),null;let d=XMLHttpRequest.prototype,h=Object.getOwnPropertyDescriptor(d,"open"),g=Object.getOwnPropertyDescriptor(d,"send");if(!h||!("value"in h)||typeof h.value!="function"||!g||!("value"in g)||typeof g.value!="function")return a.log("xhr capture unavailable: XMLHttpRequest methods missing"),null;let y=h.value,F=g.value;if(U(y)||U(F))return a.log("xhr capture unavailable: an equivalent capture is already active"),null;let N=new WeakMap,f=new Set,R=!1,x={open(...l){var i;let t=Reflect.apply(y,this,l);if(!b||!R)return t;try{let E=N.get(this);E&&(E.reported=!0,(i=E.cleanupListeners)==null||i.call(E));let B=String(l[0]).toUpperCase(),v=C(l[1],B);v?N.set(this,{method:B,url:v.url,path:v.path,reported:!1}):N.delete(this)}catch(E){a.log("xhr open observation failed",E)}return t}}.open,j={send(...l){let t=b&&R?N.get(this):void 0;if(!t||t.reported||t.cleanupListeners)return Reflect.apply(F,this,l);let i=()=>{},E=!1;try{t.requestId=ae();let v={direction:"request",transport:"xhr",method:t.method,url:t.url,path:t.path};t.requestBody=m&&typeof l[0]=="string"?D(l[0],v,c):void 0;let K=()=>{t.outcome===void 0&&(t.outcome="abort")},W=()=>{t.outcome===void 0&&(t.outcome="timeout")},s=()=>{t.outcome===void 0&&(t.outcome="error")},u=()=>{var I;i();try{if(!b||!R||t.reported||!t.requestId)return;t.reported=!0;let O={direction:"response",transport:"xhr",method:t.method,url:t.url,path:t.path},Q=this.status,ne={requestId:t.requestId,transport:"xhr",method:t.method,url:t.url,path:t.path,status:Q,ok:Q>=200&&Q<300,outcome:(I=t.outcome)!=null?I:"load",durationMs:t.startedAt!==void 0?Date.now()-t.startedAt:void 0,responseUrl:this.responseURL||void 0,requestBody:t.requestBody,responseBody:H?fe(this,le=>D(le,O,q)):void 0};t.requestEmitted?L(ne):t.pendingExchange=ne}catch(O){a.log("xhr exchange observation failed",O)}finally{N.get(this)===t&&N.delete(this)}},S=()=>{try{this.readyState===XMLHttpRequest.DONE&&this.status!==0&&u()}catch(I){a.log("xhr ready-state observation failed",I)}},T=()=>u();i=()=>{for(let[I,O]of[["readystatechange",S],["abort",K],["timeout",W],["error",s],["loadend",T]])this.removeEventListener(I,O);t.cleanupListeners===i&&(t.cleanupListeners=void 0),f.delete(i)},this.addEventListener("readystatechange",S),this.addEventListener("abort",K),this.addEventListener("timeout",W),this.addEventListener("error",s),this.addEventListener("loadend",T),t.cleanupListeners=i,f.add(i),t.startedAt=Date.now(),E=!0}catch(v){a.log("xhr send observation failed",v),i()}let B;try{B=Reflect.apply(F,this,l)}catch(v){throw i(),v}if(E&&t.requestId!==void 0&&t.startedAt!==void 0){t.requestEmitted=!0,$({requestId:t.requestId,transport:"xhr",method:t.method,url:t.url,path:t.path,startedAt:t.startedAt,requestBody:t.requestBody});let v=t.pendingExchange;t.pendingExchange=void 0,v&&L(v)}return B}}.send;return X(x,y),X(j,F),h.writable!==!0||g.writable!==!0?(a.log("xhr capture unavailable: XMLHttpRequest methods are not writable"),null):(Object.defineProperty(d,"open",{...h,value:x}),Object.defineProperty(d,"send",{...g,value:j}),R=!0,()=>{R=!1;for(let l of[...f])l();V(d,"open",x,h,a),V(d,"send",j,g,a)})},G=()=>{let d=globalThis,h=Object.getOwnPropertyDescriptor(d,"fetch");if(!h||!("value"in h))return a.log("fetch capture unavailable: fetch is not an own data property"),null;let g=h.value;if(typeof g!="function")return a.log("fetch capture unavailable: fetch missing"),null;if(U(g))return a.log("fetch capture unavailable: an equivalent capture is already active"),null;let y=!1,F=async(f,R,x,j)=>{try{if(!b||!y){ee(x);return}let[l,t]=await Promise.all([j!=null?j:Promise.resolve(void 0),x?ue(x,a):Promise.resolve(void 0)]);if(!b||!y)return;let i={direction:"request",transport:"fetch",method:f.method,url:f.url,path:f.path},E={...i,direction:"response"},B=f.requestBody;B===void 0&&l!==void 0&&(B=D(l,i,c));let v=t!==void 0?D(t,E,q):void 0;L({requestId:f.requestId,transport:"fetch",method:f.method,url:f.url,path:f.path,status:R.status,ok:R.ok,outcome:"load",durationMs:Date.now()-f.startedAt,responseUrl:R.url||void 0,requestBody:B,responseBody:v})}catch(l){a.log("fetch exchange observation failed",l)}},N={fetch(...f){var B,v,K,W;let R;try{let s=f[0],u=f[1];if(b&&y&&m&&typeof Request!="undefined"&&s instanceof Request&&(u==null?void 0:u.body)===void 0&&s.body){let S=String((B=u==null?void 0:u.method)!=null?B:s.method).toUpperCase(),T=(v=s.headers.get("content-type"))!=null?v:"";C(s.url,S)&&ie(T)&&(R=s.clone())}}catch(s){a.log("fetch observation failed",s)}let x,j=Date.now();try{x=Reflect.apply(g,this,f)}catch(s){throw ee(R),s}let l,t;try{if(b&&y){let s=f[0],u=f[1],S=typeof Request!="undefined"&&s instanceof Request,T=String((K=u==null?void 0:u.method)!=null?K:S?s.method:"GET").toUpperCase(),I=S?s.url:s,O=C(I,T);O&&(l={requestId:ae(),method:T,url:O.url,path:O.path,startedAt:j},t=(W=u==null?void 0:u.signal)!=null?W:S?s.signal:void 0,m&&typeof(u==null?void 0:u.body)=="string"&&(l.requestBody=D(u.body,{direction:"request",transport:"fetch",method:T,url:O.url,path:O.path},c)))}}catch(s){a.log("fetch observation failed",s)}if(!l)return ee(R),x;let i=l;$({requestId:i.requestId,transport:"fetch",method:i.method,url:i.url,path:i.path,startedAt:i.startedAt,requestBody:i.requestBody});let E=R?ue(R,a):void 0;return x.then(s=>{var S;let u;try{if(b&&y&&H){let T=(S=s.headers.get("content-type"))!=null?S:"";ie(T)&&s.body&&(u=s.clone())}}catch{}F(i,s,u,E)},s=>{try{if(!b||!y)return;let u=(t==null?void 0:t.aborted)===!0||(s==null?void 0:s.name)==="AbortError"||typeof DOMException!="undefined"&&s instanceof DOMException&&s.code===DOMException.ABORT_ERR;L({requestId:i.requestId,transport:"fetch",method:i.method,url:i.url,path:i.path,status:0,ok:!1,outcome:u?"abort":"error",durationMs:Date.now()-i.startedAt})}catch(u){a.log("fetch failure observation failed",u)}}),x}}.fetch;return X(N,g),h.writable!==!0?(a.log("fetch capture unavailable: fetch is not writable"),null):(Object.defineProperty(d,"fetch",{...h,value:N}),y=!0,()=>{y=!1,V(d,"fetch",N,h,a)})},A=[];if(p.includes("xhr")){let d=M();d&&A.push(d)}if(p.includes("fetch")){let d=G();d&&A.push(d)}return A.length===0?k():(b=!0,{mode:"standard",disconnect:()=>{b=!1;for(let d of A.splice(0))d()}})}function we(e){let r=e.onNavigate;if(typeof r!="function")throw new TypeError("captureNavigation requires an onNavigate callback");let n=_(e.logger),o,a,p,c,q,m;try{if(o=window,a=o==null?void 0:o.history,!o||!a)return n.log("navigation capture unavailable: window/history missing"),k();if(q=de(a,"pushState"),m=de(a,"replaceState"),!q||!m)return n.log("navigation capture unavailable: history method descriptors missing"),k();if(p=q.descriptor.value,c=m.descriptor.value,typeof p!="function"||typeof c!="function")return n.log("navigation capture unavailable: history methods missing"),k();if(typeof o.addEventListener!="function"||typeof o.removeEventListener!="function")return n.log("navigation capture unavailable: window event methods missing"),k()}catch(w){return n.log("navigation capture unavailable: history inspection failed",w),k()}if(U(p)||U(c))return n.log("navigation capture unavailable: an equivalent capture is already active"),k();let H=!1,b=()=>({path:o.location.pathname,search:o.location.search,hash:o.location.hash}),L;try{L=b()}catch(w){return n.log("navigation capture unavailable: location inspection failed",w),k()}let $=z(n,"navigation",w=>{if(H)return r(w)}),D=w=>{if(H)try{let P=b();if(P.path===L.path&&P.search===L.search&&P.hash===L.hash)return;L=P,$({...P,source:w})}catch(P){n.log("navigation observation failed",P)}},C={pushState(...w){let P=Reflect.apply(p,this,w);return D("push"),P}}.pushState,M={replaceState(...w){let P=Reflect.apply(c,this,w);return D("replace"),P}}.replaceState;X(C,p),X(M,c);let G=()=>D("pop"),A=()=>D("hash");try{if(ce(q,C),ce(m,M),a.pushState!==C||a.replaceState!==M)throw new Error("history method replacement did not take effect");o.addEventListener("popstate",G),o.addEventListener("hashchange",A),H=!0}catch(w){return H=!1,J(o,"popstate",G,n),J(o,"hashchange",A,n),Y(m,M,n),Y(q,C,n),n.log("navigation capture unavailable: history methods are not writable",w),r=()=>{},$=()=>{},n=_(),k()}return{mode:"standard",disconnect:()=>{H=!1,r=()=>{},J(o,"popstate",G,n),J(o,"hashchange",A,n),Y(q,C,n),Y(m,M,n),$=()=>{},n=_()}}}function de(e,r){let n=e;for(;n;){let o=Object.getOwnPropertyDescriptor(n,r);if(o)return!("value"in o)||typeof o.value!="function"?null:{owner:n,key:r,descriptor:o};n=Object.getPrototypeOf(n)}return null}function ce(e,r){if(e.descriptor.writable!==!0)throw new TypeError(`${e.key} is not writable`);let n=Object.getOwnPropertyDescriptor(e.owner,e.key);if(!Z(n,e.descriptor))throw new Error(`${e.key} changed during installation`);Object.defineProperty(e.owner,e.key,{...e.descriptor,value:r})}function Y(e,r,n){V(e.owner,e.key,r,e.descriptor,n,`navigation ${e.key}`)}function J(e,r,n,o){try{e.removeEventListener(r,n)}catch(a){o.log(`navigation ${r} listener removal skipped`,a)}}var qe="1.2.0";export{_ as a,U as b,X as c,k as d,z as e,ve as f,we as g,qe as h};
@@ -0,0 +1 @@
1
+ var d=Object.defineProperty;var e=(b,a,c)=>a in b?d(b,a,{enumerable:!0,configurable:!0,writable:!0,value:c}):b[a]=c;var f=(b,a,c)=>e(b,typeof a!="symbol"?a+"":a,c);export{f as a};
@@ -0,0 +1 @@
1
+ import{a as E}from"./chunk-JR557W27.mjs";function J(n,t=2166136261){let e=t>>>0;for(let r=0;r<n.length;r++)e^=n.charCodeAt(r),e=Math.imul(e,16777619);return e>>>0}function B(n){return J(n).toString(36).padStart(7,"0")+J(n,1540483477).toString(36).padStart(7,"0")}function Wt(n){return JSON.stringify(_(n))}function _(n){if(Array.isArray(n))return n.map(_);if(n&&typeof n=="object"){let t={};for(let e of Object.keys(n).sort())t[e]=_(n[e]);return t}return n}function nt(n){let t=0;for(let e=0;e<n.length;e++){let r=n.charCodeAt(e);r<128?t+=1:r<2048?t+=2:r>=55296&&r<=56319&&e+1<n.length?(t+=4,e++):t+=3}return t}function Vt(n){try{let t=JSON.stringify(n);return t===void 0?0:nt(t)}catch{return 1/0}}var p=n=>n.toLowerCase().replace(/[-_\s]/g,""),T=new Map;function et(n){let t=T.get(n);if(!t){let e=n.split("").map(r=>r==="*"?".*":r==="?"?".":r.replace(/[.+^${}()|[\]\\/]/g,"\\$&")).join("");t=new RegExp(`^${e}$`,"i"),T.size>500&&T.clear(),T.set(n,t)}return t}function A(n,t){if(n===void 0)return!0;let e=typeof n=="string"?[n]:n;for(let r of e)if(et(r).test(t))return!0;return!1}var k=n=>n===void 0?[]:Array.isArray(n)?n:[n];function x(n){let t=new Uint8Array(n);try{let e=typeof crypto!="undefined"?crypto:void 0;if(e&&typeof e.getRandomValues=="function")return e.getRandomValues(t),t}catch{}for(let e=0;e<n;e++)t[e]=Math.floor(Math.random()*256);return t}var rt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";function Xt(n){let t=x(n),e="";for(let r=0;r<n;r++)e+=rt[t[r]&63];return e}function Gt(n){try{return n()}catch{return}}function O(n){let t=n.trim();if(t.startsWith("{")&&t.endsWith("}")||t.startsWith("[")&&t.endsWith("]"))try{return JSON.parse(t)}catch{return}}function H(n){return!!n&&typeof n=="object"&&!Array.isArray(n)}function Yt(n){try{return n.getAttribute("id")||void 0}catch{return}}function qt(n){var e;let t=(e=n.getAttribute("action"))!=null?e:"";try{return new URL(t,document.baseURI).href}catch{return t}}function Qt(n){return(n.getAttribute("method")||"get").toLowerCase()}var it=new Set(["drop","presence","length"]),st=/(^|\s)(current-password|new-password|one-time-code|cc-[a-z-]+)(\s|$)/i,ot=/(password|passwd|passcode|^pwd$|^otp|otp$|onetime|^pin$|^cvv|^cvc|^ssn$|securitycode|verificationcode)/;function N(n){try{let t=n.value;return typeof t=="string"?t:""}catch{return""}}function X(n){var t,e,r;try{let i=n;if(n.tagName==="INPUT"&&(i.type||"").toLowerCase()==="password")return!0;let s=(t=n.getAttribute("autocomplete"))!=null?t:"";if(st.test(s))return!0;for(let c of[i.name,n.id])if(c&&ot.test(p(c)))return!0;let o=(e=i.form)!=null?e:n.closest("form");if(o){for(let c of Array.from(o.querySelectorAll("input[autocomplete]")).slice(0,50))if(/(^|\s)webauthn(\s|$)/i.test((r=c.getAttribute("autocomplete"))!=null?r:""))return!0}return!1}catch{return!0}}function nn(n,t,e){let r=X(n)&&!it.has(t.method)?{method:"length"}:t;return e(N(n),r)}function en(n){return N(n).length}var F=6,ct=4096,ft=400,z=class{constructor(){E(this,"base1");E(this,"base2");E(this,"byLength",new Map);E(this,"order",[]);let t=x(8),e=r=>(t[r]<<24|t[r+1]<<16|t[r+2]<<8|t[r+3])>>>0;this.base1=(e(0)|65537)>>>0,this.base2=(e(4)|65537)>>>0}get size(){return this.order.length}add(t){if(typeof t!="string"||t.length<F||t.length>ct)return;let e=new Set([t]);try{e.add(encodeURIComponent(t))}catch{}try{e.add(new URLSearchParams({v:t}).toString().slice(2))}catch{}e.add(JSON.stringify(t).slice(1,-1));for(let r of e)this.addOne(r)}addOne(t){var i;let e=this.fingerprint(t,0,t.length),r=this.byLength.get(t.length);if(r||this.byLength.set(t.length,r=new Set),!r.has(e))for(r.add(e),this.order.push([t.length,e]);this.order.length>ft;){let[s,o]=this.order.shift();(i=this.byLength.get(s))==null||i.delete(o)}}fingerprint(t,e,r){let i=0,s=0;for(let o=e;o<e+r;o++){let c=t.charCodeAt(o);i=Math.imul(i,this.base1)+c>>>0,s=Math.imul(s,this.base2)+c>>>0}return`${i}:${s}`}scrub(t){if(this.order.length===0||t.length<F)return t;let e=[];for(let[o,c]of this.byLength){if(c.size===0||o>t.length)continue;let f=1,d=1;for(let u=0;u<o-1;u++)f=Math.imul(f,this.base1)>>>0,d=Math.imul(d,this.base2)>>>0;let h=0,a=0;for(let u=0;u<o;u++){let g=t.charCodeAt(u);h=Math.imul(h,this.base1)+g>>>0,a=Math.imul(a,this.base2)+g>>>0}for(let u=0;;u++){c.has(`${h}:${a}`)&&e.push([u,u+o]);let g=u+o;if(g>=t.length)break;let l=t.charCodeAt(u),b=t.charCodeAt(g);h=Math.imul(h-Math.imul(l,f)>>>0,this.base1)+b>>>0,a=Math.imul(a-Math.imul(l,d)>>>0,this.base2)+b>>>0}}if(e.length===0)return t;e.sort((o,c)=>o[0]-c[0]||c[1]-o[1]);let r="",i=0,s=0;for(;s<e.length;){let[o,c]=e[s];for(s++;s<e.length&&e[s][0]<c;)c=Math.max(c,e[s][1]),s++;o<i&&(o=i),r+=t.slice(i,o)+`<tainted:${c-o}>`,i=c}return r+t.slice(i)}};function rn(n=[]){let t=new z;for(let e of n)t.add(e);return t}var ut=new Set(["challenge","id","rawId","userHandle","signature","clientDataJSON","authenticatorData","attestationObject","publicKey"].map(p));function sn(n,t){if(!t||typeof t!="object")return;let e=t;for(let r of["requestOptionsJson","creationOptionsJson","credentialJson"]){let i=e[r];if(typeof i!="string")continue;n.add(i);let s;try{s=JSON.parse(i)}catch{continue}let o=0,c=(f,d,h)=>{if(!(h>8||++o>500)){if(typeof f=="string"){ut.has(p(d))&&n.add(f);return}if(Array.isArray(f)){for(let a of f.slice(0,50))c(a,d,h+1);return}if(f&&typeof f=="object")for(let[a,u]of Object.entries(f))c(u,a,h+1)}};c(s,"",0)}}function on(n,t){if(t)try{let e=Array.from(t.querySelectorAll("input, textarea")).slice(0,200),r=0;for(let i of e){if(r>=30)break;X(i)&&(r++,n.add(N(i)))}}catch{}}function cn(n,t){for(let e of t.split(";").slice(0,100)){let r=e.indexOf("=");if(r<0)continue;let i=e.slice(r+1).trim();n.add(i);try{let s=decodeURIComponent(i);s!==i&&n.add(s)}catch{}}}function fn(n,t){if(typeof t!="string")return;n.add(t);let e=t.trim().split(/\s+/);e.length>1&&n.add(e.slice(1).join(" "))}var at=new Set(["password","passwd","pwd","passphrase","clientDataJSON","authenticatorData","signature","attestationObject","userHandle","authorization","proxyAuthorization","cookie","setCookie","privateKey","clientSecret"].map(p));function y(n){let t=p(n);return at.has(t)||t.includes("password")}var dt=/eyJ0eXBlIjoid2ViYXV0aG4u[A-Za-z0-9_\-+/=]*/gi,ht=/eyJ[A-Za-z0-9_-]{16,}(?:\.[A-Za-z0-9_-]*){0,4}/gi,gt=/("|\\")(password|passwd|pwd|clientDataJSON|authenticatorData|signature|attestationObject|userHandle|authorization)\1(\s*:\s*)\1(?!<)((?:(?!\1)[^\\]|\\.)*?)\1/gi,lt=/(^|[?&;\s,])(password|passwd|pwd)=([^&\s;,]+)/gi,pt=/\b(Bearer|Basic)\s+([A-Za-z0-9._~+/=-]{8,})/g,mt=/\b((?:proxy-)?authorization)(\s*[:=]\s*|"\s*:\s*")((?:Bearer|Basic|Digest|Token|Negotiate)\s+)?(?!<)([^\s,;"&]+)/gi;function j(n){return n.replace(mt,(t,e,r,i,s)=>`${e}${r}${i!=null?i:""}<redacted:${s.length}>`)}var bt=/\d(?:[ -]?\d){12,}/g,yt=/[A-Za-z0-9_\-+/]{24,}={0,2}/g;function $t(n){let t=0,e=!1;for(let r=n.length-1;r>=0;r--){let i=n.charCodeAt(r)-48;e&&(i*=2,i>9&&(i-=9)),t+=i,e=!e}return t%10===0}function G(n){for(let t=13;t<=Math.min(19,n.length);t++)for(let e=0;e+t<=n.length;e++)if($t(n.slice(e,e+t)))return!0;return!1}function wt(n){var r;let t=new Map;for(let i of n)t.set(i,((r=t.get(i))!=null?r:0)+1);let e=0;for(let i of t.values()){let s=i/n.length;e-=s*Math.log2(s)}return e}function W(n){return n.length>=24&&/\d/.test(n)&&/[A-Za-z]/.test(n)&&wt(n)>=3}var At=/^([A-Za-z][a-z]*(?:[-_.][A-Za-z]+)*|v\d{1,2}|\d{1,5}|)$/;function Rt(n){if(!n.includes("/"))return!1;let t=n.split("/");return t.filter(r=>At.test(r)).length*2>=t.length}function St(n){return Rt(n)?n.split("/").map(t=>W(t)?`<tok:${t.length}>`:t).join("/"):W(n)?`<tok:${n.length}>`:n}function V(n,t){let e=t?t.scrub(n):n;return e=j(e),e=e.replace(gt,(r,i,s,o,c)=>`${i}${s}${i}${o}${i}<redacted:${c.length}>${i}`),e=e.replace(lt,(r,i,s,o)=>o.startsWith("<")?r:`${i}${s}=<redacted:${o.length}>`),e=e.replace(pt,(r,i,s)=>`${i} <redacted:${s.length}>`),e=e.replace(dt,r=>`<webauthn:${r.length}>`),e=e.replace(ht,r=>`<jwt:${r.length}>`),e=e.replace(bt,r=>{let i=r.replace(/[ -]/g,"");return i.length>19?`<digits:${i.length}>`:G(i)?`<card:${i.length}>`:r}),e=e.replace(yt,St),e}function Et(n){if(!Number.isFinite(n))return null;if(!Number.isInteger(n))return n;let t=String(Math.abs(n));return t.length>=13&&G(t)?`<card:${t.length}>`:n}function Tt(n){return n==null||typeof n=="boolean"?n:typeof n=="string"?Ot.test(n)?n:`<redacted:${n.length}>`:typeof n=="number"?"<redacted:num>":"<redacted:obj>"}var Ot=/^<[a-z]+(?::[A-Za-z0-9.]{1,12})?>$/,Mt=24;function L(n,t,e){if(e>Mt)return"<deep>";if(n===null||typeof n=="boolean")return n;if(typeof n=="string")return V(n,t);if(typeof n=="number")return Et(n);if(Array.isArray(n))return n.map(r=>{let i=L(r,t,e+1);return i===void 0?null:i});if(typeof n=="object"){let r={};for(let[i,s]of Object.entries(n)){let o=V(i,t),c=y(i)?Tt(s):L(s,t,e+1);c!==void 0&&(r[o]=c)}return r}}function un(n,t){try{return L(n,t!=null?t:void 0,0)}catch{return}}var _t=/^[^\s@]{1,64}@[^\s@]+\.[^\s@]{2,}$/,kt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,xt=/^[a-z][a-z0-9+.-]*:\/\/\S+$/i,zt=/^\d{4}-\d{2}-\d{2}([T ][\d:.]+(Z|[+-]\d{2}:?\d{2})?)?$/,Lt=/^\+?[\d\s().-]{7,20}$/;function m(n){if(n==="")return"";let t=n.length;return/^eyJ/i.test(n)&&t>20?`<jwt:${t}>`:_t.test(n)?"<email>":kt.test(n)?"<uuid>":xt.test(n)?"<url>":zt.test(n)?"<date>":/^\d+$/.test(n)?`<digits:${t}>`:Lt.test(n)&&/\d{3}/.test(n)?"<phone>":/^(true|false|null|undefined)$/i.test(n)?`<${n.toLowerCase()}>`:/^[A-Za-z]+$/.test(n)?`<alpha:${t}>`:/^[0-9a-f]+$/i.test(n)&&t>=8?`<hex:${t}>`:/^[A-Za-z0-9]+$/.test(n)?`<alnum:${t}>`:/^[A-Za-z0-9_-]+$/.test(n)?`<id:${t}>`:/^[A-Za-z0-9+/]+={0,2}$/.test(n)&&t>=16?`<b64:${t}>`:/\s/.test(n.trim())?`<text:${n.trim().split(/\s+/).length}w>`:`<str:${t}>`}function w(n){return n==null||typeof n=="boolean"?n:typeof n=="number"?Number.isFinite(n)&&Number.isInteger(n)?`<int:${String(Math.abs(n)).length}>`:"<num>":typeof n=="string"?m(n):Array.isArray(n)?`<arr:${n.length}>`:typeof n=="object"?`<obj:${Object.keys(n).length}>`:`<${typeof n}>`}function I(n){return n===null?"null":Array.isArray(n)?"array":typeof n}function P(n,t=0){let e=Math.max(0,Math.min(t,n.length));return n.slice(0,e)+n.slice(e).replace(/[0-9]/g,"9").replace(/[A-Za-zÀ-ɏ]/g,"a")}function Y(n,t=0,e=0){let r=Math.max(0,t),i=Math.max(0,e);return r+i>=n.length?"*".repeat(n.length):n.slice(0,r)+"*".repeat(n.length-r-i)+n.slice(n.length-i)}var Nt=/^[A-Za-zÀ-ɏͰ-ϿЀ-ӿ]+(?:['’_.-][A-Za-zÀ-ɏͰ-ϿЀ-ӿ]+)*$/;function M(n){return n.length<=40&&Nt.test(n)}var R=Symbol("probe.drop"),jt=new Set(["otp","passcode","onetimepassword","onetimecode","securitycode","verificationcode","smscode","pin","cvv","cvc","answer","answers","securityanswer","useranswer","ssn","taxid","tin","socialsecuritynumber","token","accesstoken","idtoken","refreshtoken","sessiontoken","authtoken","bearer","apikey","ticket","codeverifier","secret","samlresponse","samlrequest","wresult","csrf","xsrf","csrftoken","xsrftoken","sessionid","deviceid","publickey","keypair","challenge","credential","assertion"].map(p)),It=/(password|passwd|token|secret|^otp|otp$|answer|ssn|ticket|cookie|credential)/,Pt=/^[A-Za-z0-9_-]{16,}$/,D=3e5,U=4e3,Dt=12,C=100,q=200,Ut=new Set(["drop","presence","length","hash"]),K=/^<[a-z]+(?::[^<>\s]{0,24})?>$/,Ct=/<[a-z]+(?::[^<>\s]{0,24})?>/,Kt=/(<[a-z]+(?::[^<>\s]{0,24})?>)/,Zt=/(^|[^A-Za-z0-9_%]|%[0-9A-Fa-f]{2})([A-Za-z_][A-Za-z0-9_.-]{0,40})(\s*[:=]\s*|%3D|%3A)((?:(?!%26|%2C|%20|%23|%3B|%7C)[^\s&"',;#<>|])+)/gi;function S(n){let t=p(n);return jt.has(t)||It.test(t)}function Jt(n,t){return/^[A-Za-z_$][\w$.:-]{0,63}$/.test(n)&&!/\d{5,}/.test(n)||/^\d{1,4}$/.test(n)?n:`<key${t}:${m(n).replace(/[<>]/g,"")}>`}function Q(n){return n.split("/").map(t=>{if(t==="")return t;let e=t;try{e=decodeURIComponent(t)}catch{}return M(e)||/^v\d{1,2}(\.\d{1,2})?$/i.test(e)||/^\d{1,3}$/.test(e)||/^[A-Za-z][A-Za-z0-9_-]{0,40}(\.[A-Za-z0-9_-]{1,40}){0,3}\.[a-z0-9]{1,6}$/i.test(e)&&!/\d{6,}/.test(e)||/^[a-z]+[-_][a-z0-9]{1,3}$/i.test(e)?t:m(e)}).join("/")}var v=class{constructor(t,e){this.rules=t;this.salt=e}ruleFor(t,e,r){for(let i of this.rules)if(this.matches(i,t,e,r))return i}matches(t,e,r,i){if(t.surface!==void 0&&!k(t.surface).includes(e.surface)||t.part!==void 0&&t.part!==e.part||t.host!==void 0&&(e.host===void 0||!A(t.host,e.host))||t.path!==void 0&&(e.path===void 0||!A(t.path,e.path)))return!1;if(t.selector!==void 0){if(!e.el)return!1;try{if(!e.el.closest(t.selector))return!1}catch{return!1}}return t.key!==void 0?r===void 0?!1:k(t.key).some(s=>Bt(s,r,i!=null?i:r)):!0}method(t,e,r,i=""){var s;switch(e.method){case"drop":return R;case"presence":return t==null?t:t===""||Array.isArray(t)&&t.length===0?"<empty>":"<set>";case"length":return t==null?t:typeof t=="string"?`<len:${t.length}>`:Array.isArray(t)?`<len:${t.length}>`:typeof t=="object"?`<len:${Object.keys(t).length}>`:`<len:${String(t).length}>`;case"hash":return t==null?t:`<h:${B(this.salt+(typeof t=="string"?t:JSON.stringify(t)))}>`;case"shape":return typeof t=="string"?P(t,e.keepPrefix):typeof t=="number"?P(String(t),e.keepPrefix):typeof t=="object"&&t!==null?this.tree(t,r,"shape",i):t;case"mask":return typeof t=="string"||typeof t=="number"?Y(String(t),e.keepStart,e.keepEnd):w(t);case"enum":return t==null||typeof t=="boolean"?t:typeof t=="string"||typeof t=="number"?((s=e.values)!=null?s:[]).includes(String(t))?t:w(t):w(t);case"clear":return this.leaf(t,r,i,e);default:return this.leaf(t,r,i,void 0)}}leaf(t,e,r,i){if(typeof t=="string"){if(t.length>D)return`<len:${t.length}>`;let s=O(t);return s!==void 0&&typeof s=="object"&&s!==null?this.tree(s,e,"values",r,i):/^https?:\/\/\S+$/i.test(t)?this.url(t,e,"values",i):/\s/.test(t.trim())?this.text(t,e,"values",i):i?t:m(t)}return t!==null&&typeof t=="object"?this.tree(t,e,"values",r,i):i?t:w(t)}keyed(t,e,r,i,s){if(y(t))return this.method(e,{method:"length"},r);let o=this.ruleFor(r,t,i);return o?this.method(e,o,r,i):S(t)?this.method(e,{method:"length"},r):p(t)==="code"&&typeof e=="string"&&Pt.test(e)?this.method(e,{method:"length"},r):this.leaf(e,r,i,s)}tree(t,e,r,i="",s,o=0){var c;if(o>Dt)return"<deep>";if(Array.isArray(t)){let f=(c=i.split(".").pop())!=null?c:"",d=[];for(let h of t.slice(0,C)){let a=h!==null&&typeof h=="object"?this.tree(h,e,r,i,s,o+1):this.scalar(f,h,e,r,i,s);a!==R&&d.push(a)}return t.length>C&&d.push(`<more:${t.length-C}>`),d}if(H(t)){let f={},d=typeof t.type=="string"&&"value"in t?t.type:void 0,h=0;for(let[a,u]of Object.entries(t)){if(h>=q){f["<more>"]=Object.keys(t).length-q;break}let g=d!==void 0&&a==="value"?d:a,l=i?`${i}.${g}`:g,b,$=r==="values"?this.hasKeyRule(g,e,l):!!this.restrictiveRule(g,e,l,r);u!==null&&typeof u=="object"&&!$?b=y(g)?this.method(u,{method:"length"},e):this.tree(u,e,r,l,s,o+1):b=this.scalar(g,u,e,r,l,s),b!==R&&(f[Jt(a,h)]=b),h++}return f}return this.scalar("",t,e,r,i,s)}hasKeyRule(t,e,r){var i;return y(t)||S(t)||((i=this.ruleFor(e,t,r))==null?void 0:i.key)!==void 0}restrictiveRule(t,e,r,i){if(!t)return;let s=this.ruleFor(e,t,r);if(!(!s||s.key===void 0))return s.method==="drop"||i==="shape"&&Ut.has(s.method)?s:void 0}scalar(t,e,r,i,s,o){if(i!=="values"){let f=this.restrictiveRule(t,r,s,i);if(f)return this.method(e,f,r,s)}if(i==="inventory")return I(e);if(i==="shape"){if(t&&(y(t)||S(t)))return this.method(e,{method:"length"},r);if(typeof e=="string"){let f=e.length<=D?O(e):void 0;if(f!==void 0&&typeof f=="object"&&f!==null)return this.tree(f,r,"shape",s)}return w(e)}if(t)return this.keyed(t,e,r,s,o);let c=this.ruleFor(r);return c?this.method(e,c,r,s):this.leaf(e,r,s,o)}text(t,e,r,i){if(r==="inventory"||r==="shape")return m(t);if(!i){let o=this.ruleFor(e);if(o){if(o.method==="class")return m(t);let c=this.method(t,o,e);if(c===R)return"";if(o.method!=="clear")return typeof c=="string"?c:JSON.stringify(c);i=o}}let s=j(t).replace(Zt,(o,c,f,d,h)=>{if(K.test(h))return o;let a;if(y(f))a=`<redacted:${h.length}>`;else{let u=this.ruleFor(e,f,f);u&&u.key!==void 0?a=this.method(h,u,e,f):S(f)&&(a=`<redacted:${h.length}>`)}return a===void 0?o:`${c}${f}${d}${a===R?"<dropped>":String(a)}`});return i?s:s.replace(/\S+/g,o=>this.token(o,e))}token(t,e,r=0){var f,d,h,a;if(K.test(t))return t;if(Ct.test(t))return t.split(Kt).map((u,g)=>g%2===1||u===""?u:this.token(u,e,r)).join("");let i=(d=(f=/^[([{"'“‘|<]+/.exec(t))==null?void 0:f[0])!=null?d:"",s=(a=(h=/[)\]}"'”’,.;:=!?|>/]+$/.exec(t.slice(i.length)))==null?void 0:h[0])!=null?a:"",o=t.slice(i.length,t.length-s.length);if(o===""||K.test(o)||M(o)||/^\d{1,3}$/.test(o))return t;if(/^https?:\/\//i.test(o))return i+this.url(o,e,"values")+s;let c=r===0?/[:=]/.exec(o):null;if(c&&c.index>0&&c.index<o.length-1){let u=o.slice(0,c.index),g=o.slice(c.index+1);return i+this.token(u,e,1)+c[0]+this.token(g,e,1)+s}return i+m(o)+s}url(t,e,r,i){var h;let s;try{s=new URL(t,typeof location!="undefined"?location.href:void 0)}catch{return r==="inventory"?"<url>":m(t)}let o={...e,host:s.hostname,path:s.pathname,part:(h=e.part)!=null?h:"url"},c=`${s.protocol}//${s.host}${Q(s.pathname)}`;if(r==="inventory")return c;let f=a=>{let u=[];return new URLSearchParams(a).forEach((g,l)=>{if(u.length>=60)return;let b=/^[\w.[\]-]{1,64}$/.test(l)?l:m(l),$;if(r==="shape"){let Z=this.restrictiveRule(l,o,l,r);$=Z?this.method(g,Z,o,l):y(l)||S(l)?`<len:${g.length}>`:w(g)}else $=this.keyed(l,g,o,l,i);$!==R&&u.push(`${b}=${typeof $=="string"?$:JSON.stringify($)}`)}),u.join("&")};s.search.length>1&&(c+=`?${f(s.search.slice(1))}`);let d=s.hash.slice(1);if(d)if(d.startsWith("/")){let a=d.indexOf("?");c+=`#${Q(a<0?d:d.slice(0,a))}${a<0?"":`?${f(d.slice(a+1))}`}`}else d.includes("=")?c+=`#${f(d)}`:c+=`#${M(d)?d:m(d)}`;return c}body(t,e,r){try{if(t==null)return;if(r==="inventory")return{type:I(t)};if(typeof t=="string"){if(t.length>D)return{len:t.length,skipped:"size"};let i=O(t);if(i!==void 0)return this.tree(i,e,r);if(Ht(t))return{form:this.tree(tt(new URLSearchParams(t)),e,r)};if(r==="shape")return{text:m(t)};let s=t.length>U?t.slice(0,U):t,o=Ft(s),c=/^\s*</.test(o)?o.replace(/</g," <").replace(/>/g,"> "):o;return{text:this.text(c,e,r).trim(),...t.length>U?{len:t.length}:{}}}if(typeof URLSearchParams!="undefined"&&t instanceof URLSearchParams)return{form:this.tree(tt(t),e,r)};if(typeof FormData!="undefined"&&t instanceof FormData){let i={};return t.forEach((s,o)=>{i[o]=typeof s=="string"?s:`<file:${s.size}>`}),{formData:this.tree(i,e,r)}}return typeof Blob!="undefined"&&t instanceof Blob?{blob:t.size}:typeof ArrayBuffer!="undefined"&&(t instanceof ArrayBuffer||ArrayBuffer.isView(t))?{bytes:t.byteLength}:typeof t=="object"?this.tree(t,e,r):this.scalar("",t,e,r,"")}catch{return{error:"redact-failed"}}}};function Bt(n,t,e){return n.includes(".")?A(n,e)||A(`*.${n}`,e):n.includes("*")||n.includes("?")?A(n,t):p(n)===p(t)}function Ht(n){return/^[^\s<>{}=&]+=[^\s<>]*(&[^\s<>{}=&]+=[^\s<>]*)*$/.test(n.trim())}function tt(n){let t={};return n.forEach((e,r)=>{r in t?t[r]=[].concat(t[r],e):t[r]=e}),t}function Ft(n){let t=e=>y(e)||S(e);return n.replace(/(<input\b[^>]*\bname\s*=\s*["']?([\w.-]+)["']?[^>]*\bvalue\s*=\s*)(["'])([^"'>]*)\3/gi,(e,r,i,s,o)=>t(i)?`${r}${s}<redacted:${o.length}>${s}`:e).replace(/(<input\b[^>]*\bvalue\s*=\s*)(["'])([^"'>]*)\2([^>]*\bname\s*=\s*["']?([\w.-]+)["']?)/gi,(e,r,i,s,o,c)=>t(c)?`${r}${i}<redacted:${s.length}>${i}${o}`:e)}export{J as a,B as b,Wt as c,Vt as d,A as e,k as f,Xt as g,Gt as h,O as i,H as j,Yt as k,qt as l,Qt as m,nn as n,en as o,z as p,rn as q,sn as r,on as s,cn as t,fn as u,un as v,m as w,w as x,I as y,R as z,Q as A,v as B};
@@ -0,0 +1,351 @@
1
+ import { p as NetworkBodyProjectionContext, l as HttpRequestStarted, H as HttpExchange, m as NavigationEvent, v as WebAuthnCeremonyEvent } from './types-lamU1Fd3.mjs';
2
+
3
+ /** Capture depth of a surface. `values` applies the redaction rules; anything no rule names becomes its class. */
4
+ type ProbeLevel = "off" | "inventory" | "shape" | "values";
5
+ /** Everything a probe config can observe. */
6
+ type ProbeSurface = "page" | "ui" | "act" | "nav" | "res" | "store" | "net" | "form" | "err" | "console" | "dl" | "msg" | "glob" | "cev";
7
+ /**
8
+ * Redaction method of a rule.
9
+ *
10
+ * - `drop`: the key / element is left out.
11
+ * - `presence`: `<set>` or `<empty>`.
12
+ * - `length`: `<len:n>`.
13
+ * - `class`: a coarse class such as `<email>`, `<digits:6>`, `<alpha:5>`, `<uuid>`, `<text:4w>` (the default).
14
+ * - `shape`: format mask — digits → `9`, letters → `a`, separators kept; optional `keepPrefix`.
15
+ * - `hash`: `<h:…>`, salted per page (the salt never leaves the page).
16
+ * - `mask`: `*` for every character except `keepStart` / `keepEnd`.
17
+ * - `enum`: the value when it is one of `values`, its class otherwise.
18
+ * - `clear`: the value itself (still subject to the always-on guards).
19
+ */
20
+ type ProbeMethod = "drop" | "presence" | "length" | "class" | "shape" | "hash" | "mask" | "enum" | "clear";
21
+ /** Options shared by every surface. */
22
+ type ProbeSurfaceConfig = {
23
+ level: ProbeLevel;
24
+ };
25
+ /** `net` surface options. */
26
+ type ProbeNetSurfaceConfig = ProbeSurfaceConfig & {
27
+ /** Host globs to observe (default: every host except Corbado's own). */
28
+ hosts?: string[];
29
+ /** Host globs never observed (Corbado's own hosts are always excluded). */
30
+ excludeHosts?: string[];
31
+ /** Path globs to observe (default: every path). */
32
+ paths?: string[];
33
+ /** Uppercase methods to observe (default: all). */
34
+ methods?: string[];
35
+ /** Read and redact bodies at `shape` / `values` (default true). */
36
+ bodies?: boolean;
37
+ };
38
+ /** `res` surface options. */
39
+ type ProbeResSurfaceConfig = ProbeSurfaceConfig & {
40
+ /** Host globs (default: all but Corbado's own). */
41
+ hosts?: string[];
42
+ /** Poll interval for new Resource Timing entries (default 5000 ms, min 1000). */
43
+ everyMs?: number;
44
+ };
45
+ /** `ui` surface options. */
46
+ type ProbeUiSurfaceConfig = ProbeSurfaceConfig & {
47
+ /** Max distinct views per document (default 30). */
48
+ maxViews?: number;
49
+ };
50
+ /** `console` surface options. */
51
+ type ProbeConsoleSurfaceConfig = ProbeSurfaceConfig & {
52
+ /** Console methods to observe (default `["error", "warn"]`). */
53
+ levels?: Array<"error" | "warn" | "info" | "log" | "debug">;
54
+ };
55
+ type ProbeSurfaces = {
56
+ page?: ProbeLevel | ProbeSurfaceConfig;
57
+ ui?: ProbeLevel | ProbeUiSurfaceConfig;
58
+ act?: ProbeLevel | ProbeSurfaceConfig;
59
+ nav?: ProbeLevel | ProbeSurfaceConfig;
60
+ res?: ProbeLevel | ProbeResSurfaceConfig;
61
+ store?: ProbeLevel | ProbeSurfaceConfig;
62
+ net?: ProbeLevel | ProbeNetSurfaceConfig;
63
+ form?: ProbeLevel | ProbeSurfaceConfig;
64
+ err?: ProbeLevel | ProbeSurfaceConfig;
65
+ console?: ProbeLevel | ProbeConsoleSurfaceConfig;
66
+ dl?: ProbeLevel | ProbeSurfaceConfig;
67
+ msg?: ProbeLevel | ProbeSurfaceConfig;
68
+ glob?: ProbeLevel | ProbeSurfaceConfig;
69
+ cev?: ProbeLevel | ProbeSurfaceConfig;
70
+ };
71
+ /** Method options (used by rules, snapshot fields and correlate values). */
72
+ type ProbeMethodOptions = {
73
+ method: ProbeMethod;
74
+ /** `enum`: the values that may be emitted as they are. */
75
+ values?: string[];
76
+ /** `shape`: leading characters kept as they are. */
77
+ keepPrefix?: number;
78
+ /** `mask`: characters kept at the start / end. */
79
+ keepStart?: number;
80
+ keepEnd?: number;
81
+ };
82
+ /**
83
+ * One redaction rule. A rule applies when every scope it names matches; the first matching rule wins.
84
+ * Keys are compared case-insensitively with `-`, `_` and spaces ignored; a key containing `.` is a dotted
85
+ * path glob matched against the end of the value's path (`data.json_data.bound`, `*.assertion_id`).
86
+ */
87
+ type ProbeRule = ProbeMethodOptions & {
88
+ surface?: ProbeSurface | ProbeSurface[];
89
+ /** Host globs of the URL the value belongs to (`net`, `res`, `page`, `nav`); the page host for DOM surfaces. */
90
+ host?: string | string[];
91
+ /** Path globs of that URL; the page path for DOM surfaces. */
92
+ path?: string | string[];
93
+ /** Key names or dotted path globs (body keys, query parameters, storage keys, form field names). */
94
+ key?: string | string[];
95
+ /** CSS selector (`ui`, `act`, `form`): applies to matching elements and their subtree. */
96
+ selector?: string;
97
+ /** `net` only: which part of the exchange. */
98
+ part?: "url" | "request" | "response";
99
+ };
100
+ /** Network matcher. */
101
+ type ProbeNetMatch = {
102
+ host?: string | string[];
103
+ path?: string | string[];
104
+ method?: string | string[];
105
+ /** Status codes, or `ok` (2xx/3xx) / `error` (0, ≥ 400 or not loaded). Ignored at request time. */
106
+ status?: number[] | "ok" | "error";
107
+ /** Request body conditions: dotted path → expected value(s), compared as strings. */
108
+ body?: Record<string, string | string[]>;
109
+ /** Response body conditions (same form). */
110
+ response?: Record<string, string | string[]>;
111
+ };
112
+ /** Something that happens on the page: used by `trigger.on`, `snapshot.on` and `count.on`. */
113
+ type ProbeMatch = {
114
+ net?: ProbeNetMatch;
115
+ /** A visible element matching this selector appears. */
116
+ selector?: string;
117
+ /** A click on (or inside) an element matching this selector. */
118
+ click?: string;
119
+ /** A form submit (`true` = any form, string = form selector). */
120
+ submit?: string | true;
121
+ /** `handle.signal(name)` from the host. */
122
+ signal?: string;
123
+ /** The host context (`deps.context().state`) enters this state. */
124
+ state?: string;
125
+ /** An uncaught error or unhandled rejection. */
126
+ error?: true;
127
+ };
128
+ /** A body value to read: dotted path (`[]` iterates arrays, `**` searches any depth; JSON strings are parsed). */
129
+ type ProbePathPick = Partial<ProbeMethodOptions> & {
130
+ path: string;
131
+ /** Output name (default: the path). */
132
+ as?: string;
133
+ };
134
+ type ProbeSnapshotAction = {
135
+ type: "snapshot";
136
+ name: string;
137
+ on: ProbeMatch;
138
+ /** Form fields: value via `method` (default `class`), validity flags, `aria-invalid`, nearby error text. */
139
+ fields?: Array<Partial<ProbeMethodOptions> & {
140
+ selector: string;
141
+ as?: string;
142
+ }>;
143
+ /** Visible texts of these selectors (free-text redaction). */
144
+ texts?: string[];
145
+ /** Request / response body values (only when `on.net` matched). */
146
+ request?: ProbePathPick[];
147
+ response?: ProbePathPick[];
148
+ /** Max snapshots per document (default 20). */
149
+ max?: number;
150
+ };
151
+ /**
152
+ * Remember `key → value` pairs seen in one exchange and resolve the key in a later one, emitting only the
153
+ * value (e.g. an OTP send: the channel id never leaves the page, its channel type does).
154
+ */
155
+ type ProbeCorrelateAction = {
156
+ type: "correlate";
157
+ name: string;
158
+ /** Item kind (default `corr`). */
159
+ kind?: string;
160
+ learn: {
161
+ net: ProbeNetMatch;
162
+ /** Body to learn from (default `response`). */
163
+ from?: "request" | "response";
164
+ /** Path of the objects to learn from (e.g. `**.channels[]`). */
165
+ items: string;
166
+ /** Path of the key inside an item (kept in memory only). */
167
+ key: string;
168
+ /** Path of the value inside an item. */
169
+ value: string;
170
+ /** How the value is emitted (default `enum` with `values`, else `class`). */
171
+ method?: ProbeMethod;
172
+ values?: string[];
173
+ /** Paths inside an item whose size is reported with the offered values (object keys / array length / 1). */
174
+ count?: string[];
175
+ };
176
+ resolve: {
177
+ net: ProbeNetMatch;
178
+ /** Body holding the key (default `request`). */
179
+ from?: "request" | "response";
180
+ /** Path(s) of the key; the first that resolves wins. */
181
+ key: string | string[];
182
+ /** Extra values emitted with the result. */
183
+ fields?: ProbePathPick[];
184
+ };
185
+ /** Max emissions per document (default 50). */
186
+ max?: number;
187
+ };
188
+ type ProbeCountAction = {
189
+ type: "count";
190
+ name: string;
191
+ on: ProbeMatch;
192
+ };
193
+ type ProbeAction = ProbeSnapshotAction | ProbeCorrelateAction | ProbeCountAction;
194
+ /** Conditions; all must hold. */
195
+ type ProbeWhen = {
196
+ /** Observe project ids (`deps.projectId`). */
197
+ projects?: string[];
198
+ /** ISO 8601 date or date-time; the probe is off after it. */
199
+ until?: string;
200
+ /** Fraction 0..1 of sessions, sticky per session id. */
201
+ sample?: number;
202
+ /** Browser names: `chrome`, `edge`, `safari`, `firefox`, `samsung`, `opera`, `other`. */
203
+ browser?: string[];
204
+ /** OS names: `windows`, `macos`, `ios`, `android`, `linux`, `chromeos`, `other`. */
205
+ os?: string[];
206
+ device?: Array<"desktop" | "mobile" | "tablet">;
207
+ /** Page path globs, evaluated per item. */
208
+ path?: string[];
209
+ /** Host context states (`deps.context().state`), evaluated per item. */
210
+ state?: string[];
211
+ /** Flow tags (`deps.tags()`): tag → allowed values (`*` = any). Items are buffered until the tag is known. */
212
+ tags?: Record<string, string[]>;
213
+ /** Integration version globs (`deps.integrationVersion`). */
214
+ integrationVersion?: string[];
215
+ };
216
+ /** Flight recorder: items are buffered and only sent when one of `on` happens. */
217
+ type ProbeTrigger = {
218
+ on: ProbeMatch[];
219
+ /** Ring buffer size in items (default 300) and bytes (default 300000). */
220
+ buffer?: number;
221
+ bufferBytes?: number;
222
+ /** After a trigger, items stream directly for this long (default 30000 ms) before buffering resumes. */
223
+ streamMs?: number;
224
+ };
225
+ type ProbeBudgets = {
226
+ /** Items per document (default 400). */
227
+ items?: number;
228
+ /** Serialized bytes per document (default 400000). */
229
+ bytes?: number;
230
+ /** Items per document and kind (defaults per kind, e.g. `ui` 40, `act` 150, `net` 150). */
231
+ perKind?: Record<string, number>;
232
+ };
233
+ /** Probe configuration, schema version 1. */
234
+ type ProbeConfig = {
235
+ v: 1;
236
+ /** Free label (not interpreted). */
237
+ name?: string;
238
+ when?: ProbeWhen;
239
+ trigger?: ProbeTrigger;
240
+ surfaces?: ProbeSurfaces;
241
+ rules?: ProbeRule[];
242
+ actions?: ProbeAction[];
243
+ budgets?: ProbeBudgets;
244
+ };
245
+ /** Host context stamped on items. */
246
+ type ProbeItemContext = {
247
+ state?: string;
248
+ flowType?: string;
249
+ step?: string;
250
+ };
251
+ /** What the engine hands to the sink (→ `tracker.probe`). */
252
+ type ProbeSinkItem = {
253
+ kind: string;
254
+ payload: Record<string, unknown> | unknown[];
255
+ pageId: string;
256
+ cfg: string;
257
+ ctx?: ProbeItemContext;
258
+ ts: number;
259
+ };
260
+ /**
261
+ * A network subscriber, shaped like autocapture-x's CaptureHub `NetworkSubscriber`: projectors run
262
+ * synchronously inside the network capture and are the only place raw bodies are seen.
263
+ */
264
+ type ProbeNetworkSubscriber = {
265
+ id: string;
266
+ match(url: URL, method: string): boolean;
267
+ projectRequest?(body: unknown, context: NetworkBodyProjectionContext<"request">): unknown;
268
+ projectResponse?(body: unknown, context: NetworkBodyProjectionContext<"response">): unknown;
269
+ onRequest?(request: HttpRequestStarted<unknown>): void;
270
+ onExchange?(exchange: HttpExchange<unknown, unknown>): void;
271
+ };
272
+ /** CaptureHub-compatible network source: `{ subscribe: (s) => hub.subscribeNetwork(s) }`. */
273
+ type ProbeNetworkSource = {
274
+ /** Called synchronously by `startProbes`; may return an unsubscribe function. */
275
+ subscribe(subscriber: ProbeNetworkSubscriber): (() => void) | void;
276
+ };
277
+ type ProbeNavigationSource = {
278
+ subscribe(listener: (event: NavigationEvent) => void): (() => void) | void;
279
+ };
280
+ type ProbeWebAuthnSource = {
281
+ subscribe(listener: (event: WebAuthnCeremonyEvent) => void): (() => void) | void;
282
+ };
283
+ type ProbeDeps = {
284
+ /** Receives every redacted item (→ `tracker.probe(item)`). */
285
+ sink(item: ProbeSinkItem): void;
286
+ projectId: string;
287
+ /** Network source; falls back to the package's own `captureNetwork` when absent. */
288
+ network?: ProbeNetworkSource;
289
+ /** Navigation source; falls back to `captureNavigation` when absent. */
290
+ navigation?: ProbeNavigationSource;
291
+ /** WebAuthn events, used only to taint ceremony values; none when absent. */
292
+ webauthn?: ProbeWebAuthnSource;
293
+ context?(): ProbeItemContext | undefined;
294
+ tags?(): Record<string, string> | undefined;
295
+ /** Session id for sticky sampling. */
296
+ sessionId?(): string | undefined;
297
+ /** For `when.integrationVersion`. */
298
+ integrationVersion?: string;
299
+ now?(): number;
300
+ };
301
+ type ProbeHandle = {
302
+ /** `active`: capturing; `off`: a condition does not hold or the config is invalid; `unavailable`: no page or another engine runs. */
303
+ readonly mode: "active" | "off" | "unavailable";
304
+ /** Config hash stamped on every item (`cfg`). */
305
+ readonly hash: string;
306
+ /** Why the probe is not active. */
307
+ readonly reason?: string;
308
+ /** Host-signalled event (e.g. a step error) for `trigger.on` / actions `{ signal }`. */
309
+ signal(name: string): void;
310
+ disconnect(): void;
311
+ };
312
+
313
+ /**
314
+ * Always-on guards. Not configurable: no config field reaches them.
315
+ *
316
+ * 1. Single DOM value read path: every field value read goes through {@link readFieldValue} /
317
+ * {@link fieldValueLength}; sensitive fields (passwords, one-time codes, card fields, inputs of
318
+ * WebAuthn-bound forms) yield at most their length.
319
+ * 2. Taint set: values that must never leave (typed passwords / OTPs, WebAuthn ceremony parts, cookie
320
+ * values, Authorization headers) are kept as salted rolling hashes; any occurrence anywhere in an
321
+ * item becomes `<tainted:len>`.
322
+ * 3. Pattern pass: JWT / JWE (any case), base64url WebAuthn client data, Luhn-valid card numbers,
323
+ * WebAuthn / password keys, high-entropy tokens ≥ 24 chars.
324
+ * 4. Fail closed: a guard that throws drops the item.
325
+ */
326
+
327
+ /** Salted rolling-hash fingerprints of values that must never leave. Values themselves are not kept. */
328
+ declare class ProbeTaint {
329
+ private readonly base1;
330
+ private readonly base2;
331
+ private readonly byLength;
332
+ private readonly order;
333
+ constructor();
334
+ /** Number of fingerprints held. */
335
+ get size(): number;
336
+ /** Adds a value (and its URL-encoded / JSON-escaped forms). Values under 6 chars are ignored. */
337
+ add(value: unknown): void;
338
+ private addOne;
339
+ private fingerprint;
340
+ /** Replaces every tainted occurrence with `<tainted:len>`. */
341
+ scrub(text: string): string;
342
+ }
343
+ /** A fresh taint set (for tests / the conformance runner), optionally pre-filled. */
344
+ declare function createProbeTaint(values?: string[]): ProbeTaint;
345
+ /**
346
+ * The final always-on pass over an item: taint, pattern and key guards. Returns a guarded copy, or
347
+ * `undefined` when the pass fails (the item must then be dropped — fail closed).
348
+ */
349
+ declare function applyGuards(item: unknown, taint?: ProbeTaint | null): unknown;
350
+
351
+ export { type ProbeTrigger as A, type ProbeUiSurfaceConfig as B, type ProbeWebAuthnSource as C, type ProbeWhen as D, applyGuards as E, createProbeTaint as F, type ProbeConfig as P, type ProbeDeps as a, type ProbeHandle as b, type ProbeAction as c, type ProbeBudgets as d, type ProbeConsoleSurfaceConfig as e, type ProbeCorrelateAction as f, type ProbeCountAction as g, type ProbeItemContext as h, type ProbeLevel as i, type ProbeMatch as j, type ProbeMethod as k, type ProbeMethodOptions as l, type ProbeNavigationSource as m, type ProbeNetMatch as n, type ProbeNetSurfaceConfig as o, type ProbeNetworkSource as p, type ProbeNetworkSubscriber as q, type ProbePathPick as r, type ProbeResSurfaceConfig as s, type ProbeRule as t, type ProbeSinkItem as u, type ProbeSnapshotAction as v, type ProbeSurface as w, type ProbeSurfaceConfig as x, type ProbeSurfaces as y, ProbeTaint as z };