discovery-media-player 0.1.120 → 0.1.121
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/README.md +5 -4
- package/package.json +1 -1
- package/server/presentations.js +24 -9
- package/server/schema.js +19 -6
package/docs/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Documentation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Three readers, one section each. Start with the one that matches what you are trying to do —
|
|
4
|
+
no document assumes you have read the others.
|
|
5
5
|
|
|
6
6
|
## You are integrating the player into an application
|
|
7
7
|
|
|
@@ -37,6 +37,7 @@ tracked version by version in the [CHANGELOG](../CHANGELOG.md).
|
|
|
37
37
|
|---|---|
|
|
38
38
|
| [`SPEC-MEMBRE-INJECTE.md`](SPEC-MEMBRE-INJECTE.md) | A specification sent to a host for agreement **before** the contract moves. Nothing in it is implemented. (French.) |
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
Public entry points are in English. Documents that remain in French — audit traces, and the
|
|
41
|
+
operational documents marked *(French)* above — are labelled explicitly, so nobody discovers
|
|
42
|
+
the language after clicking. The reasoning behind the split is at the end of the
|
|
42
43
|
[README](../README.md#contributing).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discovery-media-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.121",
|
|
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/presentations.js
CHANGED
|
@@ -848,9 +848,32 @@ let _etatDurcissement = "inconnu";
|
|
|
848
848
|
// démarrer n'a rien tenté, et rendre « actif » reviendrait à annoncer une garde active sur la foi
|
|
849
849
|
// d'une absence d'observation. Trois états, donc — la même règle que le verdict du schéma, où « rien
|
|
850
850
|
// de manquant » se lisait « tout va bien » tant qu'on ne distinguait pas « rien demandé ».
|
|
851
|
+
// ⚠️ UN SEUL CONSTRUCTEUR DE REFUS, PARCE QU'IL Y A DEUX CHEMINS. Le mode strict doit refuser à
|
|
852
|
+
// l'endroit où la RPC échoue ET à l'endroit où le mémo évite de la rappeler. Deux messages écrits
|
|
853
|
+
// séparément divergeraient, et c'est la divergence qui a produit le défaut : le premier chemin était
|
|
854
|
+
// gardé, le second non. (P1 audit externe, v0.1.120.)
|
|
855
|
+
function erreurDurcissementAbsent() {
|
|
856
|
+
const e = new Error(
|
|
857
|
+
"bootstrap de présence NON durci alors que PLAYER_PRESENCE_STRICT est posé : appliquez "
|
|
858
|
+
+ "supabase/migrations/0018-bootstrap-non-usurpable.sql, ou retirez le mode strict le temps "
|
|
859
|
+
+ "de la migration. Aucune écriture non protégée n'a été faite.",
|
|
860
|
+
);
|
|
861
|
+
e.code = "durcissement-absent";
|
|
862
|
+
return e;
|
|
863
|
+
}
|
|
864
|
+
|
|
851
865
|
async function appelerBump(corps, durcissementVoulu) {
|
|
852
866
|
const appel = (b) => PLAYER.db.request("rpc/player_attendance_bump", { method: "POST", body: b });
|
|
853
867
|
if (durcissementVoulu && Date.now() < _bumpSansDurcissementJusqua) {
|
|
868
|
+
// ⚠️ LE SECOND CHEMIN VERS LA MÊME ÉCRITURE — et c'est par là que la porte fermée se rouvrait.
|
|
869
|
+
// Le refus de 0.1.119 vivait dans le `catch`, donc sur le chemin où la RPC vient d'échouer. Une
|
|
870
|
+
// fois le mémo armé, on sort par ICI sans jamais rappeler la RPC : le premier bootstrap était
|
|
871
|
+
// refusé en 503, le deuxième écrivait sans contrôle pendant les 60 s suivantes.
|
|
872
|
+
//
|
|
873
|
+
// Corriger un chemin d'une opération qui en a deux ne corrige rien : ça déplace le défaut vers
|
|
874
|
+
// celui qu'on n'a pas regardé, et le banc reste vert parce qu'il n'éprouvait que le premier
|
|
875
|
+
// passage. Le régime se teste sur la RÉPÉTITION, pas sur l'appel initial.
|
|
876
|
+
if (PLAYER && PLAYER.config && PLAYER.config.presenceStrict) throw erreurDurcissementAbsent();
|
|
854
877
|
const { p_only_if_unclaimed: _retire, ...sansDurcissement } = corps;
|
|
855
878
|
return appel(sansDurcissement);
|
|
856
879
|
}
|
|
@@ -891,15 +914,7 @@ async function appelerBump(corps, durcissementVoulu) {
|
|
|
891
914
|
// On lève, et l'appelant rend 503 : « je n'ai pas pu vérifier », pas « c'est refusé » ni « c'est
|
|
892
915
|
// écrit ». ⚠️ Seuls les BOOTSTRAPS sont concernés (durcissementVoulu) : un battement prouvé n'a
|
|
893
916
|
// jamais emprunté ce chemin, donc une présentation en cours ne s'arrête pas. (Audit externe.)
|
|
894
|
-
if (PLAYER && PLAYER.config && PLAYER.config.presenceStrict)
|
|
895
|
-
const refus = new Error(
|
|
896
|
-
"bootstrap de présence NON durci alors que PLAYER_PRESENCE_STRICT est posé : appliquez "
|
|
897
|
-
+ "supabase/migrations/0018-bootstrap-non-usurpable.sql, ou retirez le mode strict le temps "
|
|
898
|
-
+ "de la migration. Aucune écriture non protégée n'a été faite.",
|
|
899
|
-
);
|
|
900
|
-
refus.code = "durcissement-absent";
|
|
901
|
-
throw refus;
|
|
902
|
-
}
|
|
917
|
+
if (PLAYER && PLAYER.config && PLAYER.config.presenceStrict) throw erreurDurcissementAbsent();
|
|
903
918
|
const { p_only_if_unclaimed: _retire, ...sansDurcissement } = corps;
|
|
904
919
|
return appel(sansDurcissement);
|
|
905
920
|
}
|
package/server/schema.js
CHANGED
|
@@ -304,7 +304,16 @@ async function vraimentSonderTout() {
|
|
|
304
304
|
} catch {
|
|
305
305
|
// On rend ce qu'on savait déjà — un manque constaté plus tôt reste un fait — mais le verdict
|
|
306
306
|
// dit que cette mesure-ci n'a pas eu lieu. Taire l'un ou l'autre serait mentir d'un côté.
|
|
307
|
-
|
|
307
|
+
// ⚠️ LE CHAMP DOIT ÊTRE LÀ MÊME ICI. Le contrat annonce que `durcissementBase` vaut toujours
|
|
308
|
+
// l'une des trois valeurs ; ce retour anticipé le faisait DISPARAÎTRE quand la base ne répond
|
|
309
|
+
// pas du tout. Un hôte qui teste `durcissementBase !== "applique"` avant de déployer lisait
|
|
310
|
+
// alors `undefined !== "applique"` — vrai par accident, donc juste par accident. Un champ
|
|
311
|
+
// absent est plus dangereux qu'un champ prudent : il ne se distingue pas d'un contrat plus
|
|
312
|
+
// ancien. (P2 audit externe.)
|
|
313
|
+
return {
|
|
314
|
+
...etatDuSchema(), verdict: "indetermine",
|
|
315
|
+
durcissementBase: "indetermine", durcissementBaseCouvre: PORTEE_DURCISSEMENT,
|
|
316
|
+
};
|
|
308
317
|
}
|
|
309
318
|
// ⚠️ LE TÉMOIN VIENT DE RÉPONDRE : tout « non » encore en cache est SUSPECT — il peut dater
|
|
310
319
|
// d'une panne guérie. On le jette et on repose la question, sinon ce diagnostic rendrait la
|
|
@@ -360,6 +369,14 @@ const PLAFOND_SANS_RANG = 1000;
|
|
|
360
369
|
// être un slug réel (contrat `^[A-Za-z0-9_-]{1,64}$`), et ne peut pas heurter une vraie présence.
|
|
361
370
|
// Un test de base (Postgres réel) vérifie qu'aucune ligne n'apparaît.
|
|
362
371
|
const SLUG_SONDE_DURCISSEMENT = "sonde durcissement";
|
|
372
|
+
// ⚠️ UNE SEULE DESCRIPTION, PARCE QU'IL Y A DEUX SORTIES. Le champ se pose aussi sur le retour
|
|
373
|
+
// ANTICIPÉ (base muette) ; deux textes écrits séparément divergeraient, et c'est exactement ce qui
|
|
374
|
+
// vient de se produire un cran plus haut avec le refus du mode strict.
|
|
375
|
+
const PORTEE_DURCISSEMENT =
|
|
376
|
+
"propriété de la BASE (migration 0018), globale à toutes les instances — à ne pas confondre avec "
|
|
377
|
+
+ "presenceDurcissement, qui est ce que CE processus a constaté en servant des bootstraps. "
|
|
378
|
+
+ "C'est ce champ-ci qu'on lit AVANT un déploiement ; « indetermine » = la question n'a pas pu "
|
|
379
|
+
+ "être posée, ce n'est ni un oui ni un non.";
|
|
363
380
|
|
|
364
381
|
async function ajouterDurcissement(etat) {
|
|
365
382
|
const corps = {
|
|
@@ -396,11 +413,7 @@ async function ajouterDurcissement(etat) {
|
|
|
396
413
|
}
|
|
397
414
|
} catch { /* jamais bloquant */ }
|
|
398
415
|
}
|
|
399
|
-
etat.durcissementBaseCouvre =
|
|
400
|
-
"propriété de la BASE (migration 0018), globale à toutes les instances — à ne pas confondre avec "
|
|
401
|
-
+ "presenceDurcissement, qui est ce que CE processus a constaté en servant des bootstraps. "
|
|
402
|
-
+ "C'est ce champ-ci qu'on lit AVANT un déploiement ; « indetermine » = la question n'a pas pu "
|
|
403
|
-
+ "être posée, ce n'est ni un oui ni un non.";
|
|
416
|
+
etat.durcissementBaseCouvre = PORTEE_DURCISSEMENT;
|
|
404
417
|
}
|
|
405
418
|
|
|
406
419
|
async function ajouterSansRang(etat) {
|