discovery-media-player 0.1.90 → 0.1.92

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.90",
3
+ "version": "0.1.92",
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/schema.js CHANGED
@@ -303,7 +303,35 @@ async function vraimentSonderTout() {
303
303
  for (const [cle] of quandNegatif) { connues.delete(cle); reponses.delete(cle); }
304
304
  quandNegatif.clear();
305
305
  for (const nom of Object.keys(ATTENDUES)) await attendue(nom);
306
- return etatDuSchema();
306
+ const etat = etatDuSchema();
307
+ await ajouterSansRang(etat);
308
+ return etat;
309
+ }
310
+
311
+ /**
312
+ * ⚠️ `mod_seq` NUL EST AMBIGU, ET UN NOMBRE AMBIGU NE MESURE RIEN. Le rattrapage de 0016 laisse
313
+ * DÉLIBÉRÉMENT sans rang les messages des présentations scellées (le scellé refuse de les écrire). Mais
314
+ * rien ne distingue « nul par décision » de « nul parce que le rattrapage n'a jamais tourné » : les
315
+ * deux se lisent « ligne sans rang ». On rend donc les DEUX nombres — total, et la part qui est
316
+ * légitimement scellée. Égaux ⇒ tout nul est un scellé attendu ; divergents ⇒ le rattrapage a laissé
317
+ * des lignes NON scellées derrière lui, anomalie à corriger. C'est la classe « une garde qu'on n'a pas
318
+ * vue refuser ne garde rien » appliquée à un compteur : le compteur devient un verdict. (relevé 2e hôte)
319
+ *
320
+ * Seulement si la colonne est là (sinon la question n'a pas de sens), et JAMAIS bloquant : un
321
+ * diagnostic ne doit pas casser la carte qu'il enrichit — mieux vaut pas de compteur qu'une carte muette.
322
+ */
323
+ async function ajouterSansRang(etat) {
324
+ const r = reponses.get("doc_presentation_messages.mod_seq");
325
+ if (!r || !r.present) return;
326
+ try {
327
+ const scellees = await PLAYER.db.request("doc_presentations?active=eq.false&control_hash=is.null&select=slug");
328
+ const setScellees = new Set((Array.isArray(scellees) ? scellees : []).map((p) => p.slug));
329
+ // `limit` borne un diagnostic sur une base gravement cassée : au-delà, la divergence suffit déjà à
330
+ // alerter, le compte exact n'ajoute rien. `is.null` et `eq` restent de la syntaxe portable.
331
+ const nuls = await PLAYER.db.request("doc_presentation_messages?mod_seq=is.null&select=slug&limit=1000");
332
+ const liste = Array.isArray(nuls) ? nuls : [];
333
+ etat.sansRang = { total: liste.length, dontScellees: liste.filter((m) => setScellees.has(m.slug)).length };
334
+ } catch { /* best-effort : un compteur absent vaut mieux qu'une carte en échec */ }
307
335
  }
308
336
 
309
337
  /** La réponse, retenue pour qui la demandera — sans repasser par la base. */
package/supabase/init.sql CHANGED
@@ -240,9 +240,15 @@ drop trigger if exists dpm_bump_modseq on public.doc_presentation_messages;
240
240
  create trigger dpm_bump_modseq
241
241
  before insert or update on public.doc_presentation_messages
242
242
  for each row execute function public.player_bump_message_seq();
243
- update public.doc_presentation_messages
243
+ -- ⚠️ Le rattrapage EXCLUT les présentations scellées (0007/0010) : le trigger dpm_archive_scellee lève
244
+ -- sur toute écriture dans une présentation gelée, et une seule de ses lignes ferait échouer l'install.
245
+ update public.doc_presentation_messages m
244
246
  set mod_seq = nextval('public.doc_presentation_messages_modseq')
245
- where mod_seq is null;
247
+ where m.mod_seq is null
248
+ and not exists (
249
+ select 1 from public.doc_presentations p
250
+ where p.slug = m.slug and p.active = false and p.control_hash is null
251
+ );
246
252
  create index if not exists idx_dpm_slug_modseq
247
253
  on public.doc_presentation_messages (slug, mod_seq);
248
254
 
@@ -47,10 +47,20 @@ create trigger dpm_bump_modseq
47
47
  for each row execute function public.player_bump_message_seq();
48
48
 
49
49
  -- Rattrapage des lignes déjà présentes : sans `mod_seq`, elles seraient invisibles au différentiel.
50
- -- Une seule fois, dans l'ordre d'insertion, pour donner à chacune un rang cohérent.
51
- update public.doc_presentation_messages
50
+ -- ⚠️ IL RESPECTE LE SCELLÉ D'ARCHIVE (0007/0010). Cet update écrit CHAQUE ligne — or le trigger
51
+ -- dpm_archive_scellee LÈVE sur toute écriture dans une présentation scellée (active=false ET
52
+ -- control_hash IS NULL). Une seule ligne d'une présentation scellée ferait échouer la migration
53
+ -- ENTIÈRE. On exclut donc ces lignes — une présentation scellée est GELÉE, y compris son rang : ses
54
+ -- messages restent sans mod_seq (historiques, jamais resynchronisés en direct, servis par la charge
55
+ -- complète). Deux gardes correctes — le scellé (0007) et ce rattrapage — dont la COMPOSITION
56
+ -- bloquerait sans cette exclusion, et qu'aucun des deux fichiers ne pouvait prévoir seul.
57
+ update public.doc_presentation_messages m
52
58
  set mod_seq = nextval('public.doc_presentation_messages_modseq')
53
- where mod_seq is null;
59
+ where m.mod_seq is null
60
+ and not exists (
61
+ select 1 from public.doc_presentations p
62
+ where p.slug = m.slug and p.active = false and p.control_hash is null
63
+ );
54
64
 
55
65
  -- La lecture différentielle `slug=eq.X&mod_seq=gt.N&order=mod_seq.asc` doit rester rapide.
56
66
  create index if not exists idx_dpm_slug_modseq