discovery-media-player 0.1.168 → 0.1.169

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.168",
3
+ "version": "0.1.169",
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/cache.js CHANGED
@@ -91,6 +91,15 @@ function creerCache(options) {
91
91
  // sans eux, « le cache tient » est une phrase, pas une mesure. Compteurs de processus, comme tout
92
92
  // ici : jamais remis à zéro, à lire en deltas.
93
93
  let nServies = 0, nRegroupees = 0, nProduites = 0, picEnVol = 0;
94
+ // ⚠️ LES OBSERVATEURS DE FENÊTRE, ET POURQUOI ILS NE TOUCHENT PAS À L'ÉTAT DU CACHE. `picEnVol`
95
+ // est un maximum DEPUIS LE DÉMARRAGE : quand le rapport de charge le recopiait tel quel à côté de
96
+ // hits/misses/coalesced convertis en DELTAS, une position calme héritait du pic d'une position
97
+ // chargée et affirmait une concurrence qu'elle n'avait jamais vue. Remettre `picEnVol` à zéro
98
+ // entre deux positions serait pire : on modifierait le SYSTÈME MESURÉ pour arranger l'instrument,
99
+ // et le pic historique — qui a son utilité — disparaîtrait. Un observateur est donc un compteur
100
+ // SÉPARÉ, ouvert et refermé par qui mesure, sans que le cache change de comportement.
101
+ // Relevé par un audit externe (CODEX, 15/09).
102
+ const observateurs = new Set();
94
103
 
95
104
  const oublier = (k) => {
96
105
  const e = entrees.get(k);
@@ -154,6 +163,7 @@ function creerCache(options) {
154
163
  nEnVol += 1;
155
164
  nProduites += 1;
156
165
  if (nEnVol > picEnVol) picEnVol = nEnVol;
166
+ for (const o of observateurs) if (nEnVol > o.pic) o.pic = nEnVol;
157
167
  // ⚠️ L'ÉCHÉANCE PART DE LA RÉSOLUTION, PAS DE LA DEMANDE. Posée à la demande, elle expirait
158
168
  // AVANT que la production ne réponde dès que celle-ci dépassait le TTL — et le regroupement ne
159
169
  // servait alors plus à rien pour exactement les producteurs lents, les seuls qu'il valait la
@@ -210,6 +220,17 @@ function creerCache(options) {
210
220
  * plus grand nombre de productions simultanées. Les refus sont dans `satures()`.
211
221
  */
212
222
  compteurs: () => ({ hits: nServies, coalesced: nRegroupees, misses: nProduites, peakInFlight: picEnVol }),
223
+ /**
224
+ * Ouvre une fenêtre d'observation du pic en vol : `{ pic(), fermer() }`. Le cache n'est pas
225
+ * modifié — ni remis à zéro, ni ralenti ; seul un compteur parallèle suit les productions
226
+ * simultanées TANT QUE la fenêtre est ouverte. `fermer()` est impératif : un observateur oublié
227
+ * survit au relevé qui l'a demandé.
228
+ */
229
+ observerEnVol: () => {
230
+ const o = { pic: nEnVol };
231
+ observateurs.add(o);
232
+ return { pic: () => o.pic, fermer: () => observateurs.delete(o) };
233
+ },
213
234
  /**
214
235
  * Ce que le plafond a refusé depuis le démarrage de ce processus.
215
236
  *
package/server/handler.js CHANGED
@@ -1249,6 +1249,19 @@ module.exports = { __contexte: () => PLAYER, handler, init, TIERS, POLITIQUE_PER
1249
1249
  // ⚠️ COUTURE DE BANC, PAS D'API : le cache de lecture est global au module, et un banc qui laisse des
1250
1250
  // lectures en vol contamine le suivant (128 promesses éternelles, 503 partout — trouvé par un audit
1251
1251
  // externe sous mélange, graine 20260913). Un banc doit pouvoir VÉRIFIER qu'il rend le cache vide.
1252
- __cacheLecture: cacheLecture };
1252
+ __cacheLecture: cacheLecture,
1253
+ // ⚠️ COUTURE DE MESURE : LIRE LES COMPTEURS SANS LES INCRÉMENTER. Le rapport de charge relevait
1254
+ // ces grandeurs par un `GET ?contract=1` — c'est-à-dire par une requête qui TRAVERSE le handler et
1255
+ // incrémente `mesures.statuts.ok` au passage. Le delta d'une fenêtre de 1 000 requêtes valait donc
1256
+ // 1 001, systématiquement, et pour chaque position : l'observateur se comptait lui-même. Une
1257
+ // soustraction cachée aurait corrigé le chiffre en aggravant le problème — un instrument qui se
1258
+ // retranche discrètement est plus difficile à auditer qu'un instrument faux. La couture rend l'état
1259
+ // tel qu'il est, sans le modifier ; ce que la fenêtre contient d'autre que la charge se DIT, dans
1260
+ // `counters.observerOverheadRequests`. Défaut relevé par un audit externe (CODEX, 15/09).
1261
+ __compteursSansObserver: () => ({
1262
+ lectureSaturee: { total: cacheLecture.satures().total },
1263
+ relaisRefuses: { total: relaisRefusesTotal },
1264
+ mesures: mesures.relever(),
1265
+ }) };
1253
1266
 
1254
1267
  // redeploy: forcer le build production (Vercel a sauté la prod du merge #463 — wording re-partage).