discovery-media-player 0.1.114 → 0.1.116

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.114",
3
+ "version": "0.1.116",
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",
@@ -66,7 +66,8 @@
66
66
  "typecheck": "node -e \"require('fs').existsSync('tsconfig.json')||(console.error('Ce script ne vit pas dans le paquet publié - le champ scripts annonce plus que le tarball ne contient. Clonez le depot puis npm ci : https://github.com/Juli1artha/discovery-media-player'),process.exit(1))\" && tsc --noEmit",
67
67
  "prepublishOnly": "npm run build && npm test",
68
68
  "test:e2e": "node -e \"require('fs').existsSync('vitest.e2e.config.mjs')||(console.error('Ce banc ne vit pas dans le paquet publié - le champ scripts annonce plus que le tarball ne contient. Clonez le depot puis npm ci : https://github.com/Juli1artha/discovery-media-player'),process.exit(1))\" && vitest run --config vitest.e2e.config.mjs",
69
- "test:base": "node -e \"require('fs').existsSync('vitest.base.config.mjs')||(console.error('Ce banc ne vit pas dans le paquet publié - le champ scripts annonce plus que le tarball ne contient. Clonez le depot puis npm ci : https://github.com/Juli1artha/discovery-media-player'),process.exit(1))\" && vitest run --config vitest.base.config.mjs"
69
+ "test:base": "node -e \"require('fs').existsSync('vitest.base.config.mjs')||(console.error('Ce banc ne vit pas dans le paquet publié - le champ scripts annonce plus que le tarball ne contient. Clonez le depot puis npm ci : https://github.com/Juli1artha/discovery-media-player'),process.exit(1))\" && vitest run --config vitest.base.config.mjs",
70
+ "test:charge": "node -e \"require('fs').existsSync('vitest.charge.config.mjs')||(console.error('Ce banc ne vit pas dans le paquet publié - le champ scripts annonce plus que le tarball ne contient. Clonez le depot puis npm ci : https://github.com/Juli1artha/discovery-media-player'),process.exit(1))\" && vitest run --config vitest.charge.config.mjs"
70
71
  },
71
72
  "engines": {
72
73
  "node": ">=22"
package/server/handler.js CHANGED
@@ -610,6 +610,20 @@ async function handler(req, res) {
610
610
  return typeof signer === "function" && !!signer("carte-sonde", "carte-sonde", 60);
611
611
  } catch { return false; }
612
612
  })(),
613
+ // ⚠️ LA PORTE REFUSE-T-ELLE, OU EST-ELLE SEULEMENT CONFIGURÉE POUR REFUSER ? `presenceStrict`
614
+ // au-dessus dit que la porte refuse les battements sans preuve — vrai, et mesuré (il exige de
615
+ // pouvoir émettre). Mais le contrôle anti-usurpation des BOOTSTRAPS, lui, peut être désarmé
616
+ // sans que rien ne le dise : 0018 absente, ou — avant 0.1.111 — un simple hoquet réseau. On
617
+ // avait fermé cet écart sur `presenceJetons` en mesurant plutôt qu'en déclarant, et laissé le
618
+ // champ voisin ouvert. (Nommé par le second hôte.)
619
+ //
620
+ // ⚠️ TROIS ÉTATS. « inconnu » n'est pas « actif » : un processus qui n'a pas encore servi de
621
+ // bootstrap n'a rien constaté, et annoncer une garde active sur une absence d'observation est
622
+ // exactement ce qu'on refuse ailleurs. On ne peut pas sonder la fonction sans l'appeler — elle
623
+ // écrit — donc on rend ce qui a été CONSTATÉ à l'usage, jamais une déduction.
624
+ presenceDurcissement: (() => {
625
+ try { return require("./presentations").etatDurcissementBootstrap(); } catch { return "inconnu"; }
626
+ })(),
613
627
  // ⚠️ LES JETONS DE PRÉSENCE SONT-ILS RÉELLEMENT ÉMIS ? Sans ce booléen, un exploitant qui vient
614
628
  // de poser `PLAYER_PRESENCE_SECRET` n'a AUCUN moyen de vérifier que son réglage a pris : la
