discovery-media-player 0.1.22 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bridge.d.ts CHANGED
@@ -41,8 +41,17 @@ export declare function parseHostMessage(data: unknown): HostMessage | null;
41
41
  export declare function sendToHost(msg: PlayerMessage, target?: Window | null): void;
42
42
  /** Côté HÔTE : envoie un message au player. */
43
43
  export declare function sendToPlayer(frame: HTMLIFrameElement | null | undefined, msg: HostMessage): void;
44
- /** Côté HÔTE : écoute les messages du player. Renvoie la fonction de désabonnement. */
45
- export declare function onPlayerMessage(cb: (msg: PlayerMessage) => void, win?: Window): () => void;
46
- /** Côté PLAYER : écoute les messages de l'hôte. Renvoie la fonction de désabonnement. */
44
+ /**
45
+ * Côté HÔTE : écoute les messages du player. Renvoie la fonction de désabonnement.
46
+ *
47
+ * `expected` — l'iframe du player, ou sa fenêtre. **Recommandé** : sans lui, un autre cadre peut
48
+ * se faire passer pour le player.
49
+ */
50
+ export declare function onPlayerMessage(cb: (msg: PlayerMessage) => void, win?: Window, expected?: HTMLIFrameElement | Window | null): () => void;
51
+ /**
52
+ * Côté PLAYER : écoute les messages de l'hôte. Renvoie la fonction de désabonnement.
53
+ *
54
+ * N'accepte que `window.parent` — le seul émetteur qui ait un sens dans un cadre.
55
+ */
47
56
  export declare function onHostMessage(cb: (msg: HostMessage) => void, win?: Window): () => void;
48
57
  export {};
package/dist/bridge.js CHANGED
@@ -88,12 +88,42 @@ export function sendToPlayer(frame, msg) {
88
88
  }
89
89
  catch { /* iframe déjà détruite */ }
90
90
  }
