trtc-sdk-v5 5.18.2-beta.2 → 5.18.2-beta.4

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.
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trtc-sdk-v5",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "description": "Tencent Cloud RTC SDK for Web",
5
5
  "main": "trtc.js",
6
6
  "types": "index.d.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtc-plugin/cdn-streaming",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "description": "TRTC Web SDK 5.x CDN streaming plugin",
5
5
  "main": "./cdn-streaming.esm.js",
6
6
  "module": "./cdn-streaming.esm.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtc-plugin/chorus",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "description": "TRTC Web SDK 5.x Chorus plugin",
5
5
  "main": "./chorus.esm.js",
6
6
  "module": "./chorus.esm.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtc-plugin/cross-room",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "description": "TRTC Web SDK 5.x Cross Room plugin",
5
5
  "main": "./cross-room.esm.js",
6
6
  "module": "./cross-room.esm.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtc-plugin/custom-encryption",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "main": "./custom-encryption.esm.js",
5
5
  "module": "./custom-encryption.esm.js",
6
6
  "types": "./custom-encryption.esm.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtc-plugin/device-detector",
3
- "version": "5.18.2-beta.2",
3
+ "version": "5.18.2-beta.4",
4
4
  "description": "TRTC Web SDK 5.x device detector plugin",
5
5
  "main": "./device-detector.esm.js",
6
6
  "module": "./device-detector.esm.js",