615
629
  // carte affiche `presence: {0,0}` aussi bien quand le secret est actif que quand la variable est
@@ -6,7 +6,32 @@ const crypto = require("crypto");
6
6
  // ⚠️ Le contexte est REÇU, pas construit. Ce module ne doit pas savoir d'où il vient : c'est ce
7
7
  // qui lui permettra de partir dans le dépôt du player sans emporter le studio avec lui.
8
8
  let PLAYER = null;
9
- function init(ctx) { PLAYER = ctx; _bumpSansDurcissementJusqua = 0; _avertRpcPresence = false; }
9
+ function init(ctx) { PLAYER = ctx; _bumpSansDurcissementJusqua = 0; _avertRpcPresence = false; _dernierSuccesDurcissement = 0; _dernierEchecDurcissement = 0; }
10
+
11
+ /**
12
+ * L'état OBSERVÉ du durcissement des bootstraps — pas sa configuration.
13
+ *
14
+ * ⚠️ LA CARTE RAPPORTAIT UNE CONFIGURATION, PAS UN COMPORTEMENT, et c'est le second hôte qui l'a
15
+ * nommé : `presenceStrict` pouvait dire « la porte refuse » alors que le contrôle anti-usurpation
16
+ * était désarmé — 0018 absente, ou (avant 0.1.111) un simple hoquet réseau. On a fermé cet écart sur
17
+ * `presenceJetons` en MESURANT plutôt qu'en déclarant, et on l'avait laissé ouvert sur le champ voisin.
18
+ *
19
+ * On ne peut pas sonder la fonction sans l'appeler — elle écrit. Ce qu'on peut rendre, c'est ce que le
20
+ * processus a CONSTATÉ en s'en servant : « degrade » = la dernière tentative a trouvé la signature
21
+ * absente ; « actif » = une tentative a abouti ; « inconnu » = on n'a pas encore essayé, et c'est un
22
+ * état à part entière, pas un feu vert.
23
+ */
24
+ function etatDurcissementBootstrap() {
25
+ if (Date.now() < _bumpSansDurcissementJusqua) return "degrade";
26
+ // ⚠️ « actif » EXIGE UN SUCCÈS PLUS RÉCENT QUE LE DERNIER ÉCHEC — pas un simple drapeau. Deux
27
+ // défauts tenaient dans la version précédente (relevés par le second hôte) : (1) le drapeau était
28
+ // posé AVANT l'appel, donc il enregistrait une TENTATIVE et non un succès ; (2) l'expiration du
29
+ // mémo ne rétrogradait pas l'état, elle le PROMOUVAIT — un hôte sans 0018 rendait « degrade »
30
+ // 60 s, puis « actif », sur la foi d'une tentative dont la seule chose prouvée était l'échec.
31
+ // Comparer les deux instants traite les deux d'un coup : le repli d'une preuve périmée est
32
+ // l'IGNORANCE, jamais la confiance.
33
+ return _dernierSuccesDurcissement > _dernierEchecDurcissement ? "actif" : "inconnu";
34
+ }
10
35
 
11
36
 
12
37
  const enc = encodeURIComponent;
