discovery-media-player 0.1.85 → 0.1.87
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discovery-media-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.87",
|
|
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 C=Object.defineProperty,De=Object.defineProperties,We=Object.getOwnPropertyDescriptor,Ve=Object.getOwnPropertyDescriptors,ze=Object.getOwnPropertyNames,ve=Object.getOwnPropertySymbols;var we=Object.prototype.hasOwnProperty,Fe=Object.prototype.propertyIsEnumerable;var Me=(e,n,t)=>n in e?C(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,G=(e,n)=>{for(var t in n||(n={}))we.call(n,t)&&Me(e,t,n[t]);if(ve)for(var t of ve(n))Fe.call(n,t)&&Me(e,t,n[t]);return e},xe=(e,n)=>De(e,Ve(n));var M=(e,n)=>{for(var t in n)C(e,t,{get:n[t],enumerable:!0})},Be=(e,n,t,r)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let o of ze(n))!we.call(e,o)&&o!==t&&C(e,o,{get:()=>n[o],enumerable:!(r=We(n,o))||r.enumerable});return e};var je=e=>Be(C({},\"__esModule\",{value:!0}),e);var jn={};M(jn,{bridge:()=>N,cadence:()=>L,chat:()=>H,live:()=>$,presentation:()=>U,presentationState:()=>W,tracking:()=>O,viewer:()=>D});var N={};M(N,{onHostMessage:()=>nn,onPlayerMessage:()=>en,parseHostMessage:()=>Ee,parsePlayerMessage:()=>_e,sendToHost:()=>Qe,sendToPlayer:()=>Xe,toWire:()=>Y});var K=\"3dd-doc-\",Ge=/^[A-Za-z0-9_-]{1,64}$/,Ke=[\"close\",\"share\",\"embed-ready\",\"present-left\",\"present-denied\"],Ye=[\"embed-denied\"],Ze=[\"present-invite\",\"present-handover\",\"present-switch\"],qe=[\"handover-done\"];function Y(e){let n={type:K+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 Te(e,n,t){if(!e||typeof e!=\"object\")return null;let r=e.type;if(typeof r!=\"string\"||!r.startsWith(K))return null;let o=r.slice(K.length);if(n.includes(o))return{type:o};if(Ye.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 s=e.slug;return typeof s!=\"string\"||!Ge.test(s)?null:{type:o,slug:s}}function _e(e){return Te(e,Ke,Ze)}function Ee(e){return Te(e,qe,[])}function Qe(e,n){try{let t=n||(typeof window!=\"undefined\"?window.parent:null);t&&t.postMessage(Y(e),\"*\")}catch(t){}}function Xe(e,n){var t;try{(t=e==null?void 0:e.contentWindow)==null||t.postMessage(Y(n),\"*\")}catch(r){}}function Je(e,n){var r;if(!e)return!0;let t=(r=e.contentWindow)!=null?r:e;return n===t}function en(e,n,t){let r=n||(typeof window!=\"undefined\"?window:null);if(!r)return()=>{};let o=s=>{if(!Je(t,s.source))return;let a=_e(s.data);a&&e(a)};return r.addEventListener(\"message\",o),()=>r.removeEventListener(\"message\",o)}function nn(e,n){var s;let t=n||(typeof window!=\"undefined\"?window:null);if(!t)return()=>{};let r=(s=t.parent)!=null?s:null,o=a=>{if(!r||r===t||a.source!==r)return;let l=Ee(a.data);l&&e(l)};return t.addEventListener(\"message\",o),()=>t.removeEventListener(\"message\",o)}var O={};M(O,{createTracker:()=>cn});var L={};M(L,{PRESENTER_ACTIONS_PER_HOUR:()=>X,PRESENT_CACHE_MS:()=>on,PRESENT_QUOTA_MARGIN:()=>Ce,PRESENT_QUOTA_PER_HOUR:()=>sn,PRESENT_READS_PER_HOUR:()=>Pe,PRESENT_READ_BURST:()=>Ie,PRESENT_READ_COALESCE_MS:()=>Ae,PRESENT_RESYNC_MS:()=>ke,PRESENT_SIGNAL_BUDGET_PER_HOUR:()=>rn,PRESENT_WRITE_TIMEOUT_MS:()=>J,READERS_PER_EGRESS:()=>q,RESYNC_READS_PER_HOUR:()=>Re,SESSION_IDLE_MS:()=>Q,SESSION_INTERVAL_MS:()=>Z,SESSION_QUOTA_PER_HOUR:()=>tn,SESSION_WRITES_PER_HOUR:()=>Se});var Z=3e4,Se=Math.ceil(120),q=25,tn=Se*q,Q=18e4,ke=25e3,Re=Math.ceil(36e5/ke),X=720,Pe=Re+X,rn=X,Ie=20,J=1e4,Ae=400,on=Ae,Ce=4,sn=(Pe+Ie)*q*Ce;var an=[\"mousemove\",\"mousedown\",\"keydown\",\"wheel\",\"touchstart\",\"pointerdown\"];function un(){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 ln(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 cn(e={}){var ye,be;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\",s=(ye=e.idleMs)!=null?ye:Q,a=(be=e.sessionEveryMs)!=null?be:3e4,l=e.slug||\"\",p=e.internal||null,g=e.sessionId||un(),f=e.send||ln(o,n),c={},u=0,y=0,d=0,w=0,v=null,E=r(),S=!1,V=!1,I=[],Ue=()=>!!l||!!p,ce=i=>{if(Ue())try{f(i)}catch(m){}},z=()=>!!t&&t.visibilityState===\"visible\"&&!S,de=i=>{let m=r()-i,b=Math.max(0,E-i)+s;return Math.max(0,Math.min(m,b))},F=()=>{v!=null&&u>0&&(c[u]=(c[u]||0)+de(v)/1e3),v=z()?r():null},pe=()=>{F(),v=null},B=()=>{v==null&&z()&&(v=r())},j=()=>{let i=0;for(let m in c)i+=c[m];return v!=null&&(i+=de(v)/1e3),Math.round(i)},fe=()=>{let i={};for(let m in c)i[m]=Math.round(c[m]);return i},k=()=>{E=r(),S&&(S=!1,B())},me=(i,m)=>{p||ce({slug:l,event:i,page:m||y,maxPage:d,seconds:j(),sessionId:g})},ge=\"\",A=()=>{F();let i=j(),m=`${i}|${d}|${w}`;if(m===ge)return;let b={event:\"session\",sessionId:g,numPages:w,maxPage:d,totalSeconds:i,pagesTime:fe()};p?(b.internal=!0,b.docId=p.docId,b.email=p.email,b.name=p.name,p.it&&(b.it=p.it)):b.slug=l,ge=m,ce(b)},R=(i,m,b,he)=>{!i||typeof i.addEventListener!=\"function\"||(i.addEventListener(m,b,he),I.push(()=>{i.removeEventListener(m,b,he)}))};return{sessionId:g,totalSeconds:j,maxPage:()=>d,pageTimes:fe,start(){if(V)return;V=!0,me(\"open\",1),u=1,E=r(),v=z()?r():null,R(t,\"visibilitychange\",()=>{t.visibilityState===\"hidden\"?(pe(),A()):(k(),B())}),R(n,\"focus\",()=>{k(),B()});for(let b of an)R(n,b,k,{passive:!0});R(e.scrollElement,\"scroll\",k,{passive:!0}),R(n,\"beforeunload\",A);let i=n.setInterval(()=>{!S&&r()-E>s&&(S=!0,pe())},5e3),m=n.setInterval(A,a);I.push(()=>{n.clearInterval(i),n.clearInterval(m)})},setPage(i){!i||i===y||(E=r(),F(),u=i,y=i,i>d&&(d=i,me(\"page\",i)))},setPageCount(i){w=i||0},noteActivity:k,flush:A,stop(){for(;I.length;){let i=I.pop();try{i==null||i()}catch(m){}}V=!1}}}var $={};M($,{STORAGE_KEYS:()=>x,attendeeKey:()=>mn,authorToken:()=>gn,avatarHtml:()=>ee,canModerate:()=>oe,createBudget:()=>xn,createFileEcritures:()=>Tn,createScheduler:()=>Mn,escapeHtml:()=>h,fetchBorne:()=>wn,flattenPresence:()=>dn,formatMessageBody:()=>ne,initials:()=>Ne,isMentioned:()=>bn,isMine:()=>T,presenceId:()=>_n,reactorId:()=>re,referenceAuteur:()=>yn,shouldNotify:()=>hn,unreadLabel:()=>vn});var x={attendeeKey:\"3dd-present-attkey\",authorToken:\"3dd-present-authtoken\",chatMuted:\"3dd-present-mute\",presenceId:\"3dd-present-uid\"};function h(e){return String(e==null?\"\":e).replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\").replace(/\"/g,\""\")}function Ne(e){let n=(e||\"?\").trim().split(/\\s+/);return(((n[0]||\"\")[0]||\"?\")+((n[1]||\"\")[0]||\"\")).toUpperCase()}function ee(e,n){return e?`<img src=\"${h(e)}\" alt=\"\">`:h(Ne(n))}function ne(e){let n=h(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 dn(e){let n=new Map;for(let t in e||{})for(let r of(e||{})[t]||[]){let o=String(r.uid||r.email||r.name||\"\").toLowerCase()||`_${t}_${n.size}`;(!n.get(o)||r.role===\"presenter\")&&n.set(o,r)}return[...n.values()]}function pn(e,n){try{return e?e.getItem(n):null}catch(t){return null}}function fn(e,n,t){try{e==null||e.setItem(n,t)}catch(r){}}function mn(e,n=\"anon\",t=te){try{if(!e)return`anon-${n}`;let r=e.getItem(x.attendeeKey);if(r)return r;let o=`anon-${t()}`;return e.setItem(x.attendeeKey,o),o}catch(r){return`anon-${n}`}}function te(){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 gn(e,n=te){let t=pn(e,x.authorToken);if(t)return t;let r=n();return fn(e,x.authorToken,r),r}async function yn(e,n){let t=n!==void 0?n:typeof globalThis!=\"undefined\"&&globalThis.crypto?globalThis.crypto.subtle:null;if(!t||!e)return\"\";try{let r=async o=>{let s=await t.digest(\"SHA-256\",new TextEncoder().encode(o));return Array.from(new Uint8Array(s),a=>a.toString(16).padStart(2,\"0\")).join(\"\")};return(await r(\"ref:\"+await r(e))).slice(0,16)}catch(r){return\"\"}}function re(e){return String(e&&e.ref||\"\")}function T(e,n){return!e||!n||!e.author_ref||!n.ref?!1:e.author_ref===n.ref}function oe(e){return!!(e&&e.role===\"presenter\")}function bn(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}`)&&!T(e,n):!1}function hn(e){let{msg:n,me:t,historyLoaded:r,chatHidden:o}=e;return!r||!n||n.deleted||T(n,t)?!1:o}function vn(e){return!e||e<=0?\"\":e>9?\"9+\":String(e)}function Mn(e,n={}){var y;let t=(y=n.minMs)!=null?y:300,r=n.now||(()=>Date.now()),o=n.setTimer||((d,w)=>setTimeout(d,w)),s=n.clearTimer||(d=>clearTimeout(d)),a=!1,l=!1,p=-1/0,g=null,f=!1;function c(){if(f||a){l=!0;return}let d=t-(r()-p);if(d>0){u(d);return}a=!0,l=!1,p=r();let w=!1;e(()=>{w||(w=!0,a=!1,l&&!f&&c())})}function u(d){f||g!==null||(g=o(()=>{g=null,c()},Math.max(0,d)))}return{signaler(){f||c()},maintenant(){f||(p=-1/0,c())},arreter(){f=!0,g!==null&&(s(g),g=null)}}}function wn(e,n,t=J,r={}){let o=r.fetch||(typeof fetch==\"function\"?fetch:void 0);if(!o)return Promise.reject(new Error(\"fetch indisponible\"));let s=r.setTimer||((u,y)=>setTimeout(u,y)),a=r.clearTimer||(u=>clearTimeout(u)),l=null;try{l=new AbortController}catch(u){}let p=l?xe(G({},n||{}),{signal:l.signal}):G({},n||{}),g=null,f=new Promise((u,y)=>{g=s(()=>{try{l==null||l.abort()}catch(d){}y(new Error(\"delai\"))},t)}),c=()=>{try{a(g)}catch(u){}};return Promise.race([o(e,p),f]).then(u=>(c(),u),u=>{throw c(),u})}function xn(e){let n=e.now||(()=>Date.now()),t=Math.max(1,e.rafale),r=t,o=n();return{prendre(){let s=n();return r=Math.min(t,r+(s-o)*e.parHeure/36e5),o=s,r<1?!1:(r-=1,!0)},restants:()=>r}}function Tn(e={}){var g;let n=(g=e.minMs)!=null?g:0,t=e.now||(()=>Date.now()),r=e.setTimer||((f,c)=>setTimeout(f,c)),o=new Map,s=!1,a=-1/0,l=!1;function p(){if(s||o.size===0)return;let f=n-(t()-a);if(f>0){if(l)return;l=!0,r(()=>{l=!1,p()},f);return}let c=o.keys().next().value,u=o.get(c);o.delete(c),s=!0,a=t(),Promise.resolve().then(u.tache).then(y=>u.regler(y),()=>u.regler(null)).then(()=>{s=!1,p()})}return{poser(f,c){return new Promise(u=>{let y=o.get(f);o.set(f,{tache:c,regler:d=>{y&&y.regler(d),u(d)}}),p()})},enAttente:()=>o.size}}function _n(e,n=te){try{if(e){let t=e.getItem(x.presenceId);if(t)return t;let r=`p-${n()}`;return e.setItem(x.presenceId,r),r}}catch(t){}return`p-${n()}`}var H={};M(H,{messageClassName:()=>Sn,renderActions:()=>$e,renderAttachment:()=>Oe,renderMessage:()=>En,renderReactions:()=>Le});function Le(e,n){let t=e&&e.reactions||{},r=re(n),o=\"\";for(let s in t){let a=t[s]||[];if(!a.length)continue;let l=a.indexOf(r)>=0;o+=`<button class=\"re-chip${l?\" on\":\"\"}\" data-e=\"${h(s)}\">${h(s)} ${a.length}</button>`}return o}function Oe(e){if(!e||!e.url)return\"\";let n=h(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=h(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 $e(e,n){let t=T(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||oe(n.me))&&(r+='<button class=cm-del-btn title=\"Supprimer\">\\u{1F5D1}</button>'),r}function En(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>${h(e.reply_name||\"\")}</b> ${h(e.reply_text||\"\")}</div>`:\"\",r=e.edited?\" <span class=cm-ed>(modifi\\xE9)</span>\":\"\",o=e.body?`<div class=txt>${ne(e.body)}${r}</div>`:\"\",s=e.is_presenter?\" <span class=tag>pr\\xE9sentateur</span>\":\"\";return`<span class=a>${ee(e.author_avatar,e.author_name)}</span><span class=b><div class=who><b>${h(e.author_name||\"Invit\\xE9\")}</b>${s}</div>`+t+o+Oe(e.attachment)+`<div class=cm-re>${Le(e,n.me)}</div></span><span class=cm-act>${$e(e,n)}</span>`}function Sn(e,n,t){return\"cm\"+(T(e,n)?\" me\":\"\")+(e.deleted?\" isdel\":\"\")+(t?\" mentioned\":\"\")}var U={};M(U,{DEFAULT_CENTER:()=>ae,DEFAULT_ZOOM:()=>ue,MAP_TYPES:()=>P,cycleMapType:()=>kn,initialMapContent:()=>Pn,mapTypeLabel:()=>Rn,sanitizeContent:()=>le});var P=[\"roadmap\",\"satellite\",\"hybrid\"],ae=[46.6,2.5],ue=6;function _(e){let n=Number(e);return Number.isFinite(n)?n:null}function se(e){if(!Array.isArray(e))return null;let n=_(e[0]),t=_(e[1]);return n!=null&&t!=null?[n,t]:null}var ie=(e,n,t)=>Math.max(n,Math.min(t,e));function le(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=se(n.position);if(!t)return null;let r=n.pov&&typeof n.pov==\"object\"?n.pov:null,o=r?{heading:_(r.heading)||0,pitch:ie(_(r.pitch)||0,-90,90)}:{heading:0,pitch:0};return{kind:\"streetview\",position:t,pov:o,zoom:ie(_(n.zoom)||1,0,5)}}return n.kind!==\"map\"?null:{kind:\"map\",center:se(n.center)||[...ae],zoom:ie(Math.trunc(_(n.zoom)||ue),1,21),marker:se(n.marker),mapType:P.includes(n.mapType)?n.mapType:null,label:String(n.label||\"\").slice(0,160)||null}}function kn(e){let n=P.indexOf(e);return P[(n+1)%P.length]}function Rn(e){return e===\"roadmap\"?\"\\u{1F6F0} Satellite\":e===\"satellite\"?\"\\u{1F5FA} Hybride\":\"\\u{1F5FA} Plan\"}function Pn(){return{kind:\"map\",center:[...ae],zoom:ue,marker:null,mapType:null,label:null}}var D={};M(D,{CURRENT_PAGE_MARGIN:()=>On,DEFAULT_ASPECT:()=>Cn,MAX_ZOOM:()=>An,MIN_PAGE_WIDTH:()=>Nn,MIN_ZOOM:()=>In,PRERENDER_MARGIN:()=>Ln,arrowState:()=>Un,averageColor:()=>Vn,clampPage:()=>He,clampZoom:()=>$n,fitWidth:()=>Wn,isImageDocument:()=>zn,progressPercent:()=>Hn});var In=.5,An=3,Cn=1.35,Nn=280,Ln=\"500px 0px\",On=\"-48% 0px -48% 0px\";function $n(e){let n=Math.round((Number(e)||0)*10)/10;return Math.max(.5,Math.min(3,n))}function He(e,n){return Math.max(1,Math.min(n||1,Number(e)||1))}function Hn(e,n){return n?Math.round(He(e,n)/n*100):0}function Un(e,n){return{prevDisabled:e<=1,nextDisabled:!!n&&e>=n}}var Dn=28;function Wn(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,s=((e.containerHeight||600)-Dn-(e.overlap||0)-(e.reserve||0))/r;return s>120?Math.min(t,s):t}function Vn(e){let n=e.length/4;if(!n)return\"rgb(0,0,0)\";let t=0,r=0,o=0;for(let s=0;s<e.length;s+=4)t+=e[s],r+=e[s+1],o+=e[s+2];return`rgb(${Math.round(t/n)},${Math.round(r/n)},${Math.round(o/n)})`}function zn(e,n){return/[.](png|jpe?g|webp|gif|avif)($|[?])/i.test(String(e||n||\"\"))}var W={};M(W,{presentationTransition:()=>Fn,switchDocUrl:()=>Bn});function Fn(e,n={}){if(!e)return[{kind:\"nothing\"}];if(e.active===!1)return[{kind:\"ended\"}];let t=le(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 Bn(e,n){let t=encodeURIComponent(n||String(Date.now()));return`${e}${e.includes(\"?\")?\"&\":\"?\"}v=${t}`}return je(jn);})();", SOURCE_HASH: "95b81425c70778a0" };
|
|
7
|
+
module.exports = { PLAYER_BROWSER_JS: "\"use strict\";var Player=(()=>{var C=Object.defineProperty,We=Object.defineProperties,Ve=Object.getOwnPropertyDescriptor,ze=Object.getOwnPropertyDescriptors,Fe=Object.getOwnPropertyNames,ve=Object.getOwnPropertySymbols;var we=Object.prototype.hasOwnProperty,Be=Object.prototype.propertyIsEnumerable;var Me=(e,n,t)=>n in e?C(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,K=(e,n)=>{for(var t in n||(n={}))we.call(n,t)&&Me(e,t,n[t]);if(ve)for(var t of ve(n))Be.call(n,t)&&Me(e,t,n[t]);return e},xe=(e,n)=>We(e,ze(n));var M=(e,n)=>{for(var t in n)C(e,t,{get:n[t],enumerable:!0})},je=(e,n,t,r)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let o of Fe(n))!we.call(e,o)&&o!==t&&C(e,o,{get:()=>n[o],enumerable:!(r=Ve(n,o))||r.enumerable});return e};var Ge=e=>je(C({},\"__esModule\",{value:!0}),e);var Kn={};M(Kn,{bridge:()=>N,cadence:()=>L,chat:()=>U,live:()=>H,presentation:()=>D,presentationState:()=>V,tracking:()=>$,viewer:()=>W});var N={};M(N,{onHostMessage:()=>tn,onPlayerMessage:()=>nn,parseHostMessage:()=>Te,parsePlayerMessage:()=>Ee,sendToHost:()=>Xe,sendToPlayer:()=>Je,toWire:()=>Z});var Y=\"3dd-doc-\",Ke=/^[A-Za-z0-9_-]{1,64}$/,Ye=[\"close\",\"share\",\"embed-ready\",\"present-left\",\"present-denied\"],Ze=[\"embed-denied\"],qe=[\"present-invite\",\"present-handover\",\"present-switch\"],Qe=[\"handover-done\"];function Z(e){let n={type:Y+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 _e(e,n,t){if(!e||typeof e!=\"object\")return null;let r=e.type;if(typeof r!=\"string\"||!r.startsWith(Y))return null;let o=r.slice(Y.length);if(n.includes(o))return{type:o};if(Ze.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 s=e.slug;return typeof s!=\"string\"||!Ke.test(s)?null:{type:o,slug:s}}function Ee(e){return _e(e,Ye,qe)}function Te(e){return _e(e,Qe,[])}function Xe(e,n){try{let t=n||(typeof window!=\"undefined\"?window.parent:null);t&&t.postMessage(Z(e),\"*\")}catch(t){}}function Je(e,n){var t;try{(t=e==null?void 0:e.contentWindow)==null||t.postMessage(Z(n),\"*\")}catch(r){}}function en(e,n){var r;if(!e)return!0;let t=(r=e.contentWindow)!=null?r:e;return n===t}function nn(e,n,t){let r=n||(typeof window!=\"undefined\"?window:null);if(!r)return()=>{};let o=s=>{if(!en(t,s.source))return;let a=Ee(s.data);a&&e(a)};return r.addEventListener(\"message\",o),()=>r.removeEventListener(\"message\",o)}function tn(e,n){var s;let t=n||(typeof window!=\"undefined\"?window:null);if(!t)return()=>{};let r=(s=t.parent)!=null?s:null,o=a=>{if(!r||r===t||a.source!==r)return;let l=Te(a.data);l&&e(l)};return t.addEventListener(\"message\",o),()=>t.removeEventListener(\"message\",o)}var $={};M($,{createTracker:()=>pn});var L={};M(L,{PRESENTER_ACTIONS_PER_HOUR:()=>X,PRESENT_CACHE_MS:()=>an,PRESENT_QUOTA_MARGIN:()=>Ne,PRESENT_QUOTA_PER_HOUR:()=>un,PRESENT_READS_PER_HOUR:()=>Ie,PRESENT_READ_BURST:()=>Ae,PRESENT_READ_COALESCE_MS:()=>Ce,PRESENT_RESYNC_MS:()=>Re,PRESENT_SIGNAL_BUDGET_PER_HOUR:()=>sn,PRESENT_WRITE_TIMEOUT_MS:()=>J,READERS_PER_EGRESS:()=>O,RESYNC_READS_PER_HOUR:()=>Pe,SESSION_IDLE_MS:()=>Q,SESSION_INTERVAL_MS:()=>q,SESSION_QUOTA_PER_HOUR:()=>rn,SESSION_WRITES_PER_HOUR:()=>Se,VIEW_EVENTS_PER_READER_HOUR:()=>ke,VIEW_QUOTA_PER_HOUR:()=>on});var q=3e4,Se=Math.ceil(120),O=25,rn=Se*O,ke=720,on=ke*O,Q=18e4,Re=25e3,Pe=Math.ceil(36e5/Re),X=720,Ie=Pe+X,sn=X,Ae=20,J=1e4,Ce=400,an=Ce,Ne=4,un=(Ie+Ae)*O*Ne;var ln=[\"mousemove\",\"mousedown\",\"keydown\",\"wheel\",\"touchstart\",\"pointerdown\"];function cn(){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 dn(e,n){return t=>{try{let r=JSON.stringify(t),o=n.navigator;return 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}),!0)}catch(r){return!1}}}function pn(e={}){var be,ye;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\",s=(be=e.idleMs)!=null?be:Q,a=(ye=e.sessionEveryMs)!=null?ye:3e4,l=e.slug||\"\",p=e.internal||null,g=e.sessionId||cn(),f=e.send||dn(o,n),c={},u=0,b=0,d=0,w=0,v=null,T=r(),S=!1,z=!1,I=[],De=()=>!!l||!!p,ce=i=>{if(!De())return!1;try{return f(i)!==!1}catch(m){return!1}},F=()=>!!t&&t.visibilityState===\"visible\"&&!S,de=i=>{let m=r()-i,y=Math.max(0,T-i)+s;return Math.max(0,Math.min(m,y))},B=()=>{v!=null&&u>0&&(c[u]=(c[u]||0)+de(v)/1e3),v=F()?r():null},pe=()=>{B(),v=null},j=()=>{v==null&&F()&&(v=r())},G=()=>{let i=0;for(let m in c)i+=c[m];return v!=null&&(i+=de(v)/1e3),Math.round(i)},fe=()=>{let i={};for(let m in c)i[m]=Math.round(c[m]);return i},k=()=>{T=r(),S&&(S=!1,j())},me=(i,m)=>{p||ce({slug:l,event:i,page:m||b,maxPage:d,seconds:G(),sessionId:g})},ge=\"\",A=()=>{B();let i=G(),m=`${i}|${d}|${w}`;if(m===ge)return;let y={event:\"session\",sessionId:g,numPages:w,maxPage:d,totalSeconds:i,pagesTime:fe()};p?(y.internal=!0,y.docId=p.docId,y.email=p.email,y.name=p.name,p.it&&(y.it=p.it)):y.slug=l,ce(y)&&(ge=m)},R=(i,m,y,he)=>{!i||typeof i.addEventListener!=\"function\"||(i.addEventListener(m,y,he),I.push(()=>{i.removeEventListener(m,y,he)}))};return{sessionId:g,totalSeconds:G,maxPage:()=>d,pageTimes:fe,start(){if(z)return;z=!0,me(\"open\",1),u=1,T=r(),v=F()?r():null,R(t,\"visibilitychange\",()=>{t.visibilityState===\"hidden\"?(pe(),A()):(k(),j())}),R(n,\"focus\",()=>{k(),j()});for(let y of ln)R(n,y,k,{passive:!0});R(e.scrollElement,\"scroll\",k,{passive:!0}),R(n,\"beforeunload\",A);let i=n.setInterval(()=>{!S&&r()-T>s&&(S=!0,pe())},5e3),m=n.setInterval(A,a);I.push(()=>{n.clearInterval(i),n.clearInterval(m)})},setPage(i){!i||i===b||(T=r(),B(),u=i,b=i,i>d&&(d=i,me(\"page\",i)))},setPageCount(i){w=i||0},noteActivity:k,flush:A,stop(){for(;I.length;){let i=I.pop();try{i==null||i()}catch(m){}}z=!1}}}var H={};M(H,{STORAGE_KEYS:()=>x,attendeeKey:()=>bn,authorToken:()=>yn,avatarHtml:()=>ee,canModerate:()=>oe,createBudget:()=>En,createFileEcritures:()=>Tn,createScheduler:()=>xn,escapeHtml:()=>h,fetchBorne:()=>_n,flattenPresence:()=>fn,formatMessageBody:()=>ne,initials:()=>Oe,isMentioned:()=>vn,isMine:()=>_,presenceId:()=>Sn,reactorId:()=>re,referenceAuteur:()=>hn,shouldNotify:()=>Mn,unreadLabel:()=>wn});var x={attendeeKey:\"3dd-present-attkey\",authorToken:\"3dd-present-authtoken\",chatMuted:\"3dd-present-mute\",presenceId:\"3dd-present-uid\"};function h(e){return String(e==null?\"\":e).replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\").replace(/\"/g,\""\")}function Oe(e){let n=(e||\"?\").trim().split(/\\s+/);return(((n[0]||\"\")[0]||\"?\")+((n[1]||\"\")[0]||\"\")).toUpperCase()}function ee(e,n){return e?`<img src=\"${h(e)}\" alt=\"\">`:h(Oe(n))}function ne(e){let n=h(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 fn(e){let n=new Map;for(let t in e||{})for(let r of(e||{})[t]||[]){let o=String(r.uid||r.email||r.name||\"\").toLowerCase()||`_${t}_${n.size}`;(!n.get(o)||r.role===\"presenter\")&&n.set(o,r)}return[...n.values()]}function mn(e,n){try{return e?e.getItem(n):null}catch(t){return null}}function gn(e,n,t){try{e==null||e.setItem(n,t)}catch(r){}}function bn(e,n=\"anon\",t=te){try{if(!e)return`anon-${n}`;let r=e.getItem(x.attendeeKey);if(r)return r;let o=`anon-${t()}`;return e.setItem(x.attendeeKey,o),o}catch(r){return`anon-${n}`}}function te(){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 yn(e,n=te){let t=mn(e,x.authorToken);if(t)return t;let r=n();return gn(e,x.authorToken,r),r}async function hn(e,n){let t=n!==void 0?n:typeof globalThis!=\"undefined\"&&globalThis.crypto?globalThis.crypto.subtle:null;if(!t||!e)return\"\";try{let r=async o=>{let s=await t.digest(\"SHA-256\",new TextEncoder().encode(o));return Array.from(new Uint8Array(s),a=>a.toString(16).padStart(2,\"0\")).join(\"\")};return(await r(\"ref:\"+await r(e))).slice(0,16)}catch(r){return\"\"}}function re(e){return String(e&&e.ref||\"\")}function _(e,n){return!e||!n||!e.author_ref||!n.ref?!1:e.author_ref===n.ref}function oe(e){return!!(e&&e.role===\"presenter\")}function vn(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}`)&&!_(e,n):!1}function Mn(e){let{msg:n,me:t,historyLoaded:r,chatHidden:o}=e;return!r||!n||n.deleted||_(n,t)?!1:o}function wn(e){return!e||e<=0?\"\":e>9?\"9+\":String(e)}function xn(e,n={}){var b;let t=(b=n.minMs)!=null?b:300,r=n.now||(()=>Date.now()),o=n.setTimer||((d,w)=>setTimeout(d,w)),s=n.clearTimer||(d=>clearTimeout(d)),a=!1,l=!1,p=-1/0,g=null,f=!1;function c(){if(f||a){l=!0;return}let d=t-(r()-p);if(d>0){u(d);return}a=!0,l=!1,p=r();let w=!1;e(()=>{w||(w=!0,a=!1,l&&!f&&c())})}function u(d){f||g!==null||(g=o(()=>{g=null,c()},Math.max(0,d)))}return{signaler(){f||c()},maintenant(){f||(p=-1/0,c())},arreter(){f=!0,g!==null&&(s(g),g=null)}}}function _n(e,n,t=J,r={}){let o=r.fetch||(typeof fetch==\"function\"?fetch:void 0);if(!o)return Promise.reject(new Error(\"fetch indisponible\"));let s=r.setTimer||((u,b)=>setTimeout(u,b)),a=r.clearTimer||(u=>clearTimeout(u)),l=null;try{l=new AbortController}catch(u){}let p=l?xe(K({},n||{}),{signal:l.signal}):K({},n||{}),g=null,f=new Promise((u,b)=>{g=s(()=>{try{l==null||l.abort()}catch(d){}b(new Error(\"delai\"))},t)}),c=()=>{try{a(g)}catch(u){}};return Promise.race([o(e,p),f]).then(u=>(c(),u),u=>{throw c(),u})}function En(e){let n=e.now||(()=>Date.now()),t=Math.max(1,e.rafale),r=t,o=n();return{prendre(){let s=n();return r=Math.min(t,r+(s-o)*e.parHeure/36e5),o=s,r<1?!1:(r-=1,!0)},restants:()=>r}}function Tn(e={}){var g;let n=(g=e.minMs)!=null?g:0,t=e.now||(()=>Date.now()),r=e.setTimer||((f,c)=>setTimeout(f,c)),o=new Map,s=!1,a=-1/0,l=!1;function p(){if(s||o.size===0)return;let f=n-(t()-a);if(f>0){if(l)return;l=!0,r(()=>{l=!1,p()},f);return}let c=o.keys().next().value,u=o.get(c);o.delete(c),s=!0,a=t(),Promise.resolve().then(u.tache).then(b=>u.regler(b),()=>u.regler(null)).then(()=>{s=!1,p()})}return{poser(f,c){return new Promise(u=>{let b=o.get(f);o.set(f,{tache:c,regler:d=>{b&&b.regler(d),u(d)}}),p()})},enAttente:()=>o.size}}function Sn(e,n=te){try{if(e){let t=e.getItem(x.presenceId);if(t)return t;let r=`p-${n()}`;return e.setItem(x.presenceId,r),r}}catch(t){}return`p-${n()}`}var U={};M(U,{messageClassName:()=>Rn,renderActions:()=>He,renderAttachment:()=>$e,renderMessage:()=>kn,renderReactions:()=>Le});function Le(e,n){let t=e&&e.reactions||{},r=re(n),o=\"\";for(let s in t){let a=t[s]||[];if(!a.length)continue;let l=a.indexOf(r)>=0;o+=`<button class=\"re-chip${l?\" on\":\"\"}\" data-e=\"${h(s)}\">${h(s)} ${a.length}</button>`}return o}function $e(e){if(!e||!e.url)return\"\";let n=h(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=h(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 He(e,n){let t=_(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||oe(n.me))&&(r+='<button class=cm-del-btn title=\"Supprimer\">\\u{1F5D1}</button>'),r}function kn(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>${h(e.reply_name||\"\")}</b> ${h(e.reply_text||\"\")}</div>`:\"\",r=e.edited?\" <span class=cm-ed>(modifi\\xE9)</span>\":\"\",o=e.body?`<div class=txt>${ne(e.body)}${r}</div>`:\"\",s=e.is_presenter?\" <span class=tag>pr\\xE9sentateur</span>\":\"\";return`<span class=a>${ee(e.author_avatar,e.author_name)}</span><span class=b><div class=who><b>${h(e.author_name||\"Invit\\xE9\")}</b>${s}</div>`+t+o+$e(e.attachment)+`<div class=cm-re>${Le(e,n.me)}</div></span><span class=cm-act>${He(e,n)}</span>`}function Rn(e,n,t){return\"cm\"+(_(e,n)?\" me\":\"\")+(e.deleted?\" isdel\":\"\")+(t?\" mentioned\":\"\")}var D={};M(D,{DEFAULT_CENTER:()=>ae,DEFAULT_ZOOM:()=>ue,MAP_TYPES:()=>P,cycleMapType:()=>Pn,initialMapContent:()=>An,mapTypeLabel:()=>In,sanitizeContent:()=>le});var P=[\"roadmap\",\"satellite\",\"hybrid\"],ae=[46.6,2.5],ue=6;function E(e){let n=Number(e);return Number.isFinite(n)?n:null}function se(e){if(!Array.isArray(e))return null;let n=E(e[0]),t=E(e[1]);return n!=null&&t!=null?[n,t]:null}var ie=(e,n,t)=>Math.max(n,Math.min(t,e));function le(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=se(n.position);if(!t)return null;let r=n.pov&&typeof n.pov==\"object\"?n.pov:null,o=r?{heading:E(r.heading)||0,pitch:ie(E(r.pitch)||0,-90,90)}:{heading:0,pitch:0};return{kind:\"streetview\",position:t,pov:o,zoom:ie(E(n.zoom)||1,0,5)}}return n.kind!==\"map\"?null:{kind:\"map\",center:se(n.center)||[...ae],zoom:ie(Math.trunc(E(n.zoom)||ue),1,21),marker:se(n.marker),mapType:P.includes(n.mapType)?n.mapType:null,label:String(n.label||\"\").slice(0,160)||null}}function Pn(e){let n=P.indexOf(e);return P[(n+1)%P.length]}function In(e){return e===\"roadmap\"?\"\\u{1F6F0} Satellite\":e===\"satellite\"?\"\\u{1F5FA} Hybride\":\"\\u{1F5FA} Plan\"}function An(){return{kind:\"map\",center:[...ae],zoom:ue,marker:null,mapType:null,label:null}}var W={};M(W,{CURRENT_PAGE_MARGIN:()=>Hn,DEFAULT_ASPECT:()=>On,MAX_ZOOM:()=>Nn,MIN_PAGE_WIDTH:()=>Ln,MIN_ZOOM:()=>Cn,PRERENDER_MARGIN:()=>$n,arrowState:()=>Wn,averageColor:()=>Fn,clampPage:()=>Ue,clampZoom:()=>Un,fitWidth:()=>zn,isImageDocument:()=>Bn,progressPercent:()=>Dn});var Cn=.5,Nn=3,On=1.35,Ln=280,$n=\"500px 0px\",Hn=\"-48% 0px -48% 0px\";function Un(e){let n=Math.round((Number(e)||0)*10)/10;return Math.max(.5,Math.min(3,n))}function Ue(e,n){return Math.max(1,Math.min(n||1,Number(e)||1))}function Dn(e,n){return n?Math.round(Ue(e,n)/n*100):0}function Wn(e,n){return{prevDisabled:e<=1,nextDisabled:!!n&&e>=n}}var Vn=28;function zn(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,s=((e.containerHeight||600)-Vn-(e.overlap||0)-(e.reserve||0))/r;return s>120?Math.min(t,s):t}function Fn(e){let n=e.length/4;if(!n)return\"rgb(0,0,0)\";let t=0,r=0,o=0;for(let s=0;s<e.length;s+=4)t+=e[s],r+=e[s+1],o+=e[s+2];return`rgb(${Math.round(t/n)},${Math.round(r/n)},${Math.round(o/n)})`}function Bn(e,n){return/[.](png|jpe?g|webp|gif|avif)($|[?])/i.test(String(e||n||\"\"))}var V={};M(V,{presentationTransition:()=>jn,switchDocUrl:()=>Gn});function jn(e,n={}){if(!e)return[{kind:\"nothing\"}];if(e.active===!1)return[{kind:\"ended\"}];let t=le(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 Gn(e,n){let t=encodeURIComponent(n||String(Date.now()));return`${e}${e.includes(\"?\")?\"&\":\"?\"}v=${t}`}return Ge(Kn);})();", SOURCE_HASH: "9b51a94c89b8d54f" };
|
package/server/presentations.js
CHANGED
|
@@ -731,12 +731,19 @@ async function toggleReaction(slug, msgId, emoji, reactor, etat) {
|
|
|
731
731
|
// Heartbeat d'un participant : upsert de sa ligne d'assistance. On accumule le temps de présence (intervalles
|
|
732
732
|
// < 60 s → un aller-retour ne gonfle pas total_ms) et l'ensemble des pages vues (page courante de la présentation).
|
|
733
733
|
const ATTEND_MAX_GAP_MS = 60 * 1000;
|
|
734
|
-
|
|
734
|
+
// ⚠️ SIGNATURE : `(slug, participant, { presentation })`. Le participant reste en 2e position — c'est
|
|
735
|
+
// le contrat d'export PUBLIC (`./presentations`), un hôte tiers appelle `recordAttendance(slug,
|
|
736
|
+
// participant)` à DEUX arguments. L'optimisation « présentation déjà chargée » vit dans un SAC
|
|
737
|
+
// D'OPTIONS, pas dans un slot positionnel : la ranger en 2e position (ce que faisait 0.1.84) déplaçait
|
|
738
|
+
// le vrai paramètre et faisait jeter `Cannot destructure property 'key'` sur un appel à deux arguments
|
|
739
|
+
// (P1a audit CODEX 5.6). `participant || {}` : un appel sans participant tombe en 400, jamais en throw.
|
|
740
|
+
async function recordAttendance(slug, participant, { presentation = null } = {}) {
|
|
741
|
+
const { key, name, email, avatar, isMember, isPresenter } = participant || {};
|
|
735
742
|
if (!slug || !key) return { ok: false, status: 400 };
|
|
736
|
-
//
|
|
737
|
-
// que
|
|
738
|
-
//
|
|
739
|
-
const pres =
|
|
743
|
+
// La route vient DÉJÀ de charger la présentation (contrôle présentateur) : elle la fournit dans les
|
|
744
|
+
// options plutôt que de la faire relire par battement (un battement = un aller-retour DB de moins).
|
|
745
|
+
// Repli sur une lecture si l'appelant ne la fournit pas — c'est le cas de l'appel public à 2 args.
|
|
746
|
+
const pres = presentation || await getPresentation(slug);
|
|
740
747
|
if (!pres) return { ok: false, status: 404 };
|
|
741
748
|
// ⚠️ La lecture est DÉJÀ faite ici : on s'en sert plutôt que d'en refaire une. Un battement de
|
|
742
749
|
// présence sur une session close n'a rien à mettre à jour — et il en arrive à chaque onglet
|
package/server/routes-direct.js
CHANGED
|
@@ -94,7 +94,7 @@ async function traiter(req, res, body, _slug) {
|
|
|
94
94
|
// On dérive donc la clé de ce qui est prouvé, et jamais de ce qui est affirmé. Un anonyme,
|
|
95
95
|
// lui, ne peut rien prouver : sa clé reste la sienne, mais enfermée dans un espace de noms
|
|
96
96
|
// dont elle ne peut pas sortir — elle ne pourra jamais ressembler à l'e-mail d'un membre.
|
|
97
|
-
const r = await recordAttendance(String(body.slug || ""),
|
|
97
|
+
const r = await recordAttendance(String(body.slug || ""), {
|
|
98
98
|
// ⚠️ MINUSCULÉE, ET CE DÉTAIL EST UNE LIGNE DE PRÉSENCE. La clé cliente que 0.1.42 a
|
|
99
99
|
// remplacée l'était (`me.email.toLowerCase()`) ; la clé dérivée ne l'était pas, et la
|
|
100
100
|
// ligne se retrouve par `attendee_key=eq.` — une correspondance EXACTE. Un hôte dont
|
|
@@ -110,7 +110,7 @@ async function traiter(req, res, body, _slug) {
|
|
|
110
110
|
email: profil ? profil.email : body.email,
|
|
111
111
|
avatar: (profil && profil.avatar) || body.avatar,
|
|
112
112
|
isMember: !!profil, isPresenter: estPresentateur,
|
|
113
|
-
});
|
|
113
|
+
}, { presentation: pres });
|
|
114
114
|
return jp(r.ok ? 200 : (r.status || 400), r);
|
|
115
115
|
} catch { return jp(500, { ok: false }); }
|
|
116
116
|
}
|
package/server/routes-liens.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
const { adresseAppelant } = require("./appelant");
|
|
5
5
|
const { createShare, createReshare, sendReshareEmail, revokeShare, setShareAuth, listSharesForDoc, listSessionsForDoc, internalStatsForDoc, cleIdempotence, getShareBySlug, logView, upsertSession, upsertInternalSession, overview: docOverview } = require("./shares");
|
|
6
|
-
const { SESSION_QUOTA_PER_HOUR } = require("./shared.generated.js");
|
|
6
|
+
const { SESSION_QUOTA_PER_HOUR, VIEW_QUOTA_PER_HOUR } = require("./shared.generated.js");
|
|
7
7
|
|
|
8
8
|
let PLAYER = null;
|
|
9
9
|
const init = (ctx) => { PLAYER = ctx; };
|
|
@@ -442,20 +442,37 @@ async function traiter(req, res, body, slug) {
|
|
|
442
442
|
res.statusCode = 200; res.setHeader("Content-Type", "application/json"); res.end('{"ok":true}');
|
|
443
443
|
return;
|
|
444
444
|
}
|
|
445
|
-
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
445
|
+
// ⚠️ PLAFOND ANTI-INONDATION PAR IP, EN DEUX SEAUX, ET VÉRIFIÉ AVANT DE LIRE LE LIEN (P1
|
|
446
|
+
// performance + P1b audit 5.6). Deux corrections à l'origine SESSION_QUOTA-pour-tout :
|
|
447
|
+
// • DEUX SEAUX. La session est un `upsert` riche → `sess:`, quota dérivé des écritures de
|
|
448
|
+
// session. open/page/heartbeat sont un `logView` bien meilleur marché → `view:`, leur
|
|
449
|
+
// propre quota. Les garder ensemble faisait vider le quota des sessions par les open/page :
|
|
450
|
+
// 25 lecteurs derrière une IP le dépassaient avant même d'avoir écrit une session.
|
|
451
|
+
// • QUOTA AVANT LA LECTURE DU LIEN. `getShareBySlug` est une lecture base ; la placer avant
|
|
452
|
+
// le quota faisait payer une lecture à CHAQUE requête, y compris hors quota — exactement ce
|
|
453
|
+
// qu'un plafond anti-inondation doit éviter. On tranche d'abord, on lit ensuite.
|
|
454
|
+
// Dépassé : on n'écrit pas, on ne lit pas le lien — mais on répond 200 (une mesure ne casse pas
|
|
455
|
+
// une lecture). La lecture de TEST reste exemptée d'ÉCRITURE, pas de quota (rare, interne).
|
|
450
456
|
const ipTrack = ip0 || "anon";
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
457
|
+
const estSession = body.event === "session";
|
|
458
|
+
const cleQuota = estSession ? `sess:${ipTrack}` : `view:${ipTrack}`;
|
|
459
|
+
const quotaTrack = estSession ? SESSION_QUOTA_PER_HOUR : VIEW_QUOTA_PER_HOUR;
|
|
460
|
+
if (!(await PLAYER.limits.allow(cleQuota, quotaTrack, 3600))) {
|
|
461
|
+
// ⚠️ UN REFUS MUET EST UNE TABLE QUI NE MONTE PAS SANS CAUSE NOMMÉE. Une fois par heure et
|
|
462
|
+
// par classe, on NOMME l'abandon (`abandon: true`) — c'est le signal d'abandon de télémétrie
|
|
463
|
+
// que l'exploitant peut relier à un quota, plutôt qu'une mesure qui stagne sans explication.
|
|
464
|
+
try {
|
|
465
|
+
const avert = estSession ? "sess:quota-avert" : "view:quota-avert";
|
|
466
|
+
if (await PLAYER.limits.allow(avert, 1, 3600)) PLAYER.errors.capture(new Error(`télémétrie externe abandonnée (${body.event}) : quota horaire atteint (${quotaTrack}/h par adresse)`), { route: "track", abandon: true });
|
|
467
|
+
} catch { /* jamais bloquant */ }
|
|
468
|
+
res.statusCode = 200; res.setHeader("Content-Type", "application/json"); res.end('{"ok":true}');
|
|
469
|
+
return;
|
|
454
470
|
}
|
|
455
|
-
|
|
471
|
+
const share = await getShareBySlug(body.slug || slug);
|
|
472
|
+
if (share && !share.is_test) { // répétition générale : la lecture de test ne compte pas dans les stats
|
|
456
473
|
try {
|
|
457
474
|
// 'session' = résumé riche (temps par page, appareil) → upsert ; open/page/heartbeat → journal léger (funnel/overview).
|
|
458
|
-
if (
|
|
475
|
+
if (estSession) await upsertSession(share, { sessionId: body.sessionId, numPages: body.numPages, maxPage: body.maxPage, totalSeconds: body.totalSeconds, pagesTime: body.pagesTime }, { ip: ip0, ua: ua0 });
|
|
459
476
|
else await logView(share, { event: body.event, page: body.page, maxPage: body.maxPage, seconds: body.seconds, sessionId: body.sessionId, ua: ua0 });
|
|
460
477
|
} catch (e) {
|
|
461
478
|
// ⚠️ LE MÊME `catch` MUET, SUR LE CHEMIN EXTERNE. Trouvé par la garde écrite pour
|
|
@@ -44,6 +44,8 @@ __export(shared_exports, {
|
|
|
44
44
|
SESSION_INTERVAL_MS: () => SESSION_INTERVAL_MS,
|
|
45
45
|
SESSION_QUOTA_PER_HOUR: () => SESSION_QUOTA_PER_HOUR,
|
|
46
46
|
SESSION_WRITES_PER_HOUR: () => SESSION_WRITES_PER_HOUR,
|
|
47
|
+
VIEW_EVENTS_PER_READER_HOUR: () => VIEW_EVENTS_PER_READER_HOUR,
|
|
48
|
+
VIEW_QUOTA_PER_HOUR: () => VIEW_QUOTA_PER_HOUR,
|
|
47
49
|
cycleMapType: () => cycleMapType,
|
|
48
50
|
initialMapContent: () => initialMapContent,
|
|
49
51
|
mapTypeLabel: () => mapTypeLabel,
|
|
@@ -105,6 +107,8 @@ var SESSION_INTERVAL_MS = 3e4;
|
|
|
105
107
|
var SESSION_WRITES_PER_HOUR = Math.ceil(36e5 / SESSION_INTERVAL_MS);
|
|
106
108
|
var READERS_PER_EGRESS = 25;
|
|
107
109
|
var SESSION_QUOTA_PER_HOUR = SESSION_WRITES_PER_HOUR * READERS_PER_EGRESS;
|
|
110
|
+
var VIEW_EVENTS_PER_READER_HOUR = 720;
|
|
111
|
+
var VIEW_QUOTA_PER_HOUR = VIEW_EVENTS_PER_READER_HOUR * READERS_PER_EGRESS;
|
|
108
112
|
var SESSION_IDLE_MS = 18e4;
|
|
109
113
|
var PRESENT_RESYNC_MS = 25e3;
|
|
110
114
|
var RESYNC_READS_PER_HOUR = Math.ceil(36e5 / PRESENT_RESYNC_MS);
|
|
@@ -138,6 +142,8 @@ var PRESENT_QUOTA_PER_HOUR = (PRESENT_READS_PER_HOUR + PRESENT_READ_BURST) * REA
|
|
|
138
142
|
SESSION_INTERVAL_MS,
|
|
139
143
|
SESSION_QUOTA_PER_HOUR,
|
|
140
144
|
SESSION_WRITES_PER_HOUR,
|
|
145
|
+
VIEW_EVENTS_PER_READER_HOUR,
|
|
146
|
+
VIEW_QUOTA_PER_HOUR,
|
|
141
147
|
cycleMapType,
|
|
142
148
|
initialMapContent,
|
|
143
149
|
mapTypeLabel,
|