discovery-media-player 0.1.140 → 0.1.143
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/docs/HOST-CONTRACT.md +117 -6
- package/package.json +1 -1
- package/server/browser.generated.js +1 -1
- package/server/page-audience.js +13 -6
- package/server/page-visionneuse.js +423 -17
- package/server/presentations.js +51 -3
- package/server/reponses.js +32 -1
- package/server/routes-agent.js +3 -3
- package/server/routes-direct.js +9 -9
- package/server/routes-liens.js +2 -2
- package/server/schema.js +23 -0
- package/supabase/init.sql +99 -1
- package/supabase/migrations/0021-empreintes-de-voix.sql +27 -0
- package/supabase/migrations/0024-rotation-en-direct.sql +34 -0
package/docs/HOST-CONTRACT.md
CHANGED
|
@@ -9,7 +9,7 @@ What a host application may call, what it must implement, and what will not chan
|
|
|
9
9
|
version bump. If you are integrating the player, this page and [`API.md`](https://github.com/Juli1artha/discovery-media-player/blob/main/docs/API.md) are the two you
|
|
10
10
|
need.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Six rules
|
|
13
13
|
|
|
14
14
|
1. **One source of truth.** Fix the player in the player's repository, never in a host — not even
|
|
15
15
|
in a host that once contained it. A fix written host-side is a copy, and copies drift.
|
|
@@ -23,6 +23,15 @@ need.
|
|
|
23
23
|
the context and often the fix. Releasing stays with the maintainer because publishing a version
|
|
24
24
|
decides deploy order. A local workaround is fine when you are blocked, on two conditions: report
|
|
25
25
|
it the same day, and remove it when the release lands.
|
|
26
|
+
6. **Describe what you do — including what you think is trivial.** Not *"report deviations"*: you
|
|
27
|
+
cannot know what one is, because that would mean knowing this page better than we do. ⚠️ The
|
|
28
|
+
over-specified sentence in [the `tts-cache` section](#four-things-that-will-bite) stood for
|
|
29
|
+
weeks, and it took a host mentioning its own naming **as a curiosity** for anyone to look. Its
|
|
30
|
+
own account of it, on 27/08: *"je ne l'ai décrite que parce que je citais `preview-fr-v2` comme
|
|
31
|
+
une curiosité, sans savoir que c'était un écart. Si j'avais su que votre page l'interdisait, je
|
|
32
|
+
me serais probablement conformé."* Complying would have orphaned **908 objects, permanently**.
|
|
33
|
+
A rule that asks you to spot the deviation cannot work; a rule that asks you to describe your
|
|
34
|
+
integration asks for nothing you do not already have. Boring descriptions are the useful ones.
|
|
26
35
|
|
|
27
36
|
## Identity card
|
|
28
37
|
|
|
@@ -54,6 +63,21 @@ need.
|
|
|
54
63
|
never by order. `plugins` lets you refuse to start when you depend on an optional module this
|
|
55
64
|
instance does not have.
|
|
56
65
|
|
|
66
|
+
⚠️ **`ctx.has(name)` is that same question in code — and it is documented here because it was, until
|
|
67
|
+
27/08, an accident.** The injected context carries it: `has(name)` answers whether the named plugin
|
|
68
|
+
is present, the same truth the `plugins` field above reports over HTTP. Supply it as
|
|
69
|
+
`has: (name) => !!plugins[name]`; the standalone context returns `false` for everything, having no
|
|
70
|
+
plugins at all.
|
|
71
|
+
|
|
72
|
+
**As measured on 27/08, nothing in `server/` called it** — that is a reading, not an omission of
|
|
73
|
+
this paragraph, and it is why implementing it buys you nothing immediately and skipping it costs
|
|
74
|
+
you nothing. It is written down for the opposite reason: on that day one host was found to
|
|
75
|
+
implement it *correctly and without knowing*, because the type declared it, while the shape lived
|
|
76
|
+
in 57 test fixtures and, **until this paragraph existed**, in no document at all. A seam that
|
|
77
|
+
exists, works, and is written nowhere is one rename away from being deleted as dead — and it would
|
|
78
|
+
not have been dead. If a future feature needs to ask *"does this host have that plugin?"*, this is
|
|
79
|
+
the spelling, and there should not be a second one.
|
|
80
|
+
|
|
57
81
|
⚠️ **`runtime` is the only way to see what the player is actually running on.** `nodeRequired` is
|
|
58
82
|
the floor the package declares, `node` is what the process reports — two numbers, no verdict:
|
|
59
83
|
compare them with your own semver rather than trusting a field we compute for you.
|
|
@@ -84,6 +108,58 @@ different question when you want a real answer:
|
|
|
84
108
|
GET /api/doc?contract=1&schema=1
|
|
85
109
|
```
|
|
86
110
|
|
|
111
|
+
⚠️ **And if that is what you poll, the lazy verdicts are ones you will never see — which is the
|
|
112
|
+
whole point, and worth knowing before you read a warning aimed at somebody else.** `&schema=1`
|
|
113
|
+
probes every expectation *before answering*, then keeps the answers for the life of the process. So
|
|
114
|
+
its verdict is `complet`, or `indetermine` when the witness row itself does not answer — **never**
|
|
115
|
+
`non-sonde`, and `partiel` only in the window where two of them race. A plain `?contract=1` on that
|
|
116
|
+
same process reports `complet` afterwards too, because the probing already happened.
|
|
117
|
+
|
|
118
|
+
The consequence is a split an integrating host measured on 28/08, having read `complet` for a week
|
|
119
|
+
from a daily cron and put it down to luck: **the readers who need the "do not mistake this for a
|
|
120
|
+
regression" warning and the readers who ever meet it are disjoint.** Poll with `&schema=1` and you
|
|
121
|
+
cannot observe the degradation the warning describes; read `?contract=1` alone and you meet it
|
|
122
|
+
without having asked for a probe. Neither is a defect. But if you are checking that warning against
|
|
123
|
+
what you see, and you poll with `&schema=1`, **your instance is not the one it is about**.
|
|
124
|
+
|
|
125
|
+
⚠️ **`complet` means complete *for the code you are running*, never complete for the repository —
|
|
126
|
+
and `connues` is there so you do not have to take that on trust.** The expectation list is compiled
|
|
127
|
+
into the player. A migration published after your version does not appear in it, is never probed,
|
|
128
|
+
and can therefore never turn `manquant` red. So a host who applies the schema **before** upgrading
|
|
129
|
+
the code — the safe order, the one we recommend — is exactly the host this green does not inform.
|
|
130
|
+
|
|
131
|
+
The STUDIO host measured it on both sides on 30/08: on `0.1.142` they applied migration 0024, re-read
|
|
132
|
+
the card, and got `attendues: 9 · sondees: 9 · complet · manquant: []` — word for word what they had
|
|
133
|
+
read *before* applying it. They could not watch 0024 leave a list it had never entered.
|
|
134
|
+
|
|
135
|
+
No version of this server can know a migration that postdates it. What it can do, and now does, is
|
|
136
|
+
say what it knows:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
"schema": {
|
|
140
|
+
"couvre": "colonnes-conditionnelles",
|
|
141
|
+
"attendues": 10, "sondees": 10, "verdict": "complet", "manquant": [],
|
|
142
|
+
"connues": ["supabase/migrations/0001-destinataire-atteste.sql", "…", "supabase/migrations/0024-rotation-en-direct.sql"]
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Read it this way, in this order:
|
|
147
|
+
|
|
148
|
+
1. **Is the migration you care about in `connues`?** If not, this card cannot speak about it, whatever
|
|
149
|
+
`verdict` says. Upgrade the player, or check the database directly (below).
|
|
150
|
+
2. **Only then** does `verdict` answer for it. `manquant` names its files in the same strings as
|
|
151
|
+
`connues`, so membership is a plain comparison and not an inference about our release history.
|
|
152
|
+
|
|
153
|
+
⚠️ **To check a migration this player does not know about, ask the database, not the card.** The
|
|
154
|
+
query does not depend on which version you are running, which is the only case where you need an
|
|
155
|
+
answer:
|
|
156
|
+
|
|
157
|
+
```sql
|
|
158
|
+
select column_name, data_type, is_nullable, column_default
|
|
159
|
+
from information_schema.columns
|
|
160
|
+
where table_name = 'doc_presentations' and column_name = 'view_rotation';
|
|
161
|
+
```
|
|
162
|
+
|
|
87
163
|
The three `presence*` fields report what the host has **observed**, not what it is configured to do:
|
|
88
164
|
|
|
89
165
|
| field | meaning |
|
|
@@ -217,10 +293,20 @@ it. `verdict` is then one of:
|
|
|
217
293
|
|
|
218
294
|
| verdict | meaning |
|
|
219
295
|
|---|---|
|
|
220
|
-
| `non-sonde` | nothing asked yet — **not** *nothing missing
|
|
221
|
-
| `partiel` | some
|
|
296
|
+
| `non-sonde` | nothing asked yet — **not** *nothing missing*, and **process-local**: this process has looked at nothing; another instance may have looked at everything |
|
|
297
|
+
| `partiel` | some checked, none of them missing — the probe is **lazy**: a column is inspected only once something touches it, so this is *how much has been exercised*, never *how much exists* |
|
|
222
298
|
| `complet` | all checked, all present |
|
|
223
299
|
| `incomplet` | at least one is missing — `manquant` names the file and the sleeping feature |
|
|
300
|
+
| `indetermine` | the database did not answer; this measurement did not happen |
|
|
301
|
+
|
|
302
|
+
⚠️ **The first two rows are one trap, and it fires on every deploy.** Because the probe is lazy and
|
|
303
|
+
lives in the process, a fresh instance answers `non-sonde`, then `partiel`, then `complet` as
|
|
304
|
+
traffic exercises columns — on a database that never changed. Measured at an integrating host on
|
|
305
|
+
27/08, on one unchanged base: `sondees=9 complet` on the old instance, `sondees=0 non-sonde` right
|
|
306
|
+
after the deploy, `sondees=1 partiel` sixty-seven minutes later. They looked three times before
|
|
307
|
+
concluding, because a neighbouring field had already taught them to distrust that zero — and they
|
|
308
|
+
were about to report a regression that did not exist. Read these two verdicts as *what this
|
|
309
|
+
process has asked so far*, never as a statement about the schema.
|
|
224
310
|
|
|
225
311
|
Each `manquant` entry has **exactly this shape** — pin your parser to it, not to what a schema
|
|
226
312
|
probe "should" return:
|
|
@@ -240,7 +326,6 @@ If you consume this card, test your parser against the JSON above, not against a
|
|
|
240
326
|
⚠️ **A card without a `schema` field is an alert, not a success**: it signals an instance older
|
|
241
327
|
than 0.1.58 — a version that cannot answer the question. (Rule contributed by the second host, for
|
|
242
328
|
exactly the monitoring case where "no data" would otherwise read as "all clear".)
|
|
243
|
-
| `indetermine` | the database did not answer; this measurement did not happen |
|
|
244
329
|
|
|
245
330
|
⚠️ **`incomplet` wins over `partiel`**: a missing column is a positive fact and settles the verdict
|
|
246
331
|
on its own, even when the rest has not been checked.
|
|
@@ -540,13 +625,39 @@ This is not hypothetical: an integrating host reported 908 objects it had writte
|
|
|
540
625
|
the parity was deliberate, so that one clip serves both surfaces. Nothing about the name distinguishes
|
|
541
626
|
its objects from the player's; only the missing row does.
|
|
542
627
|
|
|
543
|
-
So `doc_tts_objects` is a **host write point**, not an internal table.
|
|
544
|
-
|
|
628
|
+
So `doc_tts_objects` is a **host write point**, not an internal table. What the sweep needs from
|
|
629
|
+
you is **one property, and only this one**:
|
|
630
|
+
|
|
631
|
+
> the `hash` you write in the row **is** the object's base name — the file is `<hash>.mp3`, its
|
|
632
|
+
> alignment is `<hash>.json`, and nothing else has to be true.
|
|
633
|
+
|
|
634
|
+
⚠️ **How you compute that digest is yours, and this page used to say otherwise.** It read *"write
|
|
635
|
+
it with the same fingerprint the player computes, and nothing else"*, which made a perfectly safe
|
|
636
|
+
host non-compliant on paper — and the obvious fix, realigning the formula, is the one thing that
|
|
637
|
+
would break: the objects already in the bucket carry the **old** digest in their names, so a row
|
|
638
|
+
written with a new one points at nothing, and the real name loses its only row. Reported on 27/08
|
|
639
|
+
by a host whose third writer uses `preview-fr-v2` where the player uses `v2`. Their five write
|
|
640
|
+
sites are correct as they stand.
|
|
641
|
+
|
|
642
|
+
The sweep never recomputes anything: it reads `hash` from the row and removes `hash + ".mp3"` and
|
|
643
|
+
`hash + ".json"` (`server/retention.js`). A bench holds that property rather than a comment —
|
|
644
|
+
`retentionCacheDeVoix.test.js` builds its rows with `hash: "aaa"`, which is the sha256 of nothing,
|
|
645
|
+
and requires `tts-cache/aaa.mp3` to be the file removed.
|
|
646
|
+
|
|
647
|
+
**The player's own formula matters for one thing only, and it is not retention** — sharing. Its
|
|
648
|
+
route recomputes this digest to find a clip it already paid for, so match it *if* you want one clip
|
|
649
|
+
to serve both surfaces (as one host deliberately does, for 908 objects). If you don't, the player
|
|
650
|
+
simply synthesises its own, and nothing else changes:
|
|
545
651
|
|
|
546
652
|
```
|
|
547
653
|
hash = sha256(voiceId + "|" + modelId + "|v2|" + spokenText) -- hex, lowercase
|
|
548
654
|
```
|
|
549
655
|
|
|
656
|
+
| requirement | mandatory? | if you don't |
|
|
657
|
+
|---|---|---|
|
|
658
|
+
| the row's `hash` is the object's base name | **yes, always** | the object is invisible to the sweep, permanently |
|
|
659
|
+
| the digest matches the player's formula | no — only to share a clip | the player synthesises its own, and pays for it |
|
|
660
|
+
|
|
550
661
|
```sql
|
|
551
662
|
insert into public.doc_tts_objects (hash) values ($1)
|
|
552
663
|
on conflict (hash) do nothing;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discovery-media-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.143",
|
|
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",
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
// Injecté par api/doc.js dans un <script nonce=…> de la visionneuse. Le code navigateur du
|
|
7
7
|
// player vit en modules TypeScript testés sous player/src/ — c'est ici qu'il atterrit.
|
|
8
8
|
"use strict";
|
|
9
|
-
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: "483d392a214f6bf8" };
|
|
9
|
+
module.exports = { PLAYER_BROWSER_JS: "\"use strict\";var Player=(()=>{var O=Object.defineProperty,Be=Object.defineProperties,je=Object.getOwnPropertyDescriptor,Ge=Object.getOwnPropertyDescriptors,Ke=Object.getOwnPropertyNames,Me=Object.getOwnPropertySymbols;var _e=Object.prototype.hasOwnProperty,Ye=Object.prototype.propertyIsEnumerable;var we=(e,n,t)=>n in e?O(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,Z=(e,n)=>{for(var t in n||(n={}))_e.call(n,t)&&we(e,t,n[t]);if(Me)for(var t of Me(n))Ye.call(n,t)&&we(e,t,n[t]);return e},Ee=(e,n)=>Be(e,Ge(n));var M=(e,n)=>{for(var t in n)O(e,t,{get:n[t],enumerable:!0})},Ze=(e,n,t,r)=>{if(n&&typeof n==\"object\"||typeof n==\"function\")for(let o of Ke(n))!_e.call(e,o)&&o!==t&&O(e,o,{get:()=>n[o],enumerable:!(r=je(n,o))||r.enumerable});return e};var qe=e=>Ze(O({},\"__esModule\",{value:!0}),e);var Jn={};M(Jn,{bridge:()=>L,cadence:()=>H,chat:()=>W,live:()=>D,presentation:()=>V,presentationState:()=>F,tracking:()=>U,viewer:()=>z});var L={};M(L,{onHostMessage:()=>an,onPlayerMessage:()=>sn,parseHostMessage:()=>ke,parsePlayerMessage:()=>Se,sendToHost:()=>tn,sendToPlayer:()=>rn,toWire:()=>Q});var q=\"3dd-doc-\",Qe=/^[A-Za-z0-9_-]{1,64}$/,Xe=[\"close\",\"share\",\"embed-ready\",\"present-left\",\"present-denied\"],Je=[\"embed-denied\"],en=[\"present-invite\",\"present-handover\",\"present-switch\"],nn=[\"handover-done\"];function Q(e){let n={type:q+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(q))return null;let o=r.slice(q.length);if(n.includes(o))return{type:o};if(Je.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\"||!Qe.test(s)?null:{type:o,slug:s}}function Se(e){return Te(e,Xe,en)}function ke(e){return Te(e,nn,[])}function tn(e,n){try{let t=n||(typeof window!=\"undefined\"?window.parent:null);t&&t.postMessage(Q(e),\"*\")}catch(t){}}function rn(e,n){var t;try{(t=e==null?void 0:e.contentWindow)==null||t.postMessage(Q(n),\"*\")}catch(r){}}function on(e,n){var r;if(!e)return!0;let t=(r=e.contentWindow)!=null?r:e;return n===t}function sn(e,n,t){let r=n||(typeof window!=\"undefined\"?window:null);if(!r)return()=>{};let o=s=>{if(!on(t,s.source))return;let a=Se(s.data);a&&e(a)};return r.addEventListener(\"message\",o),()=>r.removeEventListener(\"message\",o)}function an(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 u=ke(a.data);u&&e(u)};return t.addEventListener(\"message\",o),()=>t.removeEventListener(\"message\",o)}var U={};M(U,{createTracker:()=>bn});var H={};M(H,{PRESENTER_ACTIONS_PER_HOUR:()=>ee,PRESENT_CACHE_MS:()=>dn,PRESENT_QUOTA_MARGIN:()=>Le,PRESENT_QUOTA_PER_HOUR:()=>pn,PRESENT_READS_PER_HOUR:()=>Ce,PRESENT_READ_BURST:()=>Ne,PRESENT_READ_COALESCE_MS:()=>Oe,PRESENT_RESYNC_MS:()=>Ie,PRESENT_SIGNAL_BUDGET_PER_HOUR:()=>cn,PRESENT_WRITE_TIMEOUT_MS:()=>ne,READERS_PER_EGRESS:()=>$,RESYNC_READS_PER_HOUR:()=>Pe,SESSION_IDLE_MS:()=>J,SESSION_INTERVAL_MS:()=>X,SESSION_QUOTA_PER_HOUR:()=>un,SESSION_WRITES_PER_HOUR:()=>Re,VIEW_EVENTS_PER_READER_HOUR:()=>Ae,VIEW_QUOTA_PER_HOUR:()=>ln});var X=3e4,Re=Math.ceil(120),$=25,un=Re*$,Ae=720,ln=Ae*$,J=18e4,Ie=25e3,Pe=Math.ceil(36e5/Ie),ee=720,Ce=Pe+ee,cn=ee,Ne=20,ne=1e4,Oe=400,dn=Oe,Le=4,pn=(Ce+Ne)*$*Le;var mn=[\"mousemove\",\"mousedown\",\"keydown\",\"wheel\",\"touchstart\",\"pointerdown\"];function fn(){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 gn(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 bn(e={}){var ye,xe;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:J,a=(xe=e.sessionEveryMs)!=null?xe:3e4,u=e.slug||\"\",p=e.internal||null,d=e.sessionId||fn(),m=e.send||gn(o,n),c={},l=0,b=0,f=0,w=0,v=null,S=r(),k=!1,B=!1,C=[],Fe=()=>!!u||!!p,pe=i=>{if(!Fe())return!1;try{return m(i)!==!1}catch(g){return!1}},j=()=>!!t&&t.visibilityState===\"visible\"&&!k,me=i=>{let g=r()-i,y=Math.max(0,S-i)+s;return Math.max(0,Math.min(g,y))},G=()=>{v!=null&&l>0&&(c[l]=(c[l]||0)+me(v)/1e3),v=j()?r():null},fe=()=>{G(),v=null},K=()=>{v==null&&j()&&(v=r())},Y=()=>{let i=0;for(let g in c)i+=c[g];return v!=null&&(i+=me(v)/1e3),Math.round(i)},ge=()=>{let i={};for(let g in c)i[g]=Math.round(c[g]);return i},R=()=>{S=r(),k&&(k=!1,K())},be=(i,g)=>{p||pe({slug:u,event:i,page:g||b,maxPage:f,seconds:Y(),sessionId:d})},he=\"\",N=()=>{G();let i=Y(),g=`${i}|${f}|${w}`;if(g===he)return;let y={event:\"session\",sessionId:d,numPages:w,maxPage:f,totalSeconds:i,pagesTime:ge()};p?(y.internal=!0,y.docId=p.docId,y.email=p.email,y.name=p.name,p.it&&(y.it=p.it)):y.slug=u,pe(y)&&(he=g)},A=(i,g,y,ve)=>{!i||typeof i.addEventListener!=\"function\"||(i.addEventListener(g,y,ve),C.push(()=>{i.removeEventListener(g,y,ve)}))};return{sessionId:d,totalSeconds:Y,maxPage:()=>f,pageTimes:ge,start(){if(B)return;B=!0,be(\"open\",1),l=1,S=r(),v=j()?r():null,A(t,\"visibilitychange\",()=>{t.visibilityState===\"hidden\"?(fe(),N()):(R(),K())}),A(n,\"focus\",()=>{R(),K()});for(let y of mn)A(n,y,R,{passive:!0});A(e.scrollElement,\"scroll\",R,{passive:!0}),A(n,\"beforeunload\",N);let i=n.setInterval(()=>{!k&&r()-S>s&&(k=!0,fe())},5e3),g=n.setInterval(N,a);C.push(()=>{n.clearInterval(i),n.clearInterval(g)})},setPage(i){!i||i===b||(S=r(),G(),l=i,b=i,i>f&&(f=i,be(\"page\",i)))},setPageCount(i){w=i||0},noteActivity:R,flush:N,stop(){for(;C.length;){let i=C.pop();try{i==null||i()}catch(g){}}B=!1}}}var D={};M(D,{STORAGE_KEYS:()=>_,attendeeKey:()=>vn,authorToken:()=>Mn,avatarHtml:()=>te,canModerate:()=>ie,createBudget:()=>Rn,createFileEcritures:()=>An,createScheduler:()=>Sn,escapeHtml:()=>x,fetchBorne:()=>kn,flattenPresence:()=>hn,formatMessageBody:()=>re,initials:()=>$e,isMentioned:()=>_n,isMine:()=>E,presenceId:()=>In,reactorId:()=>se,referenceAuteur:()=>wn,shouldNotify:()=>En,unreadLabel:()=>Tn});var _={attendeeKey:\"3dd-present-attkey\",authorToken:\"3dd-present-authtoken\",chatMuted:\"3dd-present-mute\",presenceId:\"3dd-present-uid\"};function x(e){return String(e==null?\"\":e).replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\").replace(/\"/g,\""\")}function $e(e){let n=(e||\"?\").trim().split(/\\s+/);return(((n[0]||\"\")[0]||\"?\")+((n[1]||\"\")[0]||\"\")).toUpperCase()}function te(e,n){return e?`<img src=\"${x(e)}\" alt=\"\">`:x($e(n))}function re(e){let n=x(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 hn(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 yn(e,n){try{return e?e.getItem(n):null}catch(t){return null}}function xn(e,n,t){try{e==null||e.setItem(n,t)}catch(r){}}function vn(e,n=\"anon\",t=oe){try{if(!e)return`anon-${n}`;let r=e.getItem(_.attendeeKey);if(r)return r;let o=`anon-${t()}`;return e.setItem(_.attendeeKey,o),o}catch(r){return`anon-${n}`}}function oe(){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 Mn(e,n=oe){let t=yn(e,_.authorToken);if(t)return t;let r=n();return xn(e,_.authorToken,r),r}async function wn(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 se(e){return String(e&&e.ref||\"\")}function E(e,n){return!e||!n||!e.author_ref||!n.ref?!1:e.author_ref===n.ref}function ie(e){return!!(e&&e.role===\"presenter\")}function _n(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(e,n):!1}function En(e){let{msg:n,me:t,historyLoaded:r,chatHidden:o}=e;return!r||!n||n.deleted||E(n,t)?!1:o}function Tn(e){return!e||e<=0?\"\":e>9?\"9+\":String(e)}function Sn(e,n={}){var b;let t=(b=n.minMs)!=null?b:300,r=n.now||(()=>Date.now()),o=n.setTimer||((f,w)=>setTimeout(f,w)),s=n.clearTimer||(f=>clearTimeout(f)),a=!1,u=!1,p=-1/0,d=null,m=!1;function c(){if(m||a){u=!0;return}let f=t-(r()-p);if(f>0){l(f);return}a=!0,u=!1,p=r();let w=!1;e(()=>{w||(w=!0,a=!1,u&&!m&&c())})}function l(f){m||d!==null||(d=o(()=>{d=null,c()},Math.max(0,f)))}return{signaler(){m||c()},maintenant(){m||(p=-1/0,c())},arreter(){m=!0,d!==null&&(s(d),d=null)}}}function kn(e,n,t=ne,r={}){let o=r.fetch||(typeof fetch==\"function\"?fetch:void 0);if(!o)return Promise.reject(new Error(\"fetch indisponible\"));let s=r.setTimer||((l,b)=>setTimeout(l,b)),a=r.clearTimer||(l=>clearTimeout(l)),u=null;try{u=new AbortController}catch(l){}let p=u?Ee(Z({},n||{}),{signal:u.signal}):Z({},n||{}),d=null,m=new Promise((l,b)=>{d=s(()=>{try{u==null||u.abort()}catch(f){}b(new Error(\"delai\"))},t)}),c=()=>{try{a(d)}catch(l){}};return Promise.race([o(e,p),m]).then(l=>(c(),l),l=>{throw c(),l})}function Rn(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 An(e={}){var d;let n=(d=e.minMs)!=null?d:0,t=e.now||(()=>Date.now()),r=e.setTimer||((m,c)=>setTimeout(m,c)),o=new Map,s=!1,a=-1/0,u=!1;function p(){if(s||o.size===0)return;let m=n-(t()-a);if(m>0){if(u)return;u=!0,r(()=>{u=!1,p()},m);return}let c=o.keys().next().value,l=o.get(c);o.delete(c),s=!0,a=t(),Promise.resolve().then(l.tache).then(b=>l.regler(b),()=>l.regler(null)).then(()=>{s=!1,p()})}return{poser(m,c){return new Promise(l=>{let b=o.get(m);o.set(m,{tache:c,regler:f=>{b&&b.regler(f),l(f)}}),p()})},enAttente:()=>o.size}}function In(e,n=oe){try{if(e){let t=e.getItem(_.presenceId);if(t)return t;let r=`p-${n()}`;return e.setItem(_.presenceId,r),r}}catch(t){}return`p-${n()}`}var W={};M(W,{messageClassName:()=>Cn,renderActions:()=>De,renderAttachment:()=>Ue,renderMessage:()=>Pn,renderReactions:()=>He});function He(e,n){let t=e&&e.reactions||{},r=se(n),o=\"\";for(let s in t){let a=t[s]||[];if(!a.length)continue;let u=a.indexOf(r)>=0;o+=`<button class=\"re-chip${u?\" on\":\"\"}\" data-e=\"${x(s)}\">${x(s)} ${a.length}</button>`}return o}function Ue(e){if(!e||!e.url)return\"\";let n=x(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=x(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 De(e,n){let t=E(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||ie(n.me))&&(r+='<button class=cm-del-btn title=\"Supprimer\">\\u{1F5D1}</button>'),r}function Pn(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>${x(e.reply_name||\"\")}</b> ${x(e.reply_text||\"\")}</div>`:\"\",r=e.edited?\" <span class=cm-ed>(modifi\\xE9)</span>\":\"\",o=e.body?`<div class=txt>${re(e.body)}${r}</div>`:\"\",s=e.is_presenter?\" <span class=tag>pr\\xE9sentateur</span>\":\"\";return`<span class=a>${te(e.author_avatar,e.author_name)}</span><span class=b><div class=who><b>${x(e.author_name||\"Invit\\xE9\")}</b>${s}</div>`+t+o+Ue(e.attachment)+`<div class=cm-re>${He(e,n.me)}</div></span><span class=cm-act>${De(e,n)}</span>`}function Cn(e,n,t){return\"cm\"+(E(e,n)?\" me\":\"\")+(e.deleted?\" isdel\":\"\")+(t?\" mentioned\":\"\")}var V={};M(V,{DEFAULT_CENTER:()=>le,DEFAULT_ZOOM:()=>ce,MAP_TYPES:()=>I,cycleMapType:()=>Nn,initialMapContent:()=>Ln,mapTypeLabel:()=>On,sanitizeContent:()=>de});var I=[\"roadmap\",\"satellite\",\"hybrid\"],le=[46.6,2.5],ce=6;function T(e){let n=Number(e);return Number.isFinite(n)?n:null}function ae(e){if(!Array.isArray(e))return null;let n=T(e[0]),t=T(e[1]);return n!=null&&t!=null?[n,t]:null}var ue=(e,n,t)=>Math.max(n,Math.min(t,e));function de(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=ae(n.position);if(!t)return null;let r=n.pov&&typeof n.pov==\"object\"?n.pov:null,o=r?{heading:T(r.heading)||0,pitch:ue(T(r.pitch)||0,-90,90)}:{heading:0,pitch:0};return{kind:\"streetview\",position:t,pov:o,zoom:ue(T(n.zoom)||1,0,5)}}return n.kind!==\"map\"?null:{kind:\"map\",center:ae(n.center)||[...le],zoom:ue(Math.trunc(T(n.zoom)||ce),1,21),marker:ae(n.marker),mapType:I.includes(n.mapType)?n.mapType:null,label:String(n.label||\"\").slice(0,160)||null}}function Nn(e){let n=I.indexOf(e);return I[(n+1)%I.length]}function On(e){return e===\"roadmap\"?\"\\u{1F6F0} Satellite\":e===\"satellite\"?\"\\u{1F5FA} Hybride\":\"\\u{1F5FA} Plan\"}function Ln(){return{kind:\"map\",center:[...le],zoom:ce,marker:null,mapType:null,label:null}}var z={};M(z,{CURRENT_PAGE_MARGIN:()=>Vn,DEFAULT_ASPECT:()=>Un,MAX_ZOOM:()=>Hn,MIN_PAGE_WIDTH:()=>Dn,MIN_ZOOM:()=>$n,PRERENDER_MARGIN:()=>Wn,ROTATIONS:()=>Zn,ancrageApresZoom:()=>qn,arrowState:()=>Bn,aspectApresRotation:()=>ze,averageColor:()=>Kn,clampPage:()=>Ve,clampZoom:()=>zn,fitWidth:()=>Gn,isImageDocument:()=>Yn,progressPercent:()=>Fn,rotationEffective:()=>P});var $n=.5,Hn=3,Un=1.35,Dn=280,Wn=\"500px 0px\",Vn=\"-48% 0px -48% 0px\";function zn(e){let n=Math.round((Number(e)||0)*10)/10;return Math.max(.5,Math.min(3,n))}function Ve(e,n){return Math.max(1,Math.min(n||1,Number(e)||1))}function Fn(e,n){return n?Math.round(Ve(e,n)/n*100):0}function Bn(e,n){return{prevDisabled:e<=1,nextDisabled:!!n&&e>=n}}var jn=28;function Gn(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=ze(e.aspect,e.rotation),s=((e.containerHeight||600)-jn-(e.overlap||0)-(e.reserve||0))/r;return s>120?Math.min(t,s):t}function Kn(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 Yn(e,n){return/[.](png|jpe?g|webp|gif|avif)($|[?])/i.test(String(e||n||\"\"))}var Zn=[0,90,180,270],h=(e,n=0)=>typeof e==\"number\"&&Number.isFinite(e)?e:n;function P(e,n){return(Math.round((h(e)+h(n))/90)%4+4)%4*90}function ze(e,n){let t=h(e,0)>0?e:1.35,r=P(0,n);return r===90||r===270?1/t:t}function We(e,n,t,r,o,s,a){let u=Math.min(Math.max(0,o),Math.max(0,r)),p=u+Math.max(0,r-u)*a,d=Math.min(Math.max(0,s),Math.max(0,r)),m=r-d>0?(p-d)/(r-d):1,c=Math.max(0,(t-r)/2),l=n+e-c,b=d+Math.max(0,l-d)*m-n;return Math.min(Math.max(0,b),Math.max(0,p-t))}function qn(e){let n=h(e.zoomAvant,0),t=h(e.zoomApres,0),r={x:h(e.defilement&&e.defilement.x),y:h(e.defilement&&e.defilement.y)};if(n<=0||t<=0)return r;let o=t/n,s=e.fixe||{largeur:0,hauteur:0},a=e.fixeDebut||{largeur:0,hauteur:0};return{x:We(r.x,h(e.point&&e.point.x),h(e.cadre&&e.cadre.largeur),h(e.contenu&&e.contenu.largeur),h(s.largeur),h(a.largeur),o),y:We(r.y,h(e.point&&e.point.y),h(e.cadre&&e.cadre.hauteur),h(e.contenu&&e.contenu.hauteur),h(s.hauteur),h(a.hauteur),o)}}var F={};M(F,{presentationTransition:()=>Qn,switchDocUrl:()=>Xn});function Qn(e,n={}){if(!e)return[{kind:\"nothing\"}];if(e.active===!1)return[{kind:\"ended\"}];let t=de(e.content);if(t)return[{kind:\"show-map\",content:t}];let r=[{kind:\"leave-map\"}],o=P(0,e.view_rotation);return o!==P(0,n.rotation)&&r.push({kind:\"rotate\",rotation:o}),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 Xn(e,n){let t=encodeURIComponent(n||String(Date.now()));return`${e}${e.includes(\"?\")?\"&\":\"?\"}v=${t}`}return qe(Jn);})();", SOURCE_HASH: "720cf1b3ec849d63" };
|
package/server/page-audience.js
CHANGED
|
@@ -20,7 +20,7 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
|
|
|
20
20
|
const presenter = esc(pres.presenter_name || "");
|
|
21
21
|
const logo = esc(logoUrl || "");
|
|
22
22
|
const fileUrl = `/api/doc?present=${encodeURIComponent(pres.slug)}&file=1`;
|
|
23
|
-
const cfg = jsonPourScript({ fileUrl, docUrl: pres.file_url, pdfjs: PDFJS, pdfjsWorker: PDFJS_WORKER, slug: pres.slug, fileName: pres.file_name || "", page: pres.current_page || 1, active: pres.active !== false, content: pres.content || null, supaUrl, supaKey, title: pres.doc_title || pres.file_name || "Document" });
|
|
23
|
+
const cfg = jsonPourScript({ fileUrl, docUrl: pres.file_url, pdfjs: PDFJS, pdfjsWorker: PDFJS_WORKER, slug: pres.slug, fileName: pres.file_name || "", page: pres.current_page || 1, rotation: pres.view_rotation || 0, active: pres.active !== false, content: pres.content || null, supaUrl, supaKey, title: pres.doc_title || pres.file_name || "Document" });
|
|
24
24
|
return `<!doctype html><html lang=fr><head><meta charset=utf-8>
|
|
25
25
|
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=3">
|
|
26
26
|
<meta name=robots content="noindex,nofollow">
|
|
@@ -95,7 +95,7 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
|
|
|
95
95
|
<script nonce="${nonce}">
|
|
96
96
|
(function(){
|
|
97
97
|
var CFG=${cfg};
|
|
98
|
-
var PDF=null, total=0, cur=CFG.page||1, ready=false;
|
|
98
|
+
var PDF=null, total=0, cur=CFG.page||1, rot=CFG.rotation||0, ready=false;
|
|
99
99
|
// ⚠️ DEUX GÉNÉRATIONS, PARCE QU'IL Y A DEUX COURSES DISTINCTES (P1 audit externe).
|
|
100
100
|
//
|
|
101
101
|
// docGen : le présentateur change de document pendant qu'un chargement est en cours. Le
|
|
@@ -137,9 +137,13 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
|
|
|
137
137
|
// arrivait : ce résultat n'est plus celui qu'on attend. On ne le pose pas.
|
|
138
138
|
if(monDoc!==docGen || monRendu!==renderGen) return;
|
|
139
139
|
var availW=Math.max(120, stage.clientWidth-40), availH=Math.max(120, stage.clientHeight-40);
|
|
140
|
-
|
|
140
|
+
// ⚠️ ON COMPOSE, ON N'ÉCRASE PAS — même piège que dans la visionneuse. getViewport prend par
|
|
141
|
+
// défaut la rotation du fichier ; passer une valeur absolue coucherait un document numérisé qui
|
|
142
|
+
// était droit. La composition vit dans src/viewer.ts, où elle est éprouvée.
|
|
143
|
+
var rotEff=Player.viewer.rotationEffective(page.rotate,rot);
|
|
144
|
+
var v1=page.getViewport({scale:1,rotation:rotEff});
|
|
141
145
|
var scale=Math.min(availW/v1.width, availH/v1.height); // fit entier → une page à l'écran
|
|
142
|
-
var dpr=window.devicePixelRatio||1, vp=page.getViewport({scale:scale});
|
|
146
|
+
var dpr=window.devicePixelRatio||1, vp=page.getViewport({scale:scale,rotation:rotEff});
|
|
143
147
|
var cv=document.createElement('canvas'); cv.width=Math.floor(vp.width*dpr); cv.height=Math.floor(vp.height*dpr);
|
|
144
148
|
cv.setAttribute('role','img'); cv.setAttribute('aria-label','Page '+n+(total>1?' sur '+total:''));
|
|
145
149
|
cv.style.width=vp.width+'px'; cv.style.height=vp.height+'px';
|
|
@@ -282,10 +286,10 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
|
|
|
282
286
|
if(!row) return;
|
|
283
287
|
// La table et la diffusion portent la même vérité : sans cette garde, chaque changement de
|
|
284
288
|
// page serait rendu deux fois (scintillement), et chaque carte ré-ouverte inutilement.
|
|
285
|
-
var sig=''; try{ sig=JSON.stringify([row.active,row.current_page,row.file_url,row.content]); }catch(e){ sig=String(Math.random()); }
|
|
289
|
+
var sig=''; try{ sig=JSON.stringify([row.active,row.current_page,row.file_url,row.content,row.view_rotation]); }catch(e){ sig=String(Math.random()); }
|
|
286
290
|
if(sig===_etatVu) return;
|
|
287
291
|
_etatVu=sig;
|
|
288
|
-
var actions=Player.presentationState.presentationTransition(row,{docUrl:CFG.docUrl});
|
|
292
|
+
var actions=Player.presentationState.presentationTransition(row,{docUrl:CFG.docUrl,rotation:rot});
|
|
289
293
|
for(var i=0;i<actions.length;i++){ var a=actions[i];
|
|
290
294
|
if(a.kind==='ended'){ ended(); return; }
|
|
291
295
|
if(a.kind==='show-map'){ if(window.Map3DD){ if(a.content.kind==='streetview') Map3DD.enterSV(a.content,false); else Map3DD.enter(a.content,false); } return; }
|
|
@@ -293,6 +297,9 @@ function presentHtml(pres, nonce, logoUrl, supaUrl, supaKey) {
|
|
|
293
297
|
// switchDoc pose LUI-MÊME docUrl/fileName/titre : les poser ici, en partie, était
|
|
294
298
|
// exactement ce qui laissait fileName en arrière.
|
|
295
299
|
if(a.kind==='switch-doc'){ switchDoc(row); return; }
|
|
300
|
+
// ⚠️ AVANT la page, et c'est l'ordre que presentationTransition garantit : tourner après avoir
|
|
301
|
+
// rendu ferait rendre deux fois, la première fois pour rien.
|
|
302
|
+
if(a.kind==='rotate'){ rot=a.rotation; renderGen++; show(cur); }
|
|
296
303
|
if(a.kind==='show-page'){ show(a.page); }
|
|
297
304
|
}
|
|
298
305
|
}
|