@@ -1 +1 @@
1
- var __create=Object.create,__defProp=Object.defineProperty,__defProps=Object.defineProperties,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropDescs=Object.getOwnPropertyDescriptors,__getOwnPropNames=Object.getOwnPropertyNames,__getOwnPropSymbols=Object.getOwnPropertySymbols,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(e,t,i)=>t in e?__defProp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,__spreadValues=(e,t)=>{for(var i in t||(t={}))__hasOwnProp.call(t,i)&&__defNormalProp(e,i,t[i]);if(__getOwnPropSymbols)for(var i of __getOwnPropSymbols(t))__propIsEnum.call(t,i)&&__defNormalProp(e,i,t[i]);return e},__spreadProps=(e,t)=>__defProps(e,__getOwnPropDescs(t)),__commonJS=(e,t)=>function(){return t||(0,e[__getOwnPropNames(e)[0]])((t={exports:{}}).exports,t),t.exports},__copyProps=(e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of __getOwnPropNames(t))__hasOwnProp.call(e,n)||n===i||__defProp(e,n,{get:()=>t[n],enumerable:!(s=__getOwnPropDesc(t,n))||s.enumerable});return e},__toESM=(e,t,i)=>(i=null!=e?__create(__getProtoOf(e)):{},__copyProps(!t&&e&&e.__esModule?i:__defProp(i,"default",{value:e,enumerable:!0}),e)),__publicField=(e,t,i)=>__defNormalProp(e,"symbol"!=typeof t?t+"":t,i),require_eventemitter3=__commonJS({"../node_modules/eventemitter3/index.js"(e,t){"use strict";var i=Object.prototype.hasOwnProperty,s="~";function n(){}function o(e,t,i){this.fn=e,this.context=t,this.once=i||!1}function r(e,t,i,n,r){if("function"!=typeof i)throw new TypeError("The listener must be a function");var l=new o(i,n||e,r),a=s?s+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],l]:e._events[a].push(l):(e._events[a]=l,e._eventsCount++),e}function l(e,t){0===--e._eventsCount?e._events=new n:delete e._events[t]}function a(){this._events=new n,this._eventsCount=0}Object.create&&(n.prototype=Object.create(null),(new n).__proto__||(s=!1)),a.prototype.eventNames=function(){var e,t,n=[];if(0===this._eventsCount)return n;for(t in e=this._events)i.call(e,t)&&n.push(s?t.slice(1):t);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(e)):n},a.prototype.listeners=function(e){var t=s?s+e:e,i=this._events[t];if(!i)return[];if(i.fn)return[i.fn];for(var n=0,o=i.length,r=new Array(o);n<o;n++)r[n]=i[n].fn;return r},a.prototype.listenerCount=function(e){var t=s?s+e:e,i=this._events[t];return i?i.fn?1:i.length:0},a.prototype.emit=function(e,t,i,n,o,r){var l=s?s+e:e;if(!this._events[l])return!1;var a,h,c=this._events[l],d=arguments.length;if(c.fn){switch(c.once&&this.removeListener(e,c.fn,void 0,!0),d){case 1:return c.fn.call(c.context),!0;case 2:return c.fn.call(c.context,t),!0;case 3:return c.fn.call(c.context,t,i),!0;case 4:return c.fn.call(c.context,t,i,n),!0;case 5:return c.fn.call(c.context,t,i,n,o),!0;case 6:return c.fn.call(c.context,t,i,n,o,r),!0}for(h=1,a=new Array(d-1);h<d;h++)a[h-1]=arguments[h];c.fn.apply(c.context,a)}else{var u,p=c.length;for(h=0;h<p;h++)switch(c[h].once&&this.removeListener(e,c[h].fn,void 0,!0),d){case 1:c[h].fn.call(c[h].context);break;case 2:c[h].fn.call(c[h].context,t);break;case 3:c[h].fn.call(c[h].context,t,i);break;case 4:c[h].fn.call(c[h].context,t,i,n);break;default:if(!a)for(u=1,a=new Array(d-1);u<d;u++)a[u-1]=arguments[u];c[h].fn.apply(c[h].context,a)}}return!0},a.prototype.on=function(e,t,i){return r(this,e,t,i,!1)},a.prototype.once=function(e,t,i){return r(this,e,t,i,!0)},a.prototype.removeListener=function(e,t,i,n){var o=s?s+e:e;if(!this._events[o])return this;if(!t)return l(this,o),this;var r=this._events[o];if(r.fn)r.fn!==t||n&&!r.once||i&&r.context!==i||l(this,o);else{for(var a=0,h=[],c=r.length;a<c;a++)(r[a].fn!==t||n&&!r[a].once||i&&r[a].context!==i)&&h.push(r[a]);h.length?this._events[o]=1===h.length?h[0]:h:l(this,o)}return this},a.prototype.removeAllListeners=function(e){var t;return e?(t=s?s+e:e,this._events[t]&&l(this,t)):(this._events=new n,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=s,a.EventEmitter=a,void 0!==t&&(t.exports=a)}}),import_eventemitter3=__toESM(require_eventemitter3(),1),WhiteboardTool=(e=>(e.Pen="pen",e.Line="line",e.Rect="rect",e.RectFill="rectFill",e.Circle="circle",e.Arrow="arrow",e.Laser="laser",e.Eraser="eraser",e))(WhiteboardTool||{}),EraserMode=(e=>(e.Object="object",e.Path="path",e))(EraserMode||{}),ClearScope=(e=>(e.All="all",e.Self="self",e.Others="others",e))(ClearScope||{}),DEFAULT_WHITEBOARD_CMD_ID=10,InteractiveWhiteboardEvent=(e=>(e.HOST_CHANGED="whiteboard:host-changed",e.REMOTE_DRAW_START="whiteboard:remote-draw-start",e.REMOTE_DRAW_END="whiteboard:remote-draw-end",e.CLEARED="whiteboard:cleared",e.ERROR="whiteboard:error",e))(InteractiveWhiteboardEvent||{}),InteractiveWhiteboardErrorCode=(e=>(e.INVALID_CONFIG="INVALID_CONFIG",e.ALREADY_STARTED="ALREADY_STARTED",e.NOT_STARTED="NOT_STARTED",e.READ_ONLY_FALLBACK="READ_ONLY_FALLBACK",e.SEND_OVERLOAD="SEND_OVERLOAD",e.SNAPSHOT_TIMEOUT="SNAPSHOT_TIMEOUT",e.VIEW_NOT_FOUND="VIEW_NOT_FOUND",e))(InteractiveWhiteboardErrorCode||{}),TOOL_VALUES=Object.values(WhiteboardTool),ERASER_MODE_VALUES=Object.values(EraserMode);function startValidateRule(e){return{type:"object",required:!0,properties:{view:{required:!0,validate(e,t,i){if("string"!=typeof e&&!(e instanceof HTMLElement))throw new Error(`[${i}] '${t}' must be an HTMLElement or a string selector.`)}},canvasInfo:{validate(e,t,i){if(void 0!==e&&(!e||"object"!=typeof e||void 0!==e.width&&("number"!=typeof e.width||e.width<=0)||void 0!==e.height&&("number"!=typeof e.height||e.height<=0)))throw new Error(`[${i}] '${t}' must be an object \`{ width?:number>0, height?:number>0 }\`.`)}},userName:{type:"string"},tool:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.name&&("string"!=typeof e.name||!TOOL_VALUES.includes(e.name)))throw new Error(`[${i}] '${t}.name' must be one of: ${TOOL_VALUES.join(", ")}.`);if(void 0!==e.color&&"string"!=typeof e.color)throw new Error(`[${i}] '${t}.color' must be a string.`);if(void 0!==e.lineWidth&&("number"!=typeof e.lineWidth||e.lineWidth<1||e.lineWidth>100))throw new Error(`[${i}] '${t}.lineWidth' must be a number in [1, 100].`);if(void 0!==e.laserFadeDuration&&("number"!=typeof e.laserFadeDuration||e.laserFadeDuration<100||e.laserFadeDuration>1e4))throw new Error(`[${i}] '${t}.laserFadeDuration' must be a number in [100, 10000].`);if(void 0!==e.eraserMode&&!ERASER_MODE_VALUES.includes(e.eraserMode))throw new Error(`[${i}] '${t}.eraserMode' must be one of: ${ERASER_MODE_VALUES.join(", ")}.`);if(void 0!==e.fillOpacity&&("number"!=typeof e.fillOpacity||e.fillOpacity<0||e.fillOpacity>1))throw new Error(`[${i}] '${t}.fillOpacity' must be in [0, 1].`)}}},config:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.interactive&&"boolean"!=typeof e.interactive)throw new Error(`[${i}] '${t}.interactive' must be a boolean.`);if(void 0!==e.cmdId&&("number"!=typeof e.cmdId||!Number.isInteger(e.cmdId)||e.cmdId<1||e.cmdId>10))throw new Error(`[${i}] '${t}.cmdId' must be an integer in [1, 10].`);if(void 0!==e.sendChannel&&"string"!=typeof e.sendChannel)throw new Error(`[${i}] '${t}.sendChannel' must be a string.`);if(void 0!==e.receiveChannel&&"string"!=typeof e.receiveChannel)throw new Error(`[${i}] '${t}.receiveChannel' must be a string.`)}}}}}}function updateValidateRule(e){return{type:"object",properties:{tool:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.name&&("string"!=typeof e.name||!TOOL_VALUES.includes(e.name)))throw new Error(`[${i}] '${t}.name' must be one of: ${TOOL_VALUES.join(", ")}.`);if(void 0!==e.color&&"string"!=typeof e.color)throw new Error(`[${i}] '${t}.color' must be a string.`);if(void 0!==e.lineWidth&&("number"!=typeof e.lineWidth||e.lineWidth<1||e.lineWidth>100))throw new Error(`[${i}] '${t}.lineWidth' must be a number in [1, 100].`);if(void 0!==e.fillOpacity&&("number"!=typeof e.fillOpacity||e.fillOpacity<0||e.fillOpacity>1))throw new Error(`[${i}] '${t}.fillOpacity' must be in [0, 1].`);if(void 0!==e.eraserMode&&!ERASER_MODE_VALUES.includes(e.eraserMode))throw new Error(`[${i}] '${t}.eraserMode' must be one of: ${ERASER_MODE_VALUES.join(", ")}.`)}}},config:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.interactive&&"boolean"!=typeof e.interactive)throw new Error(`[${i}] '${t}.interactive' must be a boolean.`)}}},operation:{type:"string",validate(e,t,i){if(void 0!==e&&!["undo","redo","clear"].includes(e))throw new Error(`[${i}] '${t}' must be one of: 'undo', 'redo', 'clear'.`)}}}}}function stopValidateRule(e){return{type:"object"}}function resolveView(e){if(e instanceof HTMLElement)return e;const t=document.getElementById(e)||document.querySelector(e);if(!(t&&t instanceof HTMLElement))throw new Error(`[InteractiveWhiteboard] view not found: ${e}`);return t}function quantize(e){return Math.max(-32768,Math.min(32767,Math.round(1e4*e)))}function dequantize(e){return e/1e4}var __strokeCounter=0;function genStrokeId(e){return __strokeCounter+=1,`${e}#${Date.now().toString(36)}#${__strokeCounter.toString(36)}`}var OVERLAY_CLASS="trtc-iw-overlay",ViewBinder=class{constructor(e){var t;__publicField(this,"container"),__publicField(this,"overlay"),__publicField(this,"canvasInfo"),__publicField(this,"resizeObserver",null),__publicField(this,"listeners",new Set),__publicField(this,"currentRect",{left:0,top:0,width:0,height:0}),__publicField(this,"onWindowResizeBound"),this.container=resolveView(e.view),this.canvasInfo={width:e.canvasInfo.width,height:e.canvasInfo.height};"static"===getComputedStyle(this.container).position&&(this.container.style.position="relative"),this.overlay=document.createElement("canvas"),this.overlay.className=OVERLAY_CLASS,Object.assign(this.overlay.style,{position:"absolute",left:"0",top:"0",width:"100%",height:"100%",pointerEvents:"auto",touchAction:"none",zIndex:String(null!=(t=e.zIndex)?t:100)}),this.container.appendChild(this.overlay),this.onWindowResizeBound=()=>this.measure(),this.measure(!1)}getContainer(){return this.container}getOverlay(){return this.overlay}setPointerEventsEnabled(e){this.overlay.style.pointerEvents=e?"auto":"none"}getRect(){return __spreadValues({},this.currentRect)}getContentRectInView(){const e=this.container.getBoundingClientRect();return{left:this.currentRect.left-e.left,top:this.currentRect.top-e.top,width:this.currentRect.width,height:this.currentRect.height}}getCanvasInfo(){return __spreadValues({},this.canvasInfo)}onResize(e){return this.listeners.add(e),()=>this.listeners.delete(e)}attach(){this.resizeObserver||(this.resizeObserver=new ResizeObserver(()=>this.measure()),this.resizeObserver.observe(this.container),window.addEventListener("resize",this.onWindowResizeBound),document.addEventListener("fullscreenchange",this.onWindowResizeBound),document.addEventListener("webkitfullscreenchange",this.onWindowResizeBound))}dispose(){this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),window.removeEventListener("resize",this.onWindowResizeBound),document.removeEventListener("fullscreenchange",this.onWindowResizeBound),document.removeEventListener("webkitfullscreenchange",this.onWindowResizeBound),this.overlay.parentNode===this.container&&this.container.removeChild(this.overlay),this.listeners.clear()}getContentRect(e,t){const i=this.overlay.width||e,s=this.overlay.height||t,n=getComputedStyle(this.overlay).objectFit;if("contain"===n){const n=Math.min(e/i,t/s);return{left:(e-i*n)/2,top:(t-s*n)/2,width:i*n,height:s*n}}if("cover"===n){const n=Math.max(e/i,t/s);return{left:(e-i*n)/2,top:(t-s*n)/2,width:i*n,height:s*n}}return{left:0,top:0,width:e,height:t}}measure(e=!0){const t=this.container.getBoundingClientRect(),i=Math.max(1,Math.floor(t.width)),s=Math.max(1,Math.floor(t.height)),n=window.devicePixelRatio||1,o=Math.max(1,Math.floor(this.canvasInfo.width)),r=Math.max(1,Math.floor(this.canvasInfo.height));this.overlay.width===o&&this.overlay.height===r||(this.overlay.width=o,this.overlay.height=r);const l=this.getContentRect(i,s),a=Math.floor(l.left),h=Math.floor(l.top),c=Math.max(1,Math.floor(l.width)),d=Math.max(1,Math.floor(l.height)),u=a!==this.currentRect.left-t.left||h!==this.currentRect.top-t.top||c!==this.currentRect.width||d!==this.currentRect.height;this.currentRect={left:t.left+a,top:t.top+h,width:c,height:d},e&&u&&this.listeners.forEach(e=>{try{e(this.currentRect,n)}catch(e){console.error("[InteractiveWhiteboard] resize listener error:",e)}})}},MAX_HISTORY_SIZE=50,DEFAULT_COLOR="#FF0000",DEFAULT_LINE_WIDTH=4,DEFAULT_FILL_OPACITY=.3,DEFAULT_LASER_FADE_DURATION=1e3,LASER_DOT_RADIUS=8,LASER_TICK_INTERVAL_MS=Math.round(1e3/12),DRAW_DELTA_INTERVAL_MS=Math.round(1e3/12),HIT_TEST_TOLERANCE=6,DrawingEngine=class{constructor(e){var t,i,s,n,o,r;__publicField(this,"canvas"),__publicField(this,"ctx"),__publicField(this,"dpr"),__publicField(this,"viewW"),__publicField(this,"viewH"),__publicField(this,"userId"),__publicField(this,"tool"),__publicField(this,"color"),__publicField(this,"lineWidth"),__publicField(this,"fillOpacity"),__publicField(this,"eraserMode"),__publicField(this,"laserFadeDuration"),__publicField(this,"onLocalCommit"),__publicField(this,"onLocalLaserTick"),__publicField(this,"onLocalDelta"),__publicField(this,"isDrawing",!1),__publicField(this,"startPoint",null),__publicField(this,"lastPoint",null),__publicField(this,"lastMovePoint",null),__publicField(this,"currentStrokePoints",[]),__publicField(this,"currentStrokeId",null),__publicField(this,"currentEraseTargets",new Set),__publicField(this,"strokes",[]),__publicField(this,"undoStack",[]),__publicField(this,"redoStack",[]),__publicField(this,"hiddenByObjectEraser",new Set),__publicField(this,"laserTrails",new Map),__publicField(this,"laserAnimationId",null),__publicField(this,"laserStrokeSeq",0),__publicField(this,"pendingLocalLaserSamples",[]),__publicField(this,"localLaserTickTimer",null),__publicField(this,"pendingLocalDeltaSamples",[]),__publicField(this,"localDeltaTickTimer",null),__publicField(this,"localDeltaTool",null),__publicField(this,"remoteInProgress",new Map),this.canvas=e.canvas;const l=this.canvas.getContext("2d");if(!l)throw new Error("[InteractiveWhiteboard] failed to get 2D context");this.ctx=l,this.dpr=e.dpr,this.viewW=Math.max(1,e.viewWidthCss),this.viewH=Math.max(1,e.viewHeightCss),this.userId=e.userId,this.tool=null!=(t=e.tool)?t:"pen",this.color=null!=(i=e.color)?i:DEFAULT_COLOR,this.lineWidth=null!=(s=e.lineWidth)?s:DEFAULT_LINE_WIDTH,this.fillOpacity=null!=(n=e.fillOpacity)?n:DEFAULT_FILL_OPACITY,this.eraserMode=null!=(o=e.eraserMode)?o:"object",this.laserFadeDuration=null!=(r=e.laserFadeDuration)?r:DEFAULT_LASER_FADE_DURATION,this.onLocalCommit=e.onLocalCommit,this.onLocalLaserTick=e.onLocalLaserTick,this.onLocalDelta=e.onLocalDelta,this.applyTransform()}setTool(e){"laser"===this.tool&&"laser"!==e&&(this.stopLocalLaserTickTimer(),this.pendingLocalLaserSamples.length=0,this.laserTrails.delete(this.userId),0===this.laserTrails.size?this.stopLaserAnimation():this.redrawAll()),this.tool=e}setColor(e){this.color=e}setLineWidth(e){this.lineWidth=e}setFillOpacity(e){this.fillOpacity=Math.max(0,Math.min(1,e))}setEraserMode(e){this.eraserMode=e}setLaserFadeDuration(e){this.laserFadeDuration=e}setUserId(e){this.userId=e}setDpr(e){this.dpr=e,this.applyTransform(),this.redrawAll()}setViewSize(e,t){const i=Math.max(1,e),s=Math.max(1,t);if(i!==this.viewW||s!==this.viewH){if(this.isDrawing){const e=i/this.viewW,t=s/this.viewH,n=i=>i?{x:i.x*e,y:i.y*t}:null;this.startPoint=n(this.startPoint),this.lastPoint=n(this.lastPoint),this.lastMovePoint=n(this.lastMovePoint),this.currentStrokePoints=this.currentStrokePoints.map(i=>({x:i.x*e,y:i.y*t}))}this.viewW=i,this.viewH=s,this.applyTransform(),this.redrawAll()}}onCanvasResized(){this.applyTransform(),this.redrawAll()}clearAll(){var e;this.strokes.length=0,this.undoStack.length=0,this.redoStack.length=0,this.hiddenByObjectEraser.clear(),this.remoteInProgress.clear(),this.stopLaserAnimation(),this.clearCanvas(),null==(e=this.onLocalCommit)||e.call(this,{kind:"clear",scope:"all"})}ingestRemoteClear(e,t){switch(e){case"all":this.strokes.length=0,this.hiddenByObjectEraser.clear(),this.remoteInProgress.clear();break;case"self":this.strokes=this.strokes.filter(e=>e.ownerId!==t),this.dropInProgressByOwner(t);break;case"others":this.strokes=this.strokes.filter(e=>e.ownerId===t);for(const[e,i]of this.remoteInProgress)i.ownerId!==t&&this.remoteInProgress.delete(e)}this.redrawAll()}undo(){var e;for(let t=this.undoStack.length-1;t>=0;t--)if(this.undoStack[t].ownerId===this.userId){const[i]=this.undoStack.splice(t,1);this.redoStack.push(i);const s=this.strokes.indexOf(i);return-1!==s&&this.strokes.splice(s,1),"eraser"===i.tool&&"object"===i.mode&&i.targetStrokeIds&&i.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.delete(e)),this.redrawAll(),void(null==(e=this.onLocalCommit)||e.call(this,{kind:"undo",record:i}))}}redo(){var e;for(let t=this.redoStack.length-1;t>=0;t--)if(this.redoStack[t].ownerId===this.userId){const[i]=this.redoStack.splice(t,1);return this.undoStack.push(i),this.strokes.push(i),"eraser"===i.tool&&"object"===i.mode&&i.targetStrokeIds&&i.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),this.redrawAll(),void(null==(e=this.onLocalCommit)||e.call(this,{kind:"redo",record:i}))}}ingestRemoteStroke(e){this.remoteInProgress.delete(e.strokeId),this.strokes.some(t=>t.strokeId===e.strokeId)||("eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),this.strokes.push(e)),this.redrawAll()}ingestRemoteDelta(e,t,i,s,n,o){if(!o||0===o.length)return;if(this.strokes.some(t=>t.strokeId===e))return;let r=this.remoteInProgress.get(e);r?(r.tool=i,r.color=s,r.lineWidth=n):(r={strokeId:e,ownerId:t,tool:i,color:s,lineWidth:n,points:[]},this.remoteInProgress.set(e,r));for(let e=0;e<o.length;e++)r.points.push(o[e]);this.redrawAll()}ingestRemoteUndo(e,t){let i=!1;this.remoteInProgress.delete(e)&&(i=!0);for(let s=this.strokes.length-1;s>=0;s--){const n=this.strokes[s];if(n.strokeId===e&&n.ownerId===t){this.strokes.splice(s,1),"eraser"===n.tool&&"object"===n.mode&&n.targetStrokeIds&&n.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.delete(e)),i=!0;break}}i&&this.redrawAll()}beginStroke(e){return this.isDrawing=!0,this.startPoint=e,this.lastPoint=e,this.lastMovePoint=null,this.currentStrokePoints=[e],this.currentStrokeId=genStrokeId(this.userId),this.currentEraseTargets.clear(),"laser"===this.tool?(this.laserStrokeSeq++,this.appendLocalLaserSample(e),this.startLocalLaserTickTimer(),void this.startLaserAnimation()):"eraser"===this.tool?"object"===this.eraserMode?(this.hitTestAt(e).forEach(e=>{this.currentEraseTargets.add(e),this.hiddenByObjectEraser.add(e)}),void(this.currentEraseTargets.size>0&&this.redrawAll())):(this.applyPenStrokeStyle(),this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.localDeltaTool="eraser",this.appendLocalDeltaSample(e),void this.startLocalDeltaTickTimer()):void("pen"===this.tool&&(this.applyPenStrokeStyle(),this.localDeltaTool="pen",this.appendLocalDeltaSample(e),this.startLocalDeltaTickTimer()))}moveStroke(e){if(this.isDrawing&&this.startPoint)switch(this.tool){case"pen":this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e,this.lastMovePoint=e,this.currentStrokePoints.push(e),this.appendLocalDeltaSample(e);break;case"eraser":if("object"===this.eraserMode){let t=!1;this.hitTestAt(e).forEach(e=>{this.currentEraseTargets.has(e)||(this.currentEraseTargets.add(e),this.hiddenByObjectEraser.add(e),t=!0)}),this.lastMovePoint=e,t&&this.redrawAll();break}this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e,this.lastMovePoint=e,this.currentStrokePoints.push(e),this.appendLocalDeltaSample(e);break;case"rect":case"rectFill":case"circle":case"arrow":case"line":this.lastMovePoint=e,this.redrawAll(),this.drawShape(this.tool,this.startPoint,e,this.color,this.scaledLineWidth(this.lineWidth));break;case"laser":this.appendLocalLaserSample(e)}}endStroke(e){var t,i;if(!this.isDrawing||!this.startPoint)return;const s=null!=(t=this.lastMovePoint)?t:e,n=null!=(i=this.currentStrokeId)?i:genStrokeId(this.userId);switch(this.tool){case"pen":{this.lastPoint&&(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(s.x,s.y),this.ctx.stroke()),this.currentStrokePoints.push(s);const e={tool:"pen",strokeId:n,ownerId:this.userId,points:this.normPolyline(this.currentStrokePoints),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"eraser":{if("object"===this.eraserMode){const e=Array.from(this.currentEraseTargets);if(0===e.length)break;const t={tool:"eraser",strokeId:n,ownerId:this.userId,mode:"object",points:[],lineWidth:this.lineWidth,targetStrokeIds:e};this.commit(t);break}this.lastPoint&&(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(s.x,s.y),this.ctx.stroke()),this.ctx.globalCompositeOperation="source-over",this.currentStrokePoints.push(s);const e={tool:"eraser",strokeId:n,ownerId:this.userId,mode:"path",points:this.normPolyline(this.currentStrokePoints),lineWidth:this.lineWidth};this.commit(e);break}case"line":{const e={tool:"line",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"rect":{const e={tool:"rect",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"rectFill":{const e={tool:"rectFill",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,fillOpacity:this.fillOpacity};this.commit(e);break}case"circle":{const e={tool:"circle",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"arrow":{const e={tool:"arrow",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"laser":this.appendLocalLaserSample(e),this.flushLocalLaserTick(),this.stopLocalLaserTickTimer()}this.isDrawing=!1,this.startPoint=null,this.lastPoint=null,this.lastMovePoint=null,this.currentStrokePoints=[],this.currentStrokeId=null,this.currentEraseTargets.clear(),this.pendingLocalDeltaSamples.length=0,this.stopLocalDeltaTickTimer(),this.localDeltaTool=null}cancelStroke(){this.isDrawing&&("eraser"===this.tool&&(this.ctx.globalCompositeOperation="source-over","object"===this.eraserMode&&this.currentEraseTargets.size>0&&(this.currentEraseTargets.forEach(e=>this.hiddenByObjectEraser.delete(e)),this.redrawAll())),"laser"===this.tool&&(this.pendingLocalLaserSamples.length=0,this.stopLocalLaserTickTimer()),this.pendingLocalDeltaSamples.length=0,this.stopLocalDeltaTickTimer(),this.localDeltaTool=null,this.isDrawing=!1,this.startPoint=null,this.lastPoint=null,this.lastMovePoint=null,this.currentStrokePoints=[],this.currentStrokeId=null,this.currentEraseTargets.clear())}dispose(){this.stopLaserAnimation(),this.stopLocalLaserTickTimer(),this.stopLocalDeltaTickTimer(),this.pendingLocalLaserSamples.length=0,this.pendingLocalDeltaSamples.length=0,this.localDeltaTool=null,this.remoteInProgress.clear(),this.laserTrails.clear(),this.clearCanvas()}commit(e){var t;this.strokes.push(e),this.undoStack.push(e),this.undoStack.length>MAX_HISTORY_SIZE&&this.undoStack.shift(),this.redoStack.length=0,this.redrawAll(),null==(t=this.onLocalCommit)||t.call(this,{kind:"stroke",record:e})}clearCanvas(){this.ctx.save(),this.ctx.setTransform(1,0,0,1,0,0),this.ctx.globalCompositeOperation="source-over",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.restore()}redrawAll(){this.clearCanvas();for(const e of this.strokes)this.hiddenByObjectEraser.has(e.strokeId)||this.replayStroke(e);if(this.remoteInProgress.size>0)for(const e of this.remoteInProgress.values())this.replayInProgress(e)}replayStroke(e){switch(this.ctx.globalCompositeOperation="source-over",e.tool){case"pen":{const t=this.scaledLineWidth(e.lineWidth);this.ctx.strokeStyle=e.color,this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(this.denormPolyline(e.points));break}case"line":{const t=this.scaledLineWidth(e.lineWidth);this.drawLine(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"rect":{const t=this.scaledLineWidth(e.lineWidth);this.drawRect(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"rectFill":this.drawRectFill(this.denormPoint(e.start),this.denormPoint(e.end),e.color,e.fillOpacity);break;case"circle":{const t=this.scaledLineWidth(e.lineWidth);this.drawCircle(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"arrow":{const t=this.scaledLineWidth(e.lineWidth);this.drawArrow(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"eraser":if("object"===e.mode)break;this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.ctx.lineWidth=this.scaledLineWidth(e.lineWidth),this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(this.denormPolyline(e.points)),this.ctx.globalCompositeOperation="source-over"}}applyPenStrokeStyle(){this.ctx.globalCompositeOperation="source-over",this.ctx.strokeStyle=this.color,this.ctx.lineWidth=this.scaledLineWidth(this.lineWidth),this.ctx.lineCap="round",this.ctx.lineJoin="round"}strokePolyline(e){if(0!==e.length){if(1===e.length)return this.ctx.beginPath(),this.ctx.arc(e[0].x,e[0].y,this.ctx.lineWidth/2,0,2*Math.PI),this.ctx.fillStyle=this.ctx.strokeStyle,void this.ctx.fill();this.ctx.beginPath(),this.ctx.moveTo(e[0].x,e[0].y);for(let t=1;t<e.length;t++)this.ctx.lineTo(e[t].x,e[t].y);this.ctx.stroke()}}drawShape(e,t,i,s,n){switch(e){case"line":this.drawLine(t,i,s,n);break;case"rect":this.drawRect(t,i,s,n);break;case"rectFill":this.drawRectFill(t,i,s,this.fillOpacity);break;case"circle":this.drawCircle(t,i,s,n);break;case"arrow":this.drawArrow(t,i,s,n)}}drawLine(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(t.x,t.y),this.ctx.stroke()}drawRect(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=Math.min(e.x,t.x),o=Math.min(e.y,t.y),r=Math.abs(t.x-e.x),l=Math.abs(t.y-e.y);this.ctx.beginPath(),this.ctx.rect(n,o,r,l),this.ctx.stroke()}drawRectFill(e,t,i,s=.3){const n=this.ctx.globalAlpha;this.ctx.globalAlpha=n*Math.max(0,Math.min(1,s)),this.ctx.fillStyle=i;const o=Math.min(e.x,t.x),r=Math.min(e.y,t.y),l=Math.abs(t.x-e.x),a=Math.abs(t.y-e.y);this.ctx.beginPath(),this.ctx.rect(o,r,l,a),this.ctx.fill(),this.ctx.globalAlpha=n}drawCircle(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=(e.x+t.x)/2,o=(e.y+t.y)/2,r=Math.abs(t.x-e.x)/2,l=Math.abs(t.y-e.y)/2;this.ctx.beginPath(),this.ctx.ellipse(n,o,r,l,0,0,2*Math.PI),this.ctx.stroke()}drawArrow(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=t.x-e.x,o=t.y-e.y,r=Math.atan2(o,n),l=Math.max(10,4*s);this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(t.x,t.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.moveTo(t.x,t.y),this.ctx.lineTo(t.x-l*Math.cos(r-Math.PI/6),t.y-l*Math.sin(r-Math.PI/6)),this.ctx.moveTo(t.x,t.y),this.ctx.lineTo(t.x-l*Math.cos(r+Math.PI/6),t.y-l*Math.sin(r+Math.PI/6)),this.ctx.stroke()}ingestRemoteLaserTick(e,t,i,s,n){if(!n||0===n.length)return;let o=this.laserTrails.get(e);o?(o.color=t,o.lineWidth=i):(o={color:t,lineWidth:i,points:[]},this.laserTrails.set(e,o));const r=performance.now();for(let e=0;e<n.length;e++){const t=this.denormPoint(n[e]);o.points.push({x:t.x,y:t.y,time:r,strokeSeq:s})}this.startLaserAnimation()}appendLocalLaserSample(e){let t=this.laserTrails.get(this.userId);t?(t.color=this.color,t.lineWidth=this.lineWidth):(t={color:this.color,lineWidth:this.lineWidth,points:[]},this.laserTrails.set(this.userId,t)),t.points.push({x:e.x,y:e.y,time:performance.now(),strokeSeq:this.laserStrokeSeq}),this.pendingLocalLaserSamples.push(this.normPoint(e))}startLocalLaserTickTimer(){null===this.localLaserTickTimer&&this.onLocalLaserTick&&(this.localLaserTickTimer=setInterval(()=>this.flushLocalLaserTick(),LASER_TICK_INTERVAL_MS))}stopLocalLaserTickTimer(){null!==this.localLaserTickTimer&&(clearInterval(this.localLaserTickTimer),this.localLaserTickTimer=null)}flushLocalLaserTick(){if(0===this.pendingLocalLaserSamples.length)return;const e=this.onLocalLaserTick;if(!e)return void(this.pendingLocalLaserSamples.length=0);const t=this.pendingLocalLaserSamples;this.pendingLocalLaserSamples=[];try{e({sq:this.laserStrokeSeq,color:this.color,lineWidth:this.lineWidth,points:t})}catch(e){}}appendLocalDeltaSample(e){this.onLocalDelta&&this.currentStrokeId&&this.pendingLocalDeltaSamples.push(this.normPoint(e))}startLocalDeltaTickTimer(){null===this.localDeltaTickTimer&&this.onLocalDelta&&(this.localDeltaTickTimer=setInterval(()=>this.flushLocalDeltaTick(),DRAW_DELTA_INTERVAL_MS))}stopLocalDeltaTickTimer(){null!==this.localDeltaTickTimer&&(clearInterval(this.localDeltaTickTimer),this.localDeltaTickTimer=null)}flushLocalDeltaTick(){if(0===this.pendingLocalDeltaSamples.length)return;const e=this.onLocalDelta;if(!e)return void(this.pendingLocalDeltaSamples.length=0);const t=this.localDeltaTool,i=this.currentStrokeId;if(!t||!i)return void(this.pendingLocalDeltaSamples.length=0);const s=this.pendingLocalDeltaSamples;this.pendingLocalDeltaSamples=[];try{e({strokeId:i,tool:t,color:this.color,lineWidth:this.lineWidth,eraserMode:"eraser"===t?"path":void 0,points:s})}catch(e){}}replayInProgress(e){if(0===e.points.length)return;const t=this.denormPolyline(e.points),i=this.scaledLineWidth(e.lineWidth);if("pen"===e.tool)return this.ctx.globalCompositeOperation="source-over",this.ctx.strokeStyle=e.color,this.ctx.lineWidth=i,this.ctx.lineCap="round",this.ctx.lineJoin="round",void this.strokePolyline(t);this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.ctx.lineWidth=i,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(t),this.ctx.globalCompositeOperation="source-over"}dropInProgressByOwner(e){if(0!==this.remoteInProgress.size)for(const[t,i]of this.remoteInProgress)i.ownerId===e&&this.remoteInProgress.delete(t)}startLaserAnimation(){if(null!==this.laserAnimationId)return;const e=()=>{this.renderLaserFrame()?this.laserAnimationId=requestAnimationFrame(e):(this.laserAnimationId=null,this.redrawAll())};this.laserAnimationId=requestAnimationFrame(e)}stopLaserAnimation(){null!==this.laserAnimationId&&(cancelAnimationFrame(this.laserAnimationId),this.laserAnimationId=null),this.laserTrails.clear()}renderLaserFrame(){const e=performance.now();let t=0;for(const[i,s]of this.laserTrails){if(0===s.points.length){this.laserTrails.delete(i);continue}const n=[];for(let t=0;t<s.points.length;t++){const i=s.points[t];e-i.time<this.laserFadeDuration&&n.push(i)}s.points=n,0!==n.length?t+=n.length:this.laserTrails.delete(i)}if(this.redrawAll(),0===t)return!1;this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.globalCompositeOperation="source-over";for(const t of this.laserTrails.values()){const i=this.scaledLineWidth(t.lineWidth);this.ctx.lineWidth=i,this.ctx.strokeStyle=t.color;for(let i=1;i<t.points.length;i++){const s=t.points[i-1],n=t.points[i];if(s.strokeSeq!==n.strokeSeq)continue;const o=e-n.time,r=Math.max(0,1-o/this.laserFadeDuration);this.ctx.globalAlpha=r,this.ctx.beginPath(),this.ctx.moveTo(s.x,s.y),this.ctx.lineTo(n.x,n.y),this.ctx.stroke()}const s=t.points[t.points.length-1],n=e-s.time,o=Math.max(0,1-n/this.laserFadeDuration);o>0&&(this.ctx.globalAlpha=o,this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(s.x,s.y,LASER_DOT_RADIUS,0,2*Math.PI),this.ctx.fill(),this.ctx.fillStyle="#FFFFFF",this.ctx.beginPath(),this.ctx.arc(s.x,s.y,.4*LASER_DOT_RADIUS,0,2*Math.PI),this.ctx.fill())}return this.ctx.globalAlpha=1,!0}hitTestAt(e){const t=[];for(const i of this.strokes)this.hiddenByObjectEraser.has(i.strokeId)||this.isHit(i,e)&&t.push(i.strokeId);return t}isHit(e,t){switch(e.tool){case"pen":return this.isHitPolyline(this.denormPolyline(e.points),e.lineWidth,t);case"line":case"arrow":return this.isHitSegment(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);case"rect":return this.isHitRectBorder(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);case"rectFill":return this.isInsideRect(this.denormPoint(e.start),this.denormPoint(e.end),t);case"circle":return this.isHitEllipse(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);default:return!1}}isHitPolyline(e,t,i){if(0===e.length)return!1;if(1===e.length){const s=this.scaledLineWidth(t)/2+HIT_TEST_TOLERANCE;return distance(e[0],i)<=s}for(let s=1;s<e.length;s++)if(this.isHitSegment(e[s-1],e[s],t,i))return!0;return!1}isHitSegment(e,t,i,s){const n=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE;return distanceToSegment(s,e,t)<=n}isHitRectBorder(e,t,i,s){const n=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE,o=Math.min(e.x,t.x),r=Math.max(e.x,t.x),l=Math.min(e.y,t.y),a=Math.max(e.y,t.y);return!(s.x<o-n||s.x>r+n||s.y<l-n||s.y>a+n)&&!(s.x>o+n&&s.x<r-n&&s.y>l+n&&s.y<a-n)}isInsideRect(e,t,i){const s=Math.min(e.x,t.x),n=Math.max(e.x,t.x),o=Math.min(e.y,t.y),r=Math.max(e.y,t.y);return i.x>=s&&i.x<=n&&i.y>=o&&i.y<=r}isHitEllipse(e,t,i,s){const n=(e.x+t.x)/2,o=(e.y+t.y)/2,r=Math.max(1,Math.abs(t.x-e.x)/2),l=Math.max(1,Math.abs(t.y-e.y)/2),a=(s.x-n)/r,h=(s.y-o)/l,c=Math.hypot(a,h);if(c<=1)return!0;const d=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE;return Math.abs(c-1)*Math.min(r,l)<=d}applyTransform(){this.ctx.setTransform(this.dpr,0,0,this.dpr,0,0)}denormPoint(e){return{x:e.nx*this.viewW,y:e.ny*this.viewH}}denormPolyline(e){const t=new Array(e.length);for(let i=0;i<e.length;i++)t[i]=this.denormPoint(e[i]);return t}normPoint(e){return{nx:e.x/this.viewW,ny:e.y/this.viewH}}normPolyline(e){const t=new Array(e.length);for(let i=0;i<e.length;i++)t[i]=this.normPoint(e[i]);return t}scaledLineWidth(e){return Math.max(.5,e)}exportSnapshot(){return this.strokes.map(e=>deepCloneRecord(e))}importSnapshot(e){this.strokes=e.map(e=>deepCloneRecord(e)),this.hiddenByObjectEraser.clear();for(const e of this.strokes)"eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e));this.redrawAll()}mergeSnapshot(e){let t=!1;const i=new Set(this.strokes.map(e=>e.strokeId));for(const s of e){if(i.has(s.strokeId))continue;const e=deepCloneRecord(s);this.strokes.push(e),i.add(e.strokeId),"eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),t=!0}t&&this.redrawAll()}getViewSize(){return{width:this.viewW,height:this.viewH}}getCanvas(){return this.canvas}};function distance(e,t){const i=e.x-t.x,s=e.y-t.y;return Math.hypot(i,s)}function distanceToSegment(e,t,i){const s=i.x-t.x,n=i.y-t.y,o=s*s+n*n;if(0===o)return distance(e,t);const r=Math.max(0,Math.min(1,((e.x-t.x)*s+(e.y-t.y)*n)/o)),l=t.x+r*s,a=t.y+r*n;return Math.hypot(e.x-l,e.y-a)}function deepCloneRecord(e){switch(e.tool){case"pen":return __spreadProps(__spreadValues({},e),{points:e.points.map(e=>__spreadValues({},e))});case"line":case"rect":case"circle":case"arrow":case"rectFill":return __spreadProps(__spreadValues({},e),{start:__spreadValues({},e.start),end:__spreadValues({},e.end)});case"eraser":return __spreadProps(__spreadValues({},e),{points:e.points.map(e=>__spreadValues({},e)),targetStrokeIds:e.targetStrokeIds?[...e.targetStrokeIds]:void 0})}}var InputHandler=class{constructor(e){__publicField(this,"container"),__publicField(this,"canvas"),__publicField(this,"engine"),__publicField(this,"canvasInfo"),__publicField(this,"isPointerDown",!1),__publicField(this,"dragListenersAttached",!1),__publicField(this,"cachedContentRect",null),__publicField(this,"resizeObserver",null),__publicField(this,"invalidateCacheBound"),__publicField(this,"onMouseDownBound"),__publicField(this,"onMouseMoveBound"),__publicField(this,"onMouseUpBound"),__publicField(this,"onWindowBlurBound"),__publicField(this,"onTouchStartBound"),__publicField(this,"onTouchMoveBound"),__publicField(this,"onTouchEndBound"),__publicField(this,"onTouchCancelBound"),this.container=e.container,this.canvas=e.canvas,this.engine=e.engine,this.canvasInfo={width:e.canvasInfo.width,height:e.canvasInfo.height},this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onWindowBlurBound=this.onWindowBlur.bind(this),this.onTouchStartBound=this.onTouchStart.bind(this),this.onTouchMoveBound=this.onTouchMove.bind(this),this.onTouchEndBound=this.onTouchEnd.bind(this),this.onTouchCancelBound=this.onTouchCancel.bind(this),this.invalidateCacheBound=()=>{this.cachedContentRect=null}}attach(){const e=this.canvas;e.addEventListener("mousedown",this.onMouseDownBound),e.addEventListener("touchstart",this.onTouchStartBound,{passive:!1}),e.addEventListener("touchmove",this.onTouchMoveBound,{passive:!1}),e.addEventListener("touchend",this.onTouchEndBound),e.addEventListener("touchcancel",this.onTouchCancelBound),this.resizeObserver=new ResizeObserver(()=>{this.cachedContentRect=null}),this.resizeObserver.observe(this.container),window.addEventListener("resize",this.invalidateCacheBound),document.addEventListener("fullscreenchange",this.invalidateCacheBound),document.addEventListener("webkitfullscreenchange",this.invalidateCacheBound)}detach(){const e=this.canvas;e.removeEventListener("mousedown",this.onMouseDownBound),e.removeEventListener("touchstart",this.onTouchStartBound),e.removeEventListener("touchmove",this.onTouchMoveBound),e.removeEventListener("touchend",this.onTouchEndBound),e.removeEventListener("touchcancel",this.onTouchCancelBound),this.detachDragListeners(),this.isPointerDown&&this.engine.cancelStroke(),this.isPointerDown=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.cachedContentRect=null,window.removeEventListener("resize",this.invalidateCacheBound),document.removeEventListener("fullscreenchange",this.invalidateCacheBound),document.removeEventListener("webkitfullscreenchange",this.invalidateCacheBound)}attachDragListeners(){this.dragListenersAttached||(window.addEventListener("mousemove",this.onMouseMoveBound),window.addEventListener("mouseup",this.onMouseUpBound),window.addEventListener("blur",this.onWindowBlurBound),this.dragListenersAttached=!0)}detachDragListeners(){this.dragListenersAttached&&(window.removeEventListener("mousemove",this.onMouseMoveBound),window.removeEventListener("mouseup",this.onMouseUpBound),window.removeEventListener("blur",this.onWindowBlurBound),this.dragListenersAttached=!1)}getContentRect(){if(this.cachedContentRect)return this.cachedContentRect;const e=this.container.getBoundingClientRect(),t=e.width||1,i=e.height||1,s=this.canvas.width||t,n=this.canvas.height||i,o=getComputedStyle(this.canvas).objectFit;if("contain"===o){const e=Math.min(t/s,i/n),o=s*e,r=n*e;this.cachedContentRect={left:(t-o)/2,top:(i-r)/2,width:o,height:r}}else if("cover"===o){const e=Math.max(t/s,i/n),o=s*e,r=n*e;this.cachedContentRect={left:(t-o)/2,top:(i-r)/2,width:o,height:r}}else this.cachedContentRect={left:0,top:0,width:t,height:i};return this.cachedContentRect}isInsideDrawableArea(e,t){const i=this.container.getBoundingClientRect(),s=e-i.left,n=t-i.top,o=this.getContentRect();return s>=o.left&&s<=o.left+o.width&&n>=o.top&&n<=o.top+o.height}toCanvasPoint(e,t){const i=this.container.getBoundingClientRect(),s=e-i.left,n=t-i.top,o=this.getContentRect(),r=(s-o.left)/(o.width||1),l=(n-o.top)/(o.height||1),a=r*this.canvasInfo.width,h=l*this.canvasInfo.height;return{x:a<0?0:a>this.canvasInfo.width?this.canvasInfo.width:a,y:h<0?0:h>this.canvasInfo.height?this.canvasInfo.height:h}}onMouseDown(e){0===e.button&&this.isInsideDrawableArea(e.clientX,e.clientY)&&(e.preventDefault(),this.isPointerDown=!0,this.attachDragListeners(),this.engine.beginStroke(this.toCanvasPoint(e.clientX,e.clientY)))}onMouseMove(e){this.isPointerDown&&this.engine.moveStroke(this.toCanvasPoint(e.clientX,e.clientY))}onMouseUp(e){this.isPointerDown&&(void 0!==e.button&&0!==e.button||(this.isPointerDown=!1,this.detachDragListeners(),this.engine.endStroke(this.toCanvasPoint(e.clientX,e.clientY))))}onWindowBlur(){this.isPointerDown&&(this.isPointerDown=!1,this.detachDragListeners(),this.engine.cancelStroke())}onTouchStart(e){if(0===e.touches.length)return;const t=e.touches[0];this.isInsideDrawableArea(t.clientX,t.clientY)&&(e.preventDefault(),this.isPointerDown=!0,this.engine.beginStroke(this.toCanvasPoint(t.clientX,t.clientY)))}onTouchMove(e){if(!this.isPointerDown||0===e.touches.length)return;e.preventDefault();const t=e.touches[0];this.engine.moveStroke(this.toCanvasPoint(t.clientX,t.clientY))}onTouchEnd(e){if(!this.isPointerDown)return;this.isPointerDown=!1;const t=e.changedTouches[0];t?this.engine.endStroke(this.toCanvasPoint(t.clientX,t.clientY)):this.engine.cancelStroke()}onTouchCancel(e){this.isPointerDown&&(this.isPointerDown=!1,this.engine.cancelStroke())}},WIRE_TOOL_TO_NAME={0:"pen",1:"line",2:"rect",3:"rectFill",4:"circle",5:"arrow",6:"eraser",7:"laser"},NAME_TO_WIRE_TOOL={pen:0,line:1,rect:2,rectFill:3,circle:4,arrow:5,eraser:6,laser:7};function colorToInt(e){if(!e)return;if("#"===e[0]){let t=e.slice(1);if(3===t.length&&(t=t.split("").map(e=>e+e).join("")),6===t.length){const e=parseInt(t,16);return Number.isFinite(e)?e:void 0}}const t=Number(e);return Number.isFinite(t)?t:void 0}function intToColor(e){if(void 0===e)return;return`#${Math.max(0,Math.min(16777215,e>>>0)).toString(16).padStart(6,"0").toUpperCase()}`}function encodePoints(e){const t=new Array(e.length),i=new Array(e.length);for(let s=0;s<e.length;s++)t[s]=quantize(e[s].nx),i[s]=quantize(e[s].ny);return{xs:t,ys:i}}function decodePoints(e,t){const i=Math.min(e.length,t.length),s=new Array(i);for(let n=0;n<i;n++)s[n]={nx:dequantize(e[n]),ny:dequantize(t[n])};return s}var PROTOCOL_VERSION=1,TEXT_ENCODER=new TextEncoder,TEXT_DECODER=new TextDecoder("utf-8");function encodeEnvelope(e){const t=JSON.stringify(e),i=TEXT_ENCODER.encode(t),s=new ArrayBuffer(i.byteLength);return new Uint8Array(s).set(i),s}function decodeEnvelope(e){const t=new Uint8Array(e),i=TEXT_DECODER.decode(t),s=JSON.parse(i);if(!s||"object"!=typeof s)throw new Error("[InteractiveWhiteboard] decodeEnvelope: not an object");if("number"!=typeof s.v||"number"!=typeof s.wt)throw new Error("[InteractiveWhiteboard] decodeEnvelope: missing v/wt");return s}var MAX_FRAME_BYTES=1e3,ENVELOPE_OVERHEAD=200,MAX_PAYLOAD_BYTES=MAX_FRAME_BYTES-ENVELOPE_OVERHEAD,REASSEMBLY_TTL_MS=1e4;function needsFragmentation(e){return e.length>MAX_PAYLOAD_BYTES}function fragment(e){const t=JSON.stringify(e.p);if(!needsFragmentation(t))return[encodeEnvelope(__spreadValues({},e))];const i=MAX_PAYLOAD_BYTES,s=Math.ceil(t.length/i),n=new Array(s);for(let o=0;o<s;o++){const r=t.slice(o*i,(o+1)*i);n[o]=encodeEnvelope(__spreadProps(__spreadValues({},e),{p:{__frag:!0,part:r},fi:o,ft:s}))}return n}var FragmentReassembler=class{constructor(){__publicField(this,"groups",new Map),__publicField(this,"gcTimer",null),"undefined"!=typeof window&&(this.gcTimer=window.setInterval(()=>this.gc(),2e3))}dispose(){null!==this.gcTimer&&"undefined"!=typeof window&&(window.clearInterval(this.gcTimer),this.gcTimer=null),this.groups.clear()}ingest(e){if(!e.ft||e.ft<=1)return e;if(void 0===e.fi||e.fi<0||e.fi>=e.ft)return null;const t=this.keyOf(e);let i=this.groups.get(t);i||(i={parts:new Array(e.ft).fill(""),receivedCount:0,total:e.ft,expiresAt:Date.now()+REASSEMBLY_TTL_MS},this.groups.set(t,i));const s=e.p;if(!s||!0!==s.__frag||"string"!=typeof s.part)return null;if(""===i.parts[e.fi]&&(i.parts[e.fi]=s.part,i.receivedCount+=1),i.receivedCount<i.total)return null;this.groups.delete(t);const n=i.parts.join("");let o;try{o=JSON.parse(n)}catch(e){return null}return __spreadProps(__spreadValues({},e),{p:o,fi:void 0,ft:void 0})}keyOf(e){return`${e.u}|${e.wt}|${e.id}|${e.s}`}gc(){const e=Date.now();for(const[t,i]of this.groups)i.expiresAt<e&&this.groups.delete(t)}},Throttler=class{constructor(e={}){var t,i,s;__publicField(this,"maxCallsPerSecond"),__publicField(this,"maxBytesPerSecond"),__publicField(this,"maxQueueLength"),__publicField(this,"onOverload"),__publicField(this,"window",[]),__publicField(this,"queue",[]),__publicField(this,"drainTimer",null),__publicField(this,"statsAnchor",Date.now()),__publicField(this,"droppedCallsThisStatsWindow",0),__publicField(this,"droppedBytesThisStatsWindow",0),__publicField(this,"sentCallsThisStatsWindow",0),__publicField(this,"sentBytesThisStatsWindow",0),this.maxCallsPerSecond=null!=(t=e.maxCallsPerSecond)?t:25,this.maxBytesPerSecond=null!=(i=e.maxBytesPerSecond)?i:7e3,this.maxQueueLength=null!=(s=e.maxQueueLength)?s:256,this.onOverload=e.onOverload}schedule(e,t,i){return this.evictExpired(),this.flushStatsIfElapsed(),this.fitsInBudget(e)?(this.commit(e,i),!0):"low"===t?(this.droppedCallsThisStatsWindow+=1,this.droppedBytesThisStatsWindow+=e,!1):(this.queue.push({bytes:e,send:i}),this.queue.length>this.maxQueueLength&&this.notifyOverload(),this.scheduleDrain(),!1)}snapshot(){return{sentCalls:this.sentCallsThisStatsWindow,sentBytes:this.sentBytesThisStatsWindow,droppedCalls:this.droppedCallsThisStatsWindow,droppedBytes:this.droppedBytesThisStatsWindow,queueLength:this.queue.length}}dispose(){null!==this.drainTimer&&(clearTimeout(this.drainTimer),this.drainTimer=null),this.queue=[],this.window=[]}fitsInBudget(e){if(this.window.length+1>this.maxCallsPerSecond)return!1;return!(this.usedBytes()+e>this.maxBytesPerSecond)}commit(e,t){const i=Date.now();this.window.push({at:i,bytes:e}),this.sentCallsThisStatsWindow+=1,this.sentBytesThisStatsWindow+=e;try{t()}catch(e){}}evictExpired(){const e=Date.now()-1e3;let t=0;for(;t<this.window.length&&this.window[t].at<=e;)t++;t>0&&this.window.splice(0,t)}usedBytes(){let e=0;for(const t of this.window)e+=t.bytes;return e}flushStatsIfElapsed(){const e=Date.now();e-this.statsAnchor<1e3||((this.droppedCallsThisStatsWindow>0||this.queue.length>0)&&this.onOverload&&this.notifyOverload(),this.statsAnchor=e,this.droppedCallsThisStatsWindow=0,this.droppedBytesThisStatsWindow=0,this.sentCallsThisStatsWindow=0,this.sentBytesThisStatsWindow=0)}notifyOverload(){if(this.onOverload)try{this.onOverload(this.snapshot())}catch(e){}}scheduleDrain(){if(null!==this.drainTimer)return;const e=Date.now();let t=e;this.window.length>0&&(t=this.window[0].at+1e3);const i=Math.max(20,t-e+5);this.drainTimer=setTimeout(()=>{this.drainTimer=null,this.drain()},i)}drain(){for(this.evictExpired(),this.flushStatsIfElapsed();this.queue.length>0;){const e=this.queue[0];if(!this.fitsInBudget(e.bytes))break;this.queue.shift(),this.commit(e.bytes,e.send)}this.queue.length>0&&this.scheduleDrain()}},DEFAULT_WINDOW=1024,DedupWindow=class{constructor(e=DEFAULT_WINDOW){this.capacity=e,__publicField(this,"slots"),__publicField(this,"cursor",0),__publicField(this,"lookup",new Set),this.slots=new Array(e)}admit(e,t){const i=`${e}#${t}`;if(this.lookup.has(i))return!1;const s=this.slots[this.cursor];return s&&this.lookup.delete(`${s.userId}#${s.seq}`),this.slots[this.cursor]={userId:e,seq:t},this.lookup.add(i),this.cursor=(this.cursor+1)%this.capacity,!0}reset(){this.cursor=0,this.lookup.clear(),this.slots=new Array(this.capacity)}},WHITEBOARD_MSG_TYPE_RANGE=new Set([1,2,3,4,5,6,7,8,9,10]),WHITEBOARD_MSG_TYPE_NAME={1:"DRAW_DELTA",2:"DRAW_COMMIT",3:"DRAW_UNDO_REDO",4:"CLEAR",5:"SNAPSHOT_REQ",6:"SNAPSHOT_RSP",7:"RECONCILE",8:"CLOCK_SYNC",9:"META",10:"LASER_TICK"};function wtName(e){var t;return null!=(t=WHITEBOARD_MSG_TYPE_NAME[e])?t:`UNKNOWN(${e})`}function isHighFrequencyMsg(e){return 10===e||8===e}var SignalManager=class{constructor(e){var t;__publicField(this,"core"),__publicField(this,"userId"),__publicField(this,"transportCmdId"),__publicField(this,"log"),__publicField(this,"throttler"),__publicField(this,"reassembler"),__publicField(this,"dedup"),__publicField(this,"nextSeq",1),__publicField(this,"handlers",new Map),__publicField(this,"isAttached",!1),__publicField(this,"offsetProvider",null),__publicField(this,"boundReceive"),this.core=e.core,this.userId=e.userId,this.transportCmdId=null!=(t=e.cmdId)?t:DEFAULT_WHITEBOARD_CMD_ID,this.log=e.log,this.throttler=new Throttler({onOverload:e.onOverload}),this.reassembler=new FragmentReassembler,this.dedup=new DedupWindow,this.boundReceive=this.receive.bind(this)}attach(){this.isAttached||(this.core.trtc.on("custom-message",this.boundReceive),this.isAttached=!0)}detach(){var e,t;this.isAttached&&(null==(t=(e=this.core.trtc).off)||t.call(e,"custom-message",this.boundReceive),this.isAttached=!1,this.reassembler.dispose(),this.dedup.reset(),this.handlers.clear(),this.throttler.dispose(),this.offsetProvider=null)}on(e,t){this.handlers.set(e,t)}setClockOffsetProvider(e){this.offsetProvider=e}getUserId(){return this.userId}getTransportCmdId(){return this.transportCmdId}send(e,t,i={}){var s,n,o;const r=this.offsetProvider?this.offsetProvider():0,l={v:PROTOCOL_VERSION,wt:e,s:null!=(s=i.seq)?s:this.nextSeq++,t:Date.now()+r,id:null!=(n=i.strokeId)?n:"",u:this.userId,p:t},a=null!=(o=i.priority)?o:"high";let h;try{h=needsFragmentation(JSON.stringify(l.p))?fragment(l):[encodeEnvelope(l)]}catch(e){return void this.log.warn("encode failed:",e)}isHighFrequencyMsg(e)||this.log.debug(`[InteractiveWhiteboard] wb-> ${wtName(e)} cmdId=${this.transportCmdId} seq=${l.s} u=${l.u} id=${l.id||"-"} frames=${h.length} priority=${a}`,l.p);for(const e of h){const t=e.byteLength;t>1e3?this.log.warn(`oversized frame after fragmentation: ${t}B`):this.throttler.schedule(t,a,()=>{if(i.onWireSend)try{i.onWireSend(Date.now())}catch(e){this.log.warn("onWireSend callback threw:",e)}try{this.core.trtc.sendCustomMessage({cmdId:this.transportCmdId,data:e})}catch(e){this.log.warn("sendCustomMessage failed:",e)}})}}receive(e){if(!e)return;if(e.cmdId!==this.transportCmdId)return;let t;try{t=decodeEnvelope(e.data)}catch(e){return void this.log.warn("decodeEnvelope failed:",e)}if(isHighFrequencyMsg(t.wt)||this.log.debug(`[InteractiveWhiteboard] wb<- ${wtName(t.wt)} cmdId=${e.cmdId} seq=${t.s} u=${e.userId} id=${t.id||"-"} bytes=${e.data.byteLength}`,t.p),!WHITEBOARD_MSG_TYPE_RANGE.has(t.wt))return;if(t.u!==e.userId&&(t.u=e.userId),t.u===this.userId)return;const i=this.reassembler.ingest(t);if(!i)return;if(10!==i.wt&&!this.dedup.admit(`${i.u}#${i.wt}`,i.s))return;if(i.v!==PROTOCOL_VERSION)return void this.log.warn(`unsupported protocol version: ${i.v}`);const s=this.handlers.get(i.wt);if(s){isHighFrequencyMsg(i.wt)||this.log.debug(`[InteractiveWhiteboard] wb-dispatch ${wtName(i.wt)} seq=${i.s} u=${i.u} id=${i.id||"-"}`,i.p);try{s(i)}catch(e){this.log.warn(`inbound handler crashed for msgType=${i.wt}:`,e)}}else isHighFrequencyMsg(i.wt)||this.log.debug(`[InteractiveWhiteboard] wb-dispatch (no handler) ${wtName(i.wt)} seq=${i.s} u=${i.u}`)}},BURST_COUNT=4,BURST_INTERVAL_MS=100,RESYNC_INTERVAL_MS=6e4,SAMPLE_RETENTION=8,SAMPLE_RTT_CEILING_MS=2e3,ClockSync=class{constructor(e){__publicField(this,"signal"),__publicField(this,"getHostId"),__publicField(this,"log"),__publicField(this,"localUserId"),__publicField(this,"offset",0),__publicField(this,"samples",[]),__publicField(this,"inflight",new Map),__publicField(this,"nextProbeId",1),__publicField(this,"burstTimer",null),__publicField(this,"resyncTimer",null),__publicField(this,"burstRemaining",0),__publicField(this,"disposed",!1),this.signal=e.signal,this.getHostId=e.getHostId,this.log=e.log,this.localUserId=this.signal.getUserId()}attach(){this.signal.on(8,e=>this.onInbound(e)),this.signal.setClockOffsetProvider(()=>this.offset)}start(){if(this.stopSchedule(),this.disposed)return;const e=this.getHostId();e&&e!==this.localUserId&&(this.burstRemaining=BURST_COUNT,this.scheduleBurstTick(0),this.scheduleResync())}rearm(){this.samples.length=0,this.start()}getOffset(){return this.offset}getSamples(){return this.samples.slice()}dispose(){this.disposed=!0,this.stopSchedule();for(const e of this.inflight.values())null!==e.watchdog&&"undefined"!=typeof window&&window.clearTimeout(e.watchdog);this.inflight.clear(),this.samples.length=0,this.signal.setClockOffsetProvider(null)}stopSchedule(){null!==this.burstTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.burstTimer),this.burstTimer=null),null!==this.resyncTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.resyncTimer),this.resyncTimer=null),this.burstRemaining=0}scheduleBurstTick(e){this.disposed||"undefined"==typeof window||(this.burstTimer=window.setTimeout(()=>{this.burstTimer=null,this.fireProbe(),this.burstRemaining-=1,this.burstRemaining>0&&this.scheduleBurstTick(BURST_INTERVAL_MS)},e))}scheduleResync(){this.disposed||"undefined"==typeof window||(this.resyncTimer=window.setTimeout(()=>{this.resyncTimer=null,this.fireProbe(),this.scheduleResync()},RESYNC_INTERVAL_MS))}fireProbe(){if(this.disposed)return;const e=this.getHostId();if(!e||e===this.localUserId)return;const t=this.nextProbeId++,i={ph:0,to:e,t1:0},s={probeId:t,t1:0,watchdog:null};this.inflight.set(t,s),"undefined"!=typeof window&&(s.watchdog=window.setTimeout(()=>{this.inflight.delete(t)},2*SAMPLE_RTT_CEILING_MS)),this.signal.send(8,i,{strokeId:String(t),priority:"low",onWireSend:e=>{s.t1=e}})}onInbound(e){const t=e.p;t&&t.to===this.localUserId&&(0===t.ph?this.handleRequest(e,t):1===t.ph&&this.handleResponse(e,t))}handleRequest(e,t){const i={ph:1,to:e.u,t1:t.t1};this.signal.send(8,i,{strokeId:e.id,priority:"low"})}handleResponse(e,t){const i=Number(e.id);if(!Number.isFinite(i))return;const s=this.inflight.get(i);if(!s)return;if(this.inflight.delete(i),null!==s.watchdog&&"undefined"!=typeof window&&window.clearTimeout(s.watchdog),s.t1<=0)return;const n=s.t1,o=e.t,r=Date.now(),l=r-n;if(l<0||l>SAMPLE_RTT_CEILING_MS)return void this.log.warn(`[ClockSync] dropped sample with rtt=${l}ms`);const a=o-(n+r)/2;this.recordSample({rtt:l,offset:a,at:r})}recordSample(e){this.samples.push(e),this.samples.length>SAMPLE_RETENTION&&this.samples.shift();let t=this.samples[0];for(const e of this.samples)e.rtt<t.rtt&&(t=e);this.offset=t.offset}},HostElector=class{constructor(e){__publicField(this,"localUserId"),__publicField(this,"localJoinTime"),__publicField(this,"members",new Map),__publicField(this,"currentHost",null),__publicField(this,"listener",null),this.localUserId=e,this.localJoinTime=Date.now(),this.members.set(e,{userId:e,joinTime:this.localJoinTime})}onHostChanged(e){return this.listener=e,()=>{this.listener===e&&(this.listener=null)}}bootstrap(){this.elect("init")}getLocalJoinTime(){return this.localJoinTime}upsertMember(e,t){if(e===this.localUserId)return!1;if(!Number.isFinite(t))return!1;const i=this.members.get(e);return!(i&&i.joinTime<=t)&&(this.members.set(e,{userId:e,joinTime:t}),!0)}removeMember(e){return!!this.members.has(e)&&(this.members.delete(e),e===this.currentHost&&(this.elect("remove"),!0))}elect(e){let t=null,i=Number.POSITIVE_INFINITY;for(const e of this.members.values())(e.joinTime<i||e.joinTime===i&&(null===t||e.userId<t))&&(i=e.joinTime,t=e.userId);if(null!==t&&t!==this.currentHost&&(this.currentHost=t,this.listener))try{this.listener({hostId:t,isLocal:t===this.localUserId,reason:e})}catch(e){}}getHost(){return this.currentHost}isLocalHost(){return this.currentHost===this.localUserId}getMemberCount(){return this.members.size}dispose(){this.members.clear(),this.currentHost=null,this.listener=null}},ANNOUNCE_REASON_PRIORITY={startup:3,"hello-reply":2,retry:1};function pickHigherPriorityReason(e,t){return null===e||ANNOUNCE_REASON_PRIORITY[t]>ANNOUNCE_REASON_PRIORITY[e]?t:e}var PresenceManager=class{constructor(e){__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"log"),__publicField(this,"onPeerObserved"),__publicField(this,"onPeerBye"),__publicField(this,"isDisposed"),__publicField(this,"announceCooldownMs",1e3),__publicField(this,"lastAnnounceSentAt",0),__publicField(this,"pendingAnnounceTimer",null),__publicField(this,"pendingAnnounceReason",null),__publicField(this,"helloSent",!1),__publicField(this,"byeSent",!1),__publicField(this,"heardFromAnyPeer",!1),__publicField(this,"startupRetryTimer",null),this.signalManager=e.signalManager,this.hostElector=e.hostElector,this.log=e.log,this.onPeerObserved=e.onPeerObserved,this.onPeerBye=e.onPeerBye,this.isDisposed=e.isDisposed}start(){this.sendHelloOnce(),this.armStartupRetry()}dispose(){"undefined"!=typeof window&&(null!==this.pendingAnnounceTimer&&window.clearTimeout(this.pendingAnnounceTimer),null!==this.startupRetryTimer&&window.clearTimeout(this.startupRetryTimer)),this.pendingAnnounceTimer=null,this.pendingAnnounceReason=null,this.startupRetryTimer=null}sendHelloOnce(){if(this.isDisposed()||this.helloSent)return;if(!this.canSend())return void this.log.debug("[InteractiveWhiteboard] presence-hello skipped (signal channel unavailable)");const e=this.hostElector.getLocalJoinTime(),t={hello:{jt:e}};try{this.signalManager.send(9,t,{priority:"low"}),this.helloSent=!0,this.log.debug(`[InteractiveWhiteboard] presence-hello sent jt=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-hello send failed:",e)}}sendByeOnce(e){if(this.byeSent)return;const t={bye:{reason:e}};try{this.signalManager.send(9,t,{priority:"high"}),this.byeSent=!0,this.log.debug(`[InteractiveWhiteboard] presence-bye sent reason=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-bye send failed:",e)}}requestAnnounceSend(e){if(this.isDisposed())return"skipped";if(!this.canSend())return this.log.debug(`[InteractiveWhiteboard] presence-announce skipped reason=${e} (signal channel unavailable)`),"skipped";if(null!==this.pendingAnnounceTimer)return this.pendingAnnounceReason=pickHigherPriorityReason(this.pendingAnnounceReason,e),"merged";const t=Date.now()-this.lastAnnounceSentAt;if(0===this.lastAnnounceSentAt||t>=this.announceCooldownMs)return this.flushAnnounceNow(e),"sent";if("undefined"==typeof window)return this.flushAnnounceNow(e),"sent";const i=Math.max(0,this.announceCooldownMs-t);return this.pendingAnnounceReason=e,this.pendingAnnounceTimer=window.setTimeout(()=>{var t;const i=null!=(t=this.pendingAnnounceReason)?t:e;this.pendingAnnounceTimer=null,this.pendingAnnounceReason=null,this.isDisposed()||this.flushAnnounceNow(i)},i),"scheduled"}flushAnnounceNow(e){if(this.isDisposed())return;if(!this.canSend())return;const t={ann:{jt:this.hostElector.getLocalJoinTime()}};try{this.signalManager.send(9,t,{priority:"low"}),this.lastAnnounceSentAt=Date.now(),this.log.debug(`[InteractiveWhiteboard] presence-announce sent reason=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-announce send failed:",e)}}armStartupRetry(){"undefined"!=typeof window&&null===this.startupRetryTimer&&(this.startupRetryTimer=window.setTimeout(()=>{this.startupRetryTimer=null,this.isDisposed()||this.heardFromAnyPeer||this.requestAnnounceSend("retry")},5e3))}handleRemoteMeta(e){var t,i,s;if(this.isDisposed())return null;const n=e.p;if(!n)return null;if(void 0!==n.bye)return null==(t=this.onPeerBye)||t.call(this,e.u,n.bye.reason),this.log.debug(`[InteractiveWhiteboard] presence-bye received from=${e.u} reason=${null!=(i=n.bye.reason)?i:"-"}`),null;let o=null;if(void 0!==n.hello){const t=n.hello.jt;if("number"==typeof t&&Number.isFinite(t)){o=t;const i=this.requestAnnounceSend("hello-reply");this.log.debug(`[InteractiveWhiteboard] presence-hello received from=${e.u} jt=${t} reply=${i}`)}else this.log.warn(`[InteractiveWhiteboard] presence-hello discarded: invalid jt from=${e.u}`)}if(void 0!==n.ann){const t=n.ann.jt;"number"==typeof t&&Number.isFinite(t)?null===o&&(o=t):this.log.warn(`[InteractiveWhiteboard] presence-announce discarded: invalid jt from=${e.u}`)}return void 0===n.ann&&void 0===n.hello?(this.log.debug(`[InteractiveWhiteboard] META frame from=${e.u} carries no recognized sub-key; ignored`),null):null===o?null:(this.heardFromAnyPeer=!0,null==(s=this.onPeerObserved)||s.call(this),{userId:e.u,joinTime:o})}canSend(){return!this.isDisposed()}};function strokeRecordToCommitBody(e,t){var i;switch(e.tool){case"pen":{const{xs:i,ys:s}=encodePoints(e.points);return{tl:0,cl:colorToInt(e.color),lw:e.lineWidth,xs:i,ys:s,un:t}}case"line":case"rect":case"circle":case"arrow":{const{xs:i,ys:s}=encodePoints([e.start,e.end]);return{tl:NAME_TO_WIRE_TOOL[e.tool],cl:colorToInt(e.color),lw:e.lineWidth,xs:i,ys:s,un:t}}case"rectFill":{const{xs:i,ys:s}=encodePoints([e.start,e.end]);return{tl:3,cl:colorToInt(e.color),lw:0,xs:i,ys:s,un:t,fo:Math.round(100*e.fillOpacity)}}case"eraser":{if("object"===e.mode)return{tl:6,lw:e.lineWidth,xs:[],ys:[],un:t,em:0,tg:null!=(i=e.targetStrokeIds)?i:[]};const{xs:s,ys:n}=encodePoints(e.points);return{tl:6,lw:e.lineWidth,xs:s,ys:n,un:t,em:1}}default:return null}}function strokeRecordToSnapshotWire(e,t){const i=strokeRecordToCommitBody(e,t);return{id:e.strokeId,o:e.ownerId,tl:i.tl,cl:i.cl,lw:i.lw,xs:i.xs,ys:i.ys,em:i.em,tg:i.tg,fo:i.fo}}function wireBodyToStrokeRecord(e,t,i){var s,n,o,r;if(!e||"object"!=typeof e)return null;const l=decodePoints(null!=(s=e.xs)?s:[],null!=(n=e.ys)?n:[]),a=null!=(o=intToColor(e.cl))?o:"#FF0000";switch(WIRE_TOOL_TO_NAME[e.tl]){case"pen":return{tool:"pen",strokeId:t,ownerId:i,points:l,color:a,lineWidth:e.lw};case"line":return l.length<2?null:{tool:"line",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"rect":return l.length<2?null:{tool:"rect",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"rectFill":return l.length<2?null:{tool:"rectFill",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,fillOpacity:"number"==typeof e.fo?e.fo/100:.3};case"circle":return l.length<2?null:{tool:"circle",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"arrow":return l.length<2?null:{tool:"arrow",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"eraser":{const s=1===e.em?"path":"object";return{tool:"eraser",strokeId:t,ownerId:i,mode:s,points:"path"===s?l:[],lineWidth:e.lw,targetStrokeIds:"object"===s?null!=(r=e.tg)?r:[]:void 0}}default:return null}}function snapshotWireToStroke(e){return wireBodyToStrokeRecord(e,e.id,e.o)}function buildLaserTickBody(e,t,i,s){var n;const{xs:o,ys:r}=encodePoints(e);return{sq:t,cl:null!=(n=colorToInt(i))?n:16711680,lw:s,xs:o,ys:r}}function buildDrawDeltaBody(e,t,i,s){const{xs:n,ys:o}=encodePoints(t),r="eraser"===e,l={tl:r?6:0,lw:s,xs:n,ys:o};return r||(l.cl=colorToInt(i)),r&&(l.em=1),l}var SNAPSHOT_BATCH_SIZE=12,SNAPSHOT_RSP_TIMEOUT_MS=1e4,SnapshotManager=class{constructor(e){__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"engine"),__publicField(this,"userId"),__publicField(this,"userName"),__publicField(this,"log"),__publicField(this,"emitEvent"),__publicField(this,"isDisposed"),__publicField(this,"isPending",!1),__publicField(this,"snapshotTimer",null),__publicField(this,"retried",!1),__publicField(this,"retryOnPeerSeen",!1),__publicField(this,"maxWaitTimer",null),this.signalManager=e.signalManager,this.hostElector=e.hostElector,this.engine=e.engine,this.userId=e.userId,this.userName=e.userName,this.log=e.log,this.emitEvent=e.emitEvent,this.isDisposed=e.isDisposed}request(){if(this.isPending=!0,this.retried=!1,this.retryOnPeerSeen=!1,this.hostElector.getMemberCount()<=1)return this.log.info("[InteractiveWhiteboard] snapshot skipped: room has no other whiteboard peer (will retry when a peer joins)"),this.retryOnPeerSeen=!0,void this.armMaxWait();this.sendRequest()}dispose(){this.clearTimers()}sendRequest(){if(!this.isPending)return;this.signalManager.send(5,{},{priority:"high"}),null!==this.snapshotTimer&&"undefined"!=typeof window&&window.clearTimeout(this.snapshotTimer),"undefined"!=typeof window&&(this.snapshotTimer=window.setTimeout(()=>this.onTimeout(),SNAPSHOT_RSP_TIMEOUT_MS))}retryIfPeerAppeared(){this.isPending&&this.retryOnPeerSeen&&(this.retryOnPeerSeen=!1,null!==this.maxWaitTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=null),this.retried=!0,this.log.debug("[InteractiveWhiteboard] snapshot retry: a whiteboard peer just appeared"),this.sendRequest())}onTimeout(){var e;if(this.snapshotTimer=null,this.isPending){if(this.retried)return this.isPending=!1,this.log&&this.log.warn("[InteractiveWhiteboard] snapshot timeout: peers were present but none responded"),void(null==(e=this.emitEvent)||e.call(this,"whiteboard:error",{code:"SNAPSHOT_TIMEOUT",message:"snapshot request timed out, no responder"}));this.retryOnPeerSeen=!0,this.armMaxWait()}}armMaxWait(){"undefined"!=typeof window&&(null!==this.maxWaitTimer&&window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=window.setTimeout(()=>{this.maxWaitTimer=null,this.isPending&&(this.isPending=!1,this.retryOnPeerSeen=!1,this.log.info("[InteractiveWhiteboard] snapshot abandoned: still no whiteboard peer in the room, starting with empty board"))},SNAPSHOT_RSP_TIMEOUT_MS))}complete(){this.isPending=!1,this.retryOnPeerSeen=!1,this.clearTimers()}clearTimers(){null!==this.snapshotTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.snapshotTimer),this.snapshotTimer=null),null!==this.maxWaitTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=null)}handleRemoteSnapshotReq(e){var t,i;if(!this.hostElector.isLocalHost())return;const s=null!=(t=e.p)?t:{},n=new Set(null!=(i=s.has)?i:[]),o=this.engine.exportSnapshot().filter(e=>!n.has(e.strokeId));if(0===o.length)return;const r=o.length;for(let t=0;t<o.length;t+=SNAPSHOT_BATCH_SIZE){const i=o.slice(t,t+SNAPSHOT_BATCH_SIZE),s={to:e.u,ss:i.map(e=>strokeRecordToSnapshotWire(e,this.userName)),total:r};this.signalManager.send(6,s,{priority:"high"})}}handleRemoteSnapshotRsp(e){var t;const i=e.p;if(!i||i.to!==this.userId)return;const s=[];for(const e of null!=(t=i.ss)?t:[]){const t=snapshotWireToStroke(e);t&&s.push(t)}s.length>0&&this.engine.mergeSnapshot(s),this.isPending&&this.complete()}},TRANSPARENT_PNG_1X1="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgAAIAAAUAAeImBZsAAAAASUVORK5CYII=";async function captureScreenshot(e){const{engine:t,viewBinder:i,log:s}=e,n=t.getCanvas(),o=()=>{try{return n.toDataURL("image/png")}catch(e){return s.warn("[InteractiveWhiteboard] overlay.toDataURL failed:",e),TRANSPARENT_PNG_1X1}};let r=null;try{r=document.createElement("canvas"),r.width=n.width,r.height=n.height;const e=r.getContext("2d");if(!e)return o();const t=i.getContainer(),l=t?t.querySelector("video"):null;if(!!l&&"number"==typeof l.videoWidth&&"number"==typeof l.videoHeight&&l.videoWidth>0&&l.videoHeight>0&&l.readyState>=2){const s=i.getContentRectInView(),o=t.getBoundingClientRect(),a=n.height/Math.max(1,s.height),h=l.getBoundingClientRect(),c=h.left-o.left,d=h.top-o.top,u=h.width,p=h.height,m=getComputedStyle(l).objectFit;let g,f,_,w;if("fill"===m)g=c,f=d,_=u,w=p;else if("cover"===m){const e=Math.max(u/l.videoWidth,p/l.videoHeight);_=l.videoWidth*e,w=l.videoHeight*e,g=c+(u-_)/2,f=d+(p-w)/2}else{const e=Math.min(u/l.videoWidth,p/l.videoHeight);_=l.videoWidth*e,w=l.videoHeight*e,g=c+(u-_)/2,f=d+(p-w)/2}const b=(g-s.left)*a,v=(f-s.top)*a,y=_*a,T=w*a;e.drawImage(l,b,v,y,T),r.width===n.width&&r.height===n.height||(r.width=n.width,r.height=n.height,e.drawImage(l,b,v,y,T))}e.drawImage(n,0,0);try{return r.toDataURL("image/png")}catch(e){return s.warn("[InteractiveWhiteboard] composite toDataURL failed (likely tainted by cross-origin video); falling back to canvas-only:",e),o()}}catch(e){return s.warn("[InteractiveWhiteboard] screenshot composition failed:",e),o()}finally{r&&(r.width=0,r.height=0)}}function scopeToWire(e){switch(e){case"all":return 0;case"self":return 1;case"others":return 2}}function wireToScope(e){switch(e){case 1:return"self";case 2:return"others";default:return"all"}}var WhiteboardContext=class{constructor(e,t){var i,s,n,o,r,l,a,h,c,d;__publicField(this,"viewBinder"),__publicField(this,"engine"),__publicField(this,"inputHandler"),__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"clockSync"),__publicField(this,"presence"),__publicField(this,"snapshot"),__publicField(this,"userId"),__publicField(this,"userName"),__publicField(this,"log"),__publicField(this,"emitEvent"),__publicField(this,"trtc"),__publicField(this,"boundOnRemoteUserExit"),__publicField(this,"boundOnBeforeUnload",null),__publicField(this,"unsubscribeResize"),__publicField(this,"unsubscribeHost"),__publicField(this,"disposed",!1),__publicField(this,"interactive",!0),__publicField(this,"remoteStartEmitted",new Set),this.userId=t.userId,this.userName=t.userName,this.log=t.logger,this.emitEvent=t.emit;const u=null!=(i=e.canvasInfo)?i:{width:1920,height:1080};this.viewBinder=new ViewBinder({view:e.view,canvasInfo:u}),this.viewBinder.attach();const p=this.viewBinder.getOverlay();this.engine=new DrawingEngine({canvas:p,userId:t.userId,dpr:1,viewWidthCss:u.width,viewHeightCss:u.height,tool:null!=(n=null==(s=e.tool)?void 0:s.name)?n:"pen",color:null==(o=e.tool)?void 0:o.color,lineWidth:null==(r=e.tool)?void 0:r.lineWidth,fillOpacity:null==(l=e.tool)?void 0:l.fillOpacity,eraserMode:null!=(h=null==(a=e.tool)?void 0:a.eraserMode)?h:"object",onLocalCommit:e=>this.handleLocalCommit(e),onLocalLaserTick:e=>this.handleLocalLaserTick(e),onLocalDelta:e=>this.handleLocalDelta(e)}),this.inputHandler=new InputHandler({container:this.viewBinder.getContainer(),canvas:p,engine:this.engine,canvasInfo:u}),this.interactive=!1!==(null==(c=e.config)?void 0:c.interactive),this.viewBinder.setPointerEventsEnabled(this.interactive),this.interactive&&this.inputHandler.attach(),this.signalManager=new SignalManager({core:t.core,userId:t.userId,cmdId:null==(d=e.config)?void 0:d.cmdId,log:t.logger,onOverload:e=>{var t;const i=`send overload: dropped=${e.droppedCalls} calls / ${e.droppedBytes}B`;this.log.warn(`[InteractiveWhiteboard] ${i}`),null==(t=this.emitEvent)||t.call(this,"whiteboard:error",{code:"SEND_OVERLOAD",message:i})}}),this.hostElector=new HostElector(t.userId),this.clockSync=new ClockSync({signal:this.signalManager,getHostId:()=>this.hostElector.getHost(),log:t.logger}),this.clockSync.attach(),this.presence=new PresenceManager({signalManager:this.signalManager,hostElector:this.hostElector,log:t.logger,onPeerObserved:()=>this.snapshot.retryIfPeerAppeared(),onPeerBye:e=>{this.hostElector.removeMember(e)},isDisposed:()=>this.disposed}),this.snapshot=new SnapshotManager({signalManager:this.signalManager,hostElector:this.hostElector,engine:this.engine,userId:t.userId,userName:t.userName,log:t.logger,emitEvent:(e,t)=>{var i;return null==(i=this.emitEvent)?void 0:i.call(this,e,t)},isDisposed:()=>this.disposed}),this.signalManager.attach(),this.signalManager.on(9,e=>this.onRemoteMeta(e)),this.signalManager.on(5,e=>this.snapshot.handleRemoteSnapshotReq(e)),this.signalManager.on(6,e=>this.snapshot.handleRemoteSnapshotRsp(e)),this.signalManager.on(2,e=>this.onRemoteDrawCommit(e)),this.signalManager.on(1,e=>this.onRemoteDrawDelta(e)),this.signalManager.on(4,e=>this.onRemoteClear(e)),this.signalManager.on(3,e=>this.onRemoteUndoRedo(e)),this.signalManager.on(10,e=>this.onRemoteLaserTick(e)),this.unsubscribeHost=this.hostElector.onHostChanged(e=>this.onHostChanged(e)),this.attachTrtcEvents(t.core),this.hostElector.bootstrap(),this.unsubscribeResize=this.viewBinder.onResize(()=>{}),this.presence.start(),this.snapshot.request(),this.attachBeforeUnload()}setTool(e){this.engine.setTool(e)}setColor(e){this.engine.setColor(e)}setLineWidth(e){this.engine.setLineWidth(e)}setFillOpacity(e){this.engine.setFillOpacity(e)}setEraserMode(e){this.engine.setEraserMode(e)}setInteractive(e){if(this.disposed)return;const t=!!e;t!==this.interactive&&(this.interactive=t,t?(this.viewBinder.setPointerEventsEnabled(!0),this.inputHandler.attach(),this.log.info("[InteractiveWhiteboard] interactive mode enabled (drawing allowed)")):(this.inputHandler.detach(),this.viewBinder.setPointerEventsEnabled(!1),this.log.info("[InteractiveWhiteboard] interactive mode disabled (read-only)")))}isInteractive(){return this.interactive}clearAll(){var e;this.assertInteractive("clear")&&(this.engine.clearAll(),null==(e=this.emitEvent)||e.call(this,"whiteboard:cleared",{operatorUserId:this.userId,scope:"all"}))}undo(){this.assertInteractive("undo")&&this.engine.undo()}redo(){this.assertInteractive("redo")&&this.engine.redo()}assertInteractive(e){return!!this.interactive||(this.log.warn(`[InteractiveWhiteboard] ${e} ignored: interactive=false (read-only mode)`),!1)}getHostId(){return this.hostElector.getHost()}async screenshot(){return captureScreenshot({engine:this.engine,viewBinder:this.viewBinder,log:this.log})}dispose(){this.presence.sendByeOnce("dispose"),this.disposed=!0,this.unsubscribeResize(),this.unsubscribeHost(),this.detachTrtcEvents(),this.presence.dispose(),this.snapshot.dispose(),this.detachBeforeUnload(),this.clockSync.dispose(),this.signalManager.detach(),this.inputHandler.detach(),this.engine.dispose(),this.viewBinder.dispose(),this.hostElector.dispose()}attachTrtcEvents(e){this.trtc=e.trtc,this.boundOnRemoteUserExit=e=>{e&&e.userId&&this.hostElector.removeMember(e.userId)};try{this.trtc.on("remote-user-exit",this.boundOnRemoteUserExit)}catch(e){this.log.warn("[InteractiveWhiteboard] failed to subscribe trtc events:",e)}}detachTrtcEvents(){var e,t;if(this.trtc)try{null==(t=(e=this.trtc).off)||t.call(e,"remote-user-exit",this.boundOnRemoteUserExit)}catch(e){}}onRemoteMeta(e){const t=this.presence.handleRemoteMeta(e);if(!t)return;this.hostElector.upsertMember(t.userId,t.joinTime)&&this.hostElector.elect("add")}onHostChanged(e){var t;const i="[InteractiveWhiteboard]";"init"===e.reason?this.log.info(`${i} host elected (init, temporary): hostId=${e.hostId} isLocal=${e.isLocal} (will be re-confirmed after ANNOUNCE exchange)`):"add"===e.reason?this.log.info(`${i} host confirmed via signaling: hostId=${e.hostId} isLocal=${e.isLocal}`):this.log.info(`${i} host re-elected after previous host left: hostId=${e.hostId} isLocal=${e.isLocal}`),this.clockSync.rearm(),null==(t=this.emitEvent)||t.call(this,"whiteboard:host-changed",{hostId:e.hostId,isLocal:e.isLocal})}handleLocalCommit(e){switch(e.kind){case"stroke":{const t=strokeRecordToCommitBody(e.record,this.userName);if(!t)return;this.signalManager.send(2,t,{strokeId:e.record.strokeId,priority:"high"});break}case"clear":{const t={sc:scopeToWire(e.scope)};this.signalManager.send(4,t,{priority:"high"});break}case"undo":{const t={op:0};this.signalManager.send(3,t,{strokeId:e.record.strokeId,priority:"high"});break}case"redo":{const t=strokeRecordToCommitBody(e.record,this.userName);if(!t)return;this.signalManager.send(2,t,{strokeId:e.record.strokeId,priority:"high"});break}}}handleLocalLaserTick(e){if(!e.points||0===e.points.length)return;const t=buildLaserTickBody(e.points,e.sq,e.color,e.lineWidth);this.signalManager.send(10,t,{priority:"low"})}handleLocalDelta(e){if(!e.points||0===e.points.length)return;const t=buildDrawDeltaBody(e.tool,e.points,e.color,e.lineWidth);this.signalManager.send(1,t,{strokeId:e.strokeId,priority:"low"})}onRemoteDrawCommit(e){var t,i;const s=wireBodyToStrokeRecord(e.p,e.id,e.u);if(!s)return;this.engine.ingestRemoteStroke(s);const n=e.p,o=n&&"string"==typeof n.un?n.un:e.u;this.remoteStartEmitted.has(s.strokeId)||(this.remoteStartEmitted.add(s.strokeId),null==(t=this.emitEvent)||t.call(this,"whiteboard:remote-draw-start",{userId:e.u,userName:o,strokeId:s.strokeId,tool:WIRE_TOOL_TO_NAME[n.tl]})),this.remoteStartEmitted.delete(s.strokeId),null==(i=this.emitEvent)||i.call(this,"whiteboard:remote-draw-end",{userId:e.u,strokeId:s.strokeId})}onRemoteClear(e){var t;const i=e.p;if(!i)return;const s=wireToScope(i.sc);this.engine.ingestRemoteClear(s,e.u),null==(t=this.emitEvent)||t.call(this,"whiteboard:cleared",{operatorUserId:e.u,scope:s})}onRemoteUndoRedo(e){const t=e.p;t&&0===t.op&&this.engine.ingestRemoteUndo(e.id,e.u)}onRemoteDrawDelta(e){var t,i;const s=e.p;if(!s||!Array.isArray(s.xs)||!Array.isArray(s.ys))return;if(!e.id)return;const n=WIRE_TOOL_TO_NAME[s.tl];if("pen"!==n&&"eraser"!==n)return;if("eraser"===n&&1!==s.em)return;const o=decodePoints(s.xs,s.ys);if(0===o.length)return;const r=null!=(t=intToColor(s.cl))?t:"#FF0000",l="number"==typeof s.lw?s.lw:4;this.engine.ingestRemoteDelta(e.id,e.u,n,r,l,o),this.remoteStartEmitted.has(e.id)||(this.remoteStartEmitted.add(e.id),null==(i=this.emitEvent)||i.call(this,"whiteboard:remote-draw-start",{userId:e.u,userName:e.u,strokeId:e.id,tool:n}))}onRemoteLaserTick(e){var t;const i=e.p;if(!i||!Array.isArray(i.xs)||!Array.isArray(i.ys))return;const s=decodePoints(i.xs,i.ys);if(0===s.length)return;const n=null!=(t=intToColor(i.cl))?t:"#FF0000",o="number"==typeof i.lw?i.lw:4,r="number"==typeof i.sq?i.sq:0;this.engine.ingestRemoteLaserTick(e.u,n,o,r,s)}attachBeforeUnload(){"undefined"!=typeof window&&(this.boundOnBeforeUnload=()=>{try{this.presence.sendByeOnce("beforeunload")}catch(e){this.log.warn("[InteractiveWhiteboard] beforeunload bye failed:",e)}},window.addEventListener("beforeunload",this.boundOnBeforeUnload))}detachBeforeUnload(){"undefined"!=typeof window&&this.boundOnBeforeUnload&&(window.removeEventListener("beforeunload",this.boundOnBeforeUnload),this.boundOnBeforeUnload=null)}},pluginSeq=0,_InteractiveWhiteboard=class e extends import_eventemitter3.EventEmitter{constructor(e){super(),this.core=e,__publicField(this,"_core"),__publicField(this,"_log"),__publicField(this,"seq"),__publicField(this,"ctx",null),pluginSeq+=1,this.seq=pluginSeq,this._log=e.log.createChild({id:`${this.getAlias()}${pluginSeq}`}),this._log.info(`[InteractiveWhiteboard] created id=${this.getAlias()}${pluginSeq}`),this._core=e}getName(){return e.Name}getAlias(){return"iwb"}getGroup(e){return"default"}getValidateRule(e){switch(e){case"start":return startValidateRule(this._core);case"update":return updateValidateRule(this._core);case"stop":return stopValidateRule(this._core)}}async start(e){var t,i,s;if(this._log.info(`[InteractiveWhiteboard] start: ${JSON.stringify({tool:null==(t=e.tool)?void 0:t.name,color:null==(i=e.tool)?void 0:i.color,lineWidth:null==(s=e.tool)?void 0:s.lineWidth})}`),this.ctx)return void this._log.warn("[InteractiveWhiteboard] already started, ignoring");const n=this._core.room.userId;if(!n)throw new Error("[InteractiveWhiteboard] start failed: not joined a room yet");const o=e.userName&&e.userName.length>0?e.userName:n;this.ctx=new WhiteboardContext(e,{core:this._core,userId:n,userName:o,logger:this._log,emit:(e,t)=>{try{this.emit(e,t)}catch(e){this._log.warn("[InteractiveWhiteboard] event listener threw:",e)}}})}async update(e){if(this._log.info(`[InteractiveWhiteboard] update: ${JSON.stringify(e)}`),!this.ctx)throw new Error("[InteractiveWhiteboard] update failed: not started");if(e.tool&&(void 0!==e.tool.name&&this.ctx.setTool(e.tool.name),void 0!==e.tool.color&&this.ctx.setColor(e.tool.color),void 0!==e.tool.lineWidth&&this.ctx.setLineWidth(e.tool.lineWidth),void 0!==e.tool.fillOpacity&&this.ctx.setFillOpacity(e.tool.fillOpacity),void 0!==e.tool.eraserMode&&this.ctx.setEraserMode(e.tool.eraserMode)),e.config&&void 0!==e.config.interactive&&this.ctx.setInteractive(e.config.interactive),e.operation)switch(e.operation){case"clear":this.ctx.clearAll();break;case"undo":this.ctx.undo();break;case"redo":this.ctx.redo()}if(e.screenshot)return this.ctx.screenshot()}async stop(e){this._log.info("[InteractiveWhiteboard] stop"),this.ctx&&(this.ctx.dispose(),this.ctx=null)}};__publicField(_InteractiveWhiteboard,"TYPE",{Tool:WhiteboardTool,ClearScope:ClearScope,EraserMode:EraserMode}),__publicField(_InteractiveWhiteboard,"EVENT",InteractiveWhiteboardEvent),__publicField(_InteractiveWhiteboard,"ERROR_CODE",InteractiveWhiteboardErrorCode),__publicField(_InteractiveWhiteboard,"Name","InteractiveWhiteboard");var InteractiveWhiteboard=_InteractiveWhiteboard,index_default=InteractiveWhiteboard;export{index_default as default};export{InteractiveWhiteboard};
1
+ var __create=Object.create,__defProp=Object.defineProperty,__defProps=Object.defineProperties,__getOwnPropDesc=Object.getOwnPropertyDescriptor,__getOwnPropDescs=Object.getOwnPropertyDescriptors,__getOwnPropNames=Object.getOwnPropertyNames,__getOwnPropSymbols=Object.getOwnPropertySymbols,__getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty,__propIsEnum=Object.prototype.propertyIsEnumerable,__defNormalProp=(e,t,i)=>t in e?__defProp(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,__spreadValues=(e,t)=>{for(var i in t||(t={}))__hasOwnProp.call(t,i)&&__defNormalProp(e,i,t[i]);if(__getOwnPropSymbols)for(var i of __getOwnPropSymbols(t))__propIsEnum.call(t,i)&&__defNormalProp(e,i,t[i]);return e},__spreadProps=(e,t)=>__defProps(e,__getOwnPropDescs(t)),__commonJS=(e,t)=>function(){return t||(0,e[__getOwnPropNames(e)[0]])((t={exports:{}}).exports,t),t.exports},__copyProps=(e,t,i,s)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of __getOwnPropNames(t))__hasOwnProp.call(e,n)||n===i||__defProp(e,n,{get:()=>t[n],enumerable:!(s=__getOwnPropDesc(t,n))||s.enumerable});return e},__toESM=(e,t,i)=>(i=null!=e?__create(__getProtoOf(e)):{},__copyProps(!t&&e&&e.__esModule?i:__defProp(i,"default",{value:e,enumerable:!0}),e)),__publicField=(e,t,i)=>__defNormalProp(e,"symbol"!=typeof t?t+"":t,i),require_eventemitter3=__commonJS({"../node_modules/.pnpm/eventemitter3@4.0.7/node_modules/eventemitter3/index.js"(e,t){"use strict";var i=Object.prototype.hasOwnProperty,s="~";function n(){}function o(e,t,i){this.fn=e,this.context=t,this.once=i||!1}function r(e,t,i,n,r){if("function"!=typeof i)throw new TypeError("The listener must be a function");var l=new o(i,n||e,r),a=s?s+t:t;return e._events[a]?e._events[a].fn?e._events[a]=[e._events[a],l]:e._events[a].push(l):(e._events[a]=l,e._eventsCount++),e}function l(e,t){0===--e._eventsCount?e._events=new n:delete e._events[t]}function a(){this._events=new n,this._eventsCount=0}Object.create&&(n.prototype=Object.create(null),(new n).__proto__||(s=!1)),a.prototype.eventNames=function(){var e,t,n=[];if(0===this._eventsCount)return n;for(t in e=this._events)i.call(e,t)&&n.push(s?t.slice(1):t);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(e)):n},a.prototype.listeners=function(e){var t=s?s+e:e,i=this._events[t];if(!i)return[];if(i.fn)return[i.fn];for(var n=0,o=i.length,r=new Array(o);n<o;n++)r[n]=i[n].fn;return r},a.prototype.listenerCount=function(e){var t=s?s+e:e,i=this._events[t];return i?i.fn?1:i.length:0},a.prototype.emit=function(e,t,i,n,o,r){var l=s?s+e:e;if(!this._events[l])return!1;var a,h,c=this._events[l],d=arguments.length;if(c.fn){switch(c.once&&this.removeListener(e,c.fn,void 0,!0),d){case 1:return c.fn.call(c.context),!0;case 2:return c.fn.call(c.context,t),!0;case 3:return c.fn.call(c.context,t,i),!0;case 4:return c.fn.call(c.context,t,i,n),!0;case 5:return c.fn.call(c.context,t,i,n,o),!0;case 6:return c.fn.call(c.context,t,i,n,o,r),!0}for(h=1,a=new Array(d-1);h<d;h++)a[h-1]=arguments[h];c.fn.apply(c.context,a)}else{var u,p=c.length;for(h=0;h<p;h++)switch(c[h].once&&this.removeListener(e,c[h].fn,void 0,!0),d){case 1:c[h].fn.call(c[h].context);break;case 2:c[h].fn.call(c[h].context,t);break;case 3:c[h].fn.call(c[h].context,t,i);break;case 4:c[h].fn.call(c[h].context,t,i,n);break;default:if(!a)for(u=1,a=new Array(d-1);u<d;u++)a[u-1]=arguments[u];c[h].fn.apply(c[h].context,a)}}return!0},a.prototype.on=function(e,t,i){return r(this,e,t,i,!1)},a.prototype.once=function(e,t,i){return r(this,e,t,i,!0)},a.prototype.removeListener=function(e,t,i,n){var o=s?s+e:e;if(!this._events[o])return this;if(!t)return l(this,o),this;var r=this._events[o];if(r.fn)r.fn!==t||n&&!r.once||i&&r.context!==i||l(this,o);else{for(var a=0,h=[],c=r.length;a<c;a++)(r[a].fn!==t||n&&!r[a].once||i&&r[a].context!==i)&&h.push(r[a]);h.length?this._events[o]=1===h.length?h[0]:h:l(this,o)}return this},a.prototype.removeAllListeners=function(e){var t;return e?(t=s?s+e:e,this._events[t]&&l(this,t)):(this._events=new n,this._eventsCount=0),this},a.prototype.off=a.prototype.removeListener,a.prototype.addListener=a.prototype.on,a.prefixed=s,a.EventEmitter=a,void 0!==t&&(t.exports=a)}}),import_eventemitter3=__toESM(require_eventemitter3(),1),WhiteboardTool=(e=>(e.Pen="pen",e.Line="line",e.Rect="rect",e.RectFill="rectFill",e.Circle="circle",e.Arrow="arrow",e.Laser="laser",e.Eraser="eraser",e))(WhiteboardTool||{}),EraserMode=(e=>(e.Object="object",e.Path="path",e))(EraserMode||{}),ClearScope=(e=>(e.All="all",e.Self="self",e.Others="others",e))(ClearScope||{}),DEFAULT_WHITEBOARD_CMD_ID=10,InteractiveWhiteboardEvent=(e=>(e.HOST_CHANGED="whiteboard:host-changed",e.REMOTE_DRAW_START="whiteboard:remote-draw-start",e.REMOTE_DRAW_END="whiteboard:remote-draw-end",e.CLEARED="whiteboard:cleared",e.ERROR="whiteboard:error",e))(InteractiveWhiteboardEvent||{}),InteractiveWhiteboardErrorCode=(e=>(e.INVALID_CONFIG="INVALID_CONFIG",e.ALREADY_STARTED="ALREADY_STARTED",e.NOT_STARTED="NOT_STARTED",e.READ_ONLY_FALLBACK="READ_ONLY_FALLBACK",e.SEND_OVERLOAD="SEND_OVERLOAD",e.SNAPSHOT_TIMEOUT="SNAPSHOT_TIMEOUT",e.VIEW_NOT_FOUND="VIEW_NOT_FOUND",e))(InteractiveWhiteboardErrorCode||{}),TOOL_VALUES=Object.values(WhiteboardTool),ERASER_MODE_VALUES=Object.values(EraserMode);function startValidateRule(e){return{type:"object",required:!0,properties:{view:{required:!0,validate(e,t,i){if("string"!=typeof e&&!(e instanceof HTMLElement))throw new Error(`[${i}] '${t}' must be an HTMLElement or a string selector.`)}},canvasInfo:{validate(e,t,i){if(void 0!==e&&(!e||"object"!=typeof e||void 0!==e.width&&("number"!=typeof e.width||e.width<=0)||void 0!==e.height&&("number"!=typeof e.height||e.height<=0)))throw new Error(`[${i}] '${t}' must be an object \`{ width?:number>0, height?:number>0 }\`.`)}},userName:{type:"string"},tool:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.name&&("string"!=typeof e.name||!TOOL_VALUES.includes(e.name)))throw new Error(`[${i}] '${t}.name' must be one of: ${TOOL_VALUES.join(", ")}.`);if(void 0!==e.color&&"string"!=typeof e.color)throw new Error(`[${i}] '${t}.color' must be a string.`);if(void 0!==e.lineWidth&&("number"!=typeof e.lineWidth||e.lineWidth<1||e.lineWidth>100))throw new Error(`[${i}] '${t}.lineWidth' must be a number in [1, 100].`);if(void 0!==e.laserFadeDuration&&("number"!=typeof e.laserFadeDuration||e.laserFadeDuration<100||e.laserFadeDuration>1e4))throw new Error(`[${i}] '${t}.laserFadeDuration' must be a number in [100, 10000].`);if(void 0!==e.eraserMode&&!ERASER_MODE_VALUES.includes(e.eraserMode))throw new Error(`[${i}] '${t}.eraserMode' must be one of: ${ERASER_MODE_VALUES.join(", ")}.`);if(void 0!==e.fillOpacity&&("number"!=typeof e.fillOpacity||e.fillOpacity<0||e.fillOpacity>1))throw new Error(`[${i}] '${t}.fillOpacity' must be in [0, 1].`)}}},config:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.interactive&&"boolean"!=typeof e.interactive)throw new Error(`[${i}] '${t}.interactive' must be a boolean.`);if(void 0!==e.cmdId&&("number"!=typeof e.cmdId||!Number.isInteger(e.cmdId)||e.cmdId<1||e.cmdId>10))throw new Error(`[${i}] '${t}.cmdId' must be an integer in [1, 10].`);if(void 0!==e.sendChannel&&"string"!=typeof e.sendChannel)throw new Error(`[${i}] '${t}.sendChannel' must be a string.`);if(void 0!==e.receiveChannel&&"string"!=typeof e.receiveChannel)throw new Error(`[${i}] '${t}.receiveChannel' must be a string.`)}}}}}}function updateValidateRule(e){return{type:"object",properties:{tool:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.name&&("string"!=typeof e.name||!TOOL_VALUES.includes(e.name)))throw new Error(`[${i}] '${t}.name' must be one of: ${TOOL_VALUES.join(", ")}.`);if(void 0!==e.color&&"string"!=typeof e.color)throw new Error(`[${i}] '${t}.color' must be a string.`);if(void 0!==e.lineWidth&&("number"!=typeof e.lineWidth||e.lineWidth<1||e.lineWidth>100))throw new Error(`[${i}] '${t}.lineWidth' must be a number in [1, 100].`);if(void 0!==e.fillOpacity&&("number"!=typeof e.fillOpacity||e.fillOpacity<0||e.fillOpacity>1))throw new Error(`[${i}] '${t}.fillOpacity' must be in [0, 1].`);if(void 0!==e.eraserMode&&!ERASER_MODE_VALUES.includes(e.eraserMode))throw new Error(`[${i}] '${t}.eraserMode' must be one of: ${ERASER_MODE_VALUES.join(", ")}.`)}}},config:{type:"object",validate(e,t,i){if(void 0!==e){if(!e||"object"!=typeof e)throw new Error(`[${i}] '${t}' must be an object.`);if(void 0!==e.interactive&&"boolean"!=typeof e.interactive)throw new Error(`[${i}] '${t}.interactive' must be a boolean.`)}}},operation:{type:"string",validate(e,t,i){if(void 0!==e&&!["undo","redo","clear"].includes(e))throw new Error(`[${i}] '${t}' must be one of: 'undo', 'redo', 'clear'.`)}}}}}function stopValidateRule(e){return{type:"object"}}function resolveView(e){if(e instanceof HTMLElement)return e;const t=document.getElementById(e)||document.querySelector(e);if(!(t&&t instanceof HTMLElement))throw new Error(`[InteractiveWhiteboard] view not found: ${e}`);return t}function quantize(e){return Math.max(-32768,Math.min(32767,Math.round(1e4*e)))}function dequantize(e){return e/1e4}var __strokeCounter=0;function genStrokeId(e){return __strokeCounter+=1,`${e}#${Date.now().toString(36)}#${__strokeCounter.toString(36)}`}var OVERLAY_CLASS="trtc-iw-overlay",ViewBinder=class{constructor(e){var t;__publicField(this,"container"),__publicField(this,"overlay"),__publicField(this,"canvasInfo"),__publicField(this,"resizeObserver",null),__publicField(this,"listeners",new Set),__publicField(this,"currentRect",{left:0,top:0,width:0,height:0}),__publicField(this,"onWindowResizeBound"),this.container=resolveView(e.view),this.canvasInfo={width:e.canvasInfo.width,height:e.canvasInfo.height};"static"===getComputedStyle(this.container).position&&(this.container.style.position="relative"),this.overlay=document.createElement("canvas"),this.overlay.className=OVERLAY_CLASS,Object.assign(this.overlay.style,{position:"absolute",left:"0",top:"0",width:"100%",height:"100%",pointerEvents:"auto",touchAction:"none",zIndex:String(null!=(t=e.zIndex)?t:100)}),this.container.appendChild(this.overlay),this.onWindowResizeBound=()=>this.measure(),this.measure(!1)}getContainer(){return this.container}getOverlay(){return this.overlay}setPointerEventsEnabled(e){this.overlay.style.pointerEvents=e?"auto":"none"}getRect(){return __spreadValues({},this.currentRect)}getContentRectInView(){const e=this.container.getBoundingClientRect();return{left:this.currentRect.left-e.left,top:this.currentRect.top-e.top,width:this.currentRect.width,height:this.currentRect.height}}getCanvasInfo(){return __spreadValues({},this.canvasInfo)}onResize(e){return this.listeners.add(e),()=>this.listeners.delete(e)}attach(){this.resizeObserver||(this.resizeObserver=new ResizeObserver(()=>this.measure()),this.resizeObserver.observe(this.container),window.addEventListener("resize",this.onWindowResizeBound),document.addEventListener("fullscreenchange",this.onWindowResizeBound),document.addEventListener("webkitfullscreenchange",this.onWindowResizeBound))}dispose(){this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),window.removeEventListener("resize",this.onWindowResizeBound),document.removeEventListener("fullscreenchange",this.onWindowResizeBound),document.removeEventListener("webkitfullscreenchange",this.onWindowResizeBound),this.overlay.parentNode===this.container&&this.container.removeChild(this.overlay),this.listeners.clear()}getContentRect(e,t){const i=this.overlay.width||e,s=this.overlay.height||t,n=getComputedStyle(this.overlay).objectFit;if("contain"===n){const n=Math.min(e/i,t/s);return{left:(e-i*n)/2,top:(t-s*n)/2,width:i*n,height:s*n}}if("cover"===n){const n=Math.max(e/i,t/s);return{left:(e-i*n)/2,top:(t-s*n)/2,width:i*n,height:s*n}}return{left:0,top:0,width:e,height:t}}measure(e=!0){const t=this.container.getBoundingClientRect(),i=Math.max(1,Math.floor(t.width)),s=Math.max(1,Math.floor(t.height)),n=window.devicePixelRatio||1,o=Math.max(1,Math.floor(this.canvasInfo.width)),r=Math.max(1,Math.floor(this.canvasInfo.height));this.overlay.width===o&&this.overlay.height===r||(this.overlay.width=o,this.overlay.height=r);const l=this.getContentRect(i,s),a=Math.floor(l.left),h=Math.floor(l.top),c=Math.max(1,Math.floor(l.width)),d=Math.max(1,Math.floor(l.height)),u=a!==this.currentRect.left-t.left||h!==this.currentRect.top-t.top||c!==this.currentRect.width||d!==this.currentRect.height;this.currentRect={left:t.left+a,top:t.top+h,width:c,height:d},e&&u&&this.listeners.forEach(e=>{try{e(this.currentRect,n)}catch(e){console.error("[InteractiveWhiteboard] resize listener error:",e)}})}},MAX_HISTORY_SIZE=50,DEFAULT_COLOR="#FF0000",DEFAULT_LINE_WIDTH=4,DEFAULT_FILL_OPACITY=.3,DEFAULT_LASER_FADE_DURATION=1e3,LASER_DOT_RADIUS=8,LASER_TICK_INTERVAL_MS=Math.round(1e3/12),DRAW_DELTA_INTERVAL_MS=Math.round(1e3/12),HIT_TEST_TOLERANCE=6,DrawingEngine=class{constructor(e){var t,i,s,n,o,r;__publicField(this,"canvas"),__publicField(this,"ctx"),__publicField(this,"dpr"),__publicField(this,"viewW"),__publicField(this,"viewH"),__publicField(this,"userId"),__publicField(this,"tool"),__publicField(this,"color"),__publicField(this,"lineWidth"),__publicField(this,"fillOpacity"),__publicField(this,"eraserMode"),__publicField(this,"laserFadeDuration"),__publicField(this,"onLocalCommit"),__publicField(this,"onLocalLaserTick"),__publicField(this,"onLocalDelta"),__publicField(this,"isDrawing",!1),__publicField(this,"startPoint",null),__publicField(this,"lastPoint",null),__publicField(this,"lastMovePoint",null),__publicField(this,"currentStrokePoints",[]),__publicField(this,"currentStrokeId",null),__publicField(this,"currentEraseTargets",new Set),__publicField(this,"strokes",[]),__publicField(this,"undoStack",[]),__publicField(this,"redoStack",[]),__publicField(this,"hiddenByObjectEraser",new Set),__publicField(this,"laserTrails",new Map),__publicField(this,"laserAnimationId",null),__publicField(this,"laserStrokeSeq",0),__publicField(this,"pendingLocalLaserSamples",[]),__publicField(this,"localLaserTickTimer",null),__publicField(this,"pendingLocalDeltaSamples",[]),__publicField(this,"localDeltaTickTimer",null),__publicField(this,"localDeltaTool",null),__publicField(this,"remoteInProgress",new Map),this.canvas=e.canvas;const l=this.canvas.getContext("2d");if(!l)throw new Error("[InteractiveWhiteboard] failed to get 2D context");this.ctx=l,this.dpr=e.dpr,this.viewW=Math.max(1,e.viewWidthCss),this.viewH=Math.max(1,e.viewHeightCss),this.userId=e.userId,this.tool=null!=(t=e.tool)?t:"pen",this.color=null!=(i=e.color)?i:DEFAULT_COLOR,this.lineWidth=null!=(s=e.lineWidth)?s:DEFAULT_LINE_WIDTH,this.fillOpacity=null!=(n=e.fillOpacity)?n:DEFAULT_FILL_OPACITY,this.eraserMode=null!=(o=e.eraserMode)?o:"object",this.laserFadeDuration=null!=(r=e.laserFadeDuration)?r:DEFAULT_LASER_FADE_DURATION,this.onLocalCommit=e.onLocalCommit,this.onLocalLaserTick=e.onLocalLaserTick,this.onLocalDelta=e.onLocalDelta,this.applyTransform()}setTool(e){"laser"===this.tool&&"laser"!==e&&(this.stopLocalLaserTickTimer(),this.pendingLocalLaserSamples.length=0,this.laserTrails.delete(this.userId),0===this.laserTrails.size?this.stopLaserAnimation():this.redrawAll()),this.tool=e}setColor(e){this.color=e}setLineWidth(e){this.lineWidth=e}setFillOpacity(e){this.fillOpacity=Math.max(0,Math.min(1,e))}setEraserMode(e){this.eraserMode=e}setLaserFadeDuration(e){this.laserFadeDuration=e}setUserId(e){this.userId=e}setDpr(e){this.dpr=e,this.applyTransform(),this.redrawAll()}setViewSize(e,t){const i=Math.max(1,e),s=Math.max(1,t);if(i!==this.viewW||s!==this.viewH){if(this.isDrawing){const e=i/this.viewW,t=s/this.viewH,n=i=>i?{x:i.x*e,y:i.y*t}:null;this.startPoint=n(this.startPoint),this.lastPoint=n(this.lastPoint),this.lastMovePoint=n(this.lastMovePoint),this.currentStrokePoints=this.currentStrokePoints.map(i=>({x:i.x*e,y:i.y*t}))}this.viewW=i,this.viewH=s,this.applyTransform(),this.redrawAll()}}onCanvasResized(){this.applyTransform(),this.redrawAll()}clearAll(){var e;this.strokes.length=0,this.undoStack.length=0,this.redoStack.length=0,this.hiddenByObjectEraser.clear(),this.remoteInProgress.clear(),this.stopLaserAnimation(),this.clearCanvas(),null==(e=this.onLocalCommit)||e.call(this,{kind:"clear",scope:"all"})}ingestRemoteClear(e,t){switch(e){case"all":this.strokes.length=0,this.hiddenByObjectEraser.clear(),this.remoteInProgress.clear();break;case"self":this.strokes=this.strokes.filter(e=>e.ownerId!==t),this.dropInProgressByOwner(t);break;case"others":this.strokes=this.strokes.filter(e=>e.ownerId===t);for(const[e,i]of this.remoteInProgress)i.ownerId!==t&&this.remoteInProgress.delete(e)}this.redrawAll()}undo(){var e;for(let t=this.undoStack.length-1;t>=0;t--)if(this.undoStack[t].ownerId===this.userId){const[i]=this.undoStack.splice(t,1);this.redoStack.push(i);const s=this.strokes.indexOf(i);return-1!==s&&this.strokes.splice(s,1),"eraser"===i.tool&&"object"===i.mode&&i.targetStrokeIds&&i.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.delete(e)),this.redrawAll(),void(null==(e=this.onLocalCommit)||e.call(this,{kind:"undo",record:i}))}}redo(){var e;for(let t=this.redoStack.length-1;t>=0;t--)if(this.redoStack[t].ownerId===this.userId){const[i]=this.redoStack.splice(t,1);return this.undoStack.push(i),this.strokes.push(i),"eraser"===i.tool&&"object"===i.mode&&i.targetStrokeIds&&i.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),this.redrawAll(),void(null==(e=this.onLocalCommit)||e.call(this,{kind:"redo",record:i}))}}ingestRemoteStroke(e){this.remoteInProgress.delete(e.strokeId),this.strokes.some(t=>t.strokeId===e.strokeId)||("eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),this.strokes.push(e)),this.redrawAll()}ingestRemoteDelta(e,t,i,s,n,o){if(!o||0===o.length)return;if(this.strokes.some(t=>t.strokeId===e))return;let r=this.remoteInProgress.get(e);r?(r.tool=i,r.color=s,r.lineWidth=n):(r={strokeId:e,ownerId:t,tool:i,color:s,lineWidth:n,points:[]},this.remoteInProgress.set(e,r));for(let e=0;e<o.length;e++)r.points.push(o[e]);this.redrawAll()}ingestRemoteUndo(e,t){let i=!1;this.remoteInProgress.delete(e)&&(i=!0);for(let s=this.strokes.length-1;s>=0;s--){const n=this.strokes[s];if(n.strokeId===e&&n.ownerId===t){this.strokes.splice(s,1),"eraser"===n.tool&&"object"===n.mode&&n.targetStrokeIds&&n.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.delete(e)),i=!0;break}}i&&this.redrawAll()}beginStroke(e){return this.isDrawing=!0,this.startPoint=e,this.lastPoint=e,this.lastMovePoint=null,this.currentStrokePoints=[e],this.currentStrokeId=genStrokeId(this.userId),this.currentEraseTargets.clear(),"laser"===this.tool?(this.laserStrokeSeq++,this.appendLocalLaserSample(e),this.startLocalLaserTickTimer(),void this.startLaserAnimation()):"eraser"===this.tool?"object"===this.eraserMode?(this.hitTestAt(e).forEach(e=>{this.currentEraseTargets.add(e),this.hiddenByObjectEraser.add(e)}),void(this.currentEraseTargets.size>0&&this.redrawAll())):(this.applyPenStrokeStyle(),this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.localDeltaTool="eraser",this.appendLocalDeltaSample(e),void this.startLocalDeltaTickTimer()):void("pen"===this.tool&&(this.applyPenStrokeStyle(),this.localDeltaTool="pen",this.appendLocalDeltaSample(e),this.startLocalDeltaTickTimer()))}moveStroke(e){if(this.isDrawing&&this.startPoint)switch(this.tool){case"pen":this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e,this.lastMovePoint=e,this.currentStrokePoints.push(e),this.appendLocalDeltaSample(e);break;case"eraser":if("object"===this.eraserMode){let t=!1;this.hitTestAt(e).forEach(e=>{this.currentEraseTargets.has(e)||(this.currentEraseTargets.add(e),this.hiddenByObjectEraser.add(e),t=!0)}),this.lastMovePoint=e,t&&this.redrawAll();break}this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e,this.lastMovePoint=e,this.currentStrokePoints.push(e),this.appendLocalDeltaSample(e);break;case"rect":case"rectFill":case"circle":case"arrow":case"line":this.lastMovePoint=e,this.redrawAll(),this.drawShape(this.tool,this.startPoint,e,this.color,this.scaledLineWidth(this.lineWidth));break;case"laser":this.appendLocalLaserSample(e)}}endStroke(e){var t,i;if(!this.isDrawing||!this.startPoint)return;const s=null!=(t=this.lastMovePoint)?t:e,n=null!=(i=this.currentStrokeId)?i:genStrokeId(this.userId);switch(this.tool){case"pen":{this.lastPoint&&(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(s.x,s.y),this.ctx.stroke()),this.currentStrokePoints.push(s);const e={tool:"pen",strokeId:n,ownerId:this.userId,points:this.normPolyline(this.currentStrokePoints),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"eraser":{if("object"===this.eraserMode){const e=Array.from(this.currentEraseTargets);if(0===e.length)break;const t={tool:"eraser",strokeId:n,ownerId:this.userId,mode:"object",points:[],lineWidth:this.lineWidth,targetStrokeIds:e};this.commit(t);break}this.lastPoint&&(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(s.x,s.y),this.ctx.stroke()),this.ctx.globalCompositeOperation="source-over",this.currentStrokePoints.push(s);const e={tool:"eraser",strokeId:n,ownerId:this.userId,mode:"path",points:this.normPolyline(this.currentStrokePoints),lineWidth:this.lineWidth};this.commit(e);break}case"line":{const e={tool:"line",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"rect":{const e={tool:"rect",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"rectFill":{const e={tool:"rectFill",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,fillOpacity:this.fillOpacity};this.commit(e);break}case"circle":{const e={tool:"circle",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"arrow":{const e={tool:"arrow",strokeId:n,ownerId:this.userId,start:this.normPoint(this.startPoint),end:this.normPoint(s),color:this.color,lineWidth:this.lineWidth};this.commit(e);break}case"laser":this.appendLocalLaserSample(e),this.flushLocalLaserTick(),this.stopLocalLaserTickTimer()}this.isDrawing=!1,this.startPoint=null,this.lastPoint=null,this.lastMovePoint=null,this.currentStrokePoints=[],this.currentStrokeId=null,this.currentEraseTargets.clear(),this.pendingLocalDeltaSamples.length=0,this.stopLocalDeltaTickTimer(),this.localDeltaTool=null}cancelStroke(){this.isDrawing&&("eraser"===this.tool&&(this.ctx.globalCompositeOperation="source-over","object"===this.eraserMode&&this.currentEraseTargets.size>0&&(this.currentEraseTargets.forEach(e=>this.hiddenByObjectEraser.delete(e)),this.redrawAll())),"laser"===this.tool&&(this.pendingLocalLaserSamples.length=0,this.stopLocalLaserTickTimer()),this.pendingLocalDeltaSamples.length=0,this.stopLocalDeltaTickTimer(),this.localDeltaTool=null,this.isDrawing=!1,this.startPoint=null,this.lastPoint=null,this.lastMovePoint=null,this.currentStrokePoints=[],this.currentStrokeId=null,this.currentEraseTargets.clear())}dispose(){this.stopLaserAnimation(),this.stopLocalLaserTickTimer(),this.stopLocalDeltaTickTimer(),this.pendingLocalLaserSamples.length=0,this.pendingLocalDeltaSamples.length=0,this.localDeltaTool=null,this.remoteInProgress.clear(),this.laserTrails.clear(),this.clearCanvas()}commit(e){var t;this.strokes.push(e),this.undoStack.push(e),this.undoStack.length>MAX_HISTORY_SIZE&&this.undoStack.shift(),this.redoStack.length=0,this.redrawAll(),null==(t=this.onLocalCommit)||t.call(this,{kind:"stroke",record:e})}clearCanvas(){this.ctx.save(),this.ctx.setTransform(1,0,0,1,0,0),this.ctx.globalCompositeOperation="source-over",this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.restore()}redrawAll(){this.clearCanvas();for(const e of this.strokes)this.hiddenByObjectEraser.has(e.strokeId)||this.replayStroke(e);if(this.remoteInProgress.size>0)for(const e of this.remoteInProgress.values())this.replayInProgress(e)}replayStroke(e){switch(this.ctx.globalCompositeOperation="source-over",e.tool){case"pen":{const t=this.scaledLineWidth(e.lineWidth);this.ctx.strokeStyle=e.color,this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(this.denormPolyline(e.points));break}case"line":{const t=this.scaledLineWidth(e.lineWidth);this.drawLine(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"rect":{const t=this.scaledLineWidth(e.lineWidth);this.drawRect(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"rectFill":this.drawRectFill(this.denormPoint(e.start),this.denormPoint(e.end),e.color,e.fillOpacity);break;case"circle":{const t=this.scaledLineWidth(e.lineWidth);this.drawCircle(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"arrow":{const t=this.scaledLineWidth(e.lineWidth);this.drawArrow(this.denormPoint(e.start),this.denormPoint(e.end),e.color,t);break}case"eraser":if("object"===e.mode)break;this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.ctx.lineWidth=this.scaledLineWidth(e.lineWidth),this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(this.denormPolyline(e.points)),this.ctx.globalCompositeOperation="source-over"}}applyPenStrokeStyle(){this.ctx.globalCompositeOperation="source-over",this.ctx.strokeStyle=this.color,this.ctx.lineWidth=this.scaledLineWidth(this.lineWidth),this.ctx.lineCap="round",this.ctx.lineJoin="round"}strokePolyline(e){if(0!==e.length){if(1===e.length)return this.ctx.beginPath(),this.ctx.arc(e[0].x,e[0].y,this.ctx.lineWidth/2,0,2*Math.PI),this.ctx.fillStyle=this.ctx.strokeStyle,void this.ctx.fill();this.ctx.beginPath(),this.ctx.moveTo(e[0].x,e[0].y);for(let t=1;t<e.length;t++)this.ctx.lineTo(e[t].x,e[t].y);this.ctx.stroke()}}drawShape(e,t,i,s,n){switch(e){case"line":this.drawLine(t,i,s,n);break;case"rect":this.drawRect(t,i,s,n);break;case"rectFill":this.drawRectFill(t,i,s,this.fillOpacity);break;case"circle":this.drawCircle(t,i,s,n);break;case"arrow":this.drawArrow(t,i,s,n)}}drawLine(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(t.x,t.y),this.ctx.stroke()}drawRect(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=Math.min(e.x,t.x),o=Math.min(e.y,t.y),r=Math.abs(t.x-e.x),l=Math.abs(t.y-e.y);this.ctx.beginPath(),this.ctx.rect(n,o,r,l),this.ctx.stroke()}drawRectFill(e,t,i,s=.3){const n=this.ctx.globalAlpha;this.ctx.globalAlpha=n*Math.max(0,Math.min(1,s)),this.ctx.fillStyle=i;const o=Math.min(e.x,t.x),r=Math.min(e.y,t.y),l=Math.abs(t.x-e.x),a=Math.abs(t.y-e.y);this.ctx.beginPath(),this.ctx.rect(o,r,l,a),this.ctx.fill(),this.ctx.globalAlpha=n}drawCircle(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=(e.x+t.x)/2,o=(e.y+t.y)/2,r=Math.abs(t.x-e.x)/2,l=Math.abs(t.y-e.y)/2;this.ctx.beginPath(),this.ctx.ellipse(n,o,r,l,0,0,2*Math.PI),this.ctx.stroke()}drawArrow(e,t,i,s){this.ctx.strokeStyle=i,this.ctx.lineWidth=s,this.ctx.lineCap="round",this.ctx.lineJoin="round";const n=t.x-e.x,o=t.y-e.y,r=Math.atan2(o,n),l=Math.max(10,4*s);this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(t.x,t.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.moveTo(t.x,t.y),this.ctx.lineTo(t.x-l*Math.cos(r-Math.PI/6),t.y-l*Math.sin(r-Math.PI/6)),this.ctx.moveTo(t.x,t.y),this.ctx.lineTo(t.x-l*Math.cos(r+Math.PI/6),t.y-l*Math.sin(r+Math.PI/6)),this.ctx.stroke()}ingestRemoteLaserTick(e,t,i,s,n){if(!n||0===n.length)return;let o=this.laserTrails.get(e);o?(o.color=t,o.lineWidth=i):(o={color:t,lineWidth:i,points:[]},this.laserTrails.set(e,o));const r=performance.now();for(let e=0;e<n.length;e++){const t=this.denormPoint(n[e]);o.points.push({x:t.x,y:t.y,time:r,strokeSeq:s})}this.startLaserAnimation()}appendLocalLaserSample(e){let t=this.laserTrails.get(this.userId);t?(t.color=this.color,t.lineWidth=this.lineWidth):(t={color:this.color,lineWidth:this.lineWidth,points:[]},this.laserTrails.set(this.userId,t)),t.points.push({x:e.x,y:e.y,time:performance.now(),strokeSeq:this.laserStrokeSeq}),this.pendingLocalLaserSamples.push(this.normPoint(e))}startLocalLaserTickTimer(){null===this.localLaserTickTimer&&this.onLocalLaserTick&&(this.localLaserTickTimer=setInterval(()=>this.flushLocalLaserTick(),LASER_TICK_INTERVAL_MS))}stopLocalLaserTickTimer(){null!==this.localLaserTickTimer&&(clearInterval(this.localLaserTickTimer),this.localLaserTickTimer=null)}flushLocalLaserTick(){if(0===this.pendingLocalLaserSamples.length)return;const e=this.onLocalLaserTick;if(!e)return void(this.pendingLocalLaserSamples.length=0);const t=this.pendingLocalLaserSamples;this.pendingLocalLaserSamples=[];try{e({sq:this.laserStrokeSeq,color:this.color,lineWidth:this.lineWidth,points:t})}catch(e){}}appendLocalDeltaSample(e){this.onLocalDelta&&this.currentStrokeId&&this.pendingLocalDeltaSamples.push(this.normPoint(e))}startLocalDeltaTickTimer(){null===this.localDeltaTickTimer&&this.onLocalDelta&&(this.localDeltaTickTimer=setInterval(()=>this.flushLocalDeltaTick(),DRAW_DELTA_INTERVAL_MS))}stopLocalDeltaTickTimer(){null!==this.localDeltaTickTimer&&(clearInterval(this.localDeltaTickTimer),this.localDeltaTickTimer=null)}flushLocalDeltaTick(){if(0===this.pendingLocalDeltaSamples.length)return;const e=this.onLocalDelta;if(!e)return void(this.pendingLocalDeltaSamples.length=0);const t=this.localDeltaTool,i=this.currentStrokeId;if(!t||!i)return void(this.pendingLocalDeltaSamples.length=0);const s=this.pendingLocalDeltaSamples;this.pendingLocalDeltaSamples=[];try{e({strokeId:i,tool:t,color:this.color,lineWidth:this.lineWidth,eraserMode:"eraser"===t?"path":void 0,points:s})}catch(e){}}replayInProgress(e){if(0===e.points.length)return;const t=this.denormPolyline(e.points),i=this.scaledLineWidth(e.lineWidth);if("pen"===e.tool)return this.ctx.globalCompositeOperation="source-over",this.ctx.strokeStyle=e.color,this.ctx.lineWidth=i,this.ctx.lineCap="round",this.ctx.lineJoin="round",void this.strokePolyline(t);this.ctx.globalCompositeOperation="destination-out",this.ctx.strokeStyle="rgba(0,0,0,1)",this.ctx.lineWidth=i,this.ctx.lineCap="round",this.ctx.lineJoin="round",this.strokePolyline(t),this.ctx.globalCompositeOperation="source-over"}dropInProgressByOwner(e){if(0!==this.remoteInProgress.size)for(const[t,i]of this.remoteInProgress)i.ownerId===e&&this.remoteInProgress.delete(t)}startLaserAnimation(){if(null!==this.laserAnimationId)return;const e=()=>{this.renderLaserFrame()?this.laserAnimationId=requestAnimationFrame(e):(this.laserAnimationId=null,this.redrawAll())};this.laserAnimationId=requestAnimationFrame(e)}stopLaserAnimation(){null!==this.laserAnimationId&&(cancelAnimationFrame(this.laserAnimationId),this.laserAnimationId=null),this.laserTrails.clear()}renderLaserFrame(){const e=performance.now();let t=0;for(const[i,s]of this.laserTrails){if(0===s.points.length){this.laserTrails.delete(i);continue}const n=[];for(let t=0;t<s.points.length;t++){const i=s.points[t];e-i.time<this.laserFadeDuration&&n.push(i)}s.points=n,0!==n.length?t+=n.length:this.laserTrails.delete(i)}if(this.redrawAll(),0===t)return!1;this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.globalCompositeOperation="source-over";for(const t of this.laserTrails.values()){const i=this.scaledLineWidth(t.lineWidth);this.ctx.lineWidth=i,this.ctx.strokeStyle=t.color;for(let i=1;i<t.points.length;i++){const s=t.points[i-1],n=t.points[i];if(s.strokeSeq!==n.strokeSeq)continue;const o=e-n.time,r=Math.max(0,1-o/this.laserFadeDuration);this.ctx.globalAlpha=r,this.ctx.beginPath(),this.ctx.moveTo(s.x,s.y),this.ctx.lineTo(n.x,n.y),this.ctx.stroke()}const s=t.points[t.points.length-1],n=e-s.time,o=Math.max(0,1-n/this.laserFadeDuration);o>0&&(this.ctx.globalAlpha=o,this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(s.x,s.y,LASER_DOT_RADIUS,0,2*Math.PI),this.ctx.fill(),this.ctx.fillStyle="#FFFFFF",this.ctx.beginPath(),this.ctx.arc(s.x,s.y,.4*LASER_DOT_RADIUS,0,2*Math.PI),this.ctx.fill())}return this.ctx.globalAlpha=1,!0}hitTestAt(e){const t=[];for(const i of this.strokes)this.hiddenByObjectEraser.has(i.strokeId)||this.isHit(i,e)&&t.push(i.strokeId);return t}isHit(e,t){switch(e.tool){case"pen":return this.isHitPolyline(this.denormPolyline(e.points),e.lineWidth,t);case"line":case"arrow":return this.isHitSegment(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);case"rect":return this.isHitRectBorder(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);case"rectFill":return this.isInsideRect(this.denormPoint(e.start),this.denormPoint(e.end),t);case"circle":return this.isHitEllipse(this.denormPoint(e.start),this.denormPoint(e.end),e.lineWidth,t);default:return!1}}isHitPolyline(e,t,i){if(0===e.length)return!1;if(1===e.length){const s=this.scaledLineWidth(t)/2+HIT_TEST_TOLERANCE;return distance(e[0],i)<=s}for(let s=1;s<e.length;s++)if(this.isHitSegment(e[s-1],e[s],t,i))return!0;return!1}isHitSegment(e,t,i,s){const n=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE;return distanceToSegment(s,e,t)<=n}isHitRectBorder(e,t,i,s){const n=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE,o=Math.min(e.x,t.x),r=Math.max(e.x,t.x),l=Math.min(e.y,t.y),a=Math.max(e.y,t.y);return!(s.x<o-n||s.x>r+n||s.y<l-n||s.y>a+n)&&!(s.x>o+n&&s.x<r-n&&s.y>l+n&&s.y<a-n)}isInsideRect(e,t,i){const s=Math.min(e.x,t.x),n=Math.max(e.x,t.x),o=Math.min(e.y,t.y),r=Math.max(e.y,t.y);return i.x>=s&&i.x<=n&&i.y>=o&&i.y<=r}isHitEllipse(e,t,i,s){const n=(e.x+t.x)/2,o=(e.y+t.y)/2,r=Math.max(1,Math.abs(t.x-e.x)/2),l=Math.max(1,Math.abs(t.y-e.y)/2),a=(s.x-n)/r,h=(s.y-o)/l,c=Math.hypot(a,h);if(c<=1)return!0;const d=this.scaledLineWidth(i)/2+HIT_TEST_TOLERANCE;return Math.abs(c-1)*Math.min(r,l)<=d}applyTransform(){this.ctx.setTransform(this.dpr,0,0,this.dpr,0,0)}denormPoint(e){return{x:e.nx*this.viewW,y:e.ny*this.viewH}}denormPolyline(e){const t=new Array(e.length);for(let i=0;i<e.length;i++)t[i]=this.denormPoint(e[i]);return t}normPoint(e){return{nx:e.x/this.viewW,ny:e.y/this.viewH}}normPolyline(e){const t=new Array(e.length);for(let i=0;i<e.length;i++)t[i]=this.normPoint(e[i]);return t}scaledLineWidth(e){return Math.max(.5,e)}exportSnapshot(){return this.strokes.map(e=>deepCloneRecord(e))}importSnapshot(e){this.strokes=e.map(e=>deepCloneRecord(e)),this.hiddenByObjectEraser.clear();for(const e of this.strokes)"eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e));this.redrawAll()}mergeSnapshot(e){let t=!1;const i=new Set(this.strokes.map(e=>e.strokeId));for(const s of e){if(i.has(s.strokeId))continue;const e=deepCloneRecord(s);this.strokes.push(e),i.add(e.strokeId),"eraser"===e.tool&&"object"===e.mode&&e.targetStrokeIds&&e.targetStrokeIds.forEach(e=>this.hiddenByObjectEraser.add(e)),t=!0}t&&this.redrawAll()}getViewSize(){return{width:this.viewW,height:this.viewH}}getCanvas(){return this.canvas}};function distance(e,t){const i=e.x-t.x,s=e.y-t.y;return Math.hypot(i,s)}function distanceToSegment(e,t,i){const s=i.x-t.x,n=i.y-t.y,o=s*s+n*n;if(0===o)return distance(e,t);const r=Math.max(0,Math.min(1,((e.x-t.x)*s+(e.y-t.y)*n)/o)),l=t.x+r*s,a=t.y+r*n;return Math.hypot(e.x-l,e.y-a)}function deepCloneRecord(e){switch(e.tool){case"pen":return __spreadProps(__spreadValues({},e),{points:e.points.map(e=>__spreadValues({},e))});case"line":case"rect":case"circle":case"arrow":case"rectFill":return __spreadProps(__spreadValues({},e),{start:__spreadValues({},e.start),end:__spreadValues({},e.end)});case"eraser":return __spreadProps(__spreadValues({},e),{points:e.points.map(e=>__spreadValues({},e)),targetStrokeIds:e.targetStrokeIds?[...e.targetStrokeIds]:void 0})}}var InputHandler=class{constructor(e){__publicField(this,"container"),__publicField(this,"canvas"),__publicField(this,"engine"),__publicField(this,"canvasInfo"),__publicField(this,"isPointerDown",!1),__publicField(this,"dragListenersAttached",!1),__publicField(this,"cachedContentRect",null),__publicField(this,"resizeObserver",null),__publicField(this,"invalidateCacheBound"),__publicField(this,"onMouseDownBound"),__publicField(this,"onMouseMoveBound"),__publicField(this,"onMouseUpBound"),__publicField(this,"onWindowBlurBound"),__publicField(this,"onTouchStartBound"),__publicField(this,"onTouchMoveBound"),__publicField(this,"onTouchEndBound"),__publicField(this,"onTouchCancelBound"),this.container=e.container,this.canvas=e.canvas,this.engine=e.engine,this.canvasInfo={width:e.canvasInfo.width,height:e.canvasInfo.height},this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onWindowBlurBound=this.onWindowBlur.bind(this),this.onTouchStartBound=this.onTouchStart.bind(this),this.onTouchMoveBound=this.onTouchMove.bind(this),this.onTouchEndBound=this.onTouchEnd.bind(this),this.onTouchCancelBound=this.onTouchCancel.bind(this),this.invalidateCacheBound=()=>{this.cachedContentRect=null}}attach(){const e=this.canvas;e.addEventListener("mousedown",this.onMouseDownBound),e.addEventListener("touchstart",this.onTouchStartBound,{passive:!1}),e.addEventListener("touchmove",this.onTouchMoveBound,{passive:!1}),e.addEventListener("touchend",this.onTouchEndBound),e.addEventListener("touchcancel",this.onTouchCancelBound),this.resizeObserver=new ResizeObserver(()=>{this.cachedContentRect=null}),this.resizeObserver.observe(this.container),window.addEventListener("resize",this.invalidateCacheBound),document.addEventListener("fullscreenchange",this.invalidateCacheBound),document.addEventListener("webkitfullscreenchange",this.invalidateCacheBound)}detach(){const e=this.canvas;e.removeEventListener("mousedown",this.onMouseDownBound),e.removeEventListener("touchstart",this.onTouchStartBound),e.removeEventListener("touchmove",this.onTouchMoveBound),e.removeEventListener("touchend",this.onTouchEndBound),e.removeEventListener("touchcancel",this.onTouchCancelBound),this.detachDragListeners(),this.isPointerDown&&this.engine.cancelStroke(),this.isPointerDown=!1,this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.cachedContentRect=null,window.removeEventListener("resize",this.invalidateCacheBound),document.removeEventListener("fullscreenchange",this.invalidateCacheBound),document.removeEventListener("webkitfullscreenchange",this.invalidateCacheBound)}attachDragListeners(){this.dragListenersAttached||(window.addEventListener("mousemove",this.onMouseMoveBound),window.addEventListener("mouseup",this.onMouseUpBound),window.addEventListener("blur",this.onWindowBlurBound),this.dragListenersAttached=!0)}detachDragListeners(){this.dragListenersAttached&&(window.removeEventListener("mousemove",this.onMouseMoveBound),window.removeEventListener("mouseup",this.onMouseUpBound),window.removeEventListener("blur",this.onWindowBlurBound),this.dragListenersAttached=!1)}getContentRect(){if(this.cachedContentRect)return this.cachedContentRect;const e=this.container.getBoundingClientRect(),t=e.width||1,i=e.height||1,s=this.canvas.width||t,n=this.canvas.height||i,o=getComputedStyle(this.canvas).objectFit;if("contain"===o){const e=Math.min(t/s,i/n),o=s*e,r=n*e;this.cachedContentRect={left:(t-o)/2,top:(i-r)/2,width:o,height:r}}else if("cover"===o){const e=Math.max(t/s,i/n),o=s*e,r=n*e;this.cachedContentRect={left:(t-o)/2,top:(i-r)/2,width:o,height:r}}else this.cachedContentRect={left:0,top:0,width:t,height:i};return this.cachedContentRect}isInsideDrawableArea(e,t){const i=this.container.getBoundingClientRect(),s=e-i.left,n=t-i.top,o=this.getContentRect();return s>=o.left&&s<=o.left+o.width&&n>=o.top&&n<=o.top+o.height}toCanvasPoint(e,t){const i=this.container.getBoundingClientRect(),s=e-i.left,n=t-i.top,o=this.getContentRect(),r=(s-o.left)/(o.width||1),l=(n-o.top)/(o.height||1),a=r*this.canvasInfo.width,h=l*this.canvasInfo.height;return{x:a<0?0:a>this.canvasInfo.width?this.canvasInfo.width:a,y:h<0?0:h>this.canvasInfo.height?this.canvasInfo.height:h}}onMouseDown(e){0===e.button&&this.isInsideDrawableArea(e.clientX,e.clientY)&&(e.preventDefault(),this.isPointerDown=!0,this.attachDragListeners(),this.engine.beginStroke(this.toCanvasPoint(e.clientX,e.clientY)))}onMouseMove(e){this.isPointerDown&&this.engine.moveStroke(this.toCanvasPoint(e.clientX,e.clientY))}onMouseUp(e){this.isPointerDown&&(void 0!==e.button&&0!==e.button||(this.isPointerDown=!1,this.detachDragListeners(),this.engine.endStroke(this.toCanvasPoint(e.clientX,e.clientY))))}onWindowBlur(){this.isPointerDown&&(this.isPointerDown=!1,this.detachDragListeners(),this.engine.cancelStroke())}onTouchStart(e){if(0===e.touches.length)return;const t=e.touches[0];this.isInsideDrawableArea(t.clientX,t.clientY)&&(e.preventDefault(),this.isPointerDown=!0,this.engine.beginStroke(this.toCanvasPoint(t.clientX,t.clientY)))}onTouchMove(e){if(!this.isPointerDown||0===e.touches.length)return;e.preventDefault();const t=e.touches[0];this.engine.moveStroke(this.toCanvasPoint(t.clientX,t.clientY))}onTouchEnd(e){if(!this.isPointerDown)return;this.isPointerDown=!1;const t=e.changedTouches[0];t?this.engine.endStroke(this.toCanvasPoint(t.clientX,t.clientY)):this.engine.cancelStroke()}onTouchCancel(e){this.isPointerDown&&(this.isPointerDown=!1,this.engine.cancelStroke())}},WIRE_TOOL_TO_NAME={0:"pen",1:"line",2:"rect",3:"rectFill",4:"circle",5:"arrow",6:"eraser",7:"laser"},NAME_TO_WIRE_TOOL={pen:0,line:1,rect:2,rectFill:3,circle:4,arrow:5,eraser:6,laser:7};function colorToInt(e){if(!e)return;if("#"===e[0]){let t=e.slice(1);if(3===t.length&&(t=t.split("").map(e=>e+e).join("")),6===t.length){const e=parseInt(t,16);return Number.isFinite(e)?e:void 0}}const t=Number(e);return Number.isFinite(t)?t:void 0}function intToColor(e){if(void 0===e)return;return`#${Math.max(0,Math.min(16777215,e>>>0)).toString(16).padStart(6,"0").toUpperCase()}`}function encodePoints(e){const t=new Array(e.length),i=new Array(e.length);for(let s=0;s<e.length;s++)t[s]=quantize(e[s].nx),i[s]=quantize(e[s].ny);return{xs:t,ys:i}}function decodePoints(e,t){const i=Math.min(e.length,t.length),s=new Array(i);for(let n=0;n<i;n++)s[n]={nx:dequantize(e[n]),ny:dequantize(t[n])};return s}var PROTOCOL_VERSION=1,TEXT_ENCODER=new TextEncoder,TEXT_DECODER=new TextDecoder("utf-8");function encodeEnvelope(e){const t=JSON.stringify(e),i=TEXT_ENCODER.encode(t),s=new ArrayBuffer(i.byteLength);return new Uint8Array(s).set(i),s}function decodeEnvelope(e){const t=new Uint8Array(e),i=TEXT_DECODER.decode(t),s=JSON.parse(i);if(!s||"object"!=typeof s)throw new Error("[InteractiveWhiteboard] decodeEnvelope: not an object");if("number"!=typeof s.v||"number"!=typeof s.wt)throw new Error("[InteractiveWhiteboard] decodeEnvelope: missing v/wt");return s}var MAX_FRAME_BYTES=1e3,ENVELOPE_OVERHEAD=200,MAX_PAYLOAD_BYTES=MAX_FRAME_BYTES-ENVELOPE_OVERHEAD,REASSEMBLY_TTL_MS=1e4;function needsFragmentation(e){return e.length>MAX_PAYLOAD_BYTES}function fragment(e){const t=JSON.stringify(e.p);if(!needsFragmentation(t))return[encodeEnvelope(__spreadValues({},e))];const i=MAX_PAYLOAD_BYTES,s=Math.ceil(t.length/i),n=new Array(s);for(let o=0;o<s;o++){const r=t.slice(o*i,(o+1)*i);n[o]=encodeEnvelope(__spreadProps(__spreadValues({},e),{p:{__frag:!0,part:r},fi:o,ft:s}))}return n}var FragmentReassembler=class{constructor(){__publicField(this,"groups",new Map),__publicField(this,"gcTimer",null),"undefined"!=typeof window&&(this.gcTimer=window.setInterval(()=>this.gc(),2e3))}dispose(){null!==this.gcTimer&&"undefined"!=typeof window&&(window.clearInterval(this.gcTimer),this.gcTimer=null),this.groups.clear()}ingest(e){if(!e.ft||e.ft<=1)return e;if(void 0===e.fi||e.fi<0||e.fi>=e.ft)return null;const t=this.keyOf(e);let i=this.groups.get(t);i||(i={parts:new Array(e.ft).fill(""),receivedCount:0,total:e.ft,expiresAt:Date.now()+REASSEMBLY_TTL_MS},this.groups.set(t,i));const s=e.p;if(!s||!0!==s.__frag||"string"!=typeof s.part)return null;if(""===i.parts[e.fi]&&(i.parts[e.fi]=s.part,i.receivedCount+=1),i.receivedCount<i.total)return null;this.groups.delete(t);const n=i.parts.join("");let o;try{o=JSON.parse(n)}catch(e){return null}return __spreadProps(__spreadValues({},e),{p:o,fi:void 0,ft:void 0})}keyOf(e){return`${e.u}|${e.wt}|${e.id}|${e.s}`}gc(){const e=Date.now();for(const[t,i]of this.groups)i.expiresAt<e&&this.groups.delete(t)}},Throttler=class{constructor(e={}){var t,i,s;__publicField(this,"maxCallsPerSecond"),__publicField(this,"maxBytesPerSecond"),__publicField(this,"maxQueueLength"),__publicField(this,"onOverload"),__publicField(this,"window",[]),__publicField(this,"queue",[]),__publicField(this,"drainTimer",null),__publicField(this,"statsAnchor",Date.now()),__publicField(this,"droppedCallsThisStatsWindow",0),__publicField(this,"droppedBytesThisStatsWindow",0),__publicField(this,"sentCallsThisStatsWindow",0),__publicField(this,"sentBytesThisStatsWindow",0),this.maxCallsPerSecond=null!=(t=e.maxCallsPerSecond)?t:25,this.maxBytesPerSecond=null!=(i=e.maxBytesPerSecond)?i:7e3,this.maxQueueLength=null!=(s=e.maxQueueLength)?s:256,this.onOverload=e.onOverload}schedule(e,t,i){return this.evictExpired(),this.flushStatsIfElapsed(),this.fitsInBudget(e)?(this.commit(e,i),!0):"low"===t?(this.droppedCallsThisStatsWindow+=1,this.droppedBytesThisStatsWindow+=e,!1):(this.queue.push({bytes:e,send:i}),this.queue.length>this.maxQueueLength&&this.notifyOverload(),this.scheduleDrain(),!1)}snapshot(){return{sentCalls:this.sentCallsThisStatsWindow,sentBytes:this.sentBytesThisStatsWindow,droppedCalls:this.droppedCallsThisStatsWindow,droppedBytes:this.droppedBytesThisStatsWindow,queueLength:this.queue.length}}dispose(){null!==this.drainTimer&&(clearTimeout(this.drainTimer),this.drainTimer=null),this.queue=[],this.window=[]}fitsInBudget(e){if(this.window.length+1>this.maxCallsPerSecond)return!1;return!(this.usedBytes()+e>this.maxBytesPerSecond)}commit(e,t){const i=Date.now();this.window.push({at:i,bytes:e}),this.sentCallsThisStatsWindow+=1,this.sentBytesThisStatsWindow+=e;try{t()}catch(e){}}evictExpired(){const e=Date.now()-1e3;let t=0;for(;t<this.window.length&&this.window[t].at<=e;)t++;t>0&&this.window.splice(0,t)}usedBytes(){let e=0;for(const t of this.window)e+=t.bytes;return e}flushStatsIfElapsed(){const e=Date.now();e-this.statsAnchor<1e3||((this.droppedCallsThisStatsWindow>0||this.queue.length>0)&&this.onOverload&&this.notifyOverload(),this.statsAnchor=e,this.droppedCallsThisStatsWindow=0,this.droppedBytesThisStatsWindow=0,this.sentCallsThisStatsWindow=0,this.sentBytesThisStatsWindow=0)}notifyOverload(){if(this.onOverload)try{this.onOverload(this.snapshot())}catch(e){}}scheduleDrain(){if(null!==this.drainTimer)return;const e=Date.now();let t=e;this.window.length>0&&(t=this.window[0].at+1e3);const i=Math.max(20,t-e+5);this.drainTimer=setTimeout(()=>{this.drainTimer=null,this.drain()},i)}drain(){for(this.evictExpired(),this.flushStatsIfElapsed();this.queue.length>0;){const e=this.queue[0];if(!this.fitsInBudget(e.bytes))break;this.queue.shift(),this.commit(e.bytes,e.send)}this.queue.length>0&&this.scheduleDrain()}},DEFAULT_WINDOW=1024,DedupWindow=class{constructor(e=DEFAULT_WINDOW){this.capacity=e,__publicField(this,"slots"),__publicField(this,"cursor",0),__publicField(this,"lookup",new Set),this.slots=new Array(e)}admit(e,t){const i=`${e}#${t}`;if(this.lookup.has(i))return!1;const s=this.slots[this.cursor];return s&&this.lookup.delete(`${s.userId}#${s.seq}`),this.slots[this.cursor]={userId:e,seq:t},this.lookup.add(i),this.cursor=(this.cursor+1)%this.capacity,!0}reset(){this.cursor=0,this.lookup.clear(),this.slots=new Array(this.capacity)}},WHITEBOARD_MSG_TYPE_RANGE=new Set([1,2,3,4,5,6,7,8,9,10]),WHITEBOARD_MSG_TYPE_NAME={1:"DRAW_DELTA",2:"DRAW_COMMIT",3:"DRAW_UNDO_REDO",4:"CLEAR",5:"SNAPSHOT_REQ",6:"SNAPSHOT_RSP",7:"RECONCILE",8:"CLOCK_SYNC",9:"META",10:"LASER_TICK"};function wtName(e){var t;return null!=(t=WHITEBOARD_MSG_TYPE_NAME[e])?t:`UNKNOWN(${e})`}function isHighFrequencyMsg(e){return 10===e||8===e}var SignalManager=class{constructor(e){var t;__publicField(this,"core"),__publicField(this,"userId"),__publicField(this,"transportCmdId"),__publicField(this,"log"),__publicField(this,"throttler"),__publicField(this,"reassembler"),__publicField(this,"dedup"),__publicField(this,"nextSeq",1),__publicField(this,"handlers",new Map),__publicField(this,"isAttached",!1),__publicField(this,"offsetProvider",null),__publicField(this,"boundReceive"),this.core=e.core,this.userId=e.userId,this.transportCmdId=null!=(t=e.cmdId)?t:DEFAULT_WHITEBOARD_CMD_ID,this.log=e.log,this.throttler=new Throttler({onOverload:e.onOverload}),this.reassembler=new FragmentReassembler,this.dedup=new DedupWindow,this.boundReceive=this.receive.bind(this)}attach(){this.isAttached||(this.core.trtc.on("custom-message",this.boundReceive),this.isAttached=!0)}detach(){var e,t;this.isAttached&&(null==(t=(e=this.core.trtc).off)||t.call(e,"custom-message",this.boundReceive),this.isAttached=!1,this.reassembler.dispose(),this.dedup.reset(),this.handlers.clear(),this.throttler.dispose(),this.offsetProvider=null)}on(e,t){this.handlers.set(e,t)}setClockOffsetProvider(e){this.offsetProvider=e}getUserId(){return this.userId}getTransportCmdId(){return this.transportCmdId}send(e,t,i={}){var s,n,o;const r=this.offsetProvider?this.offsetProvider():0,l={v:PROTOCOL_VERSION,wt:e,s:null!=(s=i.seq)?s:this.nextSeq++,t:Date.now()+r,id:null!=(n=i.strokeId)?n:"",u:this.userId,p:t},a=null!=(o=i.priority)?o:"high";let h;try{h=needsFragmentation(JSON.stringify(l.p))?fragment(l):[encodeEnvelope(l)]}catch(e){return void this.log.warn("encode failed:",e)}isHighFrequencyMsg(e)||this.log.debug(`[InteractiveWhiteboard] wb-> ${wtName(e)} cmdId=${this.transportCmdId} seq=${l.s} u=${l.u} id=${l.id||"-"} frames=${h.length} priority=${a}`,l.p);for(const e of h){const t=e.byteLength;t>1e3?this.log.warn(`oversized frame after fragmentation: ${t}B`):this.throttler.schedule(t,a,()=>{if(i.onWireSend)try{i.onWireSend(Date.now())}catch(e){this.log.warn("onWireSend callback threw:",e)}try{this.core.trtc.sendCustomMessage({cmdId:this.transportCmdId,data:e})}catch(e){this.log.warn("sendCustomMessage failed:",e)}})}}receive(e){if(!e)return;if(e.cmdId!==this.transportCmdId)return;let t;try{t=decodeEnvelope(e.data)}catch(e){return void this.log.warn("decodeEnvelope failed:",e)}if(isHighFrequencyMsg(t.wt)||this.log.debug(`[InteractiveWhiteboard] wb<- ${wtName(t.wt)} cmdId=${e.cmdId} seq=${t.s} u=${e.userId} id=${t.id||"-"} bytes=${e.data.byteLength}`,t.p),!WHITEBOARD_MSG_TYPE_RANGE.has(t.wt))return;if(t.u!==e.userId&&(t.u=e.userId),t.u===this.userId)return;const i=this.reassembler.ingest(t);if(!i)return;if(10!==i.wt&&!this.dedup.admit(`${i.u}#${i.wt}`,i.s))return;if(i.v!==PROTOCOL_VERSION)return void this.log.warn(`unsupported protocol version: ${i.v}`);const s=this.handlers.get(i.wt);if(s){isHighFrequencyMsg(i.wt)||this.log.debug(`[InteractiveWhiteboard] wb-dispatch ${wtName(i.wt)} seq=${i.s} u=${i.u} id=${i.id||"-"}`,i.p);try{s(i)}catch(e){this.log.warn(`inbound handler crashed for msgType=${i.wt}:`,e)}}else isHighFrequencyMsg(i.wt)||this.log.debug(`[InteractiveWhiteboard] wb-dispatch (no handler) ${wtName(i.wt)} seq=${i.s} u=${i.u}`)}},BURST_COUNT=4,BURST_INTERVAL_MS=100,RESYNC_INTERVAL_MS=6e4,SAMPLE_RETENTION=8,SAMPLE_RTT_CEILING_MS=2e3,ClockSync=class{constructor(e){__publicField(this,"signal"),__publicField(this,"getHostId"),__publicField(this,"log"),__publicField(this,"localUserId"),__publicField(this,"offset",0),__publicField(this,"samples",[]),__publicField(this,"inflight",new Map),__publicField(this,"nextProbeId",1),__publicField(this,"burstTimer",null),__publicField(this,"resyncTimer",null),__publicField(this,"burstRemaining",0),__publicField(this,"disposed",!1),this.signal=e.signal,this.getHostId=e.getHostId,this.log=e.log,this.localUserId=this.signal.getUserId()}attach(){this.signal.on(8,e=>this.onInbound(e)),this.signal.setClockOffsetProvider(()=>this.offset)}start(){if(this.stopSchedule(),this.disposed)return;const e=this.getHostId();e&&e!==this.localUserId&&(this.burstRemaining=BURST_COUNT,this.scheduleBurstTick(0),this.scheduleResync())}rearm(){this.samples.length=0,this.start()}getOffset(){return this.offset}getSamples(){return this.samples.slice()}dispose(){this.disposed=!0,this.stopSchedule();for(const e of this.inflight.values())null!==e.watchdog&&"undefined"!=typeof window&&window.clearTimeout(e.watchdog);this.inflight.clear(),this.samples.length=0,this.signal.setClockOffsetProvider(null)}stopSchedule(){null!==this.burstTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.burstTimer),this.burstTimer=null),null!==this.resyncTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.resyncTimer),this.resyncTimer=null),this.burstRemaining=0}scheduleBurstTick(e){this.disposed||"undefined"==typeof window||(this.burstTimer=window.setTimeout(()=>{this.burstTimer=null,this.fireProbe(),this.burstRemaining-=1,this.burstRemaining>0&&this.scheduleBurstTick(BURST_INTERVAL_MS)},e))}scheduleResync(){this.disposed||"undefined"==typeof window||(this.resyncTimer=window.setTimeout(()=>{this.resyncTimer=null,this.fireProbe(),this.scheduleResync()},RESYNC_INTERVAL_MS))}fireProbe(){if(this.disposed)return;const e=this.getHostId();if(!e||e===this.localUserId)return;const t=this.nextProbeId++,i={ph:0,to:e,t1:0},s={probeId:t,t1:0,watchdog:null};this.inflight.set(t,s),"undefined"!=typeof window&&(s.watchdog=window.setTimeout(()=>{this.inflight.delete(t)},2*SAMPLE_RTT_CEILING_MS)),this.signal.send(8,i,{strokeId:String(t),priority:"low",onWireSend:e=>{s.t1=e}})}onInbound(e){const t=e.p;t&&t.to===this.localUserId&&(0===t.ph?this.handleRequest(e,t):1===t.ph&&this.handleResponse(e,t))}handleRequest(e,t){const i={ph:1,to:e.u,t1:t.t1};this.signal.send(8,i,{strokeId:e.id,priority:"low"})}handleResponse(e,t){const i=Number(e.id);if(!Number.isFinite(i))return;const s=this.inflight.get(i);if(!s)return;if(this.inflight.delete(i),null!==s.watchdog&&"undefined"!=typeof window&&window.clearTimeout(s.watchdog),s.t1<=0)return;const n=s.t1,o=e.t,r=Date.now(),l=r-n;if(l<0||l>SAMPLE_RTT_CEILING_MS)return void this.log.warn(`[ClockSync] dropped sample with rtt=${l}ms`);const a=o-(n+r)/2;this.recordSample({rtt:l,offset:a,at:r})}recordSample(e){this.samples.push(e),this.samples.length>SAMPLE_RETENTION&&this.samples.shift();let t=this.samples[0];for(const e of this.samples)e.rtt<t.rtt&&(t=e);this.offset=t.offset}},HostElector=class{constructor(e){__publicField(this,"localUserId"),__publicField(this,"localJoinTime"),__publicField(this,"members",new Map),__publicField(this,"currentHost",null),__publicField(this,"listener",null),this.localUserId=e,this.localJoinTime=Date.now(),this.members.set(e,{userId:e,joinTime:this.localJoinTime})}onHostChanged(e){return this.listener=e,()=>{this.listener===e&&(this.listener=null)}}bootstrap(){this.elect("init")}getLocalJoinTime(){return this.localJoinTime}upsertMember(e,t){if(e===this.localUserId)return!1;if(!Number.isFinite(t))return!1;const i=this.members.get(e);return!(i&&i.joinTime<=t)&&(this.members.set(e,{userId:e,joinTime:t}),!0)}removeMember(e){return!!this.members.has(e)&&(this.members.delete(e),e===this.currentHost&&(this.elect("remove"),!0))}elect(e){let t=null,i=Number.POSITIVE_INFINITY;for(const e of this.members.values())(e.joinTime<i||e.joinTime===i&&(null===t||e.userId<t))&&(i=e.joinTime,t=e.userId);if(null!==t&&t!==this.currentHost&&(this.currentHost=t,this.listener))try{this.listener({hostId:t,isLocal:t===this.localUserId,reason:e})}catch(e){}}getHost(){return this.currentHost}isLocalHost(){return this.currentHost===this.localUserId}getMemberCount(){return this.members.size}dispose(){this.members.clear(),this.currentHost=null,this.listener=null}},ANNOUNCE_REASON_PRIORITY={startup:3,"hello-reply":2,retry:1};function pickHigherPriorityReason(e,t){return null===e||ANNOUNCE_REASON_PRIORITY[t]>ANNOUNCE_REASON_PRIORITY[e]?t:e}var PresenceManager=class{constructor(e){__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"log"),__publicField(this,"onPeerObserved"),__publicField(this,"onPeerBye"),__publicField(this,"isDisposed"),__publicField(this,"announceCooldownMs",1e3),__publicField(this,"lastAnnounceSentAt",0),__publicField(this,"pendingAnnounceTimer",null),__publicField(this,"pendingAnnounceReason",null),__publicField(this,"helloSent",!1),__publicField(this,"byeSent",!1),__publicField(this,"heardFromAnyPeer",!1),__publicField(this,"startupRetryTimer",null),this.signalManager=e.signalManager,this.hostElector=e.hostElector,this.log=e.log,this.onPeerObserved=e.onPeerObserved,this.onPeerBye=e.onPeerBye,this.isDisposed=e.isDisposed}start(){this.sendHelloOnce(),this.armStartupRetry()}dispose(){"undefined"!=typeof window&&(null!==this.pendingAnnounceTimer&&window.clearTimeout(this.pendingAnnounceTimer),null!==this.startupRetryTimer&&window.clearTimeout(this.startupRetryTimer)),this.pendingAnnounceTimer=null,this.pendingAnnounceReason=null,this.startupRetryTimer=null}sendHelloOnce(){if(this.isDisposed()||this.helloSent)return;if(!this.canSend())return void this.log.debug("[InteractiveWhiteboard] presence-hello skipped (signal channel unavailable)");const e=this.hostElector.getLocalJoinTime(),t={hello:{jt:e}};try{this.signalManager.send(9,t,{priority:"low"}),this.helloSent=!0,this.log.debug(`[InteractiveWhiteboard] presence-hello sent jt=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-hello send failed:",e)}}sendByeOnce(e){if(this.byeSent)return;const t={bye:{reason:e}};try{this.signalManager.send(9,t,{priority:"high"}),this.byeSent=!0,this.log.debug(`[InteractiveWhiteboard] presence-bye sent reason=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-bye send failed:",e)}}requestAnnounceSend(e){if(this.isDisposed())return"skipped";if(!this.canSend())return this.log.debug(`[InteractiveWhiteboard] presence-announce skipped reason=${e} (signal channel unavailable)`),"skipped";if(null!==this.pendingAnnounceTimer)return this.pendingAnnounceReason=pickHigherPriorityReason(this.pendingAnnounceReason,e),"merged";const t=Date.now()-this.lastAnnounceSentAt;if(0===this.lastAnnounceSentAt||t>=this.announceCooldownMs)return this.flushAnnounceNow(e),"sent";if("undefined"==typeof window)return this.flushAnnounceNow(e),"sent";const i=Math.max(0,this.announceCooldownMs-t);return this.pendingAnnounceReason=e,this.pendingAnnounceTimer=window.setTimeout(()=>{var t;const i=null!=(t=this.pendingAnnounceReason)?t:e;this.pendingAnnounceTimer=null,this.pendingAnnounceReason=null,this.isDisposed()||this.flushAnnounceNow(i)},i),"scheduled"}flushAnnounceNow(e){if(this.isDisposed())return;if(!this.canSend())return;const t={ann:{jt:this.hostElector.getLocalJoinTime()}};try{this.signalManager.send(9,t,{priority:"low"}),this.lastAnnounceSentAt=Date.now(),this.log.debug(`[InteractiveWhiteboard] presence-announce sent reason=${e}`)}catch(e){this.log.warn("[InteractiveWhiteboard] presence-announce send failed:",e)}}armStartupRetry(){"undefined"!=typeof window&&null===this.startupRetryTimer&&(this.startupRetryTimer=window.setTimeout(()=>{this.startupRetryTimer=null,this.isDisposed()||this.heardFromAnyPeer||this.requestAnnounceSend("retry")},5e3))}handleRemoteMeta(e){var t,i,s;if(this.isDisposed())return null;const n=e.p;if(!n)return null;if(void 0!==n.bye)return null==(t=this.onPeerBye)||t.call(this,e.u,n.bye.reason),this.log.debug(`[InteractiveWhiteboard] presence-bye received from=${e.u} reason=${null!=(i=n.bye.reason)?i:"-"}`),null;let o=null;if(void 0!==n.hello){const t=n.hello.jt;if("number"==typeof t&&Number.isFinite(t)){o=t;const i=this.requestAnnounceSend("hello-reply");this.log.debug(`[InteractiveWhiteboard] presence-hello received from=${e.u} jt=${t} reply=${i}`)}else this.log.warn(`[InteractiveWhiteboard] presence-hello discarded: invalid jt from=${e.u}`)}if(void 0!==n.ann){const t=n.ann.jt;"number"==typeof t&&Number.isFinite(t)?null===o&&(o=t):this.log.warn(`[InteractiveWhiteboard] presence-announce discarded: invalid jt from=${e.u}`)}return void 0===n.ann&&void 0===n.hello?(this.log.debug(`[InteractiveWhiteboard] META frame from=${e.u} carries no recognized sub-key; ignored`),null):null===o?null:(this.heardFromAnyPeer=!0,null==(s=this.onPeerObserved)||s.call(this),{userId:e.u,joinTime:o})}canSend(){return!this.isDisposed()}};function strokeRecordToCommitBody(e,t){var i;switch(e.tool){case"pen":{const{xs:i,ys:s}=encodePoints(e.points);return{tl:0,cl:colorToInt(e.color),lw:e.lineWidth,xs:i,ys:s,un:t}}case"line":case"rect":case"circle":case"arrow":{const{xs:i,ys:s}=encodePoints([e.start,e.end]);return{tl:NAME_TO_WIRE_TOOL[e.tool],cl:colorToInt(e.color),lw:e.lineWidth,xs:i,ys:s,un:t}}case"rectFill":{const{xs:i,ys:s}=encodePoints([e.start,e.end]);return{tl:3,cl:colorToInt(e.color),lw:0,xs:i,ys:s,un:t,fo:Math.round(100*e.fillOpacity)}}case"eraser":{if("object"===e.mode)return{tl:6,lw:e.lineWidth,xs:[],ys:[],un:t,em:0,tg:null!=(i=e.targetStrokeIds)?i:[]};const{xs:s,ys:n}=encodePoints(e.points);return{tl:6,lw:e.lineWidth,xs:s,ys:n,un:t,em:1}}default:return null}}function strokeRecordToSnapshotWire(e,t){const i=strokeRecordToCommitBody(e,t);return{id:e.strokeId,o:e.ownerId,tl:i.tl,cl:i.cl,lw:i.lw,xs:i.xs,ys:i.ys,em:i.em,tg:i.tg,fo:i.fo}}function wireBodyToStrokeRecord(e,t,i){var s,n,o,r;if(!e||"object"!=typeof e)return null;const l=decodePoints(null!=(s=e.xs)?s:[],null!=(n=e.ys)?n:[]),a=null!=(o=intToColor(e.cl))?o:"#FF0000";switch(WIRE_TOOL_TO_NAME[e.tl]){case"pen":return{tool:"pen",strokeId:t,ownerId:i,points:l,color:a,lineWidth:e.lw};case"line":return l.length<2?null:{tool:"line",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"rect":return l.length<2?null:{tool:"rect",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"rectFill":return l.length<2?null:{tool:"rectFill",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,fillOpacity:"number"==typeof e.fo?e.fo/100:.3};case"circle":return l.length<2?null:{tool:"circle",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"arrow":return l.length<2?null:{tool:"arrow",strokeId:t,ownerId:i,start:l[0],end:l[1],color:a,lineWidth:e.lw};case"eraser":{const s=1===e.em?"path":"object";return{tool:"eraser",strokeId:t,ownerId:i,mode:s,points:"path"===s?l:[],lineWidth:e.lw,targetStrokeIds:"object"===s?null!=(r=e.tg)?r:[]:void 0}}default:return null}}function snapshotWireToStroke(e){return wireBodyToStrokeRecord(e,e.id,e.o)}function buildLaserTickBody(e,t,i,s){var n;const{xs:o,ys:r}=encodePoints(e);return{sq:t,cl:null!=(n=colorToInt(i))?n:16711680,lw:s,xs:o,ys:r}}function buildDrawDeltaBody(e,t,i,s){const{xs:n,ys:o}=encodePoints(t),r="eraser"===e,l={tl:r?6:0,lw:s,xs:n,ys:o};return r||(l.cl=colorToInt(i)),r&&(l.em=1),l}var SNAPSHOT_BATCH_SIZE=12,SNAPSHOT_RSP_TIMEOUT_MS=1e4,SnapshotManager=class{constructor(e){__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"engine"),__publicField(this,"userId"),__publicField(this,"userName"),__publicField(this,"log"),__publicField(this,"emitEvent"),__publicField(this,"isDisposed"),__publicField(this,"isPending",!1),__publicField(this,"snapshotTimer",null),__publicField(this,"retried",!1),__publicField(this,"retryOnPeerSeen",!1),__publicField(this,"maxWaitTimer",null),this.signalManager=e.signalManager,this.hostElector=e.hostElector,this.engine=e.engine,this.userId=e.userId,this.userName=e.userName,this.log=e.log,this.emitEvent=e.emitEvent,this.isDisposed=e.isDisposed}request(){if(this.isPending=!0,this.retried=!1,this.retryOnPeerSeen=!1,this.hostElector.getMemberCount()<=1)return this.log.info("[InteractiveWhiteboard] snapshot skipped: room has no other whiteboard peer (will retry when a peer joins)"),this.retryOnPeerSeen=!0,void this.armMaxWait();this.sendRequest()}dispose(){this.clearTimers()}sendRequest(){if(!this.isPending)return;this.signalManager.send(5,{},{priority:"high"}),null!==this.snapshotTimer&&"undefined"!=typeof window&&window.clearTimeout(this.snapshotTimer),"undefined"!=typeof window&&(this.snapshotTimer=window.setTimeout(()=>this.onTimeout(),SNAPSHOT_RSP_TIMEOUT_MS))}retryIfPeerAppeared(){this.isPending&&this.retryOnPeerSeen&&(this.retryOnPeerSeen=!1,null!==this.maxWaitTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=null),this.retried=!0,this.log.debug("[InteractiveWhiteboard] snapshot retry: a whiteboard peer just appeared"),this.sendRequest())}onTimeout(){var e;if(this.snapshotTimer=null,this.isPending){if(this.retried)return this.isPending=!1,this.log&&this.log.warn("[InteractiveWhiteboard] snapshot timeout: peers were present but none responded"),void(null==(e=this.emitEvent)||e.call(this,"whiteboard:error",{code:"SNAPSHOT_TIMEOUT",message:"snapshot request timed out, no responder"}));this.retryOnPeerSeen=!0,this.armMaxWait()}}armMaxWait(){"undefined"!=typeof window&&(null!==this.maxWaitTimer&&window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=window.setTimeout(()=>{this.maxWaitTimer=null,this.isPending&&(this.isPending=!1,this.retryOnPeerSeen=!1,this.log.info("[InteractiveWhiteboard] snapshot abandoned: still no whiteboard peer in the room, starting with empty board"))},SNAPSHOT_RSP_TIMEOUT_MS))}complete(){this.isPending=!1,this.retryOnPeerSeen=!1,this.clearTimers()}clearTimers(){null!==this.snapshotTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.snapshotTimer),this.snapshotTimer=null),null!==this.maxWaitTimer&&"undefined"!=typeof window&&(window.clearTimeout(this.maxWaitTimer),this.maxWaitTimer=null)}handleRemoteSnapshotReq(e){var t,i;if(!this.hostElector.isLocalHost())return;const s=null!=(t=e.p)?t:{},n=new Set(null!=(i=s.has)?i:[]),o=this.engine.exportSnapshot().filter(e=>!n.has(e.strokeId));if(0===o.length)return;const r=o.length;for(let t=0;t<o.length;t+=SNAPSHOT_BATCH_SIZE){const i=o.slice(t,t+SNAPSHOT_BATCH_SIZE),s={to:e.u,ss:i.map(e=>strokeRecordToSnapshotWire(e,this.userName)),total:r};this.signalManager.send(6,s,{priority:"high"})}}handleRemoteSnapshotRsp(e){var t;const i=e.p;if(!i||i.to!==this.userId)return;const s=[];for(const e of null!=(t=i.ss)?t:[]){const t=snapshotWireToStroke(e);t&&s.push(t)}s.length>0&&this.engine.mergeSnapshot(s),this.isPending&&this.complete()}},TRANSPARENT_PNG_1X1="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgAAIAAAUAAeImBZsAAAAASUVORK5CYII=";async function captureScreenshot(e){const{engine:t,viewBinder:i,log:s}=e,n=t.getCanvas(),o=()=>{try{return n.toDataURL("image/png")}catch(e){return s.warn("[InteractiveWhiteboard] overlay.toDataURL failed:",e),TRANSPARENT_PNG_1X1}};let r=null;try{r=document.createElement("canvas"),r.width=n.width,r.height=n.height;const e=r.getContext("2d");if(!e)return o();const t=i.getContainer(),l=t?t.querySelector("video"):null;if(!!l&&"number"==typeof l.videoWidth&&"number"==typeof l.videoHeight&&l.videoWidth>0&&l.videoHeight>0&&l.readyState>=2){const s=i.getContentRectInView(),o=t.getBoundingClientRect(),a=n.height/Math.max(1,s.height),h=l.getBoundingClientRect(),c=h.left-o.left,d=h.top-o.top,u=h.width,p=h.height,m=getComputedStyle(l).objectFit;let g,f,_,w;if("fill"===m)g=c,f=d,_=u,w=p;else if("cover"===m){const e=Math.max(u/l.videoWidth,p/l.videoHeight);_=l.videoWidth*e,w=l.videoHeight*e,g=c+(u-_)/2,f=d+(p-w)/2}else{const e=Math.min(u/l.videoWidth,p/l.videoHeight);_=l.videoWidth*e,w=l.videoHeight*e,g=c+(u-_)/2,f=d+(p-w)/2}const b=(g-s.left)*a,v=(f-s.top)*a,y=_*a,T=w*a;e.drawImage(l,b,v,y,T),r.width===n.width&&r.height===n.height||(r.width=n.width,r.height=n.height,e.drawImage(l,b,v,y,T))}e.drawImage(n,0,0);try{return r.toDataURL("image/png")}catch(e){return s.warn("[InteractiveWhiteboard] composite toDataURL failed (likely tainted by cross-origin video); falling back to canvas-only:",e),o()}}catch(e){return s.warn("[InteractiveWhiteboard] screenshot composition failed:",e),o()}finally{r&&(r.width=0,r.height=0)}}function scopeToWire(e){switch(e){case"all":return 0;case"self":return 1;case"others":return 2}}function wireToScope(e){switch(e){case 1:return"self";case 2:return"others";default:return"all"}}var WhiteboardContext=class{constructor(e,t){var i,s,n,o,r,l,a,h,c,d;__publicField(this,"viewBinder"),__publicField(this,"engine"),__publicField(this,"inputHandler"),__publicField(this,"signalManager"),__publicField(this,"hostElector"),__publicField(this,"clockSync"),__publicField(this,"presence"),__publicField(this,"snapshot"),__publicField(this,"userId"),__publicField(this,"userName"),__publicField(this,"log"),__publicField(this,"emitEvent"),__publicField(this,"trtc"),__publicField(this,"boundOnRemoteUserExit"),__publicField(this,"boundOnBeforeUnload",null),__publicField(this,"unsubscribeResize"),__publicField(this,"unsubscribeHost"),__publicField(this,"disposed",!1),__publicField(this,"interactive",!0),__publicField(this,"remoteStartEmitted",new Set),this.userId=t.userId,this.userName=t.userName,this.log=t.logger,this.emitEvent=t.emit;const u=null!=(i=e.canvasInfo)?i:{width:1920,height:1080};this.viewBinder=new ViewBinder({view:e.view,canvasInfo:u}),this.viewBinder.attach();const p=this.viewBinder.getOverlay();this.engine=new DrawingEngine({canvas:p,userId:t.userId,dpr:1,viewWidthCss:u.width,viewHeightCss:u.height,tool:null!=(n=null==(s=e.tool)?void 0:s.name)?n:"pen",color:null==(o=e.tool)?void 0:o.color,lineWidth:null==(r=e.tool)?void 0:r.lineWidth,fillOpacity:null==(l=e.tool)?void 0:l.fillOpacity,eraserMode:null!=(h=null==(a=e.tool)?void 0:a.eraserMode)?h:"object",onLocalCommit:e=>this.handleLocalCommit(e),onLocalLaserTick:e=>this.handleLocalLaserTick(e),onLocalDelta:e=>this.handleLocalDelta(e)}),this.inputHandler=new InputHandler({container:this.viewBinder.getContainer(),canvas:p,engine:this.engine,canvasInfo:u}),this.interactive=!1!==(null==(c=e.config)?void 0:c.interactive),this.viewBinder.setPointerEventsEnabled(this.interactive),this.interactive&&this.inputHandler.attach(),this.signalManager=new SignalManager({core:t.core,userId:t.userId,cmdId:null==(d=e.config)?void 0:d.cmdId,log:t.logger,onOverload:e=>{var t;const i=`send overload: dropped=${e.droppedCalls} calls / ${e.droppedBytes}B`;this.log.warn(`[InteractiveWhiteboard] ${i}`),null==(t=this.emitEvent)||t.call(this,"whiteboard:error",{code:"SEND_OVERLOAD",message:i})}}),this.hostElector=new HostElector(t.userId),this.clockSync=new ClockSync({signal:this.signalManager,getHostId:()=>this.hostElector.getHost(),log:t.logger}),this.clockSync.attach(),this.presence=new PresenceManager({signalManager:this.signalManager,hostElector:this.hostElector,log:t.logger,onPeerObserved:()=>this.snapshot.retryIfPeerAppeared(),onPeerBye:e=>{this.hostElector.removeMember(e)},isDisposed:()=>this.disposed}),this.snapshot=new SnapshotManager({signalManager:this.signalManager,hostElector:this.hostElector,engine:this.engine,userId:t.userId,userName:t.userName,log:t.logger,emitEvent:(e,t)=>{var i;return null==(i=this.emitEvent)?void 0:i.call(this,e,t)},isDisposed:()=>this.disposed}),this.signalManager.attach(),this.signalManager.on(9,e=>this.onRemoteMeta(e)),this.signalManager.on(5,e=>this.snapshot.handleRemoteSnapshotReq(e)),this.signalManager.on(6,e=>this.snapshot.handleRemoteSnapshotRsp(e)),this.signalManager.on(2,e=>this.onRemoteDrawCommit(e)),this.signalManager.on(1,e=>this.onRemoteDrawDelta(e)),this.signalManager.on(4,e=>this.onRemoteClear(e)),this.signalManager.on(3,e=>this.onRemoteUndoRedo(e)),this.signalManager.on(10,e=>this.onRemoteLaserTick(e)),this.unsubscribeHost=this.hostElector.onHostChanged(e=>this.onHostChanged(e)),this.attachTrtcEvents(t.core),this.hostElector.bootstrap(),this.unsubscribeResize=this.viewBinder.onResize(()=>{}),this.presence.start(),this.snapshot.request(),this.attachBeforeUnload()}setTool(e){this.engine.setTool(e)}setColor(e){this.engine.setColor(e)}setLineWidth(e){this.engine.setLineWidth(e)}setFillOpacity(e){this.engine.setFillOpacity(e)}setEraserMode(e){this.engine.setEraserMode(e)}setInteractive(e){if(this.disposed)return;const t=!!e;t!==this.interactive&&(this.interactive=t,t?(this.viewBinder.setPointerEventsEnabled(!0),this.inputHandler.attach(),this.log.info("[InteractiveWhiteboard] interactive mode enabled (drawing allowed)")):(this.inputHandler.detach(),this.viewBinder.setPointerEventsEnabled(!1),this.log.info("[InteractiveWhiteboard] interactive mode disabled (read-only)")))}isInteractive(){return this.interactive}clearAll(){var e;this.assertInteractive("clear")&&(this.engine.clearAll(),null==(e=this.emitEvent)||e.call(this,"whiteboard:cleared",{operatorUserId:this.userId,scope:"all"}))}undo(){this.assertInteractive("undo")&&this.engine.undo()}redo(){this.assertInteractive("redo")&&this.engine.redo()}assertInteractive(e){return!!this.interactive||(this.log.warn(`[InteractiveWhiteboard] ${e} ignored: interactive=false (read-only mode)`),!1)}getHostId(){return this.hostElector.getHost()}async screenshot(){return captureScreenshot({engine:this.engine,viewBinder:this.viewBinder,log:this.log})}dispose(){this.presence.sendByeOnce("dispose"),this.disposed=!0,this.unsubscribeResize(),this.unsubscribeHost(),this.detachTrtcEvents(),this.presence.dispose(),this.snapshot.dispose(),this.detachBeforeUnload(),this.clockSync.dispose(),this.signalManager.detach(),this.inputHandler.detach(),this.engine.dispose(),this.viewBinder.dispose(),this.hostElector.dispose()}attachTrtcEvents(e){this.trtc=e.trtc,this.boundOnRemoteUserExit=e=>{e&&e.userId&&this.hostElector.removeMember(e.userId)};try{this.trtc.on("remote-user-exit",this.boundOnRemoteUserExit)}catch(e){this.log.warn("[InteractiveWhiteboard] failed to subscribe trtc events:",e)}}detachTrtcEvents(){var e,t;if(this.trtc)try{null==(t=(e=this.trtc).off)||t.call(e,"remote-user-exit",this.boundOnRemoteUserExit)}catch(e){}}onRemoteMeta(e){const t=this.presence.handleRemoteMeta(e);if(!t)return;this.hostElector.upsertMember(t.userId,t.joinTime)&&this.hostElector.elect("add")}onHostChanged(e){var t;const i="[InteractiveWhiteboard]";"init"===e.reason?this.log.info(`${i} host elected (init, temporary): hostId=${e.hostId} isLocal=${e.isLocal} (will be re-confirmed after ANNOUNCE exchange)`):"add"===e.reason?this.log.info(`${i} host confirmed via signaling: hostId=${e.hostId} isLocal=${e.isLocal}`):this.log.info(`${i} host re-elected after previous host left: hostId=${e.hostId} isLocal=${e.isLocal}`),this.clockSync.rearm(),null==(t=this.emitEvent)||t.call(this,"whiteboard:host-changed",{hostId:e.hostId,isLocal:e.isLocal})}handleLocalCommit(e){switch(e.kind){case"stroke":{const t=strokeRecordToCommitBody(e.record,this.userName);if(!t)return;this.signalManager.send(2,t,{strokeId:e.record.strokeId,priority:"high"});break}case"clear":{const t={sc:scopeToWire(e.scope)};this.signalManager.send(4,t,{priority:"high"});break}case"undo":{const t={op:0};this.signalManager.send(3,t,{strokeId:e.record.strokeId,priority:"high"});break}case"redo":{const t=strokeRecordToCommitBody(e.record,this.userName);if(!t)return;this.signalManager.send(2,t,{strokeId:e.record.strokeId,priority:"high"});break}}}handleLocalLaserTick(e){if(!e.points||0===e.points.length)return;const t=buildLaserTickBody(e.points,e.sq,e.color,e.lineWidth);this.signalManager.send(10,t,{priority:"low"})}handleLocalDelta(e){if(!e.points||0===e.points.length)return;const t=buildDrawDeltaBody(e.tool,e.points,e.color,e.lineWidth);this.signalManager.send(1,t,{strokeId:e.strokeId,priority:"low"})}onRemoteDrawCommit(e){var t,i;const s=wireBodyToStrokeRecord(e.p,e.id,e.u);if(!s)return;this.engine.ingestRemoteStroke(s);const n=e.p,o=n&&"string"==typeof n.un?n.un:e.u;this.remoteStartEmitted.has(s.strokeId)||(this.remoteStartEmitted.add(s.strokeId),null==(t=this.emitEvent)||t.call(this,"whiteboard:remote-draw-start",{userId:e.u,userName:o,strokeId:s.strokeId,tool:WIRE_TOOL_TO_NAME[n.tl]})),this.remoteStartEmitted.delete(s.strokeId),null==(i=this.emitEvent)||i.call(this,"whiteboard:remote-draw-end",{userId:e.u,strokeId:s.strokeId})}onRemoteClear(e){var t;const i=e.p;if(!i)return;const s=wireToScope(i.sc);this.engine.ingestRemoteClear(s,e.u),null==(t=this.emitEvent)||t.call(this,"whiteboard:cleared",{operatorUserId:e.u,scope:s})}onRemoteUndoRedo(e){const t=e.p;t&&0===t.op&&this.engine.ingestRemoteUndo(e.id,e.u)}onRemoteDrawDelta(e){var t,i;const s=e.p;if(!s||!Array.isArray(s.xs)||!Array.isArray(s.ys))return;if(!e.id)return;const n=WIRE_TOOL_TO_NAME[s.tl];if("pen"!==n&&"eraser"!==n)return;if("eraser"===n&&1!==s.em)return;const o=decodePoints(s.xs,s.ys);if(0===o.length)return;const r=null!=(t=intToColor(s.cl))?t:"#FF0000",l="number"==typeof s.lw?s.lw:4;this.engine.ingestRemoteDelta(e.id,e.u,n,r,l,o),this.remoteStartEmitted.has(e.id)||(this.remoteStartEmitted.add(e.id),null==(i=this.emitEvent)||i.call(this,"whiteboard:remote-draw-start",{userId:e.u,userName:e.u,strokeId:e.id,tool:n}))}onRemoteLaserTick(e){var t;const i=e.p;if(!i||!Array.isArray(i.xs)||!Array.isArray(i.ys))return;const s=decodePoints(i.xs,i.ys);if(0===s.length)return;const n=null!=(t=intToColor(i.cl))?t:"#FF0000",o="number"==typeof i.lw?i.lw:4,r="number"==typeof i.sq?i.sq:0;this.engine.ingestRemoteLaserTick(e.u,n,o,r,s)}attachBeforeUnload(){"undefined"!=typeof window&&(this.boundOnBeforeUnload=()=>{try{this.presence.sendByeOnce("beforeunload")}catch(e){this.log.warn("[InteractiveWhiteboard] beforeunload bye failed:",e)}},window.addEventListener("beforeunload",this.boundOnBeforeUnload))}detachBeforeUnload(){"undefined"!=typeof window&&this.boundOnBeforeUnload&&(window.removeEventListener("beforeunload",this.boundOnBeforeUnload),this.boundOnBeforeUnload=null)}},pluginSeq=0,_InteractiveWhiteboard=class e extends import_eventemitter3.EventEmitter{constructor(e){super(),this.core=e,__publicField(this,"_core"),__publicField(this,"_log"),__publicField(this,"seq"),__publicField(this,"ctx",null),pluginSeq+=1,this.seq=pluginSeq,this._log=e.log.createChild({id:`${this.getAlias()}${pluginSeq}`}),this._log.info(`[InteractiveWhiteboard] created id=${this.getAlias()}${pluginSeq}`),this._core=e}getName(){return e.Name}getAlias(){return"iwb"}getGroup(e){return"default"}getValidateRule(e){switch(e){case"start":return startValidateRule(this._core);case"update":return updateValidateRule(this._core);case"stop":return stopValidateRule(this._core)}}async start(e){var t,i,s;if(this._log.info(`[InteractiveWhiteboard] start: ${JSON.stringify({tool:null==(t=e.tool)?void 0:t.name,color:null==(i=e.tool)?void 0:i.color,lineWidth:null==(s=e.tool)?void 0:s.lineWidth})}`),this.ctx)return void this._log.warn("[InteractiveWhiteboard] already started, ignoring");const n=this._core.room.userId;if(!n)throw new Error("[InteractiveWhiteboard] start failed: not joined a room yet");const o=e.userName&&e.userName.length>0?e.userName:n;this.ctx=new WhiteboardContext(e,{core:this._core,userId:n,userName:o,logger:this._log,emit:(e,t)=>{try{this.emit(e,t)}catch(e){this._log.warn("[InteractiveWhiteboard] event listener threw:",e)}}})}async update(e){if(this._log.info(`[InteractiveWhiteboard] update: ${JSON.stringify(e)}`),!this.ctx)throw new Error("[InteractiveWhiteboard] update failed: not started");if(e.tool&&(void 0!==e.tool.name&&this.ctx.setTool(e.tool.name),void 0!==e.tool.color&&this.ctx.setColor(e.tool.color),void 0!==e.tool.lineWidth&&this.ctx.setLineWidth(e.tool.lineWidth),void 0!==e.tool.fillOpacity&&this.ctx.setFillOpacity(e.tool.fillOpacity),void 0!==e.tool.eraserMode&&this.ctx.setEraserMode(e.tool.eraserMode)),e.config&&void 0!==e.config.interactive&&this.ctx.setInteractive(e.config.interactive),e.operation)switch(e.operation){case"clear":this.ctx.clearAll();break;case"undo":this.ctx.undo();break;case"redo":this.ctx.redo()}if(e.screenshot)return this.ctx.screenshot()}async stop(e){this._log.info("[InteractiveWhiteboard] stop"),this.ctx&&(this.ctx.dispose(),this.ctx=null)}};__publicField(_InteractiveWhiteboard,"TYPE",{Tool:WhiteboardTool,ClearScope:ClearScope,EraserMode:EraserMode}),__publicField(_InteractiveWhiteboard,"EVENT",InteractiveWhiteboardEvent),__publicField(_InteractiveWhiteboard,"ERROR_CODE",InteractiveWhiteboardErrorCode),__publicField(_InteractiveWhiteboard,"Name","InteractiveWhiteboard");var InteractiveWhiteboard=_InteractiveWhiteboard,index_default=InteractiveWhiteboard;export{index_default as default};export{InteractiveWhiteboard};