discovery-media-player 0.1.14 → 0.1.16

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/bin/serve.js CHANGED
@@ -50,7 +50,11 @@ function versParametres(url) {
50
50
  return q;
51
51
  }
52
52
 
53
- const AFFICHABLES = new Set([".pdf", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif", ".svg"]);
53
+ // ⚠️ DÉRIVÉE, PAS RECOPIÉE. Cette liste disait encore `.svg` après son retrait de la table des
54
+ // types en 0.1.7 : la page de premier contact proposait un format que la visionneuse ne sait plus
55
+ // ouvrir. Un clic, un téléchargement, et l'impression que le projet ne marche pas — sur l'écran
56
+ // qui ne se rejoue pas.
57
+ const AFFICHABLES = new Set(require("../context/storage").EXTENSIONS_AFFICHABLES);
54
58
 
55
59
  /**
56
60
  * Page d'accueil du mode dossier : ce qu'il y a à lire, et où le prendre.
@@ -229,7 +229,18 @@ async function fetchAllowedFile(url, { range } = {}, { origins, hostBase, root,
229
229
  return fetch(url, { headers });
230
230
  }
231
231
 
232
+ /**
233
+ * Les extensions que le player sait AFFICHER — dérivées de la table ci-dessus, jamais recopiées.
234
+ *
235
+ * ⚠️ `bin/serve.js` en tenait une seconde liste pour sa page d'accueil, et elle contenait encore
236
+ * `.svg` après son retrait en 0.1.7. La page de PREMIER CONTACT proposait donc un format que la
237
+ * visionneuse ne sait plus ouvrir : on clique, et on reçoit un téléchargement. Deux listes du même
238
+ * fait finissent toujours par diverger — celle-ci se déduit.
239
+ */
240
+ const EXTENSIONS_AFFICHABLES = Object.freeze(Object.keys(TYPES));
241
+
232
242
  module.exports = {
243
+ EXTENSIONS_AFFICHABLES,
233
244
  PUBLIC_OBJECT_PREFIX,
234
245
  storageOrigins,
235
246
  hostFetchBase,
@@ -25,11 +25,12 @@ need.
25
25
  {
26
26
  "product": "discovery-media-player",
27
27
  "contract": 1,
28
- "version": "0.1.9",
29
- "capabilities": ["docshare", "presentations", "embed-denied", "host-fetch", "brand-reference", "host-auth", "host-share"],
28
+ "version": "<the running version>",
29
+ "capabilities": ["docshare", "presentations", "embed-denied", "host-fetch", "brand-reference", "host-auth", "host-share", "host-mail"],
30
30
  "frameAncestors": ["'self'", "https://*.vercel.app", "https://app.example.com"],
31
31
  "separateIssuer": true,
32
32
  "hostShare": true,
33
+ "hostMail": true,
33
34
  "plugins": { "bot": false, "visitors": false, "brandIntro": false, "botBrowser": false, "providerQuotas": false }
34
35
  }
35
36
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
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",
package/server/handler.js CHANGED
@@ -1407,7 +1407,27 @@ function viewerHtml(share, nonce, logoUrl, pitch) {
1407
1407
  // INTÉGRÉ (?embed=1) : la visionneuse est en surimpression dans une page hôte de MÊME
1408
1408
  // ORIGINE (le plan d'un lot dans une expérience 3D). L'hôte n'a alors plus besoin de sa
1409
1409
  // propre barre de titre : celle-ci porte la croix, et la sortie remonte en postMessage.
1410
+ // ⚠️ DEUX QUESTIONS DIFFÉRENTES, QU'UNE SEULE VARIABLE CONFONDAIT.
1411
+ //
1412
+ // `embed` décide de l'HABILLAGE : la visionneuse porte sa propre croix, et l'hôte retire sa
1413
+ // barre de titre. L'aperçu a déjà la sienne (`closeBtn`, à droite) — lever la condition
1414
+ // afficherait donc DEUX croix. Le `!preview` n'était pas arbitraire.
1415
+ //
1416
+ // `embedded` répond à l'autre question : cette page est-elle SERVIE dans un cadre ? C'est elle
1417
+ // qui commande la poignée de main. Le serveur le sait déjà — il en tire les `frame-ancestors`
1418
+ // de la réponse — mais le navigateur ne l'apprenait qu'en aperçu de lien tracé.
1419
+ //
1420
+ // ⚠️ Conséquence signalée par le second hôte, et c'est exactement la panne que le contrat
1421
+ // décrit : `embed-ready` n'était jamais émis en aperçu, donc l'hôte recevait un SILENCE. Or le
1422
+ // silence couvre deux cas opposés — instance absente, ou player vivant. Leur guetteur de
1423
+ // démarrage a conclu « injoignable » et remplacé un player qui fonctionnait par la visionneuse
1424
+ // du navigateur, six secondes après l'ouverture, sous les yeux du lecteur. Et l'aperçu est
1425
+ // précisément le mode qu'un hôte utilise pour SES documents.
1426
+ //
1427
+ // La page était pourtant encadrable et parlait déjà (`share`, `close` en postMessage) : il ne
1428
+ // lui manquait que de dire qu'elle était là.
1410
1429
  const embed = !preview && !!share.embed;
1430
+ const embedded = !!share.embed;
1411
1431
  const fileUrl = preview ? share.stream_url : `/api/doc?slug=${encodeURIComponent(share.slug)}&file=1`;
1412
1432
  // Logo de MARQUE du loader : celui du promoteur (brand_logo, ex. MJ
1413
1433
  // Développement) s'il est renseigné, avec la mention de l'éditeur dessous (si configurée)
@@ -1421,7 +1441,7 @@ function viewerHtml(share, nonce, logoUrl, pitch) {
1421
1441
  // En aperçu interne, on embarque de quoi démarrer une présentation live (URL Storage brute + métadonnées).
1422
1442
  // `fileName` : c'est LUI qui dit la nature du document côté page. L'URL publique est
1423
1443
  // `/api/doc?slug=…&file=1`, sans extension — sans ce champ, une image partait dans pdf.js.
1424
- const cfg = JSON.stringify({ brand: PLAYER.branding.name, slug: preview ? "" : share.slug, fileUrl, fileName: share.file_name || "", pdfjs: PDFJS, title, preview, embed, bot: botOn, botGuided: !preview && !!share.bot_enabled && share.bot_guided !== false, botAv: (!preview && share.bot_enabled && share.bot_avatar) || "", botName: (!preview && share.bot_enabled && share.bot_name) || "", botGreet: (!preview && share.bot_enabled && share.bot_greeting) || "", botGreetDoc: (!preview && share.bot_enabled && share.bot_greeting_doc) || "", dl: share.allow_download !== false, autoPresent: !!share.auto_present, botAnim: share.bot_page_anim !== false, botVoice: !preview && !!share.bot_enabled && !!process.env.ELEVENLABS_API_KEY, vIcOn: ICONS.sound, vIcOff: ICONS.mute, kStyle: (!preview && share.bot_enabled && share.bot_karaoke) || "classic", vLayout: (!preview && share.bot_enabled && share.video_layout) || "", vClips: !preview && !!share.bot_vclips, botVAv: (!preview && share.bot_enabled && share.bot_vphoto) || "", resumeSlug: preview ? (share.resume_slug || "") : "", supaUrl: preview ? (share.supa_url || "") : "", supaKey: preview ? (share.supa_key || "") : "", internal: preview && share.internal_email ? { email: share.internal_email, name: share.presenter_name || "", docId: share.doc_id || "" } : null, present: preview ? { url: share.raw_url || "", name: share.file_name || "", title: share.doc_title || "", docId: share.doc_id || "", by: share.presenter_name || "", email: share.internal_email || "", av: share.presenter_avatar || "" } : null });
1444
+ const cfg = JSON.stringify({ brand: PLAYER.branding.name, slug: preview ? "" : share.slug, fileUrl, fileName: share.file_name || "", pdfjs: PDFJS, title, preview, embed, embedded, bot: botOn, botGuided: !preview && !!share.bot_enabled && share.bot_guided !== false, botAv: (!preview && share.bot_enabled && share.bot_avatar) || "", botName: (!preview && share.bot_enabled && share.bot_name) || "", botGreet: (!preview && share.bot_enabled && share.bot_greeting) || "", botGreetDoc: (!preview && share.bot_enabled && share.bot_greeting_doc) || "", dl: share.allow_download !== false, autoPresent: !!share.auto_present, botAnim: share.bot_page_anim !== false, botVoice: !preview && !!share.bot_enabled && !!process.env.ELEVENLABS_API_KEY, vIcOn: ICONS.sound, vIcOff: ICONS.mute, kStyle: (!preview && share.bot_enabled && share.bot_karaoke) || "classic", vLayout: (!preview && share.bot_enabled && share.video_layout) || "", vClips: !preview && !!share.bot_vclips, botVAv: (!preview && share.bot_enabled && share.bot_vphoto) || "", resumeSlug: preview ? (share.resume_slug || "") : "", supaUrl: preview ? (share.supa_url || "") : "", supaKey: preview ? (share.supa_key || "") : "", internal: preview && share.internal_email ? { email: share.internal_email, name: share.presenter_name || "", docId: share.doc_id || "" } : null, present: preview ? { url: share.raw_url || "", name: share.file_name || "", title: share.doc_title || "", docId: share.doc_id || "", by: share.presenter_name || "", email: share.internal_email || "", av: share.presenter_avatar || "" } : null });
1425
1445
  return `<!doctype html><html lang=fr><head><meta charset=utf-8>
1426
1446
  <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=3,viewport-fit=cover,interactive-widget=resizes-content">
1427
1447
  <meta name=robots content="noindex,nofollow">
@@ -1744,7 +1764,7 @@ ${LEGAL_CSS}
1744
1764
  // qu'on est là — sans cette poignée de main elle ne peut pas savoir si la croix
1745
1765
  // existe (visionneuse d'une version antérieure) et garde la sienne par sécurité.
1746
1766
  // Le format du fil, le targetOrigin et la validation vivent dans player/src/bridge.ts.
1747
- if(CFG.embed){
1767
+ if(CFG.embedded){
1748
1768
  Player.bridge.sendToHost({type:'embed-ready'});
1749
1769
  var _xb=document.getElementById('embedCloseBtn');
1750
1770
  if(_xb) _xb.addEventListener('click',function(){ Player.bridge.sendToHost({type:'close'}); });
@@ -2810,7 +2830,7 @@ async function handler(req, res) {
2810
2830
  }
2811
2831
  const supaUrl = (PLAYER.config && PLAYER.config.supabaseUrl) || "";
2812
2832
  const supaKey = (PLAYER.config && PLAYER.config.supabasePublishableKey) || "";
2813
- const pseudo = { preview: true, slug: "", file_name: String(q.name || "document.pdf"), doc_title: String(q.title || q.name || "Document"), raw_url: url, doc_id: String(q.docId || ""), presenter_name: String(q.by || ""), presenter_avatar: String(q.av || ""), internal_email: String(q.uemail || ""), supa_url: supaUrl, supa_key: supaKey, auto_present: String(q.autopresent || "") === "1", resume_slug: String(q.resume || ""), stream_url: `/api/doc?preview=1&stream=1&url=${encodeURIComponent(url)}&name=${encodeURIComponent(String(q.name || ""))}` };
2833
+ const pseudo = { preview: true, embed, slug: "", file_name: String(q.name || "document.pdf"), doc_title: String(q.title || q.name || "Document"), raw_url: url, doc_id: String(q.docId || ""), presenter_name: String(q.by || ""), presenter_avatar: String(q.av || ""), internal_email: String(q.uemail || ""), supa_url: supaUrl, supa_key: supaKey, auto_present: String(q.autopresent || "") === "1", resume_slug: String(q.resume || ""), stream_url: `/api/doc?preview=1&stream=1&url=${encodeURIComponent(url)}&name=${encodeURIComponent(String(q.name || ""))}` };
2814
2834
  let plogo = ""; try { plogo = await PLAYER.branding.logo(); } catch { /* sans logo */ }
2815
2835
  const pnonce = crypto.randomBytes(16).toString("base64");
2816
2836
  // Aperçu interne : CSP relâchée (supabase-js jsdelivr + Realtime wss) pour la présence + le chat live,