@@ -811,6 +836,16 @@ function signatureAbsente(erreur) {
811
836
  // silence. Un « oui » (la signature existe) n'a pas besoin d'expirer : une fonction ne disparaît pas.
812
837
  let _bumpSansDurcissementJusqua = 0;
813
838
  const MEMO_SANS_DURCISSEMENT_MS = 60 * 1000;
839
+ // ⚠️ DEUX INSTANTS, PAS UN DRAPEAU — parce que l'ORDRE est ce qui distingue « réparé » de « cassé ».
840
+ // Un booléen « on a essayé » ne peut pas dire si le dernier mot fut un succès ou un échec, et c'est
841
+ // exactement le mot qui décide. Un succès plus récent que le dernier échec ⇒ la signature existe
842
+ // (une fonction ne disparaît pas toute seule) ; un échec plus récent, mémo expiré ⇒ on ne sait plus.
843
+ let _dernierSuccesDurcissement = 0;
844
+ let _dernierEchecDurcissement = 0;
845
+ // ⚠️ A-T-ON SEULEMENT ESSAYÉ ? « Pas dégradé » n'est pas « vérifié » : un processus qui vient de
846
+ // démarrer n'a rien tenté, et rendre « actif » reviendrait à annoncer une garde active sur la foi
847
+ // d'une absence d'observation. Trois états, donc — la même règle que le verdict du schéma, où « rien
848
+ // de manquant » se lisait « tout va bien » tant qu'on ne distinguait pas « rien demandé ».
814
849
  async function appelerBump(corps, durcissementVoulu) {
815
850
  const appel = (b) => PLAYER.db.request("rpc/player_attendance_bump", { method: "POST", body: b });
816
851
  if (durcissementVoulu && Date.now() < _bumpSansDurcissementJusqua) {
@@ -818,7 +853,12 @@ async function appelerBump(corps, durcissementVoulu) {
818
853
  return appel(sansDurcissement);
819
854
  }
820
855
  try {
821
- return await appel(corps);
856
+ const r = await appel(corps);
857
+ // ⚠️ ON NE MARQUE LE SUCCÈS QU'ICI — l'appel est REVENU, donc la signature à 12 arguments existe.
858
+ // Un rendu `{ok:false, usurpe:true}` compte : seule 0018 sait répondre ça. Ce qui se mesure est
859
+ // le RETOUR, jamais l'intention de partir.
860
+ if (durcissementVoulu) _dernierSuccesDurcissement = Date.now();
861
+ return r;
822
862
  } catch (erreur) {
823
863
  if (!durcissementVoulu) throw erreur; // rien à retirer : l'échec est réel
824
864
  // ⚠️ ON NE SE REPLIE QUE SUR LA PREUVE. Toute autre erreur remonte telle quelle : l'appelant
@@ -826,7 +866,8 @@ async function appelerBump(corps, durcissementVoulu) {
826
866
  if (!signatureAbsente(erreur)) throw erreur;
827
867
  // La signature à 12 arguments n'existe pas (0018 non appliquée) : on retire l'argument et on
828
868
  // réessaie. Le durcissement n'est alors PAS appliqué — et ça se dit, une fois, plus bas.
829
- _bumpSansDurcissementJusqua = Date.now() + MEMO_SANS_DURCISSEMENT_MS;
869
+ _dernierEchecDurcissement = Date.now();
870
+ _bumpSansDurcissementJusqua = _dernierEchecDurcissement + MEMO_SANS_DURCISSEMENT_MS;
830
871
  // ⚠️ CE QUI DISPARAÎT SE DIT. Le durcissement demandé n'est pas appliqué : sous
831
872
  // PLAYER_PRESENCE_STRICT, la porte se fermerait sur les battements legacy tout en laissant un
832
873
  // bootstrap auto-déclaré s'emparer d'une présence réclamée — c'est-à-dire une fermeture qui
@@ -1183,4 +1224,4 @@ async function listPresentationsForDoc(docId, email, isAdmin, autoriseLarge) {
1183
1224
  module.exports = {
1184
1225
  reacteurDepuisJeton,
1185
1226
  purgerPerimees,
1186
- messagePublic, CHAMPS_PUBLICS, cheminPieceJointe, init, createPresentation, getPresentation, setPage, endPresentation, addMessage, listMessages, toggleReaction, editMessage, deleteMessage, setChatLock, createUploadUrl, reclaimPresentation, touchPresentation, listActivePresentations, handoverPresentation, endPresentationByOwner, recordAttendance, presentationStats, listPresentationsForDoc, switchPresentationDoc, setPresentationContent , STALE_MS};
1227
+ messagePublic, CHAMPS_PUBLICS, etatDurcissementBootstrap, cheminPieceJointe, init, createPresentation, getPresentation, setPage, endPresentation, addMessage, listMessages, toggleReaction, editMessage, deleteMessage, setChatLock, createUploadUrl, reclaimPresentation, touchPresentation, listActivePresentations, handoverPresentation, endPresentationByOwner, recordAttendance, presentationStats, listPresentationsForDoc, switchPresentationDoc, setPresentationContent , STALE_MS};