91
- /** Côté HÔTE : écoute les messages du player. Renvoie la fonction de désabonnement. */
92
- export function onPlayerMessage(cb, win) {
91
+ /**
92
+ * ⚠️ POURQUOI ON NE VÉRIFIE PAS L'ORIGINE, ET CE QU'ON VÉRIFIE À LA PLACE.
93
+ *
94
+ * Un contrôle d'origine est impossible ici : le player est encadré par des hôtes sur des domaines
95
+ * quelconques, déclarés à l'exploitation (`DOC_FRAME_ANCESTORS`), et il ne connaît pas celui de son
96
+ * hôte au moment où il écoute. C'est pour cette raison que le contrôle avait été écarté.
97
+ *
98
+ * Mais comparer la FENÊTRE SOURCE ne demande aucune origine. `e.source` est une référence : soit
99
+ * elle est celle qu'on attend, soit elle vient d'ailleurs. Sans ce test, n'importe quel onglet ou
100
+ * cadre détenant une référence à la fenêtre pouvait envoyer `close`, `share` ou `handover-done` —
101
+ * et la page les traitait comme venant de son hôte.
102
+ *
103
+ * Côté player, la fermeture est PAR DÉFAUT : le seul émetteur légitime est `window.parent`, aucun
104
+ * hôte n'a de code à changer. Côté hôte, le paramètre est optionnel — imposer une fermeture par
105
+ * défaut ferait taire les messages chez tous ceux qui ne l'auraient pas encore passé, et un
106
+ * message qui n'arrive plus est la pire façon d'annoncer un durcissement.
107
+ */
108
+ function memeFenetre(attendue, source) {
109
+ if (!attendue)
110
+ return true; // rien d'attendu : on n'exclut rien
111
+ const w = attendue.contentWindow ?? attendue;
112
+ return source === w;
113
+ }
114
+ /**
115
+ * Côté HÔTE : écoute les messages du player. Renvoie la fonction de désabonnement.
116
+ *
117
+ * `expected` — l'iframe du player, ou sa fenêtre. **Recommandé** : sans lui, un autre cadre peut
118
+ * se faire passer pour le player.
119
+ */
120
+ export function onPlayerMessage(cb, win, expected) {
93
121
  const target = win || (typeof window !== "undefined" ? window : null);
94
122
  if (!target)
95
123
  return () => { };
96
124
  const handler = (e) => {
125
+ if (!memeFenetre(expected, e.source))
126
+ return;
97
127
  const msg = parsePlayerMessage(e.data);
98
128
  if (msg)
99
129
  cb(msg);
@@ -101,12 +131,21 @@ export function onPlayerMessage(cb, win) {
101
131
  target.addEventListener("message", handler);
102
132
  return () => target.removeEventListener("message", handler);
103
133
  }
104
- /** Côté PLAYER : écoute les messages de l'hôte. Renvoie la fonction de désabonnement. */
134
+ /**
135
+ * Côté PLAYER : écoute les messages de l'hôte. Renvoie la fonction de désabonnement.
136
+ *
137
+ * N'accepte que `window.parent` — le seul émetteur qui ait un sens dans un cadre.
138
+ */
105
139
  export function onHostMessage(cb, win) {
106
140
  const target = win || (typeof window !== "undefined" ? window : null);
107
141
  if (!target)
108
142
  return () => { };
143
+ const parent = target.parent ?? null;
109
144
  const handler = (e) => {
145
+ // ⚠️ `parent === target` quand la page n'est PAS encadrée : il n'y a alors pas d'hôte, donc
146
+ // rien à accepter — et surtout pas ses propres messages renvoyés par un script de la page.
147
+ if (!parent || parent === target || e.source !== parent)
148
+ return;
110
149
  const msg = parseHostMessage(e.data);
111
150
  if (msg)
112
151
  cb(msg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
5
5
  "keywords": [
6
6
  "pdf-viewer",
@@ -4,4 +4,4 @@
4
4
  // Injecté par api/doc.js dans un <script nonce=…> de la visionneuse. Le code navigateur du
5
5
  // player vit en modules TypeScript testés sous player/src/ — c'est ici qu'il atterrit.
6
6
  "use strict";
7
- module.exports = { PLAYER_BROWSER_JS: "\"use strict\";var Player=(()=>{var U=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var Me=Object.getOwnPropertyNames;var xe=Object.prototype.hasOwnProperty;var d=(e,n)=>{for(var t in n)U(e,t,{get:n[t],enumerable:!0})},we=(e,n,t,r)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let o of Me(n))!xe.call(e,o)&&o!==t&&U(e,o,{get:()=>n[o],enumerable:!(r=ve(n,o))||r.enumerable});return e};var ke=e=>we(U({},\"__esModule\",{value:!0}),e);var pn={};d(pn,{bridge:()=>S,chat:()=>C,live:()=>I,presentation:()=>L,presentationState:()=>R,tracking:()=>A,viewer:()=>$});var S={};d(S,{onHostMessage:()=>Le,onPlayerMessage:()=>Ce,parseHostMessage:()=>de,parsePlayerMessage:()=>ce,sendToHost:()=>Ae,sendToPlayer:()=>Ie,toWire:()=>K});var V=\"3dd-doc-\",Te=/^[A-Za-z0-9_-]{1,64}$/,_e=[\"close\",\"share\",\"embed-ready\",\"present-left\",\"present-denied\"],Pe=[\"embed-denied\"],Ee=[\"present-invite\",\"present-handover\",\"present-switch\"],Se=[\"handover-done\"];function K(e){let n={type:V+e.type};return\"slug\"in e&&e.slug&&(n.slug=e.slug),\"reason\"in e&&e.reason&&(n.reason=String(e.reason).slice(0,40)),n}function ue(e,n,t){if(!e||typeof e!=\"object\")return null;let r=e.type;if(typeof r!=\"string\"||!r.startsWith(V))return null;let o=r.slice(V.length);if(n.includes(o))return{type:o};if(Pe.includes(o)){let u=e.reason;return{type:o,reason:/^[a-z-]{1,40}$/.test(String(u||\"\"))?String(u):\"unknown\"}}if(!t.includes(o))return null;let i=e.slug;return typeof i!=\"string\"||!Te.test(i)?null:{type:o,slug:i}}function ce(e){return ue(e,_e,Ee)}function de(e){return ue(e,Se,[])}function Ae(e,n){try{let t=n||(typeof window!=\"undefined\"?window.parent:null);t&&t.postMessage(K(e),\"*\")}catch(t){}}function Ie(e,n){var t;try{(t=e==null?void 0:e.contentWindow)==null||t.postMessage(K(n),\"*\")}catch(r){}}function Ce(e,n){let t=n||(typeof window!=\"undefined\"?window:null);if(!t)return()=>{};let r=o=>{let i=ce(o.data);i&&e(i)};return t.addEventListener(\"message\",r),()=>t.removeEventListener(\"message\",r)}function Le(e,n){let t=n||(typeof window!=\"undefined\"?window:null);if(!t)return()=>{};let r=o=>{let i=de(o.data);i&&e(i)};return t.addEventListener(\"message\",r),()=>t.removeEventListener(\"message\",r)}var A={};d(A,{createTracker:()=>Ne});var $e=[\"mousemove\",\"mousedown\",\"keydown\",\"wheel\",\"touchstart\",\"pointerdown\"];function Re(){return Math.random().toString(36).slice(2)+Date.now().toString(36)}function He(e,n){return t=>{try{let r=JSON.stringify(t),o=n.navigator;o&&typeof o.sendBeacon==\"function\"?o.sendBeacon(e,new Blob([r],{type:\"application/json\"})):n.fetch(e,{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:r,keepalive:!0})}catch(r){}}}function Ne(e={}){var ie,ae;let n=e.win||(typeof window!=\"undefined\"?window:null),t=e.doc||n&&n.document,r=e.now||(()=>Date.now()),o=e.endpoint||\"/api/doc\",i=(ie=e.idleMs)!=null?ie:6e4,u=(ae=e.sessionEveryMs)!=null?ae:12e3,y=e.slug||\"\",p=e.internal||null,H=e.sessionId||Re(),he=e.send||He(o,n),f={},v=0,N=0,M=0,ee=0,c=null,_=r(),x=!1,O=!1,P=[],ye=()=>!!y||!!p,ne=s=>{if(ye())try{he(s)}catch(a){}},te=()=>!!t&&t.visibilityState===\"visible\"&&(typeof t.hasFocus==\"function\"?t.hasFocus():!0)&&!x,re=s=>{let a=r()-s,m=Math.max(0,_-s)+i;return Math.max(0,Math.min(a,m))},W=()=>{c!=null&&v>0&&(f[v]=(f[v]||0)+re(c)/1e3),c=te()?r():null},D=()=>{W(),c=null},F=()=>{c==null&&te()&&(c=r())},z=()=>{let s=0;for(let a in f)s+=f[a];return c!=null&&(s+=re(c)/1e3),Math.round(s)},oe=()=>{let s={};for(let a in f)s[a]=Math.round(f[a]);return s},w=()=>{_=r(),x&&(x=!1,F())},se=(s,a)=>{p||ne({slug:y,event:s,page:a||N,maxPage:M,seconds:z(),sessionId:H})},E=()=>{W();let s={event:\"session\",sessionId:H,numPages:ee,maxPage:M,totalSeconds:z(),pagesTime:oe()};p?(s.internal=!0,s.docId=p.docId,s.email=p.email,s.name=p.name):s.slug=y,ne(s)},g=(s,a,m,le)=>{!s||typeof s.addEventListener!=\"function\"||(s.addEventListener(a,m,le),P.push(()=>{s.removeEventListener(a,m,le)}))};return{sessionId:H,totalSeconds:z,maxPage:()=>M,pageTimes:oe,start(){if(O)return;O=!0,se(\"open\",1),v=1,c=r(),_=r(),g(t,\"visibilitychange\",()=>{t.visibilityState===\"hidden\"?(D(),E()):(w(),F())}),g(n,\"blur\",D),g(n,\"focus\",()=>{w(),F()});for(let m of $e)g(n,m,w,{passive:!0});g(e.scrollElement,\"scroll\",w,{passive:!0}),g(n,\"beforeunload\",E);let s=n.setInterval(()=>{!x&&r()-_>i&&(x=!0,D())},5e3),a=n.setInterval(E,u);P.push(()=>{n.clearInterval(s),n.clearInterval(a)})},setPage(s){!s||s===N||(W(),v=s,N=s,s>M&&(M=s,se(\"page\",s)))},setPageCount(s){ee=s||0},noteActivity:w,flush:E,stop(){for(;P.length;){let s=P.pop();try{s==null||s()}catch(a){}}O=!1}}}var I={};d(I,{STORAGE_KEYS:()=>k,attendeeKey:()=>Fe,authorToken:()=>ze,avatarHtml:()=>G,canModerate:()=>Z,escapeHtml:()=>l,flattenPresence:()=>Oe,formatMessageBody:()=>j,initials:()=>pe,isMentioned:()=>Ue,isMine:()=>b,reactorId:()=>B,shouldNotify:()=>Ve,unreadLabel:()=>Ke});var k={attendeeKey:\"3dd-present-attkey\",authorToken:\"3dd-present-authtoken\",chatMuted:\"3dd-present-mute\"};function l(e){return String(e==null?\"\":e).replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\")}function pe(e){let n=(e||\"?\").trim().split(/\\s+/);return(((n[0]||\"\")[0]||\"?\")+((n[1]||\"\")[0]||\"\")).toUpperCase()}function G(e,n){return e?`<img src=\"${l(e)}\" alt=\"\">`:l(pe(n))}function j(e){let n=l(e);return n=n.replace(/(https?:\\/\\/[^\\s<]+)/g,t=>`<a href=\"${t}\" target=_blank rel=noreferrer class=cm-link>${t}</a>`),n=n.replace(/(^|\\s)@([\\p{L}0-9_'.-]+)/gu,(t,r,o)=>`${r}<span class=cm-mention>@${o}</span>`),n}function Oe(e){let n={},t=[];for(let r in e||{})for(let o of(e||{})[r]||[]){let i=String(o.uid||o.email||o.name||\"\").toLowerCase()||`_${r}_${t.length}`;n[i]?o.role===\"presenter\"&&(n[i]=o):(n[i]=o,t.push(i))}return t.map(r=>n[r])}function We(e,n){try{return e?e.getItem(n):null}catch(t){return null}}function De(e,n,t){try{e==null||e.setItem(n,t)}catch(r){}}function Fe(e,n,t=\"anon\",r=()=>Math.random().toString(36).slice(2,10)){if(e!=null&&e.email)return String(e.email).toLowerCase();try{if(!n)return`anon-${t}`;let o=n.getItem(k.attendeeKey);if(o)return o;let i=`anon-${r()}`;return n.setItem(k.attendeeKey,i),i}catch(o){return`anon-${t}`}}function ze(e,n=()=>Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2)){let t=We(e,k.authorToken);if(t)return t;let r=n();return De(e,k.authorToken,r),r}function B(e){return String(e&&(e.email||e.name)||\"\").toLowerCase()}function b(e,n){return!e||!n?!1:e.author_email&&n.email?e.author_email===n.email:!e.author_email&&!n.email?e.author_name===n.name:!1}function Z(e){return!!(e&&e.role===\"presenter\")}function Ue(e,n){if(!n||!n.name)return!1;let t=(n.name.split(/\\s+/)[0]||\"\").toLowerCase();return t?String(e&&e.body||\"\").toLowerCase().includes(`@${t}`)&&!b(e,n):!1}function Ve(e){let{msg:n,me:t,historyLoaded:r,chatHidden:o}=e;return!r||!n||n.deleted||b(n,t)?!1:o}function Ke(e){return!e||e<=0?\"\":e>9?\"9+\":String(e)}var C={};d(C,{messageClassName:()=>je,renderActions:()=>me,renderAttachment:()=>ge,renderMessage:()=>Ge,renderReactions:()=>fe});function fe(e,n){let t=e&&e.reactions||{},r=B(n),o=\"\";for(let i in t){let u=t[i]||[];if(!u.length)continue;let y=u.indexOf(r)>=0;o+=`<button class=\"re-chip${y?\" on\":\"\"}\" data-e=\"${l(i)}\">${l(i)} ${u.length}</button>`}return o}function ge(e){if(!e||!e.url)return\"\";let n=l(e.url);if(e.kind===\"image\")return`<a class=cm-att href=\"${n}\" target=_blank rel=noreferrer><img src=\"${n}\" alt=\"\" loading=lazy></a>`;let t=l(e.name||\"Document.pdf\");return`<a class=cm-att-pdf href=\"${n}\" target=_blank rel=noreferrer data-pdf=\"${n}\"><span class=cm-att-ph></span><span class=cm-pdflabel>${t}</span></a>`}function me(e,n){let t=b(e,n.me),r=`<button class=cm-react title=\"R\\xE9agir\">${n.reactIcon||\"\"}</button><button class=cm-reply title=\"R\\xE9pondre\">\\u21A9</button>`;return t&&(r+='<button class=cm-edit title=\"Modifier\">\\u270E</button>'),(t||Z(n.me))&&(r+='<button class=cm-del-btn title=\"Supprimer\">\\u{1F5D1}</button>'),r}function Ge(e,n){if(e.deleted)return'<span class=a></span><span class=b><div class=\"txt cm-del\">Message supprim\\xE9</div></span>';let t=e.reply_to?`<div class=cm-q><b>${l(e.reply_name||\"\")}</b> ${l(e.reply_text||\"\")}</div>`:\"\",r=e.edited?\" <span class=cm-ed>(modifi\\xE9)</span>\":\"\",o=e.body?`<div class=txt>${j(e.body)}${r}</div>`:\"\",i=e.is_presenter?\" <span class=tag>pr\\xE9sentateur</span>\":\"\";return`<span class=a>${G(e.author_avatar,e.author_name)}</span><span class=b><div class=who><b>${l(e.author_name||\"Invit\\xE9\")}</b>${i}</div>`+t+o+ge(e.attachment)+`<div class=cm-re>${fe(e,n.me)}</div></span><span class=cm-act>${me(e,n)}</span>`}function je(e,n,t){return\"cm\"+(b(e,n)?\" me\":\"\")+(e.deleted?\" isdel\":\"\")+(t?\" mentioned\":\"\")}var L={};d(L,{DEFAULT_CENTER:()=>X,DEFAULT_ZOOM:()=>J,MAP_TYPES:()=>T,cycleMapType:()=>Be,initialMapContent:()=>Ye,mapTypeLabel:()=>Ze,sanitizeContent:()=>Q});var T=[\"roadmap\",\"satellite\",\"hybrid\"],X=[46.6,2.5],J=6;function h(e){let n=Number(e);return Number.isFinite(n)?n:null}function Y(e){if(!Array.isArray(e))return null;let n=h(e[0]),t=h(e[1]);return n!=null&&t!=null?[n,t]:null}var q=(e,n,t)=>Math.max(n,Math.min(t,e));function Q(e){if(!e||typeof e!=\"object\")return null;let n=e;if(n.kind===\"pdf\"||n.kind==null)return null;if(n.kind===\"streetview\"){let t=Y(n.position);if(!t)return null;let r=n.pov&&typeof n.pov==\"object\"?n.pov:null,o=r?{heading:h(r.heading)||0,pitch:q(h(r.pitch)||0,-90,90)}:{heading:0,pitch:0};return{kind:\"streetview\",position:t,pov:o,zoom:q(h(n.zoom)||1,0,5)}}return n.kind!==\"map\"?null:{kind:\"map\",center:Y(n.center)||[...X],zoom:q(Math.trunc(h(n.zoom)||J),1,21),marker:Y(n.marker),mapType:T.includes(n.mapType)?n.mapType:null,label:String(n.label||\"\").slice(0,160)||null}}function Be(e){let n=T.indexOf(e);return T[(n+1)%T.length]}function Ze(e){return e===\"roadmap\"?\"\\u{1F6F0} Satellite\":e===\"satellite\"?\"\\u{1F5FA} Hybride\":\"\\u{1F5FA} Plan\"}function Ye(){return{kind:\"map\",center:[...X],zoom:J,marker:null,mapType:null,label:null}}var $={};d($,{CURRENT_PAGE_MARGIN:()=>nn,DEFAULT_ASPECT:()=>Je,MAX_ZOOM:()=>Xe,MIN_PAGE_WIDTH:()=>Qe,MIN_ZOOM:()=>qe,PRERENDER_MARGIN:()=>en,arrowState:()=>on,averageColor:()=>ln,clampPage:()=>be,clampZoom:()=>tn,fitWidth:()=>an,isImageDocument:()=>un,progressPercent:()=>rn});var qe=.5,Xe=3,Je=1.35,Qe=280,en=\"500px 0px\",nn=\"-48% 0px -48% 0px\";function tn(e){let n=Math.round((Number(e)||0)*10)/10;return Math.max(.5,Math.min(3,n))}function be(e,n){return Math.max(1,Math.min(n||1,Number(e)||1))}function rn(e,n){return n?Math.round(be(e,n)/n*100):0}function on(e,n){return{prevDisabled:e<=1,nextDisabled:!!n&&e>=n}}var sn=28;function an(e){var u;let n=(u=e.zoom)!=null?u:1,t=Math.max(280,e.containerWidth||900)*n;if(!e.onePage)return t;let r=e.aspect||1.35,i=((e.containerHeight||600)-sn-(e.overlap||0)-(e.reserve||0))/r;return i>120?Math.min(t,i):t}function ln(e){let n=e.length/4;if(!n)return\"rgb(0,0,0)\";let t=0,r=0,o=0;for(let i=0;i<e.length;i+=4)t+=e[i],r+=e[i+1],o+=e[i+2];return`rgb(${Math.round(t/n)},${Math.round(r/n)},${Math.round(o/n)})`}function un(e,n){return/[.](png|jpe?g|webp|gif|avif)($|[?])/i.test(String(e||n||\"\"))}var R={};d(R,{presentationTransition:()=>cn,switchDocUrl:()=>dn});function cn(e,n={}){if(!e)return[{kind:\"nothing\"}];if(e.active===!1)return[{kind:\"ended\"}];let t=Q(e.content);if(t)return[{kind:\"show-map\",content:t}];let r=[{kind:\"leave-map\"}];return e.file_url&&e.file_url!==n.docUrl?(r.push({kind:\"switch-doc\",url:e.file_url,name:e.file_name||void 0,title:e.doc_title||void 0,updatedAt:e.updated_at||void 0}),r):(e.current_page&&r.push({kind:\"show-page\",page:e.current_page}),r)}function dn(e,n){let t=encodeURIComponent(n||String(Date.now()));return`${e}${e.includes(\"?\")?\"&\":\"?\"}v=${t}`}return ke(pn);})();", SOURCE_HASH: "51c05545eb241d37" };
7
+ module.exports = { PLAYER_BROWSER_JS: "\"use strict\";var Player=(()=>{var z=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var Me=Object.getOwnPropertyNames;var xe=Object.prototype.hasOwnProperty;var p=(e,n)=>{for(var t in n)z(e,t,{get:n[t],enumerable:!0})},we=(e,n,t,r)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let o of Me(n))!xe.call(e,o)&&o!==t&&z(e,o,{get:()=>n[o],enumerable:!(r=ve(n,o))||r.enumerable});return e};var ke=e=>we(z({},\"__esModule\",{value:!0}),e);var gn={};p(gn,{bridge:()=>I,chat:()=>C,live:()=>A,presentation:()=>L,presentationState:()=>$,tracking:()=>S,viewer:()=>R});var I={};p(I,{onHostMessage:()=>Re,onPlayerMessage:()=>Le,parseHostMessage:()=>de,parsePlayerMessage:()=>ce,sendToHost:()=>Se,sendToPlayer:()=>Ae,toWire:()=>j});var V=\"3dd-doc-\",Te=/^[A-Za-z0-9_-]{1,64}$/,_e=[\"close\",\"share\",\"embed-ready\",\"present-left\",\"present-denied\"],Ee=[\"embed-denied\"],Pe=[\"present-invite\",\"present-handover\",\"present-switch\"],Ie=[\"handover-done\"];function j(e){let n={type:V+e.type};return\"slug\"in e&&e.slug&&(n.slug=e.slug),\"reason\"in e&&e.reason&&(n.reason=String(e.reason).slice(0,40)),n}function ue(e,n,t){if(!e||typeof e!=\"object\")return null;let r=e.type;if(typeof r!=\"string\"||!r.startsWith(V))return null;let o=r.slice(V.length);if(n.includes(o))return{type:o};if(Ee.includes(o)){let a=e.reason;return{type:o,reason:/^[a-z-]{1,40}$/.test(String(a||\"\"))?String(a):\"unknown\"}}if(!t.includes(o))return null;let i=e.slug;return typeof i!=\"string\"||!Te.test(i)?null:{type:o,slug:i}}function ce(e){return ue(e,_e,Pe)}function de(e){return ue(e,Ie,[])}function Se(e,n){try{let t=n||(typeof window!=\"undefined\"?window.parent:null);t&&t.postMessage(j(e),\"*\")}catch(t){}}function Ae(e,n){var t;try{(t=e==null?void 0:e.contentWindow)==null||t.postMessage(j(n),\"*\")}catch(r){}}function Ce(e,n){var r;if(!e)return!0;let t=(r=e.contentWindow)!=null?r:e;return n===t}function Le(e,n,t){let r=n||(typeof window!=\"undefined\"?window:null);if(!r)return()=>{};let o=i=>{if(!Ce(t,i.source))return;let a=ce(i.data);a&&e(a)};return r.addEventListener(\"message\",o),()=>r.removeEventListener(\"message\",o)}function Re(e,n){var i;let t=n||(typeof window!=\"undefined\"?window:null);if(!t)return()=>{};let r=(i=t.parent)!=null?i:null,o=a=>{if(!r||r===t||a.source!==r)return;let d=de(a.data);d&&e(d)};return t.addEventListener(\"message\",o),()=>t.removeEventListener(\"message\",o)}var S={};p(S,{createTracker:()=>De});var $e=[\"mousemove\",\"mousedown\",\"keydown\",\"wheel\",\"touchstart\",\"pointerdown\"];function He(){let e=typeof globalThis!=\"undefined\"?globalThis.crypto:void 0;if(e&&typeof e.randomUUID==\"function\")return e.randomUUID().replace(/-/g,\"\");if(e&&typeof e.getRandomValues==\"function\"){let n=e.getRandomValues(new Uint8Array(16));return Array.from(n,t=>t.toString(16).padStart(2,\"0\")).join(\"\")}return Math.random().toString(36).slice(2)+Date.now().toString(36)}function We(e,n){return t=>{try{let r=JSON.stringify(t),o=n.navigator;o&&typeof o.sendBeacon==\"function\"?o.sendBeacon(e,new Blob([r],{type:\"application/json\"})):n.fetch(e,{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:r,keepalive:!0})}catch(r){}}}function De(e={}){var ie,ae;let n=e.win||(typeof window!=\"undefined\"?window:null),t=e.doc||n&&n.document,r=e.now||(()=>Date.now()),o=e.endpoint||\"/api/doc\",i=(ie=e.idleMs)!=null?ie:6e4,a=(ae=e.sessionEveryMs)!=null?ae:12e3,d=e.slug||\"\",f=e.internal||null,H=e.sessionId||He(),ye=e.send||We(o,n),g={},v=0,W=0,M=0,ee=0,c=null,_=r(),x=!1,D=!1,E=[],he=()=>!!d||!!f,ne=s=>{if(he())try{ye(s)}catch(l){}},te=()=>!!t&&t.visibilityState===\"visible\"&&(typeof t.hasFocus==\"function\"?t.hasFocus():!0)&&!x,re=s=>{let l=r()-s,b=Math.max(0,_-s)+i;return Math.max(0,Math.min(l,b))},N=()=>{c!=null&&v>0&&(g[v]=(g[v]||0)+re(c)/1e3),c=te()?r():null},O=()=>{N(),c=null},U=()=>{c==null&&te()&&(c=r())},F=()=>{let s=0;for(let l in g)s+=g[l];return c!=null&&(s+=re(c)/1e3),Math.round(s)},oe=()=>{let s={};for(let l in g)s[l]=Math.round(g[l]);return s},w=()=>{_=r(),x&&(x=!1,U())},se=(s,l)=>{f||ne({slug:d,event:s,page:l||W,maxPage:M,seconds:F(),sessionId:H})},P=()=>{N();let s={event:\"session\",sessionId:H,numPages:ee,maxPage:M,totalSeconds:F(),pagesTime:oe()};f?(s.internal=!0,s.docId=f.docId,s.email=f.email,s.name=f.name):s.slug=d,ne(s)},m=(s,l,b,le)=>{!s||typeof s.addEventListener!=\"function\"||(s.addEventListener(l,b,le),E.push(()=>{s.removeEventListener(l,b,le)}))};return{sessionId:H,totalSeconds:F,maxPage:()=>M,pageTimes:oe,start(){if(D)return;D=!0,se(\"open\",1),v=1,c=r(),_=r(),m(t,\"visibilitychange\",()=>{t.visibilityState===\"hidden\"?(O(),P()):(w(),U())}),m(n,\"blur\",O),m(n,\"focus\",()=>{w(),U()});for(let b of $e)m(n,b,w,{passive:!0});m(e.scrollElement,\"scroll\",w,{passive:!0}),m(n,\"beforeunload\",P);let s=n.setInterval(()=>{!x&&r()-_>i&&(x=!0,O())},5e3),l=n.setInterval(P,a);E.push(()=>{n.clearInterval(s),n.clearInterval(l)})},setPage(s){!s||s===W||(N(),v=s,W=s,s>M&&(M=s,se(\"page\",s)))},setPageCount(s){ee=s||0},noteActivity:w,flush:P,stop(){for(;E.length;){let s=E.pop();try{s==null||s()}catch(l){}}D=!1}}}var A={};p(A,{STORAGE_KEYS:()=>k,attendeeKey:()=>Fe,authorToken:()=>Ve,avatarHtml:()=>K,canModerate:()=>Z,escapeHtml:()=>u,flattenPresence:()=>Ne,formatMessageBody:()=>G,initials:()=>pe,isMentioned:()=>je,isMine:()=>y,reactorId:()=>B,shouldNotify:()=>Ke,unreadLabel:()=>Ge});var k={attendeeKey:\"3dd-present-attkey\",authorToken:\"3dd-present-authtoken\",chatMuted:\"3dd-present-mute\"};function u(e){return String(e==null?\"\":e).replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/\"/g,\"&quot;\")}function pe(e){let n=(e||\"?\").trim().split(/\\s+/);return(((n[0]||\"\")[0]||\"?\")+((n[1]||\"\")[0]||\"\")).toUpperCase()}function K(e,n){return e?`<img src=\"${u(e)}\" alt=\"\">`:u(pe(n))}function G(e){let n=u(e);return n=n.replace(/(https?:\\/\\/[^\\s<]+)/g,t=>`<a href=\"${t}\" target=_blank rel=noreferrer class=cm-link>${t}</a>`),n=n.replace(/(^|\\s)@([\\p{L}0-9_'.-]+)/gu,(t,r,o)=>`${r}<span class=cm-mention>@${o}</span>`),n}function Ne(e){let n={},t=[];for(let r in e||{})for(let o of(e||{})[r]||[]){let i=String(o.uid||o.email||o.name||\"\").toLowerCase()||`_${r}_${t.length}`;n[i]?o.role===\"presenter\"&&(n[i]=o):(n[i]=o,t.push(i))}return t.map(r=>n[r])}function Oe(e,n){try{return e?e.getItem(n):null}catch(t){return null}}function Ue(e,n,t){try{e==null||e.setItem(n,t)}catch(r){}}function Fe(e,n,t=\"anon\",r=()=>Math.random().toString(36).slice(2,10)){if(e!=null&&e.email)return String(e.email).toLowerCase();try{if(!n)return`anon-${t}`;let o=n.getItem(k.attendeeKey);if(o)return o;let i=`anon-${r()}`;return n.setItem(k.attendeeKey,i),i}catch(o){return`anon-${t}`}}function ze(){let e=typeof globalThis!=\"undefined\"?globalThis.crypto:void 0;if(e&&typeof e.randomUUID==\"function\")return e.randomUUID().replace(/-/g,\"\");if(e&&typeof e.getRandomValues==\"function\"){let n=e.getRandomValues(new Uint8Array(24));return Array.from(n,t=>t.toString(16).padStart(2,\"0\")).join(\"\")}try{console.warn(\"[player] crypto indisponible : jeton d'auteur affaibli\")}catch(n){}return Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2)}function Ve(e,n=ze){let t=Oe(e,k.authorToken);if(t)return t;let r=n();return Ue(e,k.authorToken,r),r}function B(e){return String(e&&(e.email||e.name)||\"\").toLowerCase()}function y(e,n){return!e||!n?!1:e.author_email&&n.email?e.author_email===n.email:!e.author_email&&!n.email?e.author_name===n.name:!1}function Z(e){return!!(e&&e.role===\"presenter\")}function je(e,n){if(!n||!n.name)return!1;let t=(n.name.split(/\\s+/)[0]||\"\").toLowerCase();return t?String(e&&e.body||\"\").toLowerCase().includes(`@${t}`)&&!y(e,n):!1}function Ke(e){let{msg:n,me:t,historyLoaded:r,chatHidden:o}=e;return!r||!n||n.deleted||y(n,t)?!1:o}function Ge(e){return!e||e<=0?\"\":e>9?\"9+\":String(e)}var C={};p(C,{messageClassName:()=>Ze,renderActions:()=>me,renderAttachment:()=>ge,renderMessage:()=>Be,renderReactions:()=>fe});function fe(e,n){let t=e&&e.reactions||{},r=B(n),o=\"\";for(let i in t){let a=t[i]||[];if(!a.length)continue;let d=a.indexOf(r)>=0;o+=`<button class=\"re-chip${d?\" on\":\"\"}\" data-e=\"${u(i)}\">${u(i)} ${a.length}</button>`}return o}function ge(e){if(!e||!e.url)return\"\";let n=u(e.url);if(e.kind===\"image\")return`<a class=cm-att href=\"${n}\" target=_blank rel=noreferrer><img src=\"${n}\" alt=\"\" loading=lazy></a>`;let t=u(e.name||\"Document.pdf\");return`<a class=cm-att-pdf href=\"${n}\" target=_blank rel=noreferrer data-pdf=\"${n}\"><span class=cm-att-ph></span><span class=cm-pdflabel>${t}</span></a>`}function me(e,n){let t=y(e,n.me),r=`<button class=cm-react title=\"R\\xE9agir\">${n.reactIcon||\"\"}</button><button class=cm-reply title=\"R\\xE9pondre\">\\u21A9</button>`;return t&&(r+='<button class=cm-edit title=\"Modifier\">\\u270E</button>'),(t||Z(n.me))&&(r+='<button class=cm-del-btn title=\"Supprimer\">\\u{1F5D1}</button>'),r}function Be(e,n){if(e.deleted)return'<span class=a></span><span class=b><div class=\"txt cm-del\">Message supprim\\xE9</div></span>';let t=e.reply_to?`<div class=cm-q><b>${u(e.reply_name||\"\")}</b> ${u(e.reply_text||\"\")}</div>`:\"\",r=e.edited?\" <span class=cm-ed>(modifi\\xE9)</span>\":\"\",o=e.body?`<div class=txt>${G(e.body)}${r}</div>`:\"\",i=e.is_presenter?\" <span class=tag>pr\\xE9sentateur</span>\":\"\";return`<span class=a>${K(e.author_avatar,e.author_name)}</span><span class=b><div class=who><b>${u(e.author_name||\"Invit\\xE9\")}</b>${i}</div>`+t+o+ge(e.attachment)+`<div class=cm-re>${fe(e,n.me)}</div></span><span class=cm-act>${me(e,n)}</span>`}function Ze(e,n,t){return\"cm\"+(y(e,n)?\" me\":\"\")+(e.deleted?\" isdel\":\"\")+(t?\" mentioned\":\"\")}var L={};p(L,{DEFAULT_CENTER:()=>X,DEFAULT_ZOOM:()=>J,MAP_TYPES:()=>T,cycleMapType:()=>Ye,initialMapContent:()=>Xe,mapTypeLabel:()=>qe,sanitizeContent:()=>Q});var T=[\"roadmap\",\"satellite\",\"hybrid\"],X=[46.6,2.5],J=6;function h(e){let n=Number(e);return Number.isFinite(n)?n:null}function Y(e){if(!Array.isArray(e))return null;let n=h(e[0]),t=h(e[1]);return n!=null&&t!=null?[n,t]:null}var q=(e,n,t)=>Math.max(n,Math.min(t,e));function Q(e){if(!e||typeof e!=\"object\")return null;let n=e;if(n.kind===\"pdf\"||n.kind==null)return null;if(n.kind===\"streetview\"){let t=Y(n.position);if(!t)return null;let r=n.pov&&typeof n.pov==\"object\"?n.pov:null,o=r?{heading:h(r.heading)||0,pitch:q(h(r.pitch)||0,-90,90)}:{heading:0,pitch:0};return{kind:\"streetview\",position:t,pov:o,zoom:q(h(n.zoom)||1,0,5)}}return n.kind!==\"map\"?null:{kind:\"map\",center:Y(n.center)||[...X],zoom:q(Math.trunc(h(n.zoom)||J),1,21),marker:Y(n.marker),mapType:T.includes(n.mapType)?n.mapType:null,label:String(n.label||\"\").slice(0,160)||null}}function Ye(e){let n=T.indexOf(e);return T[(n+1)%T.length]}function qe(e){return e===\"roadmap\"?\"\\u{1F6F0} Satellite\":e===\"satellite\"?\"\\u{1F5FA} Hybride\":\"\\u{1F5FA} Plan\"}function Xe(){return{kind:\"map\",center:[...X],zoom:J,marker:null,mapType:null,label:null}}var R={};p(R,{CURRENT_PAGE_MARGIN:()=>rn,DEFAULT_ASPECT:()=>en,MAX_ZOOM:()=>Qe,MIN_PAGE_WIDTH:()=>nn,MIN_ZOOM:()=>Je,PRERENDER_MARGIN:()=>tn,arrowState:()=>an,averageColor:()=>cn,clampPage:()=>be,clampZoom:()=>on,fitWidth:()=>un,isImageDocument:()=>dn,progressPercent:()=>sn});var Je=.5,Qe=3,en=1.35,nn=280,tn=\"500px 0px\",rn=\"-48% 0px -48% 0px\";function on(e){let n=Math.round((Number(e)||0)*10)/10;return Math.max(.5,Math.min(3,n))}function be(e,n){return Math.max(1,Math.min(n||1,Number(e)||1))}function sn(e,n){return n?Math.round(be(e,n)/n*100):0}function an(e,n){return{prevDisabled:e<=1,nextDisabled:!!n&&e>=n}}var ln=28;function un(e){var a;let n=(a=e.zoom)!=null?a:1,t=Math.max(280,e.containerWidth||900)*n;if(!e.onePage)return t;let r=e.aspect||1.35,i=((e.containerHeight||600)-ln-(e.overlap||0)-(e.reserve||0))/r;return i>120?Math.min(t,i):t}function cn(e){let n=e.length/4;if(!n)return\"rgb(0,0,0)\";let t=0,r=0,o=0;for(let i=0;i<e.length;i+=4)t+=e[i],r+=e[i+1],o+=e[i+2];return`rgb(${Math.round(t/n)},${Math.round(r/n)},${Math.round(o/n)})`}function dn(e,n){return/[.](png|jpe?g|webp|gif|avif)($|[?])/i.test(String(e||n||\"\"))}var $={};p($,{presentationTransition:()=>pn,switchDocUrl:()=>fn});function pn(e,n={}){if(!e)return[{kind:\"nothing\"}];if(e.active===!1)return[{kind:\"ended\"}];let t=Q(e.content);if(t)return[{kind:\"show-map\",content:t}];let r=[{kind:\"leave-map\"}];return e.file_url&&e.file_url!==n.docUrl?(r.push({kind:\"switch-doc\",url:e.file_url,name:e.file_name||void 0,title:e.doc_title||void 0,updatedAt:e.updated_at||void 0}),r):(e.current_page&&r.push({kind:\"show-page\",page:e.current_page}),r)}function fn(e,n){let t=encodeURIComponent(n||String(Date.now()));return`${e}${e.includes(\"?\")?\"&\":\"?\"}v=${t}`}return ke(gn);})();", SOURCE_HASH: "951763e203aba2b4" };
package/server/shares.js CHANGED
@@ -202,7 +202,12 @@ async function overview() {
202
202
 
203
203
  // Parse minimal d'un User-Agent → appareil / OS / navigateur (sans dépendance).
204
204
  function parseUa(ua) {
205
- const s = String(ua || "");
205
+ // ⚠️ Bornée AVANT analyse. L'analyse statique signale `Android.*Mobile` comme pouvant revenir en
206
+ // arrière ; mesuré avant de corriger, V8 traite ce motif en temps linéaire même sur 200 000
207
+ // caractères — ce n'était donc pas une lenteur réelle. On borne quand même : la colonne stockée
208
+ // était déjà tronquée à 300, seule l'analyse recevait la chaîne entière. Faire entrer une
209
+ // longueur non bornée dans une expression régulière est une habitude qui finit par coûter.
210
+ const s = String(ua || "").slice(0, 300);
206
211
  let device = /Mobile|iPhone|Android.*Mobile/.test(s) ? "Mobile" : /iPad|Tablet/.test(s) ? "Tablette" : "Ordinateur";
207
212
  let os = /Windows/.test(s) ? "Windows" : /iPhone|iPad|iOS/.test(s) ? "iOS" : /Mac OS X|Macintosh/.test(s) ? "macOS" : /Android/.test(s) ? "Android" : /Linux/.test(s) ? "Linux" : "—";
208
213
  let browser = /Edg\//.test(s) ? "Edge" : /OPR\/|Opera/.test(s) ? "Opera" : /Chrome\//.test(s) ? "Chrome" : /Firefox\//.test(s) ? "Firefox" : /Safari\//.test(s) ? "Safari" : "—";