image-pii-redactor 0.3.4 → 0.3.5

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
@@ -1,5 +1,8 @@
1
1
  # image-pii-redactor
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/image-pii-redactor)](https://www.npmjs.com/package/image-pii-redactor)
4
+ [![npm downloads](https://img.shields.io/npm/dm/image-pii-redactor)](https://www.npmjs.com/package/image-pii-redactor)
5
+
3
6
  A Web Component that redacts personal information from AI chat screenshots entirely in the browser. No data ever leaves your device.
4
7
 
5
8
  **[Try the live demo →](https://athal7.github.io/image-pii-redactor/)**
@@ -815,11 +815,18 @@ const nt = Re`
815
815
  flex-wrap: wrap;
816
816
  }
817
817
 
818
- /* Utility row: Add box, Undo, Select all, Deselect all */
818
+ /* Utility row: Add box, Undo, Select all, Deselect all — compact on mobile */
819
819
  .toolbar-utils {
820
820
  flex-wrap: wrap;
821
821
  }
822
822
 
823
+ .toolbar-utils button {
824
+ flex: 1;
825
+ min-width: 0;
826
+ padding: 8px 10px;
827
+ font-size: 13px;
828
+ }
829
+
823
830
  /* Actions row: Cancel + Confirm always together, Confirm stretches to fill */
824
831
  .toolbar-actions {
825
832
  display: flex;
@@ -1 +1 @@
1
- {"version":3,"file":"image-pii-redactor.js","sources":["../node_modules/@lit/reactive-element/css-tag.js","../node_modules/@lit/reactive-element/reactive-element.js","../node_modules/lit-html/lit-html.js","../node_modules/lit-element/lit-element.js","../node_modules/@lit/reactive-element/decorators/custom-element.js","../node_modules/@lit/reactive-element/decorators/property.js","../node_modules/@lit/reactive-element/decorators/state.js","../node_modules/@lit/reactive-element/decorators/base.js","../node_modules/@lit/reactive-element/decorators/query.js","../src/component/styles.ts","../src/component/icons.ts","../src/pipeline/preprocess.ts","../src/pipeline/ocr.ts","../src/pipeline/pii-ner.ts","../src/pipeline/pii-regex.ts","../src/pipeline/bridge.ts","../src/pipeline/redact.ts","../src/pipeline/index.ts","../src/types.ts","../src/component/pii-redactor.ts","../src/sw-registration.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&\"adoptedStyleSheets\"in Document.prototype&&\"replace\"in CSSStyleSheet.prototype,s=Symbol(),o=new WeakMap;class n{constructor(t,e,o){if(this._$cssResult$=!0,o!==s)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const s=this.t;if(e&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o.set(s,t))}return t}toString(){return this.cssText}}const r=t=>new n(\"string\"==typeof t?t:t+\"\",void 0,s),i=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,s,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if(\"number\"==typeof t)return t;throw Error(\"Value passed to 'css' function must be a 'css' function result: \"+t+\". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.\")})(s)+t[o+1],t[0]);return new n(o,t,s)},S=(s,o)=>{if(e)s.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement(\"style\"),n=t.litNonce;void 0!==n&&o.setAttribute(\"nonce\",n),o.textContent=e.cssText,s.appendChild(o)}},c=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e=\"\";for(const s of t.cssRules)e+=s.cssText;return r(e)})(t):t;export{n as CSSResult,S as adoptStyles,i as css,c as getCompatibleStyle,e as supportsAdoptingStyleSheets,r as unsafeCSS};\n//# sourceMappingURL=css-tag.js.map\n","import{getCompatibleStyle as t,adoptStyles as s}from\"./css-tag.js\";export{CSSResult,css,supportsAdoptingStyleSheets,unsafeCSS}from\"./css-tag.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const{is:i,defineProperty:e,getOwnPropertyDescriptor:h,getOwnPropertyNames:r,getOwnPropertySymbols:o,getPrototypeOf:n}=Object,a=globalThis,c=a.trustedTypes,l=c?c.emptyScript:\"\",p=a.reactiveElementPolyfillSupport,d=(t,s)=>t,u={toAttribute(t,s){switch(s){case Boolean:t=t?l:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},f=(t,s)=>!i(t,s),b={attribute:!0,type:String,converter:u,reflect:!1,useDefault:!1,hasChanged:f};Symbol.metadata??=Symbol(\"metadata\"),a.litPropertyMetadata??=new WeakMap;class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=!0),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e(this.prototype,t,h)}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t}};return{get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d(\"elementProperties\")))return;const t=n(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(d(\"finalized\")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(d(\"properties\"))){const t=this.properties,s=[...r(t),...o(t)];for(const i of s)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(t(s))}else void 0!==s&&i.push(t(s));return i}static _$Eu(t,s){const i=s.attribute;return!1===i?void 0:\"string\"==typeof i?i:\"string\"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return s(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,s,i){this._$AK(t,i)}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&!0===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h=\"function\"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null}}requestUpdate(t,s,i,e=!1,h){if(void 0!==t){const r=this.constructor;if(!1===e&&(h=this[t]),i??=r.getPropertyOptions(t),!((i.hasChanged??f)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,i))))return;this.C(t,s,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),!0!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),!0===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];!0!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e)}}let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(s)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(s)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}y.elementStyles=[],y.shadowRootOptions={mode:\"open\"},y[d(\"elementProperties\")]=new Map,y[d(\"finalized\")]=new Map,p?.({ReactiveElement:y}),(a.reactiveElementVersions??=[]).push(\"2.1.2\");export{y as ReactiveElement,s as adoptStyles,u as defaultConverter,t as getCompatibleStyle,f as notEqual};\n//# sourceMappingURL=reactive-element.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,i=t=>t,s=t.trustedTypes,e=s?s.createPolicy(\"lit-html\",{createHTML:t=>t}):void 0,h=\"$lit$\",o=`lit$${Math.random().toFixed(9).slice(2)}$`,n=\"?\"+o,r=`<${n}>`,l=document,c=()=>l.createComment(\"\"),a=t=>null===t||\"object\"!=typeof t&&\"function\"!=typeof t,u=Array.isArray,d=t=>u(t)||\"function\"==typeof t?.[Symbol.iterator],f=\"[ \\t\\n\\f\\r]\",v=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${f}(?:([^\\\\s\"'>=/]+)(${f}*=${f}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,\"g\"),g=/'/g,$=/\"/g,y=/^(?:script|style|textarea|title)$/i,x=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),b=x(1),w=x(2),T=x(3),E=Symbol.for(\"lit-noChange\"),A=Symbol.for(\"lit-nothing\"),C=new WeakMap,P=l.createTreeWalker(l,129);function V(t,i){if(!u(t)||!t.hasOwnProperty(\"raw\"))throw Error(\"invalid template strings array\");return void 0!==e?e.createHTML(i):i}const N=(t,i)=>{const s=t.length-1,e=[];let n,l=2===i?\"<svg>\":3===i?\"<math>\":\"\",c=v;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,f=0;for(;f<s.length&&(c.lastIndex=f,u=c.exec(s),null!==u);)f=c.lastIndex,c===v?\"!--\"===u[1]?c=_:void 0!==u[1]?c=m:void 0!==u[2]?(y.test(u[2])&&(n=RegExp(\"</\"+u[2],\"g\")),c=p):void 0!==u[3]&&(c=p):c===p?\">\"===u[0]?(c=n??v,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?p:'\"'===u[3]?$:g):c===$||c===g?c=p:c===_||c===m?c=v:(c=p,n=void 0);const x=c===p&&t[i+1].startsWith(\"/>\")?\" \":\"\";l+=c===v?s+r:d>=0?(e.push(a),s.slice(0,d)+h+s.slice(d)+o+x):s+o+(-2===d?i:x)}return[V(t,l+(t[s]||\"<?>\")+(2===i?\"</svg>\":3===i?\"</math>\":\"\")),e]};class S{constructor({strings:t,_$litType$:i},e){let r;this.parts=[];let l=0,a=0;const u=t.length-1,d=this.parts,[f,v]=N(t,i);if(this.el=S.createElement(f,e),P.currentNode=this.el.content,2===i||3===i){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(r=P.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(h)){const i=v[a++],s=r.getAttribute(t).split(o),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:l,name:e[2],strings:s,ctor:\".\"===e[1]?I:\"?\"===e[1]?L:\"@\"===e[1]?z:H}),r.removeAttribute(t)}else t.startsWith(o)&&(d.push({type:6,index:l}),r.removeAttribute(t));if(y.test(r.tagName)){const t=r.textContent.split(o),i=t.length-1;if(i>0){r.textContent=s?s.emptyScript:\"\";for(let s=0;s<i;s++)r.append(t[s],c()),P.nextNode(),d.push({type:2,index:++l});r.append(t[i],c())}}}else if(8===r.nodeType)if(r.data===n)d.push({type:2,index:l});else{let t=-1;for(;-1!==(t=r.data.indexOf(o,t+1));)d.push({type:7,index:l}),t+=o.length-1}l++}}static createElement(t,i){const s=l.createElement(\"template\");return s.innerHTML=t,s}}function M(t,i,s=t,e){if(i===E)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=a(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(!1),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=M(t,h._$AS(t,i.values),h,e)),i}class R{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??l).importNode(i,!0);P.currentNode=e;let h=P.nextNode(),o=0,n=0,r=s[0];for(;void 0!==r;){if(o===r.index){let i;2===r.type?i=new k(h,h.nextSibling,this,t):1===r.type?i=new r.ctor(h,r.name,r.strings,this,t):6===r.type&&(i=new Z(h,this,t)),this._$AV.push(i),r=s[++n]}o!==r?.index&&(h=P.nextNode(),o++)}return P.currentNode=l,e}p(t){let i=0;for(const s of this._$AV)void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++}}class k{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=M(this,t,i),a(t)?t===A||null==t||\"\"===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==E&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):d(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==A&&a(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t}$(t){const{values:i,_$litType$:s}=t,e=\"number\"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=S.createElement(V(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else{const t=new R(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t}}_$AC(t){let i=C.get(t.strings);return void 0===i&&C.set(t.strings,i=new S(t)),i}k(t){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new k(this.O(c()),this.O(c()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const s=i(t).nextSibling;i(t).remove(),t=s}}setConnected(t){void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t))}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||\"\"!==s[0]||\"\"!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A}_$AI(t,i=this,s,e){const h=this.strings;let o=!1;if(void 0===h)t=M(this,t,i,0),o=!a(t)||t!==this._$AH&&t!==E,o&&(this._$AH=t);else{const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=M(this,e[s+n],i,n),r===E&&(r=this._$AH[n]),o||=!a(r)||r!==this._$AH[n],r===A?t=A:t!==A&&(t+=(r??\"\")+h[n+1]),this._$AH[n]=r}o&&!e&&this.j(t)}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??\"\")}}class I extends H{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===A?void 0:t}}class L extends H{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==A)}}class z extends H{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5}_$AI(t,i=this){if((t=M(this,t,i,0)??A)===E)return;const s=this._$AH,e=t===A&&s!==A||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==A&&(s===A||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){\"function\"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){M(this,t)}}const j={M:h,P:o,A:n,C:1,L:N,R,D:d,V:M,I:k,H,N:L,U:z,B:I,F:Z},B=t.litHtmlPolyfillSupport;B?.(S,k),(t.litHtmlVersions??=[]).push(\"3.3.2\");const D=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new k(i.insertBefore(c(),t),t,void 0,s??{})}return h._$AI(t),h};export{j as _$LH,b as html,T as mathml,E as noChange,A as nothing,D as render,w as svg};\n//# sourceMappingURL=lit-html.js.map\n","import{ReactiveElement as t}from\"@lit/reactive-element\";export*from\"@lit/reactive-element\";import{render as e,noChange as r}from\"lit-html\";export*from\"lit-html\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const s=globalThis;class i extends t{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=e(r,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return r}}i._$litElement$=!0,i[\"finalized\"]=!0,s.litElementHydrateSupport?.({LitElement:i});const o=s.litElementPolyfillSupport;o?.({LitElement:i});const n={_$AK:(t,e,r)=>{t._$AK(e,r)},_$AL:t=>t._$AL};(s.litElementVersions??=[]).push(\"4.2.2\");export{i as LitElement,n as _$LE};\n//# sourceMappingURL=lit-element.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=t=>(e,o)=>{void 0!==o?o.addInitializer(()=>{customElements.define(t,e)}):customElements.define(t,e)};export{t as customElement};\n//# sourceMappingURL=custom-element.js.map\n","import{notEqual as t,defaultConverter as e}from\"../reactive-element.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const o={attribute:!0,type:String,converter:e,reflect:!1,hasChanged:t},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),\"setter\"===n&&((t=Object.create(t)).wrapped=!0),s.set(r.name,t),\"accessor\"===n){const{name:o}=r;return{set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t,!0,r)},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if(\"setter\"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t,!0,r)}}throw Error(\"Unsupported decorator location: \"+n)};function n(t){return(e,o)=>\"object\"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}export{n as property,r as standardProperty};\n//# sourceMappingURL=property.js.map\n","import{property as t}from\"./property.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function r(r){return t({...r,state:!0,attribute:!1})}export{r as state};\n//# sourceMappingURL=state.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst e=(e,t,c)=>(c.configurable=!0,c.enumerable=!0,Reflect.decorate&&\"object\"!=typeof t&&Object.defineProperty(e,t,c),c);export{e as desc};\n//# sourceMappingURL=base.js.map\n","import{desc as t}from\"./base.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function e(e,r){return(n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;if(r){const{get:e,set:r}=\"object\"==typeof s?n:i??(()=>{const t=Symbol();return{get(){return this[t]},set(e){this[t]=e}}})();return t(n,s,{get(){let t=e.call(this);return void 0===t&&(t=o(this),(null!==t||this.hasUpdated)&&r.call(this,t)),t}})}return t(n,s,{get(){return o(this)}})}}export{e as query};\n//# sourceMappingURL=query.js.map\n","import { css } from \"lit\";\n\nexport const redactorStyles = css`\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Arial, sans-serif;\n color: #1a1a2e;\n --accent: #0060df; /* Mozilla blue */\n --accent-hover: #0250bb;\n --danger: #d73a49;\n --success: #2da44e;\n --bg: #ffffff;\n --bg-secondary: #f6f8fa;\n --border: #d0d7de;\n --text: #1a1a2e;\n --text-secondary: #656d76;\n --redaction-fill: rgba(0, 0, 0, 0.75);\n --redaction-stroke: #ff3b3b;\n --radius: 8px;\n --max-width: 100%;\n container-type: inline-size;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .container {\n max-width: var(--max-width);\n margin: 0 auto;\n }\n\n /* --- Trust banner --- */\n .trust-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n background: #e8f5e9;\n border: 1px solid #a5d6a7;\n border-radius: var(--radius);\n font-size: 13px;\n color: #2e7d32;\n margin-bottom: 12px;\n }\n\n .trust-banner .shield-icon {\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n }\n\n /* --- Drop zone --- */\n .dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n min-height: 240px;\n padding: 32px 24px;\n border: 2px dashed var(--border);\n border-radius: var(--radius);\n background: var(--bg-secondary);\n cursor: pointer;\n transition: border-color 0.2s, background 0.2s;\n text-align: center;\n -webkit-tap-highlight-color: transparent;\n }\n\n .dropzone.dragover {\n border-color: var(--accent);\n background: #f0f6ff;\n }\n\n .dropzone-icon {\n width: 48px;\n height: 48px;\n color: var(--text-secondary);\n }\n\n .dropzone-text {\n font-size: 16px;\n color: var(--text-secondary);\n }\n\n .dropzone-text strong {\n color: var(--accent);\n }\n\n .dropzone-hint {\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .file-input {\n display: none;\n }\n\n /* --- Progress --- */\n .progress-container {\n padding: 32px 24px;\n text-align: center;\n }\n\n .progress-bar-track {\n width: 100%;\n height: 6px;\n background: var(--bg-secondary);\n border-radius: 3px;\n overflow: hidden;\n margin: 16px 0;\n }\n\n .progress-bar-fill {\n height: 100%;\n background: var(--accent);\n border-radius: 3px;\n transition: width 0.3s ease;\n }\n\n .progress-message {\n font-size: 14px;\n color: var(--text-secondary);\n margin: 8px 0;\n }\n\n .progress-phase {\n font-size: 16px;\n font-weight: 600;\n color: var(--text);\n margin-bottom: 4px;\n }\n\n /* --- Editor / review --- */\n .editor {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .viewport {\n position: relative;\n background: #e5e5e5;\n border-radius: var(--radius);\n border: 1px solid var(--border);\n }\n\n .viewport-inner {\n position: relative;\n display: inline-block;\n /* Scale image to fit viewport width on mobile */\n width: 100%;\n }\n\n .viewport img {\n display: block;\n width: 100%;\n height: auto;\n user-select: none;\n -webkit-user-select: none;\n pointer-events: none;\n }\n\n .viewport svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n touch-action: pan-x pan-y;\n }\n\n /* In draw mode there's no scroll container clipping the SVG, so\n touch-action:none on the SVG itself is sufficient to block the\n page scroll gesture and let the draw drag register. */\n .viewport svg.draw-mode {\n touch-action: none;\n }\n\n .viewport svg rect.redaction-box {\n fill: var(--redaction-fill);\n stroke: var(--redaction-stroke);\n stroke-width: 2;\n cursor: pointer;\n transition: fill 0.15s;\n }\n\n .viewport svg rect.redaction-box:hover,\n .viewport svg rect.redaction-box.active {\n fill: rgba(255, 59, 59, 0.4);\n stroke-width: 3;\n }\n\n .viewport svg rect.redaction-box.disabled {\n fill: rgba(0, 0, 0, 0.15);\n stroke: #999;\n stroke-dasharray: 4 2;\n }\n\n .viewport svg rect.drawing {\n fill: rgba(0, 96, 223, 0.2);\n stroke: var(--accent);\n stroke-width: 2;\n stroke-dasharray: 6 3;\n }\n\n /* --- Toolbar --- */\n .toolbar {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px;\n position: sticky;\n top: 0;\n z-index: 10;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n margin-bottom: 8px;\n }\n\n .toolbar-row {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n\n /* Utility row: Add box, Undo, Select all, Deselect all */\n .toolbar-utils {\n flex-wrap: wrap;\n }\n\n /* Actions row: Cancel + Confirm always together, Confirm stretches to fill */\n .toolbar-actions {\n display: flex;\n gap: 8px;\n }\n\n .toolbar-actions .danger {\n flex-shrink: 0;\n }\n\n .toolbar-actions .primary {\n flex: 1;\n }\n\n .toolbar button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n -webkit-tap-highlight-color: transparent;\n min-height: 44px;\n min-width: 44px;\n }\n\n .toolbar button:hover {\n background: var(--bg-secondary);\n border-color: var(--accent);\n }\n\n .toolbar button:active {\n background: #e8e8e8;\n }\n\n .toolbar button.primary {\n background: var(--success);\n color: white;\n border-color: var(--success);\n }\n\n .toolbar button.primary:hover {\n background: #278c41;\n }\n\n .toolbar button.danger {\n color: var(--danger);\n border-color: var(--danger);\n }\n\n .toolbar button.danger:hover {\n background: #fff5f5;\n }\n\n .toolbar button.active {\n background: var(--accent);\n color: white;\n border-color: var(--accent);\n }\n\n /* --- Entity list (bottom sheet on mobile, sidebar on desktop) --- */\n .entity-list {\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n max-height: 200px;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n .entity-list-header {\n position: sticky;\n top: 0;\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 600;\n color: var(--text-secondary);\n background: var(--bg-secondary);\n border-bottom: 1px solid var(--border);\n }\n\n .entity-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--border);\n font-size: 14px;\n min-height: 44px; /* Touch target */\n }\n\n .entity-item:last-child {\n border-bottom: none;\n }\n\n .entity-item input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n accent-color: var(--accent);\n }\n\n .entity-label {\n display: inline-block;\n padding: 2px 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: 4px;\n background: #eef1f5;\n color: var(--text-secondary);\n white-space: nowrap;\n }\n\n .entity-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--text);\n }\n\n .entity-source {\n font-size: 11px;\n color: var(--text-secondary);\n }\n\n /* --- Error state --- */\n .error {\n padding: 24px;\n text-align: center;\n color: var(--danger);\n }\n\n .error button {\n margin-top: 12px;\n padding: 8px 16px;\n border: 1px solid var(--danger);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--danger);\n cursor: pointer;\n min-height: 44px;\n }\n\n /* --- Done state --- */\n .done {\n padding: 32px 24px;\n text-align: center;\n }\n\n .done-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--success);\n margin-bottom: 20px;\n }\n\n .done-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n justify-content: center;\n }\n\n .done-actions button {\n display: inline-flex;\n align-items: center;\n padding: 10px 20px;\n font-size: 15px;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n cursor: pointer;\n min-height: 44px;\n -webkit-tap-highlight-color: transparent;\n }\n\n .done-actions button.primary {\n background: var(--accent);\n color: white;\n border-color: var(--accent);\n }\n\n .done-actions button:hover {\n background: var(--bg-secondary);\n }\n\n .done-actions button.primary:hover {\n background: var(--accent-hover);\n }\n\n .done-network {\n margin-top: 20px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .done-network-zero {\n color: var(--success);\n font-weight: 500;\n }\n\n /* --- Responsive --- */\n @container (min-width: 640px) {\n .editor {\n display: grid;\n grid-template-columns: 1fr 260px;\n grid-template-rows: auto 1fr;\n gap: 12px;\n }\n\n .toolbar {\n grid-column: 1 / -1;\n flex-direction: row;\n align-items: center;\n }\n\n .toolbar-utils {\n flex: 1;\n flex-wrap: nowrap;\n }\n\n .toolbar-actions {\n flex-shrink: 0;\n }\n\n .toolbar-actions .primary {\n flex: none;\n }\n\n .entity-list {\n max-height: none;\n grid-row: 2;\n grid-column: 2;\n }\n }\n\n /* --- Reduced motion --- */\n @media (prefers-reduced-motion: reduce) {\n .progress-bar-fill {\n transition: none;\n }\n }\n`;\n","import { svg } from \"lit\";\n\n/** Shield icon for the trust banner. */\nexport const shieldIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"shield-icon\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"/>\n <path d=\"m9 12 2 2 4-4\"/>\n </svg>\n`;\n\n/** Upload icon for the drop zone. */\nexport const uploadIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"dropzone-icon\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/>\n <polyline points=\"17 8 12 3 7 8\"/>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"/>\n </svg>\n`;\n\n/** Camera icon for mobile capture. */\nexport const cameraIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"width:18px;height:18px\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/>\n <circle cx=\"12\" cy=\"13\" r=\"3\"/>\n </svg>\n`;\n","/**\n * Image pre-processing for OCR accuracy improvement.\n *\n * Dark-background screenshots (dark-mode chat UIs, blue chat bubbles) make\n * Tesseract miss text because it expects dark text on a light background.\n *\n * This module:\n * 1. Samples the image to detect if the background is dark\n * 2. If dark: inverts the image so text becomes dark-on-light\n * 3. Boosts contrast to sharpen text edges\n *\n * All processing is done on an OffscreenCanvas — no data leaves the browser.\n */\n\n/** Luminance threshold below which a background is considered \"dark\". */\nexport const DARK_THRESHOLD = 128;\n\n/**\n * Compute the perceived average luminance of an RGBA pixel buffer.\n *\n * Uses the ITU-R BT.601 luma coefficients:\n * Y = 0.299R + 0.587G + 0.114B\n *\n * Returns a value in [0, 255], or 255 if the buffer is empty (treat as light).\n */\nexport function computeAverageLuminance(pixels: Uint8ClampedArray): number {\n const pixelCount = Math.floor(pixels.length / 4);\n if (pixelCount === 0) return 255; // No data → treat as light background\n\n let total = 0;\n for (let i = 0; i < pixelCount; i++) {\n const r = pixels[i * 4];\n const g = pixels[i * 4 + 1];\n const b = pixels[i * 4 + 2];\n // Perceived luminance (ITU-R BT.601)\n total += 0.299 * r + 0.587 * g + 0.114 * b;\n }\n return total / pixelCount;\n}\n\n/**\n * Return true if the pixel data represents a dark-background image.\n */\nexport function isDarkBackground(pixels: Uint8ClampedArray): boolean {\n return computeAverageLuminance(pixels) < DARK_THRESHOLD;\n}\n\n/**\n * Pre-process an image for better OCR accuracy.\n *\n * - If the background is dark, inverts the image.\n * - Applies a mild contrast boost (factor 1.4) to sharpen text edges.\n *\n * Returns a Blob (PNG) suitable for passing to Tesseract.js.\n * Falls back to the original Blob if canvas is unavailable.\n */\nexport async function preprocessForOcr(\n source: Blob,\n): Promise<Blob> {\n // Use OffscreenCanvas when available (Worker + main thread), fall back to\n // regular canvas in environments that don't support it (e.g. jsdom tests).\n let canvas: OffscreenCanvas | HTMLCanvasElement;\n let ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n\n try {\n // Decode the image\n const imageBitmap = await createImageBitmap(source);\n const { width, height } = imageBitmap;\n\n if (typeof OffscreenCanvas !== \"undefined\") {\n canvas = new OffscreenCanvas(width, height);\n ctx = canvas.getContext(\"2d\") as OffscreenCanvasRenderingContext2D;\n } else {\n canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n }\n\n if (!ctx) {\n imageBitmap.close();\n return source; // Canvas not available — return original\n }\n\n // Draw original image\n ctx.drawImage(imageBitmap, 0, 0);\n imageBitmap.close();\n\n // Sample pixels to detect background darkness\n // We sample a reduced grid (max 1024 pixels) for speed\n const sampleSize = Math.min(width * height, 1024);\n const sampleW = Math.ceil(Math.sqrt((sampleSize * width) / height));\n const sampleH = Math.ceil(Math.sqrt((sampleSize * height) / width));\n const sampleData = ctx.getImageData(0, 0, sampleW, sampleH);\n const dark = isDarkBackground(sampleData.data);\n\n if (!dark) {\n // Light background — no inversion needed, still apply mild contrast\n return await applyContrast(canvas, ctx, width, height, 1.2);\n }\n\n // Dark background — invert the image first, then boost contrast\n const imageData = ctx.getImageData(0, 0, width, height);\n const data = imageData.data;\n\n for (let i = 0; i < data.length; i += 4) {\n data[i] = 255 - data[i]; // R\n data[i + 1] = 255 - data[i + 1]; // G\n data[i + 2] = 255 - data[i + 2]; // B\n // Alpha unchanged\n }\n\n ctx.putImageData(imageData, 0, 0);\n\n // Boost contrast after inversion (1.5 is stronger for previously-dark text)\n return await applyContrast(canvas, ctx, width, height, 1.5);\n } catch {\n // If anything fails (e.g. corrupt image), return original\n return source;\n }\n}\n\n/**\n * Apply a contrast boost to the canvas content.\n *\n * Uses the standard contrast formula:\n * pixel' = (pixel - 128) * factor + 128\n *\n * Returns a PNG Blob.\n */\nasync function applyContrast(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n width: number,\n height: number,\n factor: number,\n): Promise<Blob> {\n const imageData = ctx.getImageData(0, 0, width, height);\n const data = imageData.data;\n\n for (let i = 0; i < data.length; i += 4) {\n data[i] = clamp((data[i] - 128) * factor + 128);\n data[i + 1] = clamp((data[i + 1] - 128) * factor + 128);\n data[i + 2] = clamp((data[i + 2] - 128) * factor + 128);\n // Alpha unchanged\n }\n\n ctx.putImageData(imageData, 0, 0);\n\n if (canvas instanceof OffscreenCanvas) {\n return canvas.convertToBlob({ type: \"image/png\" });\n } else {\n return await new Promise<Blob>((resolve, reject) => {\n (canvas as HTMLCanvasElement).toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"toBlob returned null\"));\n }, \"image/png\");\n });\n }\n}\n\n/** Clamp a number to [0, 255] and round. */\nfunction clamp(value: number): number {\n return Math.max(0, Math.min(255, Math.round(value)));\n}\n","import type { OcrResult, OcrWord, ProgressEvent } from \"../types.js\";\nimport { preprocessForOcr } from \"./preprocess.js\";\n\n/**\n * Runs Tesseract.js OCR on an image, returning word-level bounding boxes\n * with character offsets into the reconstructed full text.\n *\n * Tesseract.js manages its own Web Worker internally.\n */\nexport async function runOcr(\n image: ImageBitmap | HTMLImageElement | Blob,\n lang: string = \"eng\",\n onProgress?: (event: ProgressEvent) => void,\n): Promise<OcrResult> {\n // Dynamic import — Tesseract.js is heavy, only load when needed\n const Tesseract = await import(\"tesseract.js\");\n\n const worker = await Tesseract.createWorker(lang, undefined, {\n logger: (m: { status: string; progress: number }) => {\n onProgress?.({\n phase: \"ocr\",\n progress: m.progress,\n message: m.status,\n });\n },\n });\n\n // Get the image source as a Blob so we can pre-process it.\n // Also capture dimensions now — Tesseract doesn't always expose them.\n let rawBlob: Blob;\n let knownWidth = 0;\n let knownHeight = 0;\n\n if (image instanceof ImageBitmap) {\n knownWidth = image.width;\n knownHeight = image.height;\n const canvas = new OffscreenCanvas(image.width, image.height);\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(image, 0, 0);\n rawBlob = await canvas.convertToBlob({ type: \"image/png\" });\n } else if (image instanceof Blob) {\n // Decode to get dimensions, then pass original blob for pre-processing\n try {\n const bmp = await createImageBitmap(image);\n knownWidth = bmp.width;\n knownHeight = bmp.height;\n bmp.close();\n } catch {\n // Non-fatal: dimensions stay 0, Tesseract fallback will fill them\n }\n rawBlob = image;\n } else {\n // HTMLImageElement\n knownWidth = image.naturalWidth;\n knownHeight = image.naturalHeight;\n const canvas = new OffscreenCanvas(image.naturalWidth, image.naturalHeight);\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(image, 0, 0);\n rawBlob = await canvas.convertToBlob({ type: \"image/png\" });\n }\n\n // Pre-process: invert dark backgrounds, boost contrast\n const source = await preprocessForOcr(rawBlob);\n\n let result: Awaited<ReturnType<typeof worker.recognize>>;\n try {\n result = await worker.recognize(source);\n } finally {\n // Always terminate the worker — even on error — to prevent memory leaks\n await worker.terminate();\n }\n\n // Build word index with cumulative character offsets.\n // We reconstruct the full text by joining words with spaces within a line,\n // and lines with newlines.\n const words: OcrWord[] = [];\n let fullText = \"\";\n let charOffset = 0;\n\n const lines = result.data.lines ?? [];\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex];\n const lineWords = line.words ?? [];\n\n for (let wi = 0; wi < lineWords.length; wi++) {\n const w = lineWords[wi];\n const text = w.text;\n const charStart = charOffset;\n const charEnd = charOffset + text.length;\n\n words.push({\n text,\n bbox: {\n x0: w.bbox.x0,\n y0: w.bbox.y0,\n x1: w.bbox.x1,\n y1: w.bbox.y1,\n },\n confidence: w.confidence,\n charStart,\n charEnd,\n lineIndex,\n });\n\n fullText += text;\n charOffset += text.length;\n\n // Add space between words within a line\n if (wi < lineWords.length - 1) {\n fullText += \" \";\n charOffset += 1;\n }\n }\n\n // Add newline between lines\n if (lineIndex < lines.length - 1) {\n fullText += \"\\n\";\n charOffset += 1;\n }\n }\n\n // Determine image dimensions: prefer Tesseract's values, fall back to\n // the dimensions we captured before pre-processing.\n const data = result.data as any;\n const imageWidth: number = data.imageWidth ?? knownWidth;\n const imageHeight: number = data.imageHeight ?? knownHeight;\n\n return { fullText, words, imageWidth, imageHeight };\n}\n\n/**\n * Given a character span (start, end) in the full text, find all words\n * whose character ranges overlap with that span.\n */\nexport function findWordsInSpan(\n words: OcrWord[],\n start: number,\n end: number,\n): OcrWord[] {\n return words.filter((w) => w.charStart < end && w.charEnd > start);\n}\n","import type { PiiEntity, ProgressEvent } from \"../types.js\";\n\n// Singleton pipeline — loaded once, reused across calls.\n// This avoids re-downloading the model on every invocation.\nlet pipelineInstance: any = null;\nlet pipelineModelId: string | null = null;\n\ninterface RawNerToken {\n entity: string;\n entity_group?: string;\n score: number;\n word: string;\n start: number | null;\n end: number | null;\n index?: number;\n}\n\n/**\n * Run NER-based PII detection using Transformers.js.\n *\n * Uses the token-classification pipeline with the specified model.\n * WebGPU is attempted first, falling back to WASM.\n */\nexport async function detectPiiNer(\n text: string,\n modelId: string,\n minConfidence: number = 0.7,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<PiiEntity[]> {\n const pipeline = await loadPipeline(modelId, onProgress);\n\n onProgress?.({\n phase: \"detecting\",\n progress: 0,\n message: \"Running PII detection...\",\n });\n\n // Try aggregation strategies in order of preference.\n // \"first\" is the most conservative (uses first token's label for a span),\n // \"simple\" averages scores. Both should merge sub-word tokens.\n // If both fail (some model/runtime combos don't support it), fall back to\n // manual BIO aggregation.\n let rawEntities: RawNerToken[];\n try {\n rawEntities = await pipeline(text, {\n aggregation_strategy: \"first\",\n });\n } catch {\n try {\n rawEntities = await pipeline(text, {\n aggregation_strategy: \"simple\",\n });\n } catch {\n // Last resort: raw BIO tokens, aggregated manually below\n rawEntities = await pipeline(text);\n }\n }\n\n\n\n onProgress?.({\n phase: \"detecting\",\n progress: 1,\n message: \"PII detection complete.\",\n });\n\n // Check if we got aggregated results (entity_group) or raw tokens (entity with B-/I- prefix)\n const isAggregated = rawEntities.length > 0 && rawEntities[0].entity_group != null;\n\n if (isAggregated) {\n return mapAggregatedEntities(rawEntities, text, minConfidence);\n } else {\n return aggregateAndMapTokens(rawEntities, text, minConfidence);\n }\n}\n\n/**\n * Map pre-aggregated entities (when Transformers.js aggregation works).\n */\nfunction mapAggregatedEntities(\n rawEntities: RawNerToken[],\n text: string,\n minConfidence: number,\n): PiiEntity[] {\n let idCounter = 0;\n const entities: PiiEntity[] = [];\n\n for (const entity of rawEntities) {\n if (entity.score < minConfidence) continue;\n\n const label = entity.entity_group ?? entity.entity ?? \"UNKNOWN\";\n const word = entity.word ?? \"\";\n\n let start = entity.start;\n let end = entity.end;\n\n // If offsets are missing, find by text matching\n if (start == null || end == null) {\n const found = findTextInString(text, word, entities.length > 0 ? (entities[entities.length - 1].end ?? 0) : 0);\n if (found) {\n start = found.start;\n end = found.end;\n } else {\n continue; // Can't locate this entity\n }\n }\n\n // Use canonical text from source string to avoid any tokenizer artifacts\n const canonicalText = text.slice(start, end);\n\n entities.push({\n id: `ner-${idCounter++}`,\n label: cleanLabel(label),\n text: canonicalText || word,\n start,\n end,\n score: entity.score,\n source: \"ner\",\n });\n }\n\n return entities;\n}\n\n/**\n * Manually aggregate BIO-tagged tokens into entities with character offsets.\n * This handles the case where Transformers.js returns raw token-level results.\n */\nfunction aggregateAndMapTokens(\n tokens: RawNerToken[],\n text: string,\n minConfidence: number,\n): PiiEntity[] {\n const entities: PiiEntity[] = [];\n let idCounter = 0;\n\n // Group consecutive tokens with the same entity type (BIO scheme)\n let currentGroup: RawNerToken[] = [];\n let currentType: string = \"\";\n\n for (const token of tokens) {\n const entity = token.entity ?? \"\";\n // Skip \"O\" (outside) tokens\n if (entity === \"O\" || entity === \"\") {\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n currentGroup = [];\n currentType = \"\";\n }\n continue;\n }\n\n // Parse BIO label: B-TYPE, I-TYPE, or just TYPE\n const bioPrefix = entity.substring(0, 2);\n const typeLabel = entity.includes(\"-\") ? entity.substring(2) : entity;\n\n if (bioPrefix === \"B-\" || typeLabel !== currentType) {\n // Start of a new entity\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n }\n currentGroup = [token];\n currentType = typeLabel;\n } else {\n // Continuation of current entity\n currentGroup.push(token);\n }\n }\n\n // Don't forget the last group\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n }\n\n return entities;\n}\n\n/**\n * Merge a group of BIO tokens into a single PiiEntity.\n */\nfunction mergeTokenGroup(\n tokens: RawNerToken[],\n typeLabel: string,\n text: string,\n id: number,\n minConfidence: number,\n): PiiEntity | null {\n if (tokens.length === 0) return null;\n\n const avgScore = tokens.reduce((sum, t) => sum + t.score, 0) / tokens.length;\n if (avgScore < minConfidence) return null;\n\n // If any token has start/end offsets, use them as the span —\n // they're more reliable than reconstructing from stripped sub-word pieces.\n const firstWithStart = tokens.find((t) => t.start != null);\n const lastWithEnd = [...tokens].reverse().find((t) => t.end != null);\n\n let start: number;\n let end: number;\n let entityText: string;\n\n if (firstWithStart?.start != null && lastWithEnd?.end != null) {\n start = firstWithStart.start;\n end = lastWithEnd.end;\n // Use canonical text from the source string (avoids ▁ / ## artifacts)\n entityText = text.slice(start, end);\n } else {\n // No offsets — reconstruct text from token words and find in source\n const mergedText = tokens\n .map((t) => {\n let word = t.word ?? \"\";\n if (word.startsWith(\"##\")) word = word.slice(2);\n word = word.replace(/^▁/, \"\");\n return word;\n })\n .join(\"\");\n\n const found = findTextInString(text, mergedText, 0);\n if (!found) {\n // Try matching just the first token's word\n const firstWord = tokens[0].word?.replace(/^▁/, \"\").replace(/^##/, \"\") ?? \"\";\n const found2 = findTextInString(text, firstWord, 0);\n if (!found2) return null;\n start = found2.start;\n end = start + mergedText.length;\n } else {\n start = found.start;\n end = found.end;\n }\n entityText = text.slice(start, end);\n }\n\n return {\n id: `ner-${id}`,\n label: cleanLabel(typeLabel),\n text: entityText,\n start,\n end,\n score: avgScore,\n source: \"ner\",\n };\n}\n\n/**\n * Find a substring in text, starting from a given offset.\n * Case-insensitive to handle OCR variations.\n */\nfunction findTextInString(\n text: string,\n needle: string,\n fromIndex: number,\n): { start: number; end: number } | null {\n if (!needle || needle.length === 0) return null;\n\n // Try exact match first\n let idx = text.indexOf(needle, fromIndex);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n\n // Try case-insensitive\n const lowerText = text.toLowerCase();\n const lowerNeedle = needle.toLowerCase();\n idx = lowerText.indexOf(lowerNeedle, fromIndex);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n\n // Try from the beginning if fromIndex > 0\n if (fromIndex > 0) {\n idx = lowerText.indexOf(lowerNeedle, 0);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n }\n\n return null;\n}\n\n/**\n * Clean BIO prefix from label if present.\n */\nfunction cleanLabel(label: string): string {\n if (label.startsWith(\"B-\") || label.startsWith(\"I-\")) {\n return label.substring(2);\n }\n return label;\n}\n\n/**\n * Load (or reuse) the Transformers.js token-classification pipeline.\n */\nasync function loadPipeline(\n modelId: string,\n onProgress?: (event: ProgressEvent) => void,\n) {\n if (pipelineInstance && pipelineModelId === modelId) {\n return pipelineInstance;\n }\n\n onProgress?.({\n phase: \"loading\",\n progress: 0,\n message: \"Loading PII detection model...\",\n });\n\n // Dynamic import — only load Transformers.js when needed\n const { pipeline, env } = await import(\"@xenova/transformers\");\n\n // Attempt WebGPU, fall back gracefully\n env.allowLocalModels = false;\n\n // On mobile, skip the WebGPU probe (adds latency + often falls back anyway)\n // and go straight to WASM. On desktop, \"auto\" tries WebGPU first.\n const isMobile =\n typeof navigator !== \"undefined\" &&\n /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n const pipelineOptions: Record<string, unknown> = {\n progress_callback: (p: any) => {\n if (p.status === \"progress\" && p.total) {\n onProgress?.({\n phase: \"loading\",\n progress: p.loaded / p.total,\n message: `Downloading model: ${Math.round((p.loaded / p.total) * 100)}%`,\n });\n }\n },\n // Use WASM on mobile (avoids slow WebGPU probe), auto on desktop\n device: isMobile ? \"wasm\" : \"auto\",\n // q4 (~45 MB) vs q8 (~85 MB) — halves the download with minimal accuracy loss\n dtype: \"q4\",\n };\n\n pipelineInstance = await pipeline(\n \"token-classification\",\n modelId,\n pipelineOptions as any,\n );\n\n pipelineModelId = modelId;\n\n onProgress?.({\n phase: \"loading\",\n progress: 1,\n message: \"Model loaded.\",\n });\n\n return pipelineInstance;\n}\n\n/**\n * Pre-load the model without running inference.\n * The host app can call this to warm up the cache.\n */\nexport async function preloadNerModel(\n modelId: string,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<void> {\n await loadPipeline(modelId, onProgress);\n}\n\n/**\n * Release the NER model from memory.\n *\n * Disposes the underlying ONNX session if the pipeline supports it,\n * then clears the singleton so the next call to detectPiiNer reloads.\n *\n * Use this in low-memory mode after OCR completes and before NER loads,\n * or after the component is disconnected.\n */\nexport async function releaseNerModel(): Promise<void> {\n if (pipelineInstance) {\n try {\n // Transformers.js pipelines may expose a dispose() method\n if (typeof pipelineInstance.dispose === \"function\") {\n await pipelineInstance.dispose();\n }\n } catch {\n // Non-fatal — just clear the reference\n }\n pipelineInstance = null;\n pipelineModelId = null;\n }\n}\n","import type { PiiEntity } from \"../types.js\";\n\n/**\n * Regex-based PII detection for structured patterns that NER models\n * typically miss. These complement the NER model, not replace it.\n *\n * Each pattern has a label matching the NER entity taxonomy where possible.\n */\ninterface PiiPattern {\n label: string;\n pattern: RegExp;\n}\n\nconst PII_PATTERNS: PiiPattern[] = [\n // Email addresses\n {\n label: \"EMAIL\",\n pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g,\n },\n // Phone numbers (various formats)\n {\n label: \"TELEPHONENUM\",\n pattern:\n /(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}(?:\\s*(?:ext|x)\\.?\\s*\\d{1,5})?/g,\n },\n // International phone numbers\n {\n label: \"TELEPHONENUM\",\n pattern: /\\+\\d{1,3}[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,9}/g,\n },\n // Social Security Numbers (US)\n {\n label: \"SSN\",\n pattern: /\\b\\d{3}[-.\\s]?\\d{2}[-.\\s]?\\d{4}\\b/g,\n },\n // Credit card numbers (basic — 13-19 digits with optional separators)\n {\n label: \"CREDITCARD\",\n pattern: /\\b(?:\\d{4}[-.\\s]?){3,4}\\d{1,4}\\b/g,\n },\n // IP addresses (v4)\n {\n label: \"IP_ADDRESS\",\n pattern:\n /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g,\n },\n // Dates (various formats — these often contain birth dates)\n {\n label: \"DATE\",\n pattern:\n /\\b(?:\\d{1,2}[/.-]\\d{1,2}[/.-]\\d{2,4}|\\d{4}[/.-]\\d{1,2}[/.-]\\d{1,2})\\b/g,\n },\n // URLs with paths (may contain identifying query params)\n {\n label: \"URL\",\n pattern: /https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g,\n },\n // Street addresses (basic US pattern)\n {\n label: \"STREET\",\n pattern: /\\b\\d{1,5}\\s+[\\w\\s]{1,30}(?:street|st|avenue|ave|road|rd|drive|dr|lane|ln|boulevard|blvd|court|ct|way|place|pl)\\.?\\b/gi,\n },\n // Zip codes (US)\n {\n label: \"ZIPCODE\",\n pattern: /\\b\\d{5}(?:-\\d{4})?\\b/g,\n },\n // Usernames / handles (@mentions)\n {\n label: \"USERNAME\",\n pattern: /@[a-zA-Z0-9_]{2,30}\\b/g,\n },\n];\n\nlet idCounter = 0;\n\n/**\n * Run regex-based PII detection on the OCR text.\n * Returns deduplicated entities sorted by position.\n */\nexport function detectPiiRegex(text: string): PiiEntity[] {\n const entities: PiiEntity[] = [];\n\n for (const { label, pattern } of PII_PATTERNS) {\n // Reset regex state (global flag)\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n entities.push({\n id: `regex-${idCounter++}`,\n label,\n text: match[0],\n start: match.index,\n end: match.index + match[0].length,\n score: 1.0,\n source: \"regex\",\n });\n }\n }\n\n // Sort by start position, then deduplicate overlapping spans\n entities.sort((a, b) => a.start - b.start || b.end - a.end);\n return deduplicateEntities(entities);\n}\n\n/**\n * Remove entities that are fully contained within another entity.\n * When two overlap, keep the longer one.\n */\nfunction deduplicateEntities(sorted: PiiEntity[]): PiiEntity[] {\n const result: PiiEntity[] = [];\n\n for (const entity of sorted) {\n const prev = result[result.length - 1];\n if (prev && entity.start >= prev.start && entity.end <= prev.end) {\n // Current is fully contained in previous — skip\n continue;\n }\n if (prev && entity.start < prev.end) {\n // Overlapping — keep the longer one\n if (entity.end - entity.start > prev.end - prev.start) {\n result[result.length - 1] = entity;\n }\n continue;\n }\n result.push(entity);\n }\n\n return result;\n}\n","import type { BBox, OcrWord, PiiEntity, Redaction } from \"../types.js\";\nimport { findWordsInSpan } from \"./ocr.js\";\n\nlet redactionIdCounter = 0;\n\n/**\n * The core bridge: maps PII entity character spans to image pixel bounding\n * boxes by finding which OCR words overlap each entity span, then merging\n * their bounding boxes.\n *\n * This is the piece that doesn't exist in any library — the connection\n * between text-domain PII detection and pixel-domain redaction.\n *\n * @param imageWidth Used to clamp bbox x1 within image bounds (0 = no clamp)\n * @param imageHeight Used to clamp bbox y1 within image bounds (0 = no clamp)\n */\nexport function entitiesToRedactions(\n entities: PiiEntity[],\n words: OcrWord[],\n imageWidth: number = 0,\n imageHeight: number = 0,\n): Redaction[] {\n const redactions: Redaction[] = [];\n\n for (const entity of entities) {\n // Skip entities without valid offsets\n if (entity.start == null || entity.end == null) {\n continue;\n }\n\n const overlapping = findWordsInSpan(words, entity.start, entity.end);\n\n // Fallback: if no words overlap by char offset, try fuzzy text matching\n let matchedWords = overlapping;\n if (matchedWords.length === 0 && entity.text) {\n matchedWords = findWordsByText(words, entity.text);\n }\n\n if (matchedWords.length === 0) {\n continue;\n }\n\n // Group overlapping words by line to avoid creating a single huge\n // bounding box that spans multiple lines\n const byLine = groupByLine(matchedWords);\n\n for (const lineWords of byLine.values()) {\n const merged = mergeBBoxes(lineWords.map((w) => w.bbox));\n redactions.push({\n id: `redact-${redactionIdCounter++}`,\n bbox: padBBox(merged, 2, imageWidth, imageHeight),\n source: \"auto\",\n entityId: entity.id,\n enabled: true,\n label: entity.label,\n });\n }\n }\n\n return redactions;\n}\n\n/**\n * Fallback: find words whose text matches (or contains) the entity text.\n * Used when character offset mapping fails.\n */\nfunction findWordsByText(words: OcrWord[], entityText: string): OcrWord[] {\n const lower = entityText.toLowerCase().trim();\n if (!lower) return [];\n\n // Try to find a contiguous sequence of words that form the entity text\n const entityWords = lower.split(/\\s+/);\n\n for (let i = 0; i <= words.length - entityWords.length; i++) {\n let match = true;\n for (let j = 0; j < entityWords.length; j++) {\n if (!words[i + j].text.toLowerCase().includes(entityWords[j]) &&\n !entityWords[j].includes(words[i + j].text.toLowerCase())) {\n match = false;\n break;\n }\n }\n if (match) {\n return words.slice(i, i + entityWords.length);\n }\n }\n\n // Single word match fallback\n const matched = words.filter((w) => {\n const wl = w.text.toLowerCase();\n return wl === lower || lower.includes(wl) || wl.includes(lower);\n });\n\n return matched;\n}\n\n/**\n * Group words by their line index. This prevents a multi-line entity\n * (rare, but possible with addresses) from producing one giant bbox\n * that covers everything between the first and last line.\n */\nfunction groupByLine(words: OcrWord[]): Map<number, OcrWord[]> {\n const map = new Map<number, OcrWord[]>();\n for (const word of words) {\n const group = map.get(word.lineIndex) ?? [];\n group.push(word);\n map.set(word.lineIndex, group);\n }\n return map;\n}\n\n/**\n * Merge an array of bounding boxes into a single box that contains all of them.\n */\nfunction mergeBBoxes(boxes: BBox[]): BBox {\n return {\n x0: Math.min(...boxes.map((b) => b.x0)),\n y0: Math.min(...boxes.map((b) => b.y0)),\n x1: Math.max(...boxes.map((b) => b.x1)),\n y1: Math.max(...boxes.map((b) => b.y1)),\n };\n}\n\n/**\n * Add padding to a bounding box, clamped to image bounds.\n *\n * @param maxW Image width (0 = no upper clamp on x)\n * @param maxH Image height (0 = no upper clamp on y)\n */\nfunction padBBox(bbox: BBox, padding: number, maxW: number = 0, maxH: number = 0): BBox {\n const x1 = bbox.x1 + padding;\n const y1 = bbox.y1 + padding;\n return {\n x0: Math.max(0, bbox.x0 - padding),\n y0: Math.max(0, bbox.y0 - padding),\n x1: maxW > 0 ? Math.min(maxW, x1) : x1,\n y1: maxH > 0 ? Math.min(maxH, y1) : y1,\n };\n}\n\n/**\n * Merge entities from NER and regex, deduplicating overlapping spans.\n * When NER and regex detect the same span, prefer the NER result\n * (it has a more specific label).\n */\nexport function mergeEntities(\n nerEntities: PiiEntity[],\n regexEntities: PiiEntity[],\n): PiiEntity[] {\n const all = [...nerEntities, ...regexEntities];\n all.sort((a, b) => a.start - b.start || b.end - a.end);\n\n const result: PiiEntity[] = [];\n\n for (const entity of all) {\n const prev = result[result.length - 1];\n if (!prev) {\n result.push(entity);\n continue;\n }\n\n // Check for overlap\n if (entity.start < prev.end) {\n // Overlapping — keep the one with higher confidence,\n // preferring NER over regex when scores are close\n const prevScore = prev.source === \"ner\" ? prev.score + 0.1 : prev.score;\n const currScore =\n entity.source === \"ner\" ? entity.score + 0.1 : entity.score;\n\n if (currScore > prevScore) {\n result[result.length - 1] = entity;\n }\n continue;\n }\n\n result.push(entity);\n }\n\n return result;\n}\n","import type { BBox, Redaction, RedactionResult } from \"../types.js\";\n\n/**\n * Render the original image with redaction boxes burned in.\n * Returns a PNG blob ready for upload.\n *\n * This is intentionally simple: draw the image, then fill black rectangles.\n * The simplicity is a feature — it's trivially auditable for a privacy tool.\n */\nexport async function renderRedactedImage(\n originalImage: HTMLImageElement | ImageBitmap,\n redactions: Redaction[],\n): Promise<RedactionResult> {\n const width =\n originalImage instanceof HTMLImageElement\n ? originalImage.naturalWidth\n : originalImage.width;\n const height =\n originalImage instanceof HTMLImageElement\n ? originalImage.naturalHeight\n : originalImage.height;\n\n // Use OffscreenCanvas if available (better for memory on mobile),\n // fall back to regular canvas\n const canvas = createCanvas(width, height);\n const ctx = getContext(canvas);\n\n // Draw original image\n ctx.drawImage(originalImage, 0, 0, width, height);\n\n // Draw black rectangles over enabled redactions\n ctx.fillStyle = \"#000000\";\n const appliedEntities: RedactionResult[\"entities\"] = [];\n\n for (const redaction of redactions) {\n if (!redaction.enabled) continue;\n\n const { x0, y0, x1, y1 } = redaction.bbox;\n ctx.fillRect(x0, y0, x1 - x0, y1 - y0);\n\n appliedEntities.push({\n label: redaction.label ?? \"UNKNOWN\",\n bbox: redaction.bbox,\n source: redaction.source,\n });\n }\n\n // Export as PNG\n const blob = await canvasToBlob(canvas);\n\n return {\n blob,\n entities: appliedEntities,\n width,\n height,\n };\n}\n\n/**\n * Quick preview: draw redaction boxes onto an existing canvas context.\n * Used for the live preview in the review phase (not for export).\n */\nexport function drawRedactionPreview(\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n redactions: Redaction[],\n style: { fill: string; stroke: string; lineWidth: number } = {\n fill: \"rgba(0, 0, 0, 0.7)\",\n stroke: \"#ff3333\",\n lineWidth: 2,\n },\n): void {\n for (const redaction of redactions) {\n if (!redaction.enabled) continue;\n\n const { x0, y0, x1, y1 } = redaction.bbox;\n const w = x1 - x0;\n const h = y1 - y0;\n\n ctx.fillStyle = style.fill;\n ctx.fillRect(x0, y0, w, h);\n\n ctx.strokeStyle = style.stroke;\n ctx.lineWidth = style.lineWidth;\n ctx.strokeRect(x0, y0, w, h);\n }\n}\n\n// --- Canvas helpers (abstract over OffscreenCanvas / HTMLCanvasElement) ---\n\nfunction createCanvas(\n width: number,\n height: number,\n): OffscreenCanvas | HTMLCanvasElement {\n if (typeof OffscreenCanvas !== \"undefined\") {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\nfunction getContext(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"Could not get 2D canvas context\");\n return ctx as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n}\n\nasync function canvasToBlob(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n): Promise<Blob> {\n if (canvas instanceof OffscreenCanvas) {\n return canvas.convertToBlob({ type: \"image/png\" });\n }\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Canvas toBlob failed\"));\n },\n \"image/png\",\n );\n });\n}\n","/**\n * The complete redaction pipeline.\n *\n * This orchestrates: image → OCR → NER + regex → span→bbox bridge → redactions.\n * All processing happens in the browser. Nothing is sent to any server.\n */\n\nimport type {\n OcrResult,\n PiiEntity,\n ProgressEvent,\n Redaction,\n RedactorConfig,\n} from \"../types.js\";\nimport { runOcr } from \"./ocr.js\";\nimport { detectPiiNer, preloadNerModel, releaseNerModel } from \"./pii-ner.js\";\nimport { detectPiiRegex } from \"./pii-regex.js\";\nimport { entitiesToRedactions, mergeEntities } from \"./bridge.js\";\nimport { renderRedactedImage } from \"./redact.js\";\n\nexport { runOcr } from \"./ocr.js\";\nexport { detectPiiNer, preloadNerModel, releaseNerModel } from \"./pii-ner.js\";\nexport { detectPiiRegex } from \"./pii-regex.js\";\nexport { entitiesToRedactions, mergeEntities } from \"./bridge.js\";\nexport { renderRedactedImage, drawRedactionPreview } from \"./redact.js\";\nexport { preprocessForOcr, computeAverageLuminance, isDarkBackground, DARK_THRESHOLD } from \"./preprocess.js\";\n\n/**\n * Run the full pipeline: OCR → PII detection → redaction mapping.\n *\n * Returns the OCR text, detected entities, and proposed redaction boxes.\n * Does NOT render the final image — that happens when the user confirms.\n */\nexport async function analyzeImage(\n image: HTMLImageElement | ImageBitmap | Blob,\n config: RedactorConfig,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<{\n ocr: OcrResult;\n entities: PiiEntity[];\n redactions: Redaction[];\n}> {\n const cfg = { ...config } as Required<RedactorConfig>;\n\n // Resolve memory mode: detect low-memory devices automatically\n const resolvedMemoryMode = resolveMemoryMode(cfg.memoryMode);\n\n // Step 1: OCR\n onProgress?.({ phase: \"ocr\", progress: 0, message: \"Starting OCR...\" });\n const ocr = await runOcr(image, cfg.lang, onProgress);\n\n if (!ocr.fullText.trim()) {\n return { ocr, entities: [], redactions: [] };\n }\n\n // Step 2: PII detection (NER + regex in parallel)\n onProgress?.({\n phase: \"detecting\",\n progress: 0,\n message: \"Detecting personal information...\",\n });\n\n const regexEntities = cfg.useRegex ? detectPiiRegex(ocr.fullText) : [];\n\n // In low-memory mode, release any cached NER model before loading a fresh\n // one — this avoids holding two large model allocations simultaneously.\n // (The OCR worker was already terminated in runOcr's finally block.)\n if (resolvedMemoryMode === \"low\") {\n await releaseNerModel();\n }\n\n // Run NER (async, slower)\n const nerEntities = await detectPiiNer(ocr.fullText, cfg.nerModel, cfg.minConfidence, onProgress);\n\n // Step 3: Merge and deduplicate\n const entities = mergeEntities(nerEntities, regexEntities);\n\n // Step 4: Map to image bounding boxes\n const redactions = entitiesToRedactions(entities, ocr.words, ocr.imageWidth, ocr.imageHeight);\n\n onProgress?.({\n phase: \"reviewing\",\n progress: 1,\n message: `Found ${redactions.length} items to redact.`,\n });\n\n return { ocr, entities, redactions };\n}\n\n/**\n * Determine the effective memory mode.\n *\n * \"auto\" uses `navigator.deviceMemory` (Chrome/Edge only; undefined elsewhere).\n * When the API is unavailable we default to \"normal\" to avoid unnecessary\n * sequential delays on desktop browsers that don't expose memory info.\n */\nfunction resolveMemoryMode(mode: Required<RedactorConfig>[\"memoryMode\"]): \"low\" | \"normal\" {\n if (mode === \"low\") return \"low\";\n if (mode === \"normal\") return \"normal\";\n\n // \"auto\": probe the device memory API\n const deviceMemory = (navigator as any).deviceMemory as number | undefined;\n if (deviceMemory !== undefined && deviceMemory < 4) {\n return \"low\";\n }\n return \"normal\";\n}\n","/**\n * Bounding box in original image pixel coordinates.\n */\nexport interface BBox {\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n}\n\n/**\n * A word extracted by OCR, with its position in both the image and the\n * reconstructed full-text string.\n */\nexport interface OcrWord {\n text: string;\n bbox: BBox;\n confidence: number;\n /** Inclusive start index in the reconstructed full text. */\n charStart: number;\n /** Exclusive end index in the reconstructed full text. */\n charEnd: number;\n /** Index of the line this word belongs to. */\n lineIndex: number;\n}\n\n/**\n * Full result from the OCR stage.\n */\nexport interface OcrResult {\n /** Reconstructed full text (words joined by spaces, lines by newlines). */\n fullText: string;\n words: OcrWord[];\n /** Original image dimensions in pixels. */\n imageWidth: number;\n imageHeight: number;\n}\n\n/**\n * A PII entity detected by the NER model or regex patterns.\n */\nexport interface PiiEntity {\n id: string;\n /** NER label: GIVENNAME, SURNAME, EMAIL, TELEPHONENUM, CITY, DATE, etc. */\n label: string;\n /** The matched text. */\n text: string;\n /** Character offset (inclusive) in the OCR full text. */\n start: number;\n /** Character offset (exclusive) in the OCR full text. */\n end: number;\n /** Confidence score 0-1. For regex matches this is 1.0. */\n score: number;\n /** Detection source. */\n source: \"ner\" | \"regex\";\n}\n\n/**\n * A redaction box to be drawn on the image.\n */\nexport interface Redaction {\n id: string;\n bbox: BBox;\n /** How this redaction was created. */\n source: \"auto\" | \"manual\";\n /** If auto-detected, the entity that produced it. */\n entityId?: string;\n /** User can toggle individual redactions off. */\n enabled: boolean;\n /** Display label for the entity type. */\n label?: string;\n}\n\n/**\n * The phases the component moves through.\n */\nexport type Phase =\n | \"idle\"\n | \"loading\"\n | \"ocr\"\n | \"detecting\"\n | \"reviewing\"\n | \"exporting\"\n | \"done\";\n\n/**\n * Progress update emitted during model loading and processing.\n */\nexport interface ProgressEvent {\n phase: Phase;\n /** 0-1 progress within the current phase. */\n progress: number;\n message: string;\n}\n\n/**\n * Final output when user confirms redactions.\n */\nexport interface RedactionResult {\n /** PNG blob with redactions burned in. */\n blob: Blob;\n /** Detected entities (for metadata — contains no PII, only labels + bbox). */\n entities: Array<{\n label: string;\n bbox: BBox;\n source: \"auto\" | \"manual\";\n }>;\n /** Image dimensions. */\n width: number;\n height: number;\n}\n\n/**\n * Configuration for the redactor component.\n */\nexport interface RedactorConfig {\n /** Tesseract OCR language. Default: 'eng'. */\n lang?: string;\n /** HuggingFace model ID for NER. */\n nerModel?: string;\n /** Maximum file size in bytes. Default: 20MB. */\n maxFileSize?: number;\n /** Accepted MIME types. */\n acceptedTypes?: string[];\n /** Minimum NER confidence to auto-redact. Default: 0.7. */\n minConfidence?: number;\n /** Whether to run regex PII patterns in addition to NER. Default: true. */\n useRegex?: boolean;\n /**\n * Memory mode for constrained devices.\n *\n * - `\"auto\"`: Detect from `navigator.deviceMemory`; use \"low\" when < 4 GB.\n * - `\"low\"`: Release the Tesseract worker before loading the NER model,\n * reducing peak RAM. Adds a small sequential delay.\n * - `\"normal\"`: Run Tesseract and NER without explicit memory management.\n *\n * Default: \"auto\"\n */\n memoryMode?: \"auto\" | \"low\" | \"normal\";\n}\n\nexport const DEFAULT_CONFIG: Required<RedactorConfig> = {\n lang: \"eng\",\n nerModel: \"onnx-community/multilang-pii-ner-ONNX\",\n maxFileSize: 20 * 1024 * 1024,\n acceptedTypes: [\"image/png\", \"image/jpeg\", \"image/webp\"],\n minConfidence: 0.7,\n useRegex: true,\n memoryMode: \"auto\",\n};\n","import { LitElement, html, svg, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property, state, query } from \"lit/decorators.js\";\nimport { redactorStyles } from \"./styles.js\";\nimport { shieldIcon, uploadIcon } from \"./icons.js\";\nimport { analyzeImage } from \"../pipeline/index.js\";\nimport { renderRedactedImage } from \"../pipeline/redact.js\";\nimport { preloadNerModel } from \"../pipeline/pii-ner.js\";\nimport type {\n Phase,\n Redaction,\n PiiEntity,\n OcrResult,\n RedactorConfig,\n RedactionResult,\n ProgressEvent,\n BBox,\n DEFAULT_CONFIG,\n} from \"../types.js\";\nimport { DEFAULT_CONFIG as DEFAULTS } from \"../types.js\";\n\n/**\n * <pii-redactor> — Client-side PII redaction for screenshot images.\n *\n * All OCR and PII detection runs in the browser. Your data never leaves\n * your device.\n *\n * @fires redaction-complete - When the user confirms redactions. Detail: RedactionResult.\n * @fires redaction-cancel - When the user cancels.\n * @fires error - When an error occurs. Detail: { message: string }.\n */\n@customElement(\"pii-redactor\")\nexport class PiiRedactor extends LitElement {\n static override styles = redactorStyles;\n\n // --- Public properties (configurable via attributes) ---\n\n @property({ type: String }) lang = DEFAULTS.lang;\n @property({ type: String, attribute: \"ner-model\" }) nerModel =\n DEFAULTS.nerModel;\n @property({ type: Number, attribute: \"max-file-size\" }) maxFileSize =\n DEFAULTS.maxFileSize;\n @property({ type: Number, attribute: \"min-confidence\" }) minConfidence =\n DEFAULTS.minConfidence;\n\n\n // --- Internal state ---\n\n @state() private phase: Phase = \"idle\";\n @state() private progress = 0;\n @state() private progressMessage = \"\";\n @state() private errorMessage = \"\";\n @state() private imageUrl = \"\";\n @state() private imageWidth = 0;\n @state() private imageHeight = 0;\n @state() private redactions: Redaction[] = [];\n @state() private entities: PiiEntity[] = [];\n @state() private ocrResult: OcrResult | null = null;\n @state() private dragOver = false;\n @state() private isDrawing = false;\n @state() private drawMode = false;\n @state() private drawStart: { x: number; y: number } | null = null;\n @state() private drawCurrent: { x: number; y: number } | null = null;\n @state() private networkRequestCount = 0;\n @state() private redactedBlob: Blob | null = null;\n @state() private modelCached = false;\n\n private imageFile: File | null = null;\n private imageElement: HTMLImageElement | null = null;\n private undoStack: Redaction[][] = [];\n private perfObserver: PerformanceObserver | null = null;\n\n @query(\".file-input\") private fileInput!: HTMLInputElement;\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Count outbound network requests to HuggingFace CDN (model downloads)\n // so the trust banner shows real data. buffered:false means we only see\n // requests that happen after the component connects — not page-load assets.\n if (typeof PerformanceObserver !== \"undefined\") {\n this.perfObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n const url = (entry as PerformanceResourceTiming).name ?? \"\";\n if (url.includes(\"huggingface.co\") || url.includes(\"hf.co\")) {\n this.networkRequestCount++;\n }\n }\n });\n try {\n this.perfObserver.observe({ type: \"resource\", buffered: false });\n } catch {\n // Some environments don't support resource timing — ignore\n this.perfObserver = null;\n }\n }\n\n // Silently preload the model in the background so it's cached by the\n // time the user picks a file. Skip if the user is on a metered/slow\n // connection or low battery — we'll download on demand with visible\n // progress instead.\n this.maybePreloadModel();\n }\n\n private async maybePreloadModel(): Promise<void> {\n // Respect data-saver and slow connections\n const conn = (navigator as any).connection;\n if (conn) {\n if (conn.saveData) return;\n if (conn.effectiveType === \"2g\" || conn.effectiveType === \"slow-2g\") return;\n }\n\n // Respect low battery\n if (\"getBattery\" in navigator) {\n try {\n const battery = await (navigator as any).getBattery();\n if (!battery.charging && battery.level < 0.2) return;\n } catch {\n // getBattery not available or denied — continue with preload\n }\n }\n\n preloadNerModel(this.nerModel).catch(() => {});\n }\n\n // --- Public methods ---\n\n /** Pre-load AI models imperatively. Call this to warm up the cache ahead of time. */\n async preload(): Promise<void> {\n await preloadNerModel(this.nerModel, (e) => this.handleProgress(e));\n }\n\n /** Reset to the initial idle state. */\n reset(): void {\n this.phase = \"idle\";\n this.progress = 0;\n this.progressMessage = \"\";\n this.errorMessage = \"\";\n this.redactions = [];\n this.entities = [];\n this.ocrResult = null;\n this.imageFile = null;\n this.undoStack = [];\n this.drawMode = false;\n if (this.imageUrl) {\n URL.revokeObjectURL(this.imageUrl);\n this.imageUrl = \"\";\n }\n this.imageElement = null;\n this.redactedBlob = null;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this.imageUrl) URL.revokeObjectURL(this.imageUrl);\n this.perfObserver?.disconnect();\n this.perfObserver = null;\n }\n\n // --- Rendering ---\n\n override render() {\n return html`\n <div class=\"container\">\n ${this.renderTrustBanner()}\n ${this.phase === \"idle\" ? this.renderDropZone() : nothing}\n ${this.phase === \"loading\" ||\n this.phase === \"ocr\" ||\n this.phase === \"detecting\"\n ? this.renderProgress()\n : nothing}\n ${this.phase === \"reviewing\" ? this.renderEditor() : nothing}\n ${this.phase === \"exporting\" ? this.renderProgress() : nothing}\n ${this.phase === \"done\" ? this.renderDone() : nothing}\n ${this.errorMessage ? this.renderError() : nothing}\n </div>\n `;\n }\n\n private renderTrustBanner() {\n return html`\n <div class=\"trust-banner\">\n ${shieldIcon}\n <span>Your data never leaves your device. All processing happens in\n your browser.</span>\n </div>\n `;\n }\n\n private renderDropZone() {\n return html`\n <div\n class=\"dropzone ${this.dragOver ? \"dragover\" : \"\"}\"\n @click=${this.handleDropZoneClick}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n ${uploadIcon}\n <div class=\"dropzone-text\">\n <strong>Choose a screenshot</strong> or drag it here\n </div>\n <div class=\"dropzone-hint\">\n PNG, JPG, or WebP up to\n ${Math.round(this.maxFileSize / 1024 / 1024)}MB\n </div>\n <input\n class=\"file-input\"\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n @change=${this.handleFileSelect}\n />\n </div>\n `;\n }\n\n private renderProgress() {\n const phaseLabels: Record<string, string> = {\n loading: \"Loading AI models\",\n ocr: \"Reading text from image\",\n detecting: \"Detecting personal information\",\n exporting: \"Preparing redacted image\",\n };\n\n return html`\n <div class=\"progress-container\">\n <div class=\"progress-phase\">\n ${phaseLabels[this.phase] ?? \"Processing...\"}\n </div>\n <div class=\"progress-bar-track\">\n <div\n class=\"progress-bar-fill\"\n style=\"width: ${Math.round(this.progress * 100)}%\"\n ></div>\n </div>\n <div class=\"progress-message\">${this.progressMessage}</div>\n </div>\n `;\n }\n\n private renderEditor() {\n const vb = `0 0 ${this.imageWidth} ${this.imageHeight}`;\n\n return html`\n <div class=\"editor\">\n <div class=\"toolbar\">\n <div class=\"toolbar-row toolbar-utils\">\n <button\n class=\"${this.drawMode ? \"active\" : \"\"}\"\n @click=${this.toggleDrawMode}\n title=\"Draw a redaction box manually\"\n >\n ${this.drawMode ? \"Drawing...\" : \"+ Add box\"}\n </button>\n <button\n @click=${this.handleUndo}\n ?disabled=${this.undoStack.length === 0}\n >\n Undo\n </button>\n <button @click=${this.handleSelectAll}>Select all</button>\n <button @click=${this.handleDeselectAll}>Deselect all</button>\n </div>\n <div class=\"toolbar-row toolbar-actions\">\n <button class=\"danger\" @click=${this.handleCancel}>Cancel</button>\n <button class=\"primary\" @click=${this.handleConfirm}>\n Confirm &amp; redact\n </button>\n </div>\n </div>\n\n <div class=\"viewport\">\n <div class=\"viewport-inner\">\n <img\n src=${this.imageUrl}\n alt=\"Screenshot to redact\"\n @load=${this.handleImageLoad}\n />\n <svg\n class=${this.drawMode ? \"draw-mode\" : \"\"}\n viewBox=${vb}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n @pointerdown=${this.handleSvgPointerDown}\n @pointermove=${this.handleSvgPointerMove}\n @pointerup=${this.handleSvgPointerUp}\n @pointercancel=${this.handleSvgPointerCancel}\n >\n ${this.redactions.map(\n (r) => svg`\n <rect\n class=\"redaction-box ${r.enabled ? \"\" : \"disabled\"}\"\n x=${r.bbox.x0}\n y=${r.bbox.y0}\n width=${r.bbox.x1 - r.bbox.x0}\n height=${r.bbox.y1 - r.bbox.y0}\n data-id=${r.id}\n @click=${(e: Event) => this.handleRedactionClick(e, r.id)}\n >\n <title>${r.label ?? \"Redaction\"}: ${r.enabled ? \"enabled\" : \"disabled\"}</title>\n </rect>\n `,\n )}\n ${this.isDrawing && this.drawStart && this.drawCurrent\n ? svg`\n <rect\n class=\"drawing\"\n x=${Math.min(this.drawStart.x, this.drawCurrent.x)}\n y=${Math.min(this.drawStart.y, this.drawCurrent.y)}\n width=${Math.abs(this.drawCurrent.x - this.drawStart.x)}\n height=${Math.abs(this.drawCurrent.y - this.drawStart.y)}\n />\n `\n : nothing}\n </svg>\n </div>\n </div>\n\n <div class=\"entity-list\">\n <div class=\"entity-list-header\">\n Detected items (${this.redactions.filter((r) => r.enabled).length}\n / ${this.redactions.length})\n </div>\n ${this.redactions.map(\n (r) => html`\n <label class=\"entity-item\">\n <input\n type=\"checkbox\"\n .checked=${r.enabled}\n @change=${(e: Event) =>\n this.handleToggleRedaction(\n r.id,\n (e.target as HTMLInputElement).checked,\n )}\n />\n <span class=\"entity-label\">${r.label ?? \"manual\"}</span>\n <span class=\"entity-text\"\n >${this.getRedactionText(r)}</span\n >\n <span class=\"entity-source\">${r.source}</span>\n </label>\n `,\n )}\n </div>\n </div>\n `;\n }\n\n private renderError() {\n return html`\n <div class=\"error\">\n <p>${this.errorMessage}</p>\n <button @click=${this.reset}>Try again</button>\n </div>\n `;\n }\n\n private renderDone() {\n const canShare =\n typeof navigator.share === \"function\" &&\n typeof navigator.canShare === \"function\" &&\n this.redactedBlob != null &&\n navigator.canShare({\n files: [new File([this.redactedBlob], \"redacted.png\", { type: \"image/png\" })],\n });\n\n const networkNote = this.networkRequestCount === 0\n ? html`<p class=\"done-network done-network-zero\">\n Network requests to AI model host: 0 — served from local cache.\n </p>`\n : html`<p class=\"done-network\">\n Network requests to AI model host: ${this.networkRequestCount}.\n ${this.modelCached\n ? html`Model is now cached — next time will be 0.`\n : nothing}\n </p>`;\n\n return html`\n <div class=\"done\">\n <div class=\"done-title\">Redaction complete</div>\n <div class=\"done-actions\">\n <button class=\"primary\" @click=${this.handleDownload}>\n Download\n </button>\n ${canShare\n ? html`<button @click=${this.handleShare}>Share</button>`\n : nothing}\n <button @click=${this.reset}>Redact another</button>\n </div>\n ${networkNote}\n </div>\n `;\n }\n\n // --- File handling ---\n\n private handleDropZoneClick() {\n this.fileInput?.click();\n }\n\n private handleDragOver(e: DragEvent) {\n e.preventDefault();\n this.dragOver = true;\n }\n\n private handleDragLeave() {\n this.dragOver = false;\n }\n\n private handleDrop(e: DragEvent) {\n e.preventDefault();\n this.dragOver = false;\n const file = e.dataTransfer?.files[0];\n if (file) this.processFile(file);\n }\n\n private handleFileSelect(e: Event) {\n const input = e.target as HTMLInputElement;\n const file = input.files?.[0];\n if (file) this.processFile(file);\n // Reset input so the same file can be selected again\n input.value = \"\";\n }\n\n private async processFile(file: File) {\n // Validate\n if (!DEFAULTS.acceptedTypes.includes(file.type)) {\n this.errorMessage = `Unsupported file type: ${file.type}. Please use PNG, JPEG, or WebP.`;\n return;\n }\n if (file.size > this.maxFileSize) {\n this.errorMessage = `File too large (${Math.round(file.size / 1024 / 1024)}MB). Maximum is ${Math.round(this.maxFileSize / 1024 / 1024)}MB.`;\n return;\n }\n\n this.errorMessage = \"\";\n this.networkRequestCount = 0;\n this.imageFile = file;\n this.imageUrl = URL.createObjectURL(file);\n this.phase = \"loading\";\n\n try {\n // Load image to get dimensions\n const img = await this.loadImage(this.imageUrl);\n this.imageElement = img;\n this.imageWidth = img.naturalWidth;\n this.imageHeight = img.naturalHeight;\n\n // Run the pipeline\n const config: RedactorConfig = {\n lang: this.lang,\n nerModel: this.nerModel,\n minConfidence: this.minConfidence,\n };\n\n const result = await analyzeImage(file, config, (e) =>\n this.handleProgress(e),\n );\n\n this.ocrResult = result.ocr;\n this.entities = result.entities;\n this.redactions = result.redactions;\n this.undoStack = [];\n this.phase = \"reviewing\";\n\n // Check if model is now cached in a SW (for the done-screen hint)\n this.checkModelCached();\n } catch (err) {\n console.error(\"Pipeline error:\", err);\n this.errorMessage =\n err instanceof Error ? err.message : \"An unexpected error occurred.\";\n this.phase = \"idle\";\n }\n }\n\n private async checkModelCached(): Promise<void> {\n if (!(\"caches\" in window)) return;\n try {\n // The SW caches HuggingFace model files under a known cache name.\n // If any huggingface.co entry exists we know the model is cached.\n const cacheNames = await caches.keys();\n for (const name of cacheNames) {\n const cache = await caches.open(name);\n const keys = await cache.keys();\n if (keys.some((r) => r.url.includes(\"huggingface.co\"))) {\n this.modelCached = true;\n return;\n }\n }\n } catch {\n // Cache API blocked (e.g. private browsing on some browsers) — ignore\n }\n }\n\n private loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(\"Failed to load image\"));\n img.src = src;\n });\n }\n\n // --- Progress ---\n\n private handleProgress(event: ProgressEvent) {\n this.phase = event.phase;\n this.progress = event.progress;\n this.progressMessage = event.message;\n }\n\n // --- Redaction editing ---\n\n private handleRedactionClick(e: Event, id: string) {\n e.stopPropagation();\n if (this.drawMode) return;\n\n const redaction = this.redactions.find((r) => r.id === id);\n if (redaction) {\n this.pushUndo();\n this.redactions = this.redactions.map((r) =>\n r.id === id ? { ...r, enabled: !r.enabled } : r,\n );\n }\n }\n\n private handleToggleRedaction(id: string, enabled: boolean) {\n this.pushUndo();\n this.redactions = this.redactions.map((r) =>\n r.id === id ? { ...r, enabled } : r,\n );\n }\n\n private handleSelectAll() {\n this.pushUndo();\n this.redactions = this.redactions.map((r) => ({ ...r, enabled: true }));\n }\n\n private handleDeselectAll() {\n this.pushUndo();\n this.redactions = this.redactions.map((r) => ({ ...r, enabled: false }));\n }\n\n private handleUndo() {\n const prev = this.undoStack.pop();\n if (prev) {\n this.redactions = prev;\n // Trigger reactivity for undoStack\n this.undoStack = [...this.undoStack];\n }\n }\n\n private pushUndo() {\n this.undoStack = [...this.undoStack, [...this.redactions]];\n }\n\n // --- Drawing manual boxes ---\n\n private toggleDrawMode() {\n this.drawMode = !this.drawMode;\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n }\n\n private svgPointFromEvent(e: PointerEvent): { x: number; y: number } {\n const svg = (e.currentTarget as SVGSVGElement) ?? this.renderRoot.querySelector(\"svg\");\n if (!svg) return { x: 0, y: 0 };\n\n const pt = svg.createSVGPoint();\n pt.x = e.clientX;\n pt.y = e.clientY;\n const ctm = svg.getScreenCTM();\n if (!ctm) return { x: 0, y: 0 };\n\n const svgPt = pt.matrixTransform(ctm.inverse());\n return { x: svgPt.x, y: svgPt.y };\n }\n\n private handleSvgPointerDown(e: PointerEvent) {\n if (!this.drawMode) return;\n\n const point = this.svgPointFromEvent(e);\n this.drawStart = point;\n this.drawCurrent = point;\n this.isDrawing = true;\n\n // Capture pointer for smooth drawing\n (e.currentTarget as Element).setPointerCapture(e.pointerId);\n e.preventDefault();\n }\n\n private handleSvgPointerMove(e: PointerEvent) {\n if (!this.isDrawing || !this.drawStart) return;\n this.drawCurrent = this.svgPointFromEvent(e);\n e.preventDefault();\n }\n\n private handleSvgPointerUp(e: PointerEvent) {\n if (!this.isDrawing || !this.drawStart || !this.drawCurrent) return;\n\n const x0 = Math.min(this.drawStart.x, this.drawCurrent.x);\n const y0 = Math.min(this.drawStart.y, this.drawCurrent.y);\n const x1 = Math.max(this.drawStart.x, this.drawCurrent.x);\n const y1 = Math.max(this.drawStart.y, this.drawCurrent.y);\n\n // Only add if the box is at least 10px in image space\n if (x1 - x0 > 10 && y1 - y0 > 10) {\n this.pushUndo();\n const newRedaction: Redaction = {\n id: `manual-${Date.now()}`,\n bbox: { x0, y0, x1, y1 },\n source: \"manual\",\n enabled: true,\n label: \"MANUAL\",\n };\n this.redactions = [...this.redactions, newRedaction];\n }\n\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n this.drawMode = false;\n }\n\n private handleSvgPointerCancel() {\n // Touch was interrupted (e.g. incoming call, scroll takeover) — abort draw\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n // Keep drawMode on so the user can try again\n }\n\n // --- Actions ---\n\n private async handleConfirm() {\n if (!this.imageElement) return;\n\n this.phase = \"exporting\";\n this.progress = 0.5;\n this.progressMessage = \"Rendering redacted image...\";\n\n try {\n const result = await renderRedactedImage(\n this.imageElement,\n this.redactions,\n );\n\n this.dispatchEvent(\n new CustomEvent<RedactionResult>(\"redaction-complete\", {\n detail: result,\n bubbles: true,\n composed: true,\n }),\n );\n\n this.redactedBlob = result.blob;\n this.phase = \"done\";\n } catch (err) {\n console.error(\"Export error:\", err);\n this.errorMessage =\n err instanceof Error ? err.message : \"Failed to export redacted image.\";\n this.phase = \"reviewing\";\n }\n }\n\n private handleCancel() {\n this.dispatchEvent(\n new CustomEvent(\"redaction-cancel\", {\n bubbles: true,\n composed: true,\n }),\n );\n this.reset();\n }\n\n private handleDownload() {\n if (!this.redactedBlob) return;\n const url = URL.createObjectURL(this.redactedBlob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = this.imageFile\n ? `redacted-${this.imageFile.name.replace(/\\.[^.]+$/, \"\")}.png`\n : \"redacted.png\";\n a.click();\n URL.revokeObjectURL(url);\n }\n\n private async handleShare() {\n if (!this.redactedBlob) return;\n const filename = this.imageFile\n ? `redacted-${this.imageFile.name.replace(/\\.[^.]+$/, \"\")}.png`\n : \"redacted.png\";\n const file = new File([this.redactedBlob], filename, { type: \"image/png\" });\n try {\n await navigator.share({ files: [file] });\n } catch (err) {\n // AbortError means user dismissed the share sheet — not an error\n if (err instanceof Error && err.name !== \"AbortError\") {\n this.errorMessage = \"Share failed. Try downloading instead.\";\n }\n }\n }\n\n // --- Helpers ---\n\n private getRedactionText(r: Redaction): string {\n if (r.source === \"manual\") return \"(manually drawn)\";\n if (!r.entityId || !this.ocrResult) return \"\";\n const entity = this.entities.find((e) => e.id === r.entityId);\n return entity?.text ?? \"\";\n }\n\n private handleImageLoad(e: Event) {\n const img = e.target as HTMLImageElement;\n this.imageWidth = img.naturalWidth;\n this.imageHeight = img.naturalHeight;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"pii-redactor\": PiiRedactor;\n }\n}\n","/**\n * Service Worker registration helper for the PII redactor.\n *\n * The SW provides two capabilities:\n *\n * 1. **Model caching**: Intercepts HuggingFace model downloads and caches them\n * in Cache Storage so subsequent loads are instant and fully offline.\n *\n * 2. **Network firewall** (optional): After models are cached, the SW can\n * block all non-cached outbound requests. This is the technical proof that\n * no PII ever leaves the browser — the user can verify it by going offline.\n *\n * ## Setup\n *\n * 1. Copy `pii-redactor-sw.js` from the package's `public/` directory to your\n * web server's root (or wherever your SW scope should be).\n *\n * 2. Call `registerServiceWorker()` once on page load, before running any\n * image analysis.\n *\n * ## Two-phase CSP trust model\n *\n * - **Phase 1 (loader page)**: `connect-src *` — allow model downloads\n * - **Phase 2 (app page)**: `connect-src 'none'` — block all outbound after cache\n *\n * The SW makes Phase 2 the default once models are warm. The app page can\n * serve with strict CSP without breaking model inference.\n */\n\nexport interface SwRegistrationOptions {\n /**\n * Path to the Service Worker file on the server.\n * Default: \"/pii-redactor-sw.js\"\n */\n swPath?: string;\n\n /**\n * Service Worker scope. Controls which pages the SW can intercept.\n * Default: the directory containing the SW file.\n */\n scope?: string;\n}\n\n/**\n * Register the PII redactor Service Worker.\n *\n * Safe to call in environments without SW support — returns null gracefully.\n *\n * @returns The ServiceWorkerRegistration, or null if SW is not supported or\n * registration fails.\n */\nexport async function registerServiceWorker(\n options: SwRegistrationOptions = {},\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator) || !navigator.serviceWorker) {\n return null;\n }\n\n const swPath = options.swPath ?? \"/pii-redactor-sw.js\";\n const registerOptions: RegistrationOptions = {};\n if (options.scope) {\n registerOptions.scope = options.scope;\n }\n\n try {\n const registration = await navigator.serviceWorker.register(swPath, registerOptions);\n return registration;\n } catch {\n return null;\n }\n}\n\n/**\n * Unregister all Service Workers in the current scope.\n *\n * Useful during development or when the user wants to fully reset.\n *\n * @returns true if at least one registration was removed.\n */\nexport async function unregisterServiceWorker(): Promise<boolean> {\n if (!(\"serviceWorker\" in navigator) || !navigator.serviceWorker) {\n return false;\n }\n\n try {\n const registrations = await navigator.serviceWorker.getRegistrations();\n const results = await Promise.all(registrations.map((r) => r.unregister()));\n return results.some(Boolean);\n } catch {\n return false;\n }\n}\n"],"names":["t","e","s","o","n$3","r","n","i","S","c","h","a","l","p","d","u","f","b","y$1","y","v","_","m","g","$","x","w","E","A","C","P","V","N","I","L","z","H","R","k","Z","B","D","redactorStyles","css","shieldIcon","svg","uploadIcon","DARK_THRESHOLD","computeAverageLuminance","pixels","pixelCount","total","isDarkBackground","preprocessForOcr","source","canvas","ctx","imageBitmap","width","height","sampleSize","sampleW","sampleH","sampleData","applyContrast","imageData","data","factor","clamp","resolve","reject","blob","value","runOcr","image","lang","onProgress","worker","rawBlob","knownWidth","knownHeight","bmp","result","words","fullText","charOffset","lines","lineIndex","lineWords","wi","text","charStart","charEnd","imageWidth","imageHeight","findWordsInSpan","start","end","pipelineInstance","pipelineModelId","detectPiiNer","modelId","minConfidence","pipeline","loadPipeline","rawEntities","mapAggregatedEntities","aggregateAndMapTokens","idCounter","entities","entity","label","word","found","findTextInString","canonicalText","cleanLabel","tokens","currentGroup","currentType","token","merged","mergeTokenGroup","bioPrefix","typeLabel","id","avgScore","sum","firstWithStart","lastWithEnd","entityText","mergedText","firstWord","found2","needle","fromIndex","idx","lowerText","lowerNeedle","env","isMobile","preloadNerModel","releaseNerModel","PII_PATTERNS","detectPiiRegex","pattern","match","deduplicateEntities","sorted","prev","redactionIdCounter","entitiesToRedactions","redactions","matchedWords","findWordsByText","byLine","groupByLine","mergeBBoxes","padBBox","lower","entityWords","j","wl","map","group","boxes","bbox","padding","maxW","maxH","x1","y1","mergeEntities","nerEntities","regexEntities","all","prevScore","renderRedactedImage","originalImage","createCanvas","getContext","appliedEntities","redaction","x0","y0","canvasToBlob","drawRedactionPreview","style","analyzeImage","config","cfg","resolvedMemoryMode","resolveMemoryMode","ocr","mode","deviceMemory","DEFAULT_CONFIG","PiiRedactor","LitElement","DEFAULTS","list","entry","url","conn","battery","html","nothing","vb","canShare","networkNote","file","input","img","err","cacheNames","name","src","event","enabled","pt","ctm","svgPt","point","newRedaction","filename","__decorateClass","property","state","query","customElement","registerServiceWorker","options","swPath","registerOptions","unregisterServiceWorker","registrations"],"mappings":"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AAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AA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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8]}
1
+ {"version":3,"file":"image-pii-redactor.js","sources":["../node_modules/@lit/reactive-element/css-tag.js","../node_modules/@lit/reactive-element/reactive-element.js","../node_modules/lit-html/lit-html.js","../node_modules/lit-element/lit-element.js","../node_modules/@lit/reactive-element/decorators/custom-element.js","../node_modules/@lit/reactive-element/decorators/property.js","../node_modules/@lit/reactive-element/decorators/state.js","../node_modules/@lit/reactive-element/decorators/base.js","../node_modules/@lit/reactive-element/decorators/query.js","../src/component/styles.ts","../src/component/icons.ts","../src/pipeline/preprocess.ts","../src/pipeline/ocr.ts","../src/pipeline/pii-ner.ts","../src/pipeline/pii-regex.ts","../src/pipeline/bridge.ts","../src/pipeline/redact.ts","../src/pipeline/index.ts","../src/types.ts","../src/component/pii-redactor.ts","../src/sw-registration.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&\"adoptedStyleSheets\"in Document.prototype&&\"replace\"in CSSStyleSheet.prototype,s=Symbol(),o=new WeakMap;class n{constructor(t,e,o){if(this._$cssResult$=!0,o!==s)throw Error(\"CSSResult is not constructable. Use `unsafeCSS` or `css` instead.\");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const s=this.t;if(e&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o.set(s,t))}return t}toString(){return this.cssText}}const r=t=>new n(\"string\"==typeof t?t:t+\"\",void 0,s),i=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,s,o)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if(\"number\"==typeof t)return t;throw Error(\"Value passed to 'css' function must be a 'css' function result: \"+t+\". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.\")})(s)+t[o+1],t[0]);return new n(o,t,s)},S=(s,o)=>{if(e)s.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement(\"style\"),n=t.litNonce;void 0!==n&&o.setAttribute(\"nonce\",n),o.textContent=e.cssText,s.appendChild(o)}},c=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e=\"\";for(const s of t.cssRules)e+=s.cssText;return r(e)})(t):t;export{n as CSSResult,S as adoptStyles,i as css,c as getCompatibleStyle,e as supportsAdoptingStyleSheets,r as unsafeCSS};\n//# sourceMappingURL=css-tag.js.map\n","import{getCompatibleStyle as t,adoptStyles as s}from\"./css-tag.js\";export{CSSResult,css,supportsAdoptingStyleSheets,unsafeCSS}from\"./css-tag.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const{is:i,defineProperty:e,getOwnPropertyDescriptor:h,getOwnPropertyNames:r,getOwnPropertySymbols:o,getPrototypeOf:n}=Object,a=globalThis,c=a.trustedTypes,l=c?c.emptyScript:\"\",p=a.reactiveElementPolyfillSupport,d=(t,s)=>t,u={toAttribute(t,s){switch(s){case Boolean:t=t?l:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t)}catch(t){i=null}}return i}},f=(t,s)=>!i(t,s),b={attribute:!0,type:String,converter:u,reflect:!1,useDefault:!1,hasChanged:f};Symbol.metadata??=Symbol(\"metadata\"),a.litPropertyMetadata??=new WeakMap;class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=!0),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e(this.prototype,t,h)}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t}};return{get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d(\"elementProperties\")))return;const t=n(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(d(\"finalized\")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(d(\"properties\"))){const t=this.properties,s=[...r(t),...o(t)];for(const i of s)this.createProperty(i,t[i])}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i)}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(t(s))}else void 0!==s&&i.push(t(s));return i}static _$Eu(t,s){const i=s.attribute;return!1===i?void 0:\"string\"==typeof i?i:\"string\"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return s(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,s,i){this._$AK(t,i)}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&!0===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h=\"function\"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null}}requestUpdate(t,s,i,e=!1,h){if(void 0!==t){const r=this.constructor;if(!1===e&&(h=this[t]),i??=r.getPropertyOptions(t),!((i.hasChanged??f)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,i))))return;this.C(t,s,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),!0!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),!0===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];!0!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e)}}let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(s)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(s)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}y.elementStyles=[],y.shadowRootOptions={mode:\"open\"},y[d(\"elementProperties\")]=new Map,y[d(\"finalized\")]=new Map,p?.({ReactiveElement:y}),(a.reactiveElementVersions??=[]).push(\"2.1.2\");export{y as ReactiveElement,s as adoptStyles,u as defaultConverter,t as getCompatibleStyle,f as notEqual};\n//# sourceMappingURL=reactive-element.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=globalThis,i=t=>t,s=t.trustedTypes,e=s?s.createPolicy(\"lit-html\",{createHTML:t=>t}):void 0,h=\"$lit$\",o=`lit$${Math.random().toFixed(9).slice(2)}$`,n=\"?\"+o,r=`<${n}>`,l=document,c=()=>l.createComment(\"\"),a=t=>null===t||\"object\"!=typeof t&&\"function\"!=typeof t,u=Array.isArray,d=t=>u(t)||\"function\"==typeof t?.[Symbol.iterator],f=\"[ \\t\\n\\f\\r]\",v=/<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${f}(?:([^\\\\s\"'>=/]+)(${f}*=${f}*(?:[^ \\t\\n\\f\\r\"'\\`<>=]|(\"|')|))|$)`,\"g\"),g=/'/g,$=/\"/g,y=/^(?:script|style|textarea|title)$/i,x=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),b=x(1),w=x(2),T=x(3),E=Symbol.for(\"lit-noChange\"),A=Symbol.for(\"lit-nothing\"),C=new WeakMap,P=l.createTreeWalker(l,129);function V(t,i){if(!u(t)||!t.hasOwnProperty(\"raw\"))throw Error(\"invalid template strings array\");return void 0!==e?e.createHTML(i):i}const N=(t,i)=>{const s=t.length-1,e=[];let n,l=2===i?\"<svg>\":3===i?\"<math>\":\"\",c=v;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,f=0;for(;f<s.length&&(c.lastIndex=f,u=c.exec(s),null!==u);)f=c.lastIndex,c===v?\"!--\"===u[1]?c=_:void 0!==u[1]?c=m:void 0!==u[2]?(y.test(u[2])&&(n=RegExp(\"</\"+u[2],\"g\")),c=p):void 0!==u[3]&&(c=p):c===p?\">\"===u[0]?(c=n??v,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?p:'\"'===u[3]?$:g):c===$||c===g?c=p:c===_||c===m?c=v:(c=p,n=void 0);const x=c===p&&t[i+1].startsWith(\"/>\")?\" \":\"\";l+=c===v?s+r:d>=0?(e.push(a),s.slice(0,d)+h+s.slice(d)+o+x):s+o+(-2===d?i:x)}return[V(t,l+(t[s]||\"<?>\")+(2===i?\"</svg>\":3===i?\"</math>\":\"\")),e]};class S{constructor({strings:t,_$litType$:i},e){let r;this.parts=[];let l=0,a=0;const u=t.length-1,d=this.parts,[f,v]=N(t,i);if(this.el=S.createElement(f,e),P.currentNode=this.el.content,2===i||3===i){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(r=P.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(h)){const i=v[a++],s=r.getAttribute(t).split(o),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:l,name:e[2],strings:s,ctor:\".\"===e[1]?I:\"?\"===e[1]?L:\"@\"===e[1]?z:H}),r.removeAttribute(t)}else t.startsWith(o)&&(d.push({type:6,index:l}),r.removeAttribute(t));if(y.test(r.tagName)){const t=r.textContent.split(o),i=t.length-1;if(i>0){r.textContent=s?s.emptyScript:\"\";for(let s=0;s<i;s++)r.append(t[s],c()),P.nextNode(),d.push({type:2,index:++l});r.append(t[i],c())}}}else if(8===r.nodeType)if(r.data===n)d.push({type:2,index:l});else{let t=-1;for(;-1!==(t=r.data.indexOf(o,t+1));)d.push({type:7,index:l}),t+=o.length-1}l++}}static createElement(t,i){const s=l.createElement(\"template\");return s.innerHTML=t,s}}function M(t,i,s=t,e){if(i===E)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=a(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(!1),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=M(t,h._$AS(t,i.values),h,e)),i}class R{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??l).importNode(i,!0);P.currentNode=e;let h=P.nextNode(),o=0,n=0,r=s[0];for(;void 0!==r;){if(o===r.index){let i;2===r.type?i=new k(h,h.nextSibling,this,t):1===r.type?i=new r.ctor(h,r.name,r.strings,this,t):6===r.type&&(i=new Z(h,this,t)),this._$AV.push(i),r=s[++n]}o!==r?.index&&(h=P.nextNode(),o++)}return P.currentNode=l,e}p(t){let i=0;for(const s of this._$AV)void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++}}class k{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=M(this,t,i),a(t)?t===A||null==t||\"\"===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==E&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):d(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==A&&a(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t}$(t){const{values:i,_$litType$:s}=t,e=\"number\"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=S.createElement(V(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else{const t=new R(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t}}_$AC(t){let i=C.get(t.strings);return void 0===i&&C.set(t.strings,i=new S(t)),i}k(t){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new k(this.O(c()),this.O(c()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const s=i(t).nextSibling;i(t).remove(),t=s}}setConnected(t){void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t))}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||\"\"!==s[0]||\"\"!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A}_$AI(t,i=this,s,e){const h=this.strings;let o=!1;if(void 0===h)t=M(this,t,i,0),o=!a(t)||t!==this._$AH&&t!==E,o&&(this._$AH=t);else{const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=M(this,e[s+n],i,n),r===E&&(r=this._$AH[n]),o||=!a(r)||r!==this._$AH[n],r===A?t=A:t!==A&&(t+=(r??\"\")+h[n+1]),this._$AH[n]=r}o&&!e&&this.j(t)}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??\"\")}}class I extends H{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===A?void 0:t}}class L extends H{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==A)}}class z extends H{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5}_$AI(t,i=this){if((t=M(this,t,i,0)??A)===E)return;const s=this._$AH,e=t===A&&s!==A||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==A&&(s===A||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){\"function\"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){M(this,t)}}const j={M:h,P:o,A:n,C:1,L:N,R,D:d,V:M,I:k,H,N:L,U:z,B:I,F:Z},B=t.litHtmlPolyfillSupport;B?.(S,k),(t.litHtmlVersions??=[]).push(\"3.3.2\");const D=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new k(i.insertBefore(c(),t),t,void 0,s??{})}return h._$AI(t),h};export{j as _$LH,b as html,T as mathml,E as noChange,A as nothing,D as render,w as svg};\n//# sourceMappingURL=lit-html.js.map\n","import{ReactiveElement as t}from\"@lit/reactive-element\";export*from\"@lit/reactive-element\";import{render as e,noChange as r}from\"lit-html\";export*from\"lit-html\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const s=globalThis;class i extends t{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=e(r,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return r}}i._$litElement$=!0,i[\"finalized\"]=!0,s.litElementHydrateSupport?.({LitElement:i});const o=s.litElementPolyfillSupport;o?.({LitElement:i});const n={_$AK:(t,e,r)=>{t._$AK(e,r)},_$AL:t=>t._$AL};(s.litElementVersions??=[]).push(\"4.2.2\");export{i as LitElement,n as _$LE};\n//# sourceMappingURL=lit-element.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst t=t=>(e,o)=>{void 0!==o?o.addInitializer(()=>{customElements.define(t,e)}):customElements.define(t,e)};export{t as customElement};\n//# sourceMappingURL=custom-element.js.map\n","import{notEqual as t,defaultConverter as e}from\"../reactive-element.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */const o={attribute:!0,type:String,converter:e,reflect:!1,hasChanged:t},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),\"setter\"===n&&((t=Object.create(t)).wrapped=!0),s.set(r.name,t),\"accessor\"===n){const{name:o}=r;return{set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t,!0,r)},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if(\"setter\"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t,!0,r)}}throw Error(\"Unsupported decorator location: \"+n)};function n(t){return(e,o)=>\"object\"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}export{n as property,r as standardProperty};\n//# sourceMappingURL=property.js.map\n","import{property as t}from\"./property.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function r(r){return t({...r,state:!0,attribute:!1})}export{r as state};\n//# sourceMappingURL=state.js.map\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nconst e=(e,t,c)=>(c.configurable=!0,c.enumerable=!0,Reflect.decorate&&\"object\"!=typeof t&&Object.defineProperty(e,t,c),c);export{e as desc};\n//# sourceMappingURL=base.js.map\n","import{desc as t}from\"./base.js\";\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */function e(e,r){return(n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;if(r){const{get:e,set:r}=\"object\"==typeof s?n:i??(()=>{const t=Symbol();return{get(){return this[t]},set(e){this[t]=e}}})();return t(n,s,{get(){let t=e.call(this);return void 0===t&&(t=o(this),(null!==t||this.hasUpdated)&&r.call(this,t)),t}})}return t(n,s,{get(){return o(this)}})}}export{e as query};\n//# sourceMappingURL=query.js.map\n","import { css } from \"lit\";\n\nexport const redactorStyles = css`\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n \"Helvetica Neue\", Arial, sans-serif;\n color: #1a1a2e;\n --accent: #0060df; /* Mozilla blue */\n --accent-hover: #0250bb;\n --danger: #d73a49;\n --success: #2da44e;\n --bg: #ffffff;\n --bg-secondary: #f6f8fa;\n --border: #d0d7de;\n --text: #1a1a2e;\n --text-secondary: #656d76;\n --redaction-fill: rgba(0, 0, 0, 0.75);\n --redaction-stroke: #ff3b3b;\n --radius: 8px;\n --max-width: 100%;\n container-type: inline-size;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .container {\n max-width: var(--max-width);\n margin: 0 auto;\n }\n\n /* --- Trust banner --- */\n .trust-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 14px;\n background: #e8f5e9;\n border: 1px solid #a5d6a7;\n border-radius: var(--radius);\n font-size: 13px;\n color: #2e7d32;\n margin-bottom: 12px;\n }\n\n .trust-banner .shield-icon {\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n }\n\n /* --- Drop zone --- */\n .dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n min-height: 240px;\n padding: 32px 24px;\n border: 2px dashed var(--border);\n border-radius: var(--radius);\n background: var(--bg-secondary);\n cursor: pointer;\n transition: border-color 0.2s, background 0.2s;\n text-align: center;\n -webkit-tap-highlight-color: transparent;\n }\n\n .dropzone.dragover {\n border-color: var(--accent);\n background: #f0f6ff;\n }\n\n .dropzone-icon {\n width: 48px;\n height: 48px;\n color: var(--text-secondary);\n }\n\n .dropzone-text {\n font-size: 16px;\n color: var(--text-secondary);\n }\n\n .dropzone-text strong {\n color: var(--accent);\n }\n\n .dropzone-hint {\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .file-input {\n display: none;\n }\n\n /* --- Progress --- */\n .progress-container {\n padding: 32px 24px;\n text-align: center;\n }\n\n .progress-bar-track {\n width: 100%;\n height: 6px;\n background: var(--bg-secondary);\n border-radius: 3px;\n overflow: hidden;\n margin: 16px 0;\n }\n\n .progress-bar-fill {\n height: 100%;\n background: var(--accent);\n border-radius: 3px;\n transition: width 0.3s ease;\n }\n\n .progress-message {\n font-size: 14px;\n color: var(--text-secondary);\n margin: 8px 0;\n }\n\n .progress-phase {\n font-size: 16px;\n font-weight: 600;\n color: var(--text);\n margin-bottom: 4px;\n }\n\n /* --- Editor / review --- */\n .editor {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .viewport {\n position: relative;\n background: #e5e5e5;\n border-radius: var(--radius);\n border: 1px solid var(--border);\n }\n\n .viewport-inner {\n position: relative;\n display: inline-block;\n /* Scale image to fit viewport width on mobile */\n width: 100%;\n }\n\n .viewport img {\n display: block;\n width: 100%;\n height: auto;\n user-select: none;\n -webkit-user-select: none;\n pointer-events: none;\n }\n\n .viewport svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n touch-action: pan-x pan-y;\n }\n\n /* In draw mode there's no scroll container clipping the SVG, so\n touch-action:none on the SVG itself is sufficient to block the\n page scroll gesture and let the draw drag register. */\n .viewport svg.draw-mode {\n touch-action: none;\n }\n\n .viewport svg rect.redaction-box {\n fill: var(--redaction-fill);\n stroke: var(--redaction-stroke);\n stroke-width: 2;\n cursor: pointer;\n transition: fill 0.15s;\n }\n\n .viewport svg rect.redaction-box:hover,\n .viewport svg rect.redaction-box.active {\n fill: rgba(255, 59, 59, 0.4);\n stroke-width: 3;\n }\n\n .viewport svg rect.redaction-box.disabled {\n fill: rgba(0, 0, 0, 0.15);\n stroke: #999;\n stroke-dasharray: 4 2;\n }\n\n .viewport svg rect.drawing {\n fill: rgba(0, 96, 223, 0.2);\n stroke: var(--accent);\n stroke-width: 2;\n stroke-dasharray: 6 3;\n }\n\n /* --- Toolbar --- */\n .toolbar {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px;\n position: sticky;\n top: 0;\n z-index: 10;\n background: var(--bg);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n margin-bottom: 8px;\n }\n\n .toolbar-row {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n\n /* Utility row: Add box, Undo, Select all, Deselect all — compact on mobile */\n .toolbar-utils {\n flex-wrap: wrap;\n }\n\n .toolbar-utils button {\n flex: 1;\n min-width: 0;\n padding: 8px 10px;\n font-size: 13px;\n }\n\n /* Actions row: Cancel + Confirm always together, Confirm stretches to fill */\n .toolbar-actions {\n display: flex;\n gap: 8px;\n }\n\n .toolbar-actions .danger {\n flex-shrink: 0;\n }\n\n .toolbar-actions .primary {\n flex: 1;\n }\n\n .toolbar button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n -webkit-tap-highlight-color: transparent;\n min-height: 44px;\n min-width: 44px;\n }\n\n .toolbar button:hover {\n background: var(--bg-secondary);\n border-color: var(--accent);\n }\n\n .toolbar button:active {\n background: #e8e8e8;\n }\n\n .toolbar button.primary {\n background: var(--success);\n color: white;\n border-color: var(--success);\n }\n\n .toolbar button.primary:hover {\n background: #278c41;\n }\n\n .toolbar button.danger {\n color: var(--danger);\n border-color: var(--danger);\n }\n\n .toolbar button.danger:hover {\n background: #fff5f5;\n }\n\n .toolbar button.active {\n background: var(--accent);\n color: white;\n border-color: var(--accent);\n }\n\n /* --- Entity list (bottom sheet on mobile, sidebar on desktop) --- */\n .entity-list {\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n max-height: 200px;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n }\n\n .entity-list-header {\n position: sticky;\n top: 0;\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 600;\n color: var(--text-secondary);\n background: var(--bg-secondary);\n border-bottom: 1px solid var(--border);\n }\n\n .entity-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--border);\n font-size: 14px;\n min-height: 44px; /* Touch target */\n }\n\n .entity-item:last-child {\n border-bottom: none;\n }\n\n .entity-item input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n accent-color: var(--accent);\n }\n\n .entity-label {\n display: inline-block;\n padding: 2px 8px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: 4px;\n background: #eef1f5;\n color: var(--text-secondary);\n white-space: nowrap;\n }\n\n .entity-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--text);\n }\n\n .entity-source {\n font-size: 11px;\n color: var(--text-secondary);\n }\n\n /* --- Error state --- */\n .error {\n padding: 24px;\n text-align: center;\n color: var(--danger);\n }\n\n .error button {\n margin-top: 12px;\n padding: 8px 16px;\n border: 1px solid var(--danger);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--danger);\n cursor: pointer;\n min-height: 44px;\n }\n\n /* --- Done state --- */\n .done {\n padding: 32px 24px;\n text-align: center;\n }\n\n .done-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--success);\n margin-bottom: 20px;\n }\n\n .done-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n justify-content: center;\n }\n\n .done-actions button {\n display: inline-flex;\n align-items: center;\n padding: 10px 20px;\n font-size: 15px;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: var(--radius);\n background: var(--bg);\n color: var(--text);\n cursor: pointer;\n min-height: 44px;\n -webkit-tap-highlight-color: transparent;\n }\n\n .done-actions button.primary {\n background: var(--accent);\n color: white;\n border-color: var(--accent);\n }\n\n .done-actions button:hover {\n background: var(--bg-secondary);\n }\n\n .done-actions button.primary:hover {\n background: var(--accent-hover);\n }\n\n .done-network {\n margin-top: 20px;\n font-size: 13px;\n color: var(--text-secondary);\n }\n\n .done-network-zero {\n color: var(--success);\n font-weight: 500;\n }\n\n /* --- Responsive --- */\n @container (min-width: 640px) {\n .editor {\n display: grid;\n grid-template-columns: 1fr 260px;\n grid-template-rows: auto 1fr;\n gap: 12px;\n }\n\n .toolbar {\n grid-column: 1 / -1;\n flex-direction: row;\n align-items: center;\n }\n\n .toolbar-utils {\n flex: 1;\n flex-wrap: nowrap;\n }\n\n .toolbar-actions {\n flex-shrink: 0;\n }\n\n .toolbar-actions .primary {\n flex: none;\n }\n\n .entity-list {\n max-height: none;\n grid-row: 2;\n grid-column: 2;\n }\n }\n\n /* --- Reduced motion --- */\n @media (prefers-reduced-motion: reduce) {\n .progress-bar-fill {\n transition: none;\n }\n }\n`;\n","import { svg } from \"lit\";\n\n/** Shield icon for the trust banner. */\nexport const shieldIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"shield-icon\">\n <path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"/>\n <path d=\"m9 12 2 2 4-4\"/>\n </svg>\n`;\n\n/** Upload icon for the drop zone. */\nexport const uploadIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"dropzone-icon\">\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/>\n <polyline points=\"17 8 12 3 7 8\"/>\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"/>\n </svg>\n`;\n\n/** Camera icon for mobile capture. */\nexport const cameraIcon = svg`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"width:18px;height:18px\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z\"/>\n <circle cx=\"12\" cy=\"13\" r=\"3\"/>\n </svg>\n`;\n","/**\n * Image pre-processing for OCR accuracy improvement.\n *\n * Dark-background screenshots (dark-mode chat UIs, blue chat bubbles) make\n * Tesseract miss text because it expects dark text on a light background.\n *\n * This module:\n * 1. Samples the image to detect if the background is dark\n * 2. If dark: inverts the image so text becomes dark-on-light\n * 3. Boosts contrast to sharpen text edges\n *\n * All processing is done on an OffscreenCanvas — no data leaves the browser.\n */\n\n/** Luminance threshold below which a background is considered \"dark\". */\nexport const DARK_THRESHOLD = 128;\n\n/**\n * Compute the perceived average luminance of an RGBA pixel buffer.\n *\n * Uses the ITU-R BT.601 luma coefficients:\n * Y = 0.299R + 0.587G + 0.114B\n *\n * Returns a value in [0, 255], or 255 if the buffer is empty (treat as light).\n */\nexport function computeAverageLuminance(pixels: Uint8ClampedArray): number {\n const pixelCount = Math.floor(pixels.length / 4);\n if (pixelCount === 0) return 255; // No data → treat as light background\n\n let total = 0;\n for (let i = 0; i < pixelCount; i++) {\n const r = pixels[i * 4];\n const g = pixels[i * 4 + 1];\n const b = pixels[i * 4 + 2];\n // Perceived luminance (ITU-R BT.601)\n total += 0.299 * r + 0.587 * g + 0.114 * b;\n }\n return total / pixelCount;\n}\n\n/**\n * Return true if the pixel data represents a dark-background image.\n */\nexport function isDarkBackground(pixels: Uint8ClampedArray): boolean {\n return computeAverageLuminance(pixels) < DARK_THRESHOLD;\n}\n\n/**\n * Pre-process an image for better OCR accuracy.\n *\n * - If the background is dark, inverts the image.\n * - Applies a mild contrast boost (factor 1.4) to sharpen text edges.\n *\n * Returns a Blob (PNG) suitable for passing to Tesseract.js.\n * Falls back to the original Blob if canvas is unavailable.\n */\nexport async function preprocessForOcr(\n source: Blob,\n): Promise<Blob> {\n // Use OffscreenCanvas when available (Worker + main thread), fall back to\n // regular canvas in environments that don't support it (e.g. jsdom tests).\n let canvas: OffscreenCanvas | HTMLCanvasElement;\n let ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;\n\n try {\n // Decode the image\n const imageBitmap = await createImageBitmap(source);\n const { width, height } = imageBitmap;\n\n if (typeof OffscreenCanvas !== \"undefined\") {\n canvas = new OffscreenCanvas(width, height);\n ctx = canvas.getContext(\"2d\") as OffscreenCanvasRenderingContext2D;\n } else {\n canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n }\n\n if (!ctx) {\n imageBitmap.close();\n return source; // Canvas not available — return original\n }\n\n // Draw original image\n ctx.drawImage(imageBitmap, 0, 0);\n imageBitmap.close();\n\n // Sample pixels to detect background darkness\n // We sample a reduced grid (max 1024 pixels) for speed\n const sampleSize = Math.min(width * height, 1024);\n const sampleW = Math.ceil(Math.sqrt((sampleSize * width) / height));\n const sampleH = Math.ceil(Math.sqrt((sampleSize * height) / width));\n const sampleData = ctx.getImageData(0, 0, sampleW, sampleH);\n const dark = isDarkBackground(sampleData.data);\n\n if (!dark) {\n // Light background — no inversion needed, still apply mild contrast\n return await applyContrast(canvas, ctx, width, height, 1.2);\n }\n\n // Dark background — invert the image first, then boost contrast\n const imageData = ctx.getImageData(0, 0, width, height);\n const data = imageData.data;\n\n for (let i = 0; i < data.length; i += 4) {\n data[i] = 255 - data[i]; // R\n data[i + 1] = 255 - data[i + 1]; // G\n data[i + 2] = 255 - data[i + 2]; // B\n // Alpha unchanged\n }\n\n ctx.putImageData(imageData, 0, 0);\n\n // Boost contrast after inversion (1.5 is stronger for previously-dark text)\n return await applyContrast(canvas, ctx, width, height, 1.5);\n } catch {\n // If anything fails (e.g. corrupt image), return original\n return source;\n }\n}\n\n/**\n * Apply a contrast boost to the canvas content.\n *\n * Uses the standard contrast formula:\n * pixel' = (pixel - 128) * factor + 128\n *\n * Returns a PNG Blob.\n */\nasync function applyContrast(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n ctx: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,\n width: number,\n height: number,\n factor: number,\n): Promise<Blob> {\n const imageData = ctx.getImageData(0, 0, width, height);\n const data = imageData.data;\n\n for (let i = 0; i < data.length; i += 4) {\n data[i] = clamp((data[i] - 128) * factor + 128);\n data[i + 1] = clamp((data[i + 1] - 128) * factor + 128);\n data[i + 2] = clamp((data[i + 2] - 128) * factor + 128);\n // Alpha unchanged\n }\n\n ctx.putImageData(imageData, 0, 0);\n\n if (canvas instanceof OffscreenCanvas) {\n return canvas.convertToBlob({ type: \"image/png\" });\n } else {\n return await new Promise<Blob>((resolve, reject) => {\n (canvas as HTMLCanvasElement).toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"toBlob returned null\"));\n }, \"image/png\");\n });\n }\n}\n\n/** Clamp a number to [0, 255] and round. */\nfunction clamp(value: number): number {\n return Math.max(0, Math.min(255, Math.round(value)));\n}\n","import type { OcrResult, OcrWord, ProgressEvent } from \"../types.js\";\nimport { preprocessForOcr } from \"./preprocess.js\";\n\n/**\n * Runs Tesseract.js OCR on an image, returning word-level bounding boxes\n * with character offsets into the reconstructed full text.\n *\n * Tesseract.js manages its own Web Worker internally.\n */\nexport async function runOcr(\n image: ImageBitmap | HTMLImageElement | Blob,\n lang: string = \"eng\",\n onProgress?: (event: ProgressEvent) => void,\n): Promise<OcrResult> {\n // Dynamic import — Tesseract.js is heavy, only load when needed\n const Tesseract = await import(\"tesseract.js\");\n\n const worker = await Tesseract.createWorker(lang, undefined, {\n logger: (m: { status: string; progress: number }) => {\n onProgress?.({\n phase: \"ocr\",\n progress: m.progress,\n message: m.status,\n });\n },\n });\n\n // Get the image source as a Blob so we can pre-process it.\n // Also capture dimensions now — Tesseract doesn't always expose them.\n let rawBlob: Blob;\n let knownWidth = 0;\n let knownHeight = 0;\n\n if (image instanceof ImageBitmap) {\n knownWidth = image.width;\n knownHeight = image.height;\n const canvas = new OffscreenCanvas(image.width, image.height);\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(image, 0, 0);\n rawBlob = await canvas.convertToBlob({ type: \"image/png\" });\n } else if (image instanceof Blob) {\n // Decode to get dimensions, then pass original blob for pre-processing\n try {\n const bmp = await createImageBitmap(image);\n knownWidth = bmp.width;\n knownHeight = bmp.height;\n bmp.close();\n } catch {\n // Non-fatal: dimensions stay 0, Tesseract fallback will fill them\n }\n rawBlob = image;\n } else {\n // HTMLImageElement\n knownWidth = image.naturalWidth;\n knownHeight = image.naturalHeight;\n const canvas = new OffscreenCanvas(image.naturalWidth, image.naturalHeight);\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(image, 0, 0);\n rawBlob = await canvas.convertToBlob({ type: \"image/png\" });\n }\n\n // Pre-process: invert dark backgrounds, boost contrast\n const source = await preprocessForOcr(rawBlob);\n\n let result: Awaited<ReturnType<typeof worker.recognize>>;\n try {\n result = await worker.recognize(source);\n } finally {\n // Always terminate the worker — even on error — to prevent memory leaks\n await worker.terminate();\n }\n\n // Build word index with cumulative character offsets.\n // We reconstruct the full text by joining words with spaces within a line,\n // and lines with newlines.\n const words: OcrWord[] = [];\n let fullText = \"\";\n let charOffset = 0;\n\n const lines = result.data.lines ?? [];\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex];\n const lineWords = line.words ?? [];\n\n for (let wi = 0; wi < lineWords.length; wi++) {\n const w = lineWords[wi];\n const text = w.text;\n const charStart = charOffset;\n const charEnd = charOffset + text.length;\n\n words.push({\n text,\n bbox: {\n x0: w.bbox.x0,\n y0: w.bbox.y0,\n x1: w.bbox.x1,\n y1: w.bbox.y1,\n },\n confidence: w.confidence,\n charStart,\n charEnd,\n lineIndex,\n });\n\n fullText += text;\n charOffset += text.length;\n\n // Add space between words within a line\n if (wi < lineWords.length - 1) {\n fullText += \" \";\n charOffset += 1;\n }\n }\n\n // Add newline between lines\n if (lineIndex < lines.length - 1) {\n fullText += \"\\n\";\n charOffset += 1;\n }\n }\n\n // Determine image dimensions: prefer Tesseract's values, fall back to\n // the dimensions we captured before pre-processing.\n const data = result.data as any;\n const imageWidth: number = data.imageWidth ?? knownWidth;\n const imageHeight: number = data.imageHeight ?? knownHeight;\n\n return { fullText, words, imageWidth, imageHeight };\n}\n\n/**\n * Given a character span (start, end) in the full text, find all words\n * whose character ranges overlap with that span.\n */\nexport function findWordsInSpan(\n words: OcrWord[],\n start: number,\n end: number,\n): OcrWord[] {\n return words.filter((w) => w.charStart < end && w.charEnd > start);\n}\n","import type { PiiEntity, ProgressEvent } from \"../types.js\";\n\n// Singleton pipeline — loaded once, reused across calls.\n// This avoids re-downloading the model on every invocation.\nlet pipelineInstance: any = null;\nlet pipelineModelId: string | null = null;\n\ninterface RawNerToken {\n entity: string;\n entity_group?: string;\n score: number;\n word: string;\n start: number | null;\n end: number | null;\n index?: number;\n}\n\n/**\n * Run NER-based PII detection using Transformers.js.\n *\n * Uses the token-classification pipeline with the specified model.\n * WebGPU is attempted first, falling back to WASM.\n */\nexport async function detectPiiNer(\n text: string,\n modelId: string,\n minConfidence: number = 0.7,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<PiiEntity[]> {\n const pipeline = await loadPipeline(modelId, onProgress);\n\n onProgress?.({\n phase: \"detecting\",\n progress: 0,\n message: \"Running PII detection...\",\n });\n\n // Try aggregation strategies in order of preference.\n // \"first\" is the most conservative (uses first token's label for a span),\n // \"simple\" averages scores. Both should merge sub-word tokens.\n // If both fail (some model/runtime combos don't support it), fall back to\n // manual BIO aggregation.\n let rawEntities: RawNerToken[];\n try {\n rawEntities = await pipeline(text, {\n aggregation_strategy: \"first\",\n });\n } catch {\n try {\n rawEntities = await pipeline(text, {\n aggregation_strategy: \"simple\",\n });\n } catch {\n // Last resort: raw BIO tokens, aggregated manually below\n rawEntities = await pipeline(text);\n }\n }\n\n\n\n onProgress?.({\n phase: \"detecting\",\n progress: 1,\n message: \"PII detection complete.\",\n });\n\n // Check if we got aggregated results (entity_group) or raw tokens (entity with B-/I- prefix)\n const isAggregated = rawEntities.length > 0 && rawEntities[0].entity_group != null;\n\n if (isAggregated) {\n return mapAggregatedEntities(rawEntities, text, minConfidence);\n } else {\n return aggregateAndMapTokens(rawEntities, text, minConfidence);\n }\n}\n\n/**\n * Map pre-aggregated entities (when Transformers.js aggregation works).\n */\nfunction mapAggregatedEntities(\n rawEntities: RawNerToken[],\n text: string,\n minConfidence: number,\n): PiiEntity[] {\n let idCounter = 0;\n const entities: PiiEntity[] = [];\n\n for (const entity of rawEntities) {\n if (entity.score < minConfidence) continue;\n\n const label = entity.entity_group ?? entity.entity ?? \"UNKNOWN\";\n const word = entity.word ?? \"\";\n\n let start = entity.start;\n let end = entity.end;\n\n // If offsets are missing, find by text matching\n if (start == null || end == null) {\n const found = findTextInString(text, word, entities.length > 0 ? (entities[entities.length - 1].end ?? 0) : 0);\n if (found) {\n start = found.start;\n end = found.end;\n } else {\n continue; // Can't locate this entity\n }\n }\n\n // Use canonical text from source string to avoid any tokenizer artifacts\n const canonicalText = text.slice(start, end);\n\n entities.push({\n id: `ner-${idCounter++}`,\n label: cleanLabel(label),\n text: canonicalText || word,\n start,\n end,\n score: entity.score,\n source: \"ner\",\n });\n }\n\n return entities;\n}\n\n/**\n * Manually aggregate BIO-tagged tokens into entities with character offsets.\n * This handles the case where Transformers.js returns raw token-level results.\n */\nfunction aggregateAndMapTokens(\n tokens: RawNerToken[],\n text: string,\n minConfidence: number,\n): PiiEntity[] {\n const entities: PiiEntity[] = [];\n let idCounter = 0;\n\n // Group consecutive tokens with the same entity type (BIO scheme)\n let currentGroup: RawNerToken[] = [];\n let currentType: string = \"\";\n\n for (const token of tokens) {\n const entity = token.entity ?? \"\";\n // Skip \"O\" (outside) tokens\n if (entity === \"O\" || entity === \"\") {\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n currentGroup = [];\n currentType = \"\";\n }\n continue;\n }\n\n // Parse BIO label: B-TYPE, I-TYPE, or just TYPE\n const bioPrefix = entity.substring(0, 2);\n const typeLabel = entity.includes(\"-\") ? entity.substring(2) : entity;\n\n if (bioPrefix === \"B-\" || typeLabel !== currentType) {\n // Start of a new entity\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n }\n currentGroup = [token];\n currentType = typeLabel;\n } else {\n // Continuation of current entity\n currentGroup.push(token);\n }\n }\n\n // Don't forget the last group\n if (currentGroup.length > 0) {\n const merged = mergeTokenGroup(currentGroup, currentType, text, idCounter++, minConfidence);\n if (merged) entities.push(merged);\n }\n\n return entities;\n}\n\n/**\n * Merge a group of BIO tokens into a single PiiEntity.\n */\nfunction mergeTokenGroup(\n tokens: RawNerToken[],\n typeLabel: string,\n text: string,\n id: number,\n minConfidence: number,\n): PiiEntity | null {\n if (tokens.length === 0) return null;\n\n const avgScore = tokens.reduce((sum, t) => sum + t.score, 0) / tokens.length;\n if (avgScore < minConfidence) return null;\n\n // If any token has start/end offsets, use them as the span —\n // they're more reliable than reconstructing from stripped sub-word pieces.\n const firstWithStart = tokens.find((t) => t.start != null);\n const lastWithEnd = [...tokens].reverse().find((t) => t.end != null);\n\n let start: number;\n let end: number;\n let entityText: string;\n\n if (firstWithStart?.start != null && lastWithEnd?.end != null) {\n start = firstWithStart.start;\n end = lastWithEnd.end;\n // Use canonical text from the source string (avoids ▁ / ## artifacts)\n entityText = text.slice(start, end);\n } else {\n // No offsets — reconstruct text from token words and find in source\n const mergedText = tokens\n .map((t) => {\n let word = t.word ?? \"\";\n if (word.startsWith(\"##\")) word = word.slice(2);\n word = word.replace(/^▁/, \"\");\n return word;\n })\n .join(\"\");\n\n const found = findTextInString(text, mergedText, 0);\n if (!found) {\n // Try matching just the first token's word\n const firstWord = tokens[0].word?.replace(/^▁/, \"\").replace(/^##/, \"\") ?? \"\";\n const found2 = findTextInString(text, firstWord, 0);\n if (!found2) return null;\n start = found2.start;\n end = start + mergedText.length;\n } else {\n start = found.start;\n end = found.end;\n }\n entityText = text.slice(start, end);\n }\n\n return {\n id: `ner-${id}`,\n label: cleanLabel(typeLabel),\n text: entityText,\n start,\n end,\n score: avgScore,\n source: \"ner\",\n };\n}\n\n/**\n * Find a substring in text, starting from a given offset.\n * Case-insensitive to handle OCR variations.\n */\nfunction findTextInString(\n text: string,\n needle: string,\n fromIndex: number,\n): { start: number; end: number } | null {\n if (!needle || needle.length === 0) return null;\n\n // Try exact match first\n let idx = text.indexOf(needle, fromIndex);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n\n // Try case-insensitive\n const lowerText = text.toLowerCase();\n const lowerNeedle = needle.toLowerCase();\n idx = lowerText.indexOf(lowerNeedle, fromIndex);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n\n // Try from the beginning if fromIndex > 0\n if (fromIndex > 0) {\n idx = lowerText.indexOf(lowerNeedle, 0);\n if (idx !== -1) return { start: idx, end: idx + needle.length };\n }\n\n return null;\n}\n\n/**\n * Clean BIO prefix from label if present.\n */\nfunction cleanLabel(label: string): string {\n if (label.startsWith(\"B-\") || label.startsWith(\"I-\")) {\n return label.substring(2);\n }\n return label;\n}\n\n/**\n * Load (or reuse) the Transformers.js token-classification pipeline.\n */\nasync function loadPipeline(\n modelId: string,\n onProgress?: (event: ProgressEvent) => void,\n) {\n if (pipelineInstance && pipelineModelId === modelId) {\n return pipelineInstance;\n }\n\n onProgress?.({\n phase: \"loading\",\n progress: 0,\n message: \"Loading PII detection model...\",\n });\n\n // Dynamic import — only load Transformers.js when needed\n const { pipeline, env } = await import(\"@xenova/transformers\");\n\n // Attempt WebGPU, fall back gracefully\n env.allowLocalModels = false;\n\n // On mobile, skip the WebGPU probe (adds latency + often falls back anyway)\n // and go straight to WASM. On desktop, \"auto\" tries WebGPU first.\n const isMobile =\n typeof navigator !== \"undefined\" &&\n /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n const pipelineOptions: Record<string, unknown> = {\n progress_callback: (p: any) => {\n if (p.status === \"progress\" && p.total) {\n onProgress?.({\n phase: \"loading\",\n progress: p.loaded / p.total,\n message: `Downloading model: ${Math.round((p.loaded / p.total) * 100)}%`,\n });\n }\n },\n // Use WASM on mobile (avoids slow WebGPU probe), auto on desktop\n device: isMobile ? \"wasm\" : \"auto\",\n // q4 (~45 MB) vs q8 (~85 MB) — halves the download with minimal accuracy loss\n dtype: \"q4\",\n };\n\n pipelineInstance = await pipeline(\n \"token-classification\",\n modelId,\n pipelineOptions as any,\n );\n\n pipelineModelId = modelId;\n\n onProgress?.({\n phase: \"loading\",\n progress: 1,\n message: \"Model loaded.\",\n });\n\n return pipelineInstance;\n}\n\n/**\n * Pre-load the model without running inference.\n * The host app can call this to warm up the cache.\n */\nexport async function preloadNerModel(\n modelId: string,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<void> {\n await loadPipeline(modelId, onProgress);\n}\n\n/**\n * Release the NER model from memory.\n *\n * Disposes the underlying ONNX session if the pipeline supports it,\n * then clears the singleton so the next call to detectPiiNer reloads.\n *\n * Use this in low-memory mode after OCR completes and before NER loads,\n * or after the component is disconnected.\n */\nexport async function releaseNerModel(): Promise<void> {\n if (pipelineInstance) {\n try {\n // Transformers.js pipelines may expose a dispose() method\n if (typeof pipelineInstance.dispose === \"function\") {\n await pipelineInstance.dispose();\n }\n } catch {\n // Non-fatal — just clear the reference\n }\n pipelineInstance = null;\n pipelineModelId = null;\n }\n}\n","import type { PiiEntity } from \"../types.js\";\n\n/**\n * Regex-based PII detection for structured patterns that NER models\n * typically miss. These complement the NER model, not replace it.\n *\n * Each pattern has a label matching the NER entity taxonomy where possible.\n */\ninterface PiiPattern {\n label: string;\n pattern: RegExp;\n}\n\nconst PII_PATTERNS: PiiPattern[] = [\n // Email addresses\n {\n label: \"EMAIL\",\n pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g,\n },\n // Phone numbers (various formats)\n {\n label: \"TELEPHONENUM\",\n pattern:\n /(?:\\+?1[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}(?:\\s*(?:ext|x)\\.?\\s*\\d{1,5})?/g,\n },\n // International phone numbers\n {\n label: \"TELEPHONENUM\",\n pattern: /\\+\\d{1,3}[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,4}[-.\\s]?\\d{1,9}/g,\n },\n // Social Security Numbers (US)\n {\n label: \"SSN\",\n pattern: /\\b\\d{3}[-.\\s]?\\d{2}[-.\\s]?\\d{4}\\b/g,\n },\n // Credit card numbers (basic — 13-19 digits with optional separators)\n {\n label: \"CREDITCARD\",\n pattern: /\\b(?:\\d{4}[-.\\s]?){3,4}\\d{1,4}\\b/g,\n },\n // IP addresses (v4)\n {\n label: \"IP_ADDRESS\",\n pattern:\n /\\b(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b/g,\n },\n // Dates (various formats — these often contain birth dates)\n {\n label: \"DATE\",\n pattern:\n /\\b(?:\\d{1,2}[/.-]\\d{1,2}[/.-]\\d{2,4}|\\d{4}[/.-]\\d{1,2}[/.-]\\d{1,2})\\b/g,\n },\n // URLs with paths (may contain identifying query params)\n {\n label: \"URL\",\n pattern: /https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+/g,\n },\n // Street addresses (basic US pattern)\n {\n label: \"STREET\",\n pattern: /\\b\\d{1,5}\\s+[\\w\\s]{1,30}(?:street|st|avenue|ave|road|rd|drive|dr|lane|ln|boulevard|blvd|court|ct|way|place|pl)\\.?\\b/gi,\n },\n // Zip codes (US)\n {\n label: \"ZIPCODE\",\n pattern: /\\b\\d{5}(?:-\\d{4})?\\b/g,\n },\n // Usernames / handles (@mentions)\n {\n label: \"USERNAME\",\n pattern: /@[a-zA-Z0-9_]{2,30}\\b/g,\n },\n];\n\nlet idCounter = 0;\n\n/**\n * Run regex-based PII detection on the OCR text.\n * Returns deduplicated entities sorted by position.\n */\nexport function detectPiiRegex(text: string): PiiEntity[] {\n const entities: PiiEntity[] = [];\n\n for (const { label, pattern } of PII_PATTERNS) {\n // Reset regex state (global flag)\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = pattern.exec(text)) !== null) {\n entities.push({\n id: `regex-${idCounter++}`,\n label,\n text: match[0],\n start: match.index,\n end: match.index + match[0].length,\n score: 1.0,\n source: \"regex\",\n });\n }\n }\n\n // Sort by start position, then deduplicate overlapping spans\n entities.sort((a, b) => a.start - b.start || b.end - a.end);\n return deduplicateEntities(entities);\n}\n\n/**\n * Remove entities that are fully contained within another entity.\n * When two overlap, keep the longer one.\n */\nfunction deduplicateEntities(sorted: PiiEntity[]): PiiEntity[] {\n const result: PiiEntity[] = [];\n\n for (const entity of sorted) {\n const prev = result[result.length - 1];\n if (prev && entity.start >= prev.start && entity.end <= prev.end) {\n // Current is fully contained in previous — skip\n continue;\n }\n if (prev && entity.start < prev.end) {\n // Overlapping — keep the longer one\n if (entity.end - entity.start > prev.end - prev.start) {\n result[result.length - 1] = entity;\n }\n continue;\n }\n result.push(entity);\n }\n\n return result;\n}\n","import type { BBox, OcrWord, PiiEntity, Redaction } from \"../types.js\";\nimport { findWordsInSpan } from \"./ocr.js\";\n\nlet redactionIdCounter = 0;\n\n/**\n * The core bridge: maps PII entity character spans to image pixel bounding\n * boxes by finding which OCR words overlap each entity span, then merging\n * their bounding boxes.\n *\n * This is the piece that doesn't exist in any library — the connection\n * between text-domain PII detection and pixel-domain redaction.\n *\n * @param imageWidth Used to clamp bbox x1 within image bounds (0 = no clamp)\n * @param imageHeight Used to clamp bbox y1 within image bounds (0 = no clamp)\n */\nexport function entitiesToRedactions(\n entities: PiiEntity[],\n words: OcrWord[],\n imageWidth: number = 0,\n imageHeight: number = 0,\n): Redaction[] {\n const redactions: Redaction[] = [];\n\n for (const entity of entities) {\n // Skip entities without valid offsets\n if (entity.start == null || entity.end == null) {\n continue;\n }\n\n const overlapping = findWordsInSpan(words, entity.start, entity.end);\n\n // Fallback: if no words overlap by char offset, try fuzzy text matching\n let matchedWords = overlapping;\n if (matchedWords.length === 0 && entity.text) {\n matchedWords = findWordsByText(words, entity.text);\n }\n\n if (matchedWords.length === 0) {\n continue;\n }\n\n // Group overlapping words by line to avoid creating a single huge\n // bounding box that spans multiple lines\n const byLine = groupByLine(matchedWords);\n\n for (const lineWords of byLine.values()) {\n const merged = mergeBBoxes(lineWords.map((w) => w.bbox));\n redactions.push({\n id: `redact-${redactionIdCounter++}`,\n bbox: padBBox(merged, 2, imageWidth, imageHeight),\n source: \"auto\",\n entityId: entity.id,\n enabled: true,\n label: entity.label,\n });\n }\n }\n\n return redactions;\n}\n\n/**\n * Fallback: find words whose text matches (or contains) the entity text.\n * Used when character offset mapping fails.\n */\nfunction findWordsByText(words: OcrWord[], entityText: string): OcrWord[] {\n const lower = entityText.toLowerCase().trim();\n if (!lower) return [];\n\n // Try to find a contiguous sequence of words that form the entity text\n const entityWords = lower.split(/\\s+/);\n\n for (let i = 0; i <= words.length - entityWords.length; i++) {\n let match = true;\n for (let j = 0; j < entityWords.length; j++) {\n if (!words[i + j].text.toLowerCase().includes(entityWords[j]) &&\n !entityWords[j].includes(words[i + j].text.toLowerCase())) {\n match = false;\n break;\n }\n }\n if (match) {\n return words.slice(i, i + entityWords.length);\n }\n }\n\n // Single word match fallback\n const matched = words.filter((w) => {\n const wl = w.text.toLowerCase();\n return wl === lower || lower.includes(wl) || wl.includes(lower);\n });\n\n return matched;\n}\n\n/**\n * Group words by their line index. This prevents a multi-line entity\n * (rare, but possible with addresses) from producing one giant bbox\n * that covers everything between the first and last line.\n */\nfunction groupByLine(words: OcrWord[]): Map<number, OcrWord[]> {\n const map = new Map<number, OcrWord[]>();\n for (const word of words) {\n const group = map.get(word.lineIndex) ?? [];\n group.push(word);\n map.set(word.lineIndex, group);\n }\n return map;\n}\n\n/**\n * Merge an array of bounding boxes into a single box that contains all of them.\n */\nfunction mergeBBoxes(boxes: BBox[]): BBox {\n return {\n x0: Math.min(...boxes.map((b) => b.x0)),\n y0: Math.min(...boxes.map((b) => b.y0)),\n x1: Math.max(...boxes.map((b) => b.x1)),\n y1: Math.max(...boxes.map((b) => b.y1)),\n };\n}\n\n/**\n * Add padding to a bounding box, clamped to image bounds.\n *\n * @param maxW Image width (0 = no upper clamp on x)\n * @param maxH Image height (0 = no upper clamp on y)\n */\nfunction padBBox(bbox: BBox, padding: number, maxW: number = 0, maxH: number = 0): BBox {\n const x1 = bbox.x1 + padding;\n const y1 = bbox.y1 + padding;\n return {\n x0: Math.max(0, bbox.x0 - padding),\n y0: Math.max(0, bbox.y0 - padding),\n x1: maxW > 0 ? Math.min(maxW, x1) : x1,\n y1: maxH > 0 ? Math.min(maxH, y1) : y1,\n };\n}\n\n/**\n * Merge entities from NER and regex, deduplicating overlapping spans.\n * When NER and regex detect the same span, prefer the NER result\n * (it has a more specific label).\n */\nexport function mergeEntities(\n nerEntities: PiiEntity[],\n regexEntities: PiiEntity[],\n): PiiEntity[] {\n const all = [...nerEntities, ...regexEntities];\n all.sort((a, b) => a.start - b.start || b.end - a.end);\n\n const result: PiiEntity[] = [];\n\n for (const entity of all) {\n const prev = result[result.length - 1];\n if (!prev) {\n result.push(entity);\n continue;\n }\n\n // Check for overlap\n if (entity.start < prev.end) {\n // Overlapping — keep the one with higher confidence,\n // preferring NER over regex when scores are close\n const prevScore = prev.source === \"ner\" ? prev.score + 0.1 : prev.score;\n const currScore =\n entity.source === \"ner\" ? entity.score + 0.1 : entity.score;\n\n if (currScore > prevScore) {\n result[result.length - 1] = entity;\n }\n continue;\n }\n\n result.push(entity);\n }\n\n return result;\n}\n","import type { BBox, Redaction, RedactionResult } from \"../types.js\";\n\n/**\n * Render the original image with redaction boxes burned in.\n * Returns a PNG blob ready for upload.\n *\n * This is intentionally simple: draw the image, then fill black rectangles.\n * The simplicity is a feature — it's trivially auditable for a privacy tool.\n */\nexport async function renderRedactedImage(\n originalImage: HTMLImageElement | ImageBitmap,\n redactions: Redaction[],\n): Promise<RedactionResult> {\n const width =\n originalImage instanceof HTMLImageElement\n ? originalImage.naturalWidth\n : originalImage.width;\n const height =\n originalImage instanceof HTMLImageElement\n ? originalImage.naturalHeight\n : originalImage.height;\n\n // Use OffscreenCanvas if available (better for memory on mobile),\n // fall back to regular canvas\n const canvas = createCanvas(width, height);\n const ctx = getContext(canvas);\n\n // Draw original image\n ctx.drawImage(originalImage, 0, 0, width, height);\n\n // Draw black rectangles over enabled redactions\n ctx.fillStyle = \"#000000\";\n const appliedEntities: RedactionResult[\"entities\"] = [];\n\n for (const redaction of redactions) {\n if (!redaction.enabled) continue;\n\n const { x0, y0, x1, y1 } = redaction.bbox;\n ctx.fillRect(x0, y0, x1 - x0, y1 - y0);\n\n appliedEntities.push({\n label: redaction.label ?? \"UNKNOWN\",\n bbox: redaction.bbox,\n source: redaction.source,\n });\n }\n\n // Export as PNG\n const blob = await canvasToBlob(canvas);\n\n return {\n blob,\n entities: appliedEntities,\n width,\n height,\n };\n}\n\n/**\n * Quick preview: draw redaction boxes onto an existing canvas context.\n * Used for the live preview in the review phase (not for export).\n */\nexport function drawRedactionPreview(\n ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,\n redactions: Redaction[],\n style: { fill: string; stroke: string; lineWidth: number } = {\n fill: \"rgba(0, 0, 0, 0.7)\",\n stroke: \"#ff3333\",\n lineWidth: 2,\n },\n): void {\n for (const redaction of redactions) {\n if (!redaction.enabled) continue;\n\n const { x0, y0, x1, y1 } = redaction.bbox;\n const w = x1 - x0;\n const h = y1 - y0;\n\n ctx.fillStyle = style.fill;\n ctx.fillRect(x0, y0, w, h);\n\n ctx.strokeStyle = style.stroke;\n ctx.lineWidth = style.lineWidth;\n ctx.strokeRect(x0, y0, w, h);\n }\n}\n\n// --- Canvas helpers (abstract over OffscreenCanvas / HTMLCanvasElement) ---\n\nfunction createCanvas(\n width: number,\n height: number,\n): OffscreenCanvas | HTMLCanvasElement {\n if (typeof OffscreenCanvas !== \"undefined\") {\n return new OffscreenCanvas(width, height);\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas;\n}\n\nfunction getContext(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D {\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"Could not get 2D canvas context\");\n return ctx as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n}\n\nasync function canvasToBlob(\n canvas: OffscreenCanvas | HTMLCanvasElement,\n): Promise<Blob> {\n if (canvas instanceof OffscreenCanvas) {\n return canvas.convertToBlob({ type: \"image/png\" });\n }\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Canvas toBlob failed\"));\n },\n \"image/png\",\n );\n });\n}\n","/**\n * The complete redaction pipeline.\n *\n * This orchestrates: image → OCR → NER + regex → span→bbox bridge → redactions.\n * All processing happens in the browser. Nothing is sent to any server.\n */\n\nimport type {\n OcrResult,\n PiiEntity,\n ProgressEvent,\n Redaction,\n RedactorConfig,\n} from \"../types.js\";\nimport { runOcr } from \"./ocr.js\";\nimport { detectPiiNer, preloadNerModel, releaseNerModel } from \"./pii-ner.js\";\nimport { detectPiiRegex } from \"./pii-regex.js\";\nimport { entitiesToRedactions, mergeEntities } from \"./bridge.js\";\nimport { renderRedactedImage } from \"./redact.js\";\n\nexport { runOcr } from \"./ocr.js\";\nexport { detectPiiNer, preloadNerModel, releaseNerModel } from \"./pii-ner.js\";\nexport { detectPiiRegex } from \"./pii-regex.js\";\nexport { entitiesToRedactions, mergeEntities } from \"./bridge.js\";\nexport { renderRedactedImage, drawRedactionPreview } from \"./redact.js\";\nexport { preprocessForOcr, computeAverageLuminance, isDarkBackground, DARK_THRESHOLD } from \"./preprocess.js\";\n\n/**\n * Run the full pipeline: OCR → PII detection → redaction mapping.\n *\n * Returns the OCR text, detected entities, and proposed redaction boxes.\n * Does NOT render the final image — that happens when the user confirms.\n */\nexport async function analyzeImage(\n image: HTMLImageElement | ImageBitmap | Blob,\n config: RedactorConfig,\n onProgress?: (event: ProgressEvent) => void,\n): Promise<{\n ocr: OcrResult;\n entities: PiiEntity[];\n redactions: Redaction[];\n}> {\n const cfg = { ...config } as Required<RedactorConfig>;\n\n // Resolve memory mode: detect low-memory devices automatically\n const resolvedMemoryMode = resolveMemoryMode(cfg.memoryMode);\n\n // Step 1: OCR\n onProgress?.({ phase: \"ocr\", progress: 0, message: \"Starting OCR...\" });\n const ocr = await runOcr(image, cfg.lang, onProgress);\n\n if (!ocr.fullText.trim()) {\n return { ocr, entities: [], redactions: [] };\n }\n\n // Step 2: PII detection (NER + regex in parallel)\n onProgress?.({\n phase: \"detecting\",\n progress: 0,\n message: \"Detecting personal information...\",\n });\n\n const regexEntities = cfg.useRegex ? detectPiiRegex(ocr.fullText) : [];\n\n // In low-memory mode, release any cached NER model before loading a fresh\n // one — this avoids holding two large model allocations simultaneously.\n // (The OCR worker was already terminated in runOcr's finally block.)\n if (resolvedMemoryMode === \"low\") {\n await releaseNerModel();\n }\n\n // Run NER (async, slower)\n const nerEntities = await detectPiiNer(ocr.fullText, cfg.nerModel, cfg.minConfidence, onProgress);\n\n // Step 3: Merge and deduplicate\n const entities = mergeEntities(nerEntities, regexEntities);\n\n // Step 4: Map to image bounding boxes\n const redactions = entitiesToRedactions(entities, ocr.words, ocr.imageWidth, ocr.imageHeight);\n\n onProgress?.({\n phase: \"reviewing\",\n progress: 1,\n message: `Found ${redactions.length} items to redact.`,\n });\n\n return { ocr, entities, redactions };\n}\n\n/**\n * Determine the effective memory mode.\n *\n * \"auto\" uses `navigator.deviceMemory` (Chrome/Edge only; undefined elsewhere).\n * When the API is unavailable we default to \"normal\" to avoid unnecessary\n * sequential delays on desktop browsers that don't expose memory info.\n */\nfunction resolveMemoryMode(mode: Required<RedactorConfig>[\"memoryMode\"]): \"low\" | \"normal\" {\n if (mode === \"low\") return \"low\";\n if (mode === \"normal\") return \"normal\";\n\n // \"auto\": probe the device memory API\n const deviceMemory = (navigator as any).deviceMemory as number | undefined;\n if (deviceMemory !== undefined && deviceMemory < 4) {\n return \"low\";\n }\n return \"normal\";\n}\n","/**\n * Bounding box in original image pixel coordinates.\n */\nexport interface BBox {\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n}\n\n/**\n * A word extracted by OCR, with its position in both the image and the\n * reconstructed full-text string.\n */\nexport interface OcrWord {\n text: string;\n bbox: BBox;\n confidence: number;\n /** Inclusive start index in the reconstructed full text. */\n charStart: number;\n /** Exclusive end index in the reconstructed full text. */\n charEnd: number;\n /** Index of the line this word belongs to. */\n lineIndex: number;\n}\n\n/**\n * Full result from the OCR stage.\n */\nexport interface OcrResult {\n /** Reconstructed full text (words joined by spaces, lines by newlines). */\n fullText: string;\n words: OcrWord[];\n /** Original image dimensions in pixels. */\n imageWidth: number;\n imageHeight: number;\n}\n\n/**\n * A PII entity detected by the NER model or regex patterns.\n */\nexport interface PiiEntity {\n id: string;\n /** NER label: GIVENNAME, SURNAME, EMAIL, TELEPHONENUM, CITY, DATE, etc. */\n label: string;\n /** The matched text. */\n text: string;\n /** Character offset (inclusive) in the OCR full text. */\n start: number;\n /** Character offset (exclusive) in the OCR full text. */\n end: number;\n /** Confidence score 0-1. For regex matches this is 1.0. */\n score: number;\n /** Detection source. */\n source: \"ner\" | \"regex\";\n}\n\n/**\n * A redaction box to be drawn on the image.\n */\nexport interface Redaction {\n id: string;\n bbox: BBox;\n /** How this redaction was created. */\n source: \"auto\" | \"manual\";\n /** If auto-detected, the entity that produced it. */\n entityId?: string;\n /** User can toggle individual redactions off. */\n enabled: boolean;\n /** Display label for the entity type. */\n label?: string;\n}\n\n/**\n * The phases the component moves through.\n */\nexport type Phase =\n | \"idle\"\n | \"loading\"\n | \"ocr\"\n | \"detecting\"\n | \"reviewing\"\n | \"exporting\"\n | \"done\";\n\n/**\n * Progress update emitted during model loading and processing.\n */\nexport interface ProgressEvent {\n phase: Phase;\n /** 0-1 progress within the current phase. */\n progress: number;\n message: string;\n}\n\n/**\n * Final output when user confirms redactions.\n */\nexport interface RedactionResult {\n /** PNG blob with redactions burned in. */\n blob: Blob;\n /** Detected entities (for metadata — contains no PII, only labels + bbox). */\n entities: Array<{\n label: string;\n bbox: BBox;\n source: \"auto\" | \"manual\";\n }>;\n /** Image dimensions. */\n width: number;\n height: number;\n}\n\n/**\n * Configuration for the redactor component.\n */\nexport interface RedactorConfig {\n /** Tesseract OCR language. Default: 'eng'. */\n lang?: string;\n /** HuggingFace model ID for NER. */\n nerModel?: string;\n /** Maximum file size in bytes. Default: 20MB. */\n maxFileSize?: number;\n /** Accepted MIME types. */\n acceptedTypes?: string[];\n /** Minimum NER confidence to auto-redact. Default: 0.7. */\n minConfidence?: number;\n /** Whether to run regex PII patterns in addition to NER. Default: true. */\n useRegex?: boolean;\n /**\n * Memory mode for constrained devices.\n *\n * - `\"auto\"`: Detect from `navigator.deviceMemory`; use \"low\" when < 4 GB.\n * - `\"low\"`: Release the Tesseract worker before loading the NER model,\n * reducing peak RAM. Adds a small sequential delay.\n * - `\"normal\"`: Run Tesseract and NER without explicit memory management.\n *\n * Default: \"auto\"\n */\n memoryMode?: \"auto\" | \"low\" | \"normal\";\n}\n\nexport const DEFAULT_CONFIG: Required<RedactorConfig> = {\n lang: \"eng\",\n nerModel: \"onnx-community/multilang-pii-ner-ONNX\",\n maxFileSize: 20 * 1024 * 1024,\n acceptedTypes: [\"image/png\", \"image/jpeg\", \"image/webp\"],\n minConfidence: 0.7,\n useRegex: true,\n memoryMode: \"auto\",\n};\n","import { LitElement, html, svg, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property, state, query } from \"lit/decorators.js\";\nimport { redactorStyles } from \"./styles.js\";\nimport { shieldIcon, uploadIcon } from \"./icons.js\";\nimport { analyzeImage } from \"../pipeline/index.js\";\nimport { renderRedactedImage } from \"../pipeline/redact.js\";\nimport { preloadNerModel } from \"../pipeline/pii-ner.js\";\nimport type {\n Phase,\n Redaction,\n PiiEntity,\n OcrResult,\n RedactorConfig,\n RedactionResult,\n ProgressEvent,\n BBox,\n DEFAULT_CONFIG,\n} from \"../types.js\";\nimport { DEFAULT_CONFIG as DEFAULTS } from \"../types.js\";\n\n/**\n * <pii-redactor> — Client-side PII redaction for screenshot images.\n *\n * All OCR and PII detection runs in the browser. Your data never leaves\n * your device.\n *\n * @fires redaction-complete - When the user confirms redactions. Detail: RedactionResult.\n * @fires redaction-cancel - When the user cancels.\n * @fires error - When an error occurs. Detail: { message: string }.\n */\n@customElement(\"pii-redactor\")\nexport class PiiRedactor extends LitElement {\n static override styles = redactorStyles;\n\n // --- Public properties (configurable via attributes) ---\n\n @property({ type: String }) lang = DEFAULTS.lang;\n @property({ type: String, attribute: \"ner-model\" }) nerModel =\n DEFAULTS.nerModel;\n @property({ type: Number, attribute: \"max-file-size\" }) maxFileSize =\n DEFAULTS.maxFileSize;\n @property({ type: Number, attribute: \"min-confidence\" }) minConfidence =\n DEFAULTS.minConfidence;\n\n\n // --- Internal state ---\n\n @state() private phase: Phase = \"idle\";\n @state() private progress = 0;\n @state() private progressMessage = \"\";\n @state() private errorMessage = \"\";\n @state() private imageUrl = \"\";\n @state() private imageWidth = 0;\n @state() private imageHeight = 0;\n @state() private redactions: Redaction[] = [];\n @state() private entities: PiiEntity[] = [];\n @state() private ocrResult: OcrResult | null = null;\n @state() private dragOver = false;\n @state() private isDrawing = false;\n @state() private drawMode = false;\n @state() private drawStart: { x: number; y: number } | null = null;\n @state() private drawCurrent: { x: number; y: number } | null = null;\n @state() private networkRequestCount = 0;\n @state() private redactedBlob: Blob | null = null;\n @state() private modelCached = false;\n\n private imageFile: File | null = null;\n private imageElement: HTMLImageElement | null = null;\n private undoStack: Redaction[][] = [];\n private perfObserver: PerformanceObserver | null = null;\n\n @query(\".file-input\") private fileInput!: HTMLInputElement;\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Count outbound network requests to HuggingFace CDN (model downloads)\n // so the trust banner shows real data. buffered:false means we only see\n // requests that happen after the component connects — not page-load assets.\n if (typeof PerformanceObserver !== \"undefined\") {\n this.perfObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n const url = (entry as PerformanceResourceTiming).name ?? \"\";\n if (url.includes(\"huggingface.co\") || url.includes(\"hf.co\")) {\n this.networkRequestCount++;\n }\n }\n });\n try {\n this.perfObserver.observe({ type: \"resource\", buffered: false });\n } catch {\n // Some environments don't support resource timing — ignore\n this.perfObserver = null;\n }\n }\n\n // Silently preload the model in the background so it's cached by the\n // time the user picks a file. Skip if the user is on a metered/slow\n // connection or low battery — we'll download on demand with visible\n // progress instead.\n this.maybePreloadModel();\n }\n\n private async maybePreloadModel(): Promise<void> {\n // Respect data-saver and slow connections\n const conn = (navigator as any).connection;\n if (conn) {\n if (conn.saveData) return;\n if (conn.effectiveType === \"2g\" || conn.effectiveType === \"slow-2g\") return;\n }\n\n // Respect low battery\n if (\"getBattery\" in navigator) {\n try {\n const battery = await (navigator as any).getBattery();\n if (!battery.charging && battery.level < 0.2) return;\n } catch {\n // getBattery not available or denied — continue with preload\n }\n }\n\n preloadNerModel(this.nerModel).catch(() => {});\n }\n\n // --- Public methods ---\n\n /** Pre-load AI models imperatively. Call this to warm up the cache ahead of time. */\n async preload(): Promise<void> {\n await preloadNerModel(this.nerModel, (e) => this.handleProgress(e));\n }\n\n /** Reset to the initial idle state. */\n reset(): void {\n this.phase = \"idle\";\n this.progress = 0;\n this.progressMessage = \"\";\n this.errorMessage = \"\";\n this.redactions = [];\n this.entities = [];\n this.ocrResult = null;\n this.imageFile = null;\n this.undoStack = [];\n this.drawMode = false;\n if (this.imageUrl) {\n URL.revokeObjectURL(this.imageUrl);\n this.imageUrl = \"\";\n }\n this.imageElement = null;\n this.redactedBlob = null;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this.imageUrl) URL.revokeObjectURL(this.imageUrl);\n this.perfObserver?.disconnect();\n this.perfObserver = null;\n }\n\n // --- Rendering ---\n\n override render() {\n return html`\n <div class=\"container\">\n ${this.renderTrustBanner()}\n ${this.phase === \"idle\" ? this.renderDropZone() : nothing}\n ${this.phase === \"loading\" ||\n this.phase === \"ocr\" ||\n this.phase === \"detecting\"\n ? this.renderProgress()\n : nothing}\n ${this.phase === \"reviewing\" ? this.renderEditor() : nothing}\n ${this.phase === \"exporting\" ? this.renderProgress() : nothing}\n ${this.phase === \"done\" ? this.renderDone() : nothing}\n ${this.errorMessage ? this.renderError() : nothing}\n </div>\n `;\n }\n\n private renderTrustBanner() {\n return html`\n <div class=\"trust-banner\">\n ${shieldIcon}\n <span>Your data never leaves your device. All processing happens in\n your browser.</span>\n </div>\n `;\n }\n\n private renderDropZone() {\n return html`\n <div\n class=\"dropzone ${this.dragOver ? \"dragover\" : \"\"}\"\n @click=${this.handleDropZoneClick}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n ${uploadIcon}\n <div class=\"dropzone-text\">\n <strong>Choose a screenshot</strong> or drag it here\n </div>\n <div class=\"dropzone-hint\">\n PNG, JPG, or WebP up to\n ${Math.round(this.maxFileSize / 1024 / 1024)}MB\n </div>\n <input\n class=\"file-input\"\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n @change=${this.handleFileSelect}\n />\n </div>\n `;\n }\n\n private renderProgress() {\n const phaseLabels: Record<string, string> = {\n loading: \"Loading AI models\",\n ocr: \"Reading text from image\",\n detecting: \"Detecting personal information\",\n exporting: \"Preparing redacted image\",\n };\n\n return html`\n <div class=\"progress-container\">\n <div class=\"progress-phase\">\n ${phaseLabels[this.phase] ?? \"Processing...\"}\n </div>\n <div class=\"progress-bar-track\">\n <div\n class=\"progress-bar-fill\"\n style=\"width: ${Math.round(this.progress * 100)}%\"\n ></div>\n </div>\n <div class=\"progress-message\">${this.progressMessage}</div>\n </div>\n `;\n }\n\n private renderEditor() {\n const vb = `0 0 ${this.imageWidth} ${this.imageHeight}`;\n\n return html`\n <div class=\"editor\">\n <div class=\"toolbar\">\n <div class=\"toolbar-row toolbar-utils\">\n <button\n class=\"${this.drawMode ? \"active\" : \"\"}\"\n @click=${this.toggleDrawMode}\n title=\"Draw a redaction box manually\"\n >\n ${this.drawMode ? \"Drawing...\" : \"+ Add box\"}\n </button>\n <button\n @click=${this.handleUndo}\n ?disabled=${this.undoStack.length === 0}\n >\n Undo\n </button>\n <button @click=${this.handleSelectAll}>Select all</button>\n <button @click=${this.handleDeselectAll}>Deselect all</button>\n </div>\n <div class=\"toolbar-row toolbar-actions\">\n <button class=\"danger\" @click=${this.handleCancel}>Cancel</button>\n <button class=\"primary\" @click=${this.handleConfirm}>\n Confirm &amp; redact\n </button>\n </div>\n </div>\n\n <div class=\"viewport\">\n <div class=\"viewport-inner\">\n <img\n src=${this.imageUrl}\n alt=\"Screenshot to redact\"\n @load=${this.handleImageLoad}\n />\n <svg\n class=${this.drawMode ? \"draw-mode\" : \"\"}\n viewBox=${vb}\n preserveAspectRatio=\"xMidYMid meet\"\n xmlns=\"http://www.w3.org/2000/svg\"\n @pointerdown=${this.handleSvgPointerDown}\n @pointermove=${this.handleSvgPointerMove}\n @pointerup=${this.handleSvgPointerUp}\n @pointercancel=${this.handleSvgPointerCancel}\n >\n ${this.redactions.map(\n (r) => svg`\n <rect\n class=\"redaction-box ${r.enabled ? \"\" : \"disabled\"}\"\n x=${r.bbox.x0}\n y=${r.bbox.y0}\n width=${r.bbox.x1 - r.bbox.x0}\n height=${r.bbox.y1 - r.bbox.y0}\n data-id=${r.id}\n @click=${(e: Event) => this.handleRedactionClick(e, r.id)}\n >\n <title>${r.label ?? \"Redaction\"}: ${r.enabled ? \"enabled\" : \"disabled\"}</title>\n </rect>\n `,\n )}\n ${this.isDrawing && this.drawStart && this.drawCurrent\n ? svg`\n <rect\n class=\"drawing\"\n x=${Math.min(this.drawStart.x, this.drawCurrent.x)}\n y=${Math.min(this.drawStart.y, this.drawCurrent.y)}\n width=${Math.abs(this.drawCurrent.x - this.drawStart.x)}\n height=${Math.abs(this.drawCurrent.y - this.drawStart.y)}\n />\n `\n : nothing}\n </svg>\n </div>\n </div>\n\n <div class=\"entity-list\">\n <div class=\"entity-list-header\">\n Detected items (${this.redactions.filter((r) => r.enabled).length}\n / ${this.redactions.length})\n </div>\n ${this.redactions.map(\n (r) => html`\n <label class=\"entity-item\">\n <input\n type=\"checkbox\"\n .checked=${r.enabled}\n @change=${(e: Event) =>\n this.handleToggleRedaction(\n r.id,\n (e.target as HTMLInputElement).checked,\n )}\n />\n <span class=\"entity-label\">${r.label ?? \"manual\"}</span>\n <span class=\"entity-text\"\n >${this.getRedactionText(r)}</span\n >\n <span class=\"entity-source\">${r.source}</span>\n </label>\n `,\n )}\n </div>\n </div>\n `;\n }\n\n private renderError() {\n return html`\n <div class=\"error\">\n <p>${this.errorMessage}</p>\n <button @click=${this.reset}>Try again</button>\n </div>\n `;\n }\n\n private renderDone() {\n const canShare =\n typeof navigator.share === \"function\" &&\n typeof navigator.canShare === \"function\" &&\n this.redactedBlob != null &&\n navigator.canShare({\n files: [new File([this.redactedBlob], \"redacted.png\", { type: \"image/png\" })],\n });\n\n const networkNote = this.networkRequestCount === 0\n ? html`<p class=\"done-network done-network-zero\">\n Network requests to AI model host: 0 — served from local cache.\n </p>`\n : html`<p class=\"done-network\">\n Network requests to AI model host: ${this.networkRequestCount}.\n ${this.modelCached\n ? html`Model is now cached — next time will be 0.`\n : nothing}\n </p>`;\n\n return html`\n <div class=\"done\">\n <div class=\"done-title\">Redaction complete</div>\n <div class=\"done-actions\">\n <button class=\"primary\" @click=${this.handleDownload}>\n Download\n </button>\n ${canShare\n ? html`<button @click=${this.handleShare}>Share</button>`\n : nothing}\n <button @click=${this.reset}>Redact another</button>\n </div>\n ${networkNote}\n </div>\n `;\n }\n\n // --- File handling ---\n\n private handleDropZoneClick() {\n this.fileInput?.click();\n }\n\n private handleDragOver(e: DragEvent) {\n e.preventDefault();\n this.dragOver = true;\n }\n\n private handleDragLeave() {\n this.dragOver = false;\n }\n\n private handleDrop(e: DragEvent) {\n e.preventDefault();\n this.dragOver = false;\n const file = e.dataTransfer?.files[0];\n if (file) this.processFile(file);\n }\n\n private handleFileSelect(e: Event) {\n const input = e.target as HTMLInputElement;\n const file = input.files?.[0];\n if (file) this.processFile(file);\n // Reset input so the same file can be selected again\n input.value = \"\";\n }\n\n private async processFile(file: File) {\n // Validate\n if (!DEFAULTS.acceptedTypes.includes(file.type)) {\n this.errorMessage = `Unsupported file type: ${file.type}. Please use PNG, JPEG, or WebP.`;\n return;\n }\n if (file.size > this.maxFileSize) {\n this.errorMessage = `File too large (${Math.round(file.size / 1024 / 1024)}MB). Maximum is ${Math.round(this.maxFileSize / 1024 / 1024)}MB.`;\n return;\n }\n\n this.errorMessage = \"\";\n this.networkRequestCount = 0;\n this.imageFile = file;\n this.imageUrl = URL.createObjectURL(file);\n this.phase = \"loading\";\n\n try {\n // Load image to get dimensions\n const img = await this.loadImage(this.imageUrl);\n this.imageElement = img;\n this.imageWidth = img.naturalWidth;\n this.imageHeight = img.naturalHeight;\n\n // Run the pipeline\n const config: RedactorConfig = {\n lang: this.lang,\n nerModel: this.nerModel,\n minConfidence: this.minConfidence,\n };\n\n const result = await analyzeImage(file, config, (e) =>\n this.handleProgress(e),\n );\n\n this.ocrResult = result.ocr;\n this.entities = result.entities;\n this.redactions = result.redactions;\n this.undoStack = [];\n this.phase = \"reviewing\";\n\n // Check if model is now cached in a SW (for the done-screen hint)\n this.checkModelCached();\n } catch (err) {\n console.error(\"Pipeline error:\", err);\n this.errorMessage =\n err instanceof Error ? err.message : \"An unexpected error occurred.\";\n this.phase = \"idle\";\n }\n }\n\n private async checkModelCached(): Promise<void> {\n if (!(\"caches\" in window)) return;\n try {\n // The SW caches HuggingFace model files under a known cache name.\n // If any huggingface.co entry exists we know the model is cached.\n const cacheNames = await caches.keys();\n for (const name of cacheNames) {\n const cache = await caches.open(name);\n const keys = await cache.keys();\n if (keys.some((r) => r.url.includes(\"huggingface.co\"))) {\n this.modelCached = true;\n return;\n }\n }\n } catch {\n // Cache API blocked (e.g. private browsing on some browsers) — ignore\n }\n }\n\n private loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(\"Failed to load image\"));\n img.src = src;\n });\n }\n\n // --- Progress ---\n\n private handleProgress(event: ProgressEvent) {\n this.phase = event.phase;\n this.progress = event.progress;\n this.progressMessage = event.message;\n }\n\n // --- Redaction editing ---\n\n private handleRedactionClick(e: Event, id: string) {\n e.stopPropagation();\n if (this.drawMode) return;\n\n const redaction = this.redactions.find((r) => r.id === id);\n if (redaction) {\n this.pushUndo();\n this.redactions = this.redactions.map((r) =>\n r.id === id ? { ...r, enabled: !r.enabled } : r,\n );\n }\n }\n\n private handleToggleRedaction(id: string, enabled: boolean) {\n this.pushUndo();\n this.redactions = this.redactions.map((r) =>\n r.id === id ? { ...r, enabled } : r,\n );\n }\n\n private handleSelectAll() {\n this.pushUndo();\n this.redactions = this.redactions.map((r) => ({ ...r, enabled: true }));\n }\n\n private handleDeselectAll() {\n this.pushUndo();\n this.redactions = this.redactions.map((r) => ({ ...r, enabled: false }));\n }\n\n private handleUndo() {\n const prev = this.undoStack.pop();\n if (prev) {\n this.redactions = prev;\n // Trigger reactivity for undoStack\n this.undoStack = [...this.undoStack];\n }\n }\n\n private pushUndo() {\n this.undoStack = [...this.undoStack, [...this.redactions]];\n }\n\n // --- Drawing manual boxes ---\n\n private toggleDrawMode() {\n this.drawMode = !this.drawMode;\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n }\n\n private svgPointFromEvent(e: PointerEvent): { x: number; y: number } {\n const svg = (e.currentTarget as SVGSVGElement) ?? this.renderRoot.querySelector(\"svg\");\n if (!svg) return { x: 0, y: 0 };\n\n const pt = svg.createSVGPoint();\n pt.x = e.clientX;\n pt.y = e.clientY;\n const ctm = svg.getScreenCTM();\n if (!ctm) return { x: 0, y: 0 };\n\n const svgPt = pt.matrixTransform(ctm.inverse());\n return { x: svgPt.x, y: svgPt.y };\n }\n\n private handleSvgPointerDown(e: PointerEvent) {\n if (!this.drawMode) return;\n\n const point = this.svgPointFromEvent(e);\n this.drawStart = point;\n this.drawCurrent = point;\n this.isDrawing = true;\n\n // Capture pointer for smooth drawing\n (e.currentTarget as Element).setPointerCapture(e.pointerId);\n e.preventDefault();\n }\n\n private handleSvgPointerMove(e: PointerEvent) {\n if (!this.isDrawing || !this.drawStart) return;\n this.drawCurrent = this.svgPointFromEvent(e);\n e.preventDefault();\n }\n\n private handleSvgPointerUp(e: PointerEvent) {\n if (!this.isDrawing || !this.drawStart || !this.drawCurrent) return;\n\n const x0 = Math.min(this.drawStart.x, this.drawCurrent.x);\n const y0 = Math.min(this.drawStart.y, this.drawCurrent.y);\n const x1 = Math.max(this.drawStart.x, this.drawCurrent.x);\n const y1 = Math.max(this.drawStart.y, this.drawCurrent.y);\n\n // Only add if the box is at least 10px in image space\n if (x1 - x0 > 10 && y1 - y0 > 10) {\n this.pushUndo();\n const newRedaction: Redaction = {\n id: `manual-${Date.now()}`,\n bbox: { x0, y0, x1, y1 },\n source: \"manual\",\n enabled: true,\n label: \"MANUAL\",\n };\n this.redactions = [...this.redactions, newRedaction];\n }\n\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n this.drawMode = false;\n }\n\n private handleSvgPointerCancel() {\n // Touch was interrupted (e.g. incoming call, scroll takeover) — abort draw\n this.isDrawing = false;\n this.drawStart = null;\n this.drawCurrent = null;\n // Keep drawMode on so the user can try again\n }\n\n // --- Actions ---\n\n private async handleConfirm() {\n if (!this.imageElement) return;\n\n this.phase = \"exporting\";\n this.progress = 0.5;\n this.progressMessage = \"Rendering redacted image...\";\n\n try {\n const result = await renderRedactedImage(\n this.imageElement,\n this.redactions,\n );\n\n this.dispatchEvent(\n new CustomEvent<RedactionResult>(\"redaction-complete\", {\n detail: result,\n bubbles: true,\n composed: true,\n }),\n );\n\n this.redactedBlob = result.blob;\n this.phase = \"done\";\n } catch (err) {\n console.error(\"Export error:\", err);\n this.errorMessage =\n err instanceof Error ? err.message : \"Failed to export redacted image.\";\n this.phase = \"reviewing\";\n }\n }\n\n private handleCancel() {\n this.dispatchEvent(\n new CustomEvent(\"redaction-cancel\", {\n bubbles: true,\n composed: true,\n }),\n );\n this.reset();\n }\n\n private handleDownload() {\n if (!this.redactedBlob) return;\n const url = URL.createObjectURL(this.redactedBlob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = this.imageFile\n ? `redacted-${this.imageFile.name.replace(/\\.[^.]+$/, \"\")}.png`\n : \"redacted.png\";\n a.click();\n URL.revokeObjectURL(url);\n }\n\n private async handleShare() {\n if (!this.redactedBlob) return;\n const filename = this.imageFile\n ? `redacted-${this.imageFile.name.replace(/\\.[^.]+$/, \"\")}.png`\n : \"redacted.png\";\n const file = new File([this.redactedBlob], filename, { type: \"image/png\" });\n try {\n await navigator.share({ files: [file] });\n } catch (err) {\n // AbortError means user dismissed the share sheet — not an error\n if (err instanceof Error && err.name !== \"AbortError\") {\n this.errorMessage = \"Share failed. Try downloading instead.\";\n }\n }\n }\n\n // --- Helpers ---\n\n private getRedactionText(r: Redaction): string {\n if (r.source === \"manual\") return \"(manually drawn)\";\n if (!r.entityId || !this.ocrResult) return \"\";\n const entity = this.entities.find((e) => e.id === r.entityId);\n return entity?.text ?? \"\";\n }\n\n private handleImageLoad(e: Event) {\n const img = e.target as HTMLImageElement;\n this.imageWidth = img.naturalWidth;\n this.imageHeight = img.naturalHeight;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"pii-redactor\": PiiRedactor;\n }\n}\n","/**\n * Service Worker registration helper for the PII redactor.\n *\n * The SW provides two capabilities:\n *\n * 1. **Model caching**: Intercepts HuggingFace model downloads and caches them\n * in Cache Storage so subsequent loads are instant and fully offline.\n *\n * 2. **Network firewall** (optional): After models are cached, the SW can\n * block all non-cached outbound requests. This is the technical proof that\n * no PII ever leaves the browser — the user can verify it by going offline.\n *\n * ## Setup\n *\n * 1. Copy `pii-redactor-sw.js` from the package's `public/` directory to your\n * web server's root (or wherever your SW scope should be).\n *\n * 2. Call `registerServiceWorker()` once on page load, before running any\n * image analysis.\n *\n * ## Two-phase CSP trust model\n *\n * - **Phase 1 (loader page)**: `connect-src *` — allow model downloads\n * - **Phase 2 (app page)**: `connect-src 'none'` — block all outbound after cache\n *\n * The SW makes Phase 2 the default once models are warm. The app page can\n * serve with strict CSP without breaking model inference.\n */\n\nexport interface SwRegistrationOptions {\n /**\n * Path to the Service Worker file on the server.\n * Default: \"/pii-redactor-sw.js\"\n */\n swPath?: string;\n\n /**\n * Service Worker scope. Controls which pages the SW can intercept.\n * Default: the directory containing the SW file.\n */\n scope?: string;\n}\n\n/**\n * Register the PII redactor Service Worker.\n *\n * Safe to call in environments without SW support — returns null gracefully.\n *\n * @returns The ServiceWorkerRegistration, or null if SW is not supported or\n * registration fails.\n */\nexport async function registerServiceWorker(\n options: SwRegistrationOptions = {},\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator) || !navigator.serviceWorker) {\n return null;\n }\n\n const swPath = options.swPath ?? \"/pii-redactor-sw.js\";\n const registerOptions: RegistrationOptions = {};\n if (options.scope) {\n registerOptions.scope = options.scope;\n }\n\n try {\n const registration = await navigator.serviceWorker.register(swPath, registerOptions);\n return registration;\n } catch {\n return null;\n }\n}\n\n/**\n * Unregister all Service Workers in the current scope.\n *\n * Useful during development or when the user wants to fully reset.\n *\n * @returns true if at least one registration was removed.\n */\nexport async function unregisterServiceWorker(): Promise<boolean> {\n if (!(\"serviceWorker\" in navigator) || !navigator.serviceWorker) {\n return false;\n }\n\n try {\n const registrations = await navigator.serviceWorker.getRegistrations();\n const results = await Promise.all(registrations.map((r) => r.unregister()));\n return results.some(Boolean);\n } catch {\n return false;\n }\n}\n"],"names":["t","e","s","o","n$3","r","n","i","S","c","h","a","l","p","d","u","f","b","y$1","y","v","_","m","g","$","x","w","E","A","C","P","V","N","I","L","z","H","R","k","Z","B","D","redactorStyles","css","shieldIcon","svg","uploadIcon","DARK_THRESHOLD","computeAverageLuminance","pixels","pixelCount","total","isDarkBackground","preprocessForOcr","source","canvas","ctx","imageBitmap","width","height","sampleSize","sampleW","sampleH","sampleData","applyContrast","imageData","data","factor","clamp","resolve","reject","blob","value","runOcr","image","lang","onProgress","worker","rawBlob","knownWidth","knownHeight","bmp","result","words","fullText","charOffset","lines","lineIndex","lineWords","wi","text","charStart","charEnd","imageWidth","imageHeight","findWordsInSpan","start","end","pipelineInstance","pipelineModelId","detectPiiNer","modelId","minConfidence","pipeline","loadPipeline","rawEntities","mapAggregatedEntities","aggregateAndMapTokens","idCounter","entities","entity","label","word","found","findTextInString","canonicalText","cleanLabel","tokens","currentGroup","currentType","token","merged","mergeTokenGroup","bioPrefix","typeLabel","id","avgScore","sum","firstWithStart","lastWithEnd","entityText","mergedText","firstWord","found2","needle","fromIndex","idx","lowerText","lowerNeedle","env","isMobile","preloadNerModel","releaseNerModel","PII_PATTERNS","detectPiiRegex","pattern","match","deduplicateEntities","sorted","prev","redactionIdCounter","entitiesToRedactions","redactions","matchedWords","findWordsByText","byLine","groupByLine","mergeBBoxes","padBBox","lower","entityWords","j","wl","map","group","boxes","bbox","padding","maxW","maxH","x1","y1","mergeEntities","nerEntities","regexEntities","all","prevScore","renderRedactedImage","originalImage","createCanvas","getContext","appliedEntities","redaction","x0","y0","canvasToBlob","drawRedactionPreview","style","analyzeImage","config","cfg","resolvedMemoryMode","resolveMemoryMode","ocr","mode","deviceMemory","DEFAULT_CONFIG","PiiRedactor","LitElement","DEFAULTS","list","entry","url","conn","battery","html","nothing","vb","canShare","networkNote","file","input","img","err","cacheNames","name","src","event","enabled","pt","ctm","svgPt","point","newRedaction","filename","__decorateClass","property","state","query","customElement","registerServiceWorker","options","swPath","registerOptions","unregisterServiceWorker","registrations"],"mappings":"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AAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AAAAA;AA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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "image-pii-redactor",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Client-side PII redaction for screenshot images. OCR + NER in the browser — your data never leaves your device.",
5
5
  "type": "module",
6
6
  "main": "dist/image-pii-redactor.js",