cozy-client 60.30.1 → 60.31.0

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.
@@ -0,0 +1,1152 @@
1
+ {
2
+ "$comment": "Shared contract vectors for io.cozy.banners. Every client implementing the doctype runs these and must produce `expected` from `input`. Published with the doctype in cozy-doctypes, alongside docs/io.cozy.banners.md.",
3
+ "now": "2026-07-22T12:00:00Z",
4
+ "supportedDoctypeVersion": 1,
5
+ "expectedShape": "An ordered list of the banners a client displays, each reduced to the values that rendering depends on: bannerId, the severity and surface actually used after any fallback, and whether a call to action is shown.",
6
+ "cases": [
7
+ {
8
+ "name": "no documents renders nothing",
9
+ "input": [],
10
+ "expected": []
11
+ },
12
+ {
13
+ "name": "higher priority renders first",
14
+ "input": [
15
+ {
16
+ "_id": "doc001",
17
+ "_rev": "1-aaa",
18
+ "bannerId": "b.low",
19
+ "category": "quota",
20
+ "severity": "info",
21
+ "surface": "banner",
22
+ "text": "Message.",
23
+ "lang": "en",
24
+ "dismissible": true,
25
+ "dismissedAt": null,
26
+ "priority": 10,
27
+ "startsAt": "2026-07-01T00:00:00Z",
28
+ "endsAt": null,
29
+ "source": {
30
+ "trigger": "test",
31
+ "at": "2026-07-01T00:00:00Z"
32
+ },
33
+ "cozyMetadata": {
34
+ "createdAt": "2026-07-01T00:00:00Z",
35
+ "createdByApp": "stack",
36
+ "doctypeVersion": "1",
37
+ "metadataVersion": 1,
38
+ "updatedAt": "2026-07-01T00:00:00Z"
39
+ }
40
+ },
41
+ {
42
+ "_id": "doc002",
43
+ "_rev": "1-aaa",
44
+ "bannerId": "a.high",
45
+ "category": "quota",
46
+ "severity": "info",
47
+ "surface": "banner",
48
+ "text": "Message.",
49
+ "lang": "en",
50
+ "dismissible": true,
51
+ "dismissedAt": null,
52
+ "priority": 100,
53
+ "startsAt": "2026-07-01T00:00:00Z",
54
+ "endsAt": null,
55
+ "source": {
56
+ "trigger": "test",
57
+ "at": "2026-07-01T00:00:00Z"
58
+ },
59
+ "cozyMetadata": {
60
+ "createdAt": "2026-07-01T00:00:00Z",
61
+ "createdByApp": "stack",
62
+ "doctypeVersion": "1",
63
+ "metadataVersion": 1,
64
+ "updatedAt": "2026-07-01T00:00:00Z"
65
+ }
66
+ }
67
+ ],
68
+ "expected": [
69
+ {
70
+ "bannerId": "a.high",
71
+ "severity": "info",
72
+ "surface": "banner",
73
+ "cta": false
74
+ },
75
+ {
76
+ "bannerId": "b.low",
77
+ "severity": "info",
78
+ "surface": "banner",
79
+ "cta": false
80
+ }
81
+ ]
82
+ },
83
+ {
84
+ "name": "equal priority breaks on bannerId, compared by code unit rather than locale",
85
+ "input": [
86
+ {
87
+ "_id": "doc003",
88
+ "_rev": "1-aaa",
89
+ "bannerId": "a.lower",
90
+ "category": "quota",
91
+ "severity": "info",
92
+ "surface": "banner",
93
+ "text": "Message.",
94
+ "lang": "en",
95
+ "dismissible": true,
96
+ "dismissedAt": null,
97
+ "priority": 50,
98
+ "startsAt": "2026-07-01T00:00:00Z",
99
+ "endsAt": null,
100
+ "source": {
101
+ "trigger": "test",
102
+ "at": "2026-07-01T00:00:00Z"
103
+ },
104
+ "cozyMetadata": {
105
+ "createdAt": "2026-07-01T00:00:00Z",
106
+ "createdByApp": "stack",
107
+ "doctypeVersion": "1",
108
+ "metadataVersion": 1,
109
+ "updatedAt": "2026-07-01T00:00:00Z"
110
+ }
111
+ },
112
+ {
113
+ "_id": "doc004",
114
+ "_rev": "1-aaa",
115
+ "bannerId": "B.upper",
116
+ "category": "quota",
117
+ "severity": "info",
118
+ "surface": "banner",
119
+ "text": "Message.",
120
+ "lang": "en",
121
+ "dismissible": true,
122
+ "dismissedAt": null,
123
+ "priority": 50,
124
+ "startsAt": "2026-07-01T00:00:00Z",
125
+ "endsAt": null,
126
+ "source": {
127
+ "trigger": "test",
128
+ "at": "2026-07-01T00:00:00Z"
129
+ },
130
+ "cozyMetadata": {
131
+ "createdAt": "2026-07-01T00:00:00Z",
132
+ "createdByApp": "stack",
133
+ "doctypeVersion": "1",
134
+ "metadataVersion": 1,
135
+ "updatedAt": "2026-07-01T00:00:00Z"
136
+ }
137
+ }
138
+ ],
139
+ "expected": [
140
+ {
141
+ "bannerId": "B.upper",
142
+ "severity": "info",
143
+ "surface": "banner",
144
+ "cta": false
145
+ },
146
+ {
147
+ "bannerId": "a.lower",
148
+ "severity": "info",
149
+ "surface": "banner",
150
+ "cta": false
151
+ }
152
+ ]
153
+ },
154
+ {
155
+ "name": "a window that has not started is hidden",
156
+ "input": [
157
+ {
158
+ "_id": "doc005",
159
+ "_rev": "1-aaa",
160
+ "bannerId": "future",
161
+ "category": "quota",
162
+ "severity": "info",
163
+ "surface": "banner",
164
+ "text": "Message.",
165
+ "lang": "en",
166
+ "dismissible": true,
167
+ "dismissedAt": null,
168
+ "priority": 50,
169
+ "startsAt": "2026-07-23T00:00:00Z",
170
+ "endsAt": null,
171
+ "source": {
172
+ "trigger": "test",
173
+ "at": "2026-07-01T00:00:00Z"
174
+ },
175
+ "cozyMetadata": {
176
+ "createdAt": "2026-07-01T00:00:00Z",
177
+ "createdByApp": "stack",
178
+ "doctypeVersion": "1",
179
+ "metadataVersion": 1,
180
+ "updatedAt": "2026-07-01T00:00:00Z"
181
+ }
182
+ }
183
+ ],
184
+ "expected": []
185
+ },
186
+ {
187
+ "name": "startsAt is inclusive",
188
+ "input": [
189
+ {
190
+ "_id": "doc006",
191
+ "_rev": "1-aaa",
192
+ "bannerId": "starting",
193
+ "category": "quota",
194
+ "severity": "info",
195
+ "surface": "banner",
196
+ "text": "Message.",
197
+ "lang": "en",
198
+ "dismissible": true,
199
+ "dismissedAt": null,
200
+ "priority": 50,
201
+ "startsAt": "2026-07-22T12:00:00Z",
202
+ "endsAt": null,
203
+ "source": {
204
+ "trigger": "test",
205
+ "at": "2026-07-01T00:00:00Z"
206
+ },
207
+ "cozyMetadata": {
208
+ "createdAt": "2026-07-01T00:00:00Z",
209
+ "createdByApp": "stack",
210
+ "doctypeVersion": "1",
211
+ "metadataVersion": 1,
212
+ "updatedAt": "2026-07-01T00:00:00Z"
213
+ }
214
+ }
215
+ ],
216
+ "expected": [
217
+ {
218
+ "bannerId": "starting",
219
+ "severity": "info",
220
+ "surface": "banner",
221
+ "cta": false
222
+ }
223
+ ]
224
+ },
225
+ {
226
+ "name": "endsAt is exclusive",
227
+ "input": [
228
+ {
229
+ "_id": "doc007",
230
+ "_rev": "1-aaa",
231
+ "bannerId": "ending",
232
+ "category": "quota",
233
+ "severity": "info",
234
+ "surface": "banner",
235
+ "text": "Message.",
236
+ "lang": "en",
237
+ "dismissible": true,
238
+ "dismissedAt": null,
239
+ "priority": 50,
240
+ "startsAt": "2026-07-01T00:00:00Z",
241
+ "endsAt": "2026-07-22T12:00:00Z",
242
+ "source": {
243
+ "trigger": "test",
244
+ "at": "2026-07-01T00:00:00Z"
245
+ },
246
+ "cozyMetadata": {
247
+ "createdAt": "2026-07-01T00:00:00Z",
248
+ "createdByApp": "stack",
249
+ "doctypeVersion": "1",
250
+ "metadataVersion": 1,
251
+ "updatedAt": "2026-07-01T00:00:00Z"
252
+ }
253
+ }
254
+ ],
255
+ "expected": []
256
+ },
257
+ {
258
+ "name": "a window still open is visible",
259
+ "input": [
260
+ {
261
+ "_id": "doc008",
262
+ "_rev": "1-aaa",
263
+ "bannerId": "open",
264
+ "category": "quota",
265
+ "severity": "info",
266
+ "surface": "banner",
267
+ "text": "Message.",
268
+ "lang": "en",
269
+ "dismissible": true,
270
+ "dismissedAt": null,
271
+ "priority": 50,
272
+ "startsAt": "2026-07-01T00:00:00Z",
273
+ "endsAt": "2026-07-23T00:00:00Z",
274
+ "source": {
275
+ "trigger": "test",
276
+ "at": "2026-07-01T00:00:00Z"
277
+ },
278
+ "cozyMetadata": {
279
+ "createdAt": "2026-07-01T00:00:00Z",
280
+ "createdByApp": "stack",
281
+ "doctypeVersion": "1",
282
+ "metadataVersion": 1,
283
+ "updatedAt": "2026-07-01T00:00:00Z"
284
+ }
285
+ }
286
+ ],
287
+ "expected": [
288
+ {
289
+ "bannerId": "open",
290
+ "severity": "info",
291
+ "surface": "banner",
292
+ "cta": false
293
+ }
294
+ ]
295
+ },
296
+ {
297
+ "name": "a null endsAt is open ended",
298
+ "input": [
299
+ {
300
+ "_id": "doc009",
301
+ "_rev": "1-aaa",
302
+ "bannerId": "openended",
303
+ "category": "quota",
304
+ "severity": "info",
305
+ "surface": "banner",
306
+ "text": "Message.",
307
+ "lang": "en",
308
+ "dismissible": true,
309
+ "dismissedAt": null,
310
+ "priority": 50,
311
+ "startsAt": "2026-07-01T00:00:00Z",
312
+ "endsAt": null,
313
+ "source": {
314
+ "trigger": "test",
315
+ "at": "2026-07-01T00:00:00Z"
316
+ },
317
+ "cozyMetadata": {
318
+ "createdAt": "2026-07-01T00:00:00Z",
319
+ "createdByApp": "stack",
320
+ "doctypeVersion": "1",
321
+ "metadataVersion": 1,
322
+ "updatedAt": "2026-07-01T00:00:00Z"
323
+ }
324
+ }
325
+ ],
326
+ "expected": [
327
+ {
328
+ "bannerId": "openended",
329
+ "severity": "info",
330
+ "surface": "banner",
331
+ "cta": false
332
+ }
333
+ ]
334
+ },
335
+ {
336
+ "name": "an absent endsAt means the same as null",
337
+ "input": [
338
+ {
339
+ "_id": "doc010",
340
+ "_rev": "1-aaa",
341
+ "bannerId": "absentend",
342
+ "category": "quota",
343
+ "severity": "info",
344
+ "surface": "banner",
345
+ "text": "Message.",
346
+ "lang": "en",
347
+ "dismissible": true,
348
+ "dismissedAt": null,
349
+ "priority": 50,
350
+ "startsAt": "2026-07-01T00:00:00Z",
351
+ "source": {
352
+ "trigger": "test",
353
+ "at": "2026-07-01T00:00:00Z"
354
+ },
355
+ "cozyMetadata": {
356
+ "createdAt": "2026-07-01T00:00:00Z",
357
+ "createdByApp": "stack",
358
+ "doctypeVersion": "1",
359
+ "metadataVersion": 1,
360
+ "updatedAt": "2026-07-01T00:00:00Z"
361
+ }
362
+ }
363
+ ],
364
+ "expected": [
365
+ {
366
+ "bannerId": "absentend",
367
+ "severity": "info",
368
+ "surface": "banner",
369
+ "cta": false
370
+ }
371
+ ]
372
+ },
373
+ {
374
+ "name": "an unparseable startsAt hides the banner",
375
+ "input": [
376
+ {
377
+ "_id": "doc011",
378
+ "_rev": "1-aaa",
379
+ "bannerId": "badstart",
380
+ "category": "quota",
381
+ "severity": "info",
382
+ "surface": "banner",
383
+ "text": "Message.",
384
+ "lang": "en",
385
+ "dismissible": true,
386
+ "dismissedAt": null,
387
+ "priority": 50,
388
+ "startsAt": "not a date",
389
+ "endsAt": null,
390
+ "source": {
391
+ "trigger": "test",
392
+ "at": "2026-07-01T00:00:00Z"
393
+ },
394
+ "cozyMetadata": {
395
+ "createdAt": "2026-07-01T00:00:00Z",
396
+ "createdByApp": "stack",
397
+ "doctypeVersion": "1",
398
+ "metadataVersion": 1,
399
+ "updatedAt": "2026-07-01T00:00:00Z"
400
+ }
401
+ }
402
+ ],
403
+ "expected": []
404
+ },
405
+ {
406
+ "name": "an unparseable endsAt hides the banner",
407
+ "input": [
408
+ {
409
+ "_id": "doc012",
410
+ "_rev": "1-aaa",
411
+ "bannerId": "badend",
412
+ "category": "quota",
413
+ "severity": "info",
414
+ "surface": "banner",
415
+ "text": "Message.",
416
+ "lang": "en",
417
+ "dismissible": true,
418
+ "dismissedAt": null,
419
+ "priority": 50,
420
+ "startsAt": "2026-07-01T00:00:00Z",
421
+ "endsAt": "22/07/2026",
422
+ "source": {
423
+ "trigger": "test",
424
+ "at": "2026-07-01T00:00:00Z"
425
+ },
426
+ "cozyMetadata": {
427
+ "createdAt": "2026-07-01T00:00:00Z",
428
+ "createdByApp": "stack",
429
+ "doctypeVersion": "1",
430
+ "metadataVersion": 1,
431
+ "updatedAt": "2026-07-01T00:00:00Z"
432
+ }
433
+ }
434
+ ],
435
+ "expected": []
436
+ },
437
+ {
438
+ "name": "a dismissed banner is hidden",
439
+ "input": [
440
+ {
441
+ "_id": "doc013",
442
+ "_rev": "1-aaa",
443
+ "bannerId": "dismissed",
444
+ "category": "quota",
445
+ "severity": "info",
446
+ "surface": "banner",
447
+ "text": "Message.",
448
+ "lang": "en",
449
+ "dismissible": true,
450
+ "dismissedAt": "2026-07-21T08:00:00Z",
451
+ "priority": 50,
452
+ "startsAt": "2026-07-01T00:00:00Z",
453
+ "endsAt": null,
454
+ "source": {
455
+ "trigger": "test",
456
+ "at": "2026-07-01T00:00:00Z"
457
+ },
458
+ "cozyMetadata": {
459
+ "createdAt": "2026-07-01T00:00:00Z",
460
+ "createdByApp": "stack",
461
+ "doctypeVersion": "1",
462
+ "metadataVersion": 1,
463
+ "updatedAt": "2026-07-01T00:00:00Z"
464
+ }
465
+ }
466
+ ],
467
+ "expected": []
468
+ },
469
+ {
470
+ "name": "a dismissal recorded while dismissible wins over dismissible false",
471
+ "input": [
472
+ {
473
+ "_id": "doc014",
474
+ "_rev": "1-aaa",
475
+ "bannerId": "locked",
476
+ "category": "quota",
477
+ "severity": "info",
478
+ "surface": "banner",
479
+ "text": "Message.",
480
+ "lang": "en",
481
+ "dismissible": false,
482
+ "dismissedAt": "2026-07-21T08:00:00Z",
483
+ "priority": 50,
484
+ "startsAt": "2026-07-01T00:00:00Z",
485
+ "endsAt": null,
486
+ "source": {
487
+ "trigger": "test",
488
+ "at": "2026-07-01T00:00:00Z"
489
+ },
490
+ "cozyMetadata": {
491
+ "createdAt": "2026-07-01T00:00:00Z",
492
+ "createdByApp": "stack",
493
+ "doctypeVersion": "1",
494
+ "metadataVersion": 1,
495
+ "updatedAt": "2026-07-01T00:00:00Z"
496
+ }
497
+ }
498
+ ],
499
+ "expected": []
500
+ },
501
+ {
502
+ "name": "an unknown category still renders",
503
+ "input": [
504
+ {
505
+ "_id": "doc015",
506
+ "_rev": "1-aaa",
507
+ "bannerId": "unknowncat",
508
+ "category": "weather",
509
+ "severity": "info",
510
+ "surface": "banner",
511
+ "text": "Message.",
512
+ "lang": "en",
513
+ "dismissible": true,
514
+ "dismissedAt": null,
515
+ "priority": 50,
516
+ "startsAt": "2026-07-01T00:00:00Z",
517
+ "endsAt": null,
518
+ "source": {
519
+ "trigger": "test",
520
+ "at": "2026-07-01T00:00:00Z"
521
+ },
522
+ "cozyMetadata": {
523
+ "createdAt": "2026-07-01T00:00:00Z",
524
+ "createdByApp": "stack",
525
+ "doctypeVersion": "1",
526
+ "metadataVersion": 1,
527
+ "updatedAt": "2026-07-01T00:00:00Z"
528
+ }
529
+ }
530
+ ],
531
+ "expected": [
532
+ {
533
+ "bannerId": "unknowncat",
534
+ "severity": "info",
535
+ "surface": "banner",
536
+ "cta": false
537
+ }
538
+ ]
539
+ },
540
+ {
541
+ "name": "an unknown severity renders as warning",
542
+ "input": [
543
+ {
544
+ "_id": "doc016",
545
+ "_rev": "1-aaa",
546
+ "bannerId": "unknownsev",
547
+ "category": "quota",
548
+ "severity": "critical",
549
+ "surface": "banner",
550
+ "text": "Message.",
551
+ "lang": "en",
552
+ "dismissible": true,
553
+ "dismissedAt": null,
554
+ "priority": 50,
555
+ "startsAt": "2026-07-01T00:00:00Z",
556
+ "endsAt": null,
557
+ "source": {
558
+ "trigger": "test",
559
+ "at": "2026-07-01T00:00:00Z"
560
+ },
561
+ "cozyMetadata": {
562
+ "createdAt": "2026-07-01T00:00:00Z",
563
+ "createdByApp": "stack",
564
+ "doctypeVersion": "1",
565
+ "metadataVersion": 1,
566
+ "updatedAt": "2026-07-01T00:00:00Z"
567
+ }
568
+ }
569
+ ],
570
+ "expected": [
571
+ {
572
+ "bannerId": "unknownsev",
573
+ "severity": "warning",
574
+ "surface": "banner",
575
+ "cta": false
576
+ }
577
+ ]
578
+ },
579
+ {
580
+ "name": "an unknown surface renders as banner",
581
+ "input": [
582
+ {
583
+ "_id": "doc017",
584
+ "_rev": "1-aaa",
585
+ "bannerId": "unknownsurface",
586
+ "category": "quota",
587
+ "severity": "info",
588
+ "surface": "toast",
589
+ "text": "Message.",
590
+ "lang": "en",
591
+ "dismissible": true,
592
+ "dismissedAt": null,
593
+ "priority": 50,
594
+ "startsAt": "2026-07-01T00:00:00Z",
595
+ "endsAt": null,
596
+ "source": {
597
+ "trigger": "test",
598
+ "at": "2026-07-01T00:00:00Z"
599
+ },
600
+ "cozyMetadata": {
601
+ "createdAt": "2026-07-01T00:00:00Z",
602
+ "createdByApp": "stack",
603
+ "doctypeVersion": "1",
604
+ "metadataVersion": 1,
605
+ "updatedAt": "2026-07-01T00:00:00Z"
606
+ }
607
+ }
608
+ ],
609
+ "expected": [
610
+ {
611
+ "bannerId": "unknownsurface",
612
+ "severity": "info",
613
+ "surface": "banner",
614
+ "cta": false
615
+ }
616
+ ]
617
+ },
618
+ {
619
+ "name": "an https call to action renders",
620
+ "input": [
621
+ {
622
+ "_id": "doc018",
623
+ "_rev": "1-aaa",
624
+ "bannerId": "withcta",
625
+ "category": "quota",
626
+ "severity": "info",
627
+ "surface": "banner",
628
+ "text": "Message.",
629
+ "lang": "en",
630
+ "cta": {
631
+ "label": "Upgrade",
632
+ "url": "https://example.org/plans"
633
+ },
634
+ "dismissible": true,
635
+ "dismissedAt": null,
636
+ "priority": 50,
637
+ "startsAt": "2026-07-01T00:00:00Z",
638
+ "endsAt": null,
639
+ "source": {
640
+ "trigger": "test",
641
+ "at": "2026-07-01T00:00:00Z"
642
+ },
643
+ "cozyMetadata": {
644
+ "createdAt": "2026-07-01T00:00:00Z",
645
+ "createdByApp": "stack",
646
+ "doctypeVersion": "1",
647
+ "metadataVersion": 1,
648
+ "updatedAt": "2026-07-01T00:00:00Z"
649
+ }
650
+ }
651
+ ],
652
+ "expected": [
653
+ {
654
+ "bannerId": "withcta",
655
+ "severity": "info",
656
+ "surface": "banner",
657
+ "cta": true
658
+ }
659
+ ]
660
+ },
661
+ {
662
+ "name": "a call to action on any other scheme is dropped and the banner still renders",
663
+ "input": [
664
+ {
665
+ "_id": "doc019",
666
+ "_rev": "1-aaa",
667
+ "bannerId": "badcta",
668
+ "category": "quota",
669
+ "severity": "info",
670
+ "surface": "banner",
671
+ "text": "Message.",
672
+ "lang": "en",
673
+ "cta": {
674
+ "label": "Upgrade",
675
+ "url": "javascript:alert(1)"
676
+ },
677
+ "dismissible": true,
678
+ "dismissedAt": null,
679
+ "priority": 50,
680
+ "startsAt": "2026-07-01T00:00:00Z",
681
+ "endsAt": null,
682
+ "source": {
683
+ "trigger": "test",
684
+ "at": "2026-07-01T00:00:00Z"
685
+ },
686
+ "cozyMetadata": {
687
+ "createdAt": "2026-07-01T00:00:00Z",
688
+ "createdByApp": "stack",
689
+ "doctypeVersion": "1",
690
+ "metadataVersion": 1,
691
+ "updatedAt": "2026-07-01T00:00:00Z"
692
+ }
693
+ }
694
+ ],
695
+ "expected": [
696
+ {
697
+ "bannerId": "badcta",
698
+ "severity": "info",
699
+ "surface": "banner",
700
+ "cta": false
701
+ }
702
+ ]
703
+ },
704
+ {
705
+ "name": "a null call to action renders no button",
706
+ "input": [
707
+ {
708
+ "_id": "doc020",
709
+ "_rev": "1-aaa",
710
+ "bannerId": "nullcta",
711
+ "category": "quota",
712
+ "severity": "info",
713
+ "surface": "banner",
714
+ "text": "Message.",
715
+ "lang": "en",
716
+ "cta": null,
717
+ "dismissible": true,
718
+ "dismissedAt": null,
719
+ "priority": 50,
720
+ "startsAt": "2026-07-01T00:00:00Z",
721
+ "endsAt": null,
722
+ "source": {
723
+ "trigger": "test",
724
+ "at": "2026-07-01T00:00:00Z"
725
+ },
726
+ "cozyMetadata": {
727
+ "createdAt": "2026-07-01T00:00:00Z",
728
+ "createdByApp": "stack",
729
+ "doctypeVersion": "1",
730
+ "metadataVersion": 1,
731
+ "updatedAt": "2026-07-01T00:00:00Z"
732
+ }
733
+ }
734
+ ],
735
+ "expected": [
736
+ {
737
+ "bannerId": "nullcta",
738
+ "severity": "info",
739
+ "surface": "banner",
740
+ "cta": false
741
+ }
742
+ ]
743
+ },
744
+ {
745
+ "name": "a document written by anything other than the stack is not rendered",
746
+ "input": [
747
+ {
748
+ "_id": "doc021",
749
+ "_rev": "1-aaa",
750
+ "bannerId": "untrusted",
751
+ "category": "quota",
752
+ "severity": "info",
753
+ "surface": "banner",
754
+ "text": "Message.",
755
+ "lang": "en",
756
+ "dismissible": true,
757
+ "dismissedAt": null,
758
+ "priority": 50,
759
+ "startsAt": "2026-07-01T00:00:00Z",
760
+ "endsAt": null,
761
+ "source": {
762
+ "trigger": "test",
763
+ "at": "2026-07-01T00:00:00Z"
764
+ },
765
+ "cozyMetadata": {
766
+ "createdAt": "2026-07-01T00:00:00Z",
767
+ "createdByApp": "drive",
768
+ "doctypeVersion": "1",
769
+ "metadataVersion": 1,
770
+ "updatedAt": "2026-07-01T00:00:00Z"
771
+ }
772
+ }
773
+ ],
774
+ "expected": []
775
+ },
776
+ {
777
+ "name": "a document above the supported version is skipped",
778
+ "supportedDoctypeVersion": 1,
779
+ "input": [
780
+ {
781
+ "_id": "doc022",
782
+ "_rev": "1-aaa",
783
+ "bannerId": "toonew",
784
+ "category": "quota",
785
+ "severity": "error",
786
+ "surface": "banner",
787
+ "text": "Message.",
788
+ "lang": "en",
789
+ "dismissible": true,
790
+ "dismissedAt": null,
791
+ "priority": 50,
792
+ "startsAt": "2026-07-01T00:00:00Z",
793
+ "endsAt": null,
794
+ "source": {
795
+ "trigger": "test",
796
+ "at": "2026-07-01T00:00:00Z"
797
+ },
798
+ "cozyMetadata": {
799
+ "createdAt": "2026-07-01T00:00:00Z",
800
+ "createdByApp": "stack",
801
+ "doctypeVersion": "2",
802
+ "metadataVersion": 1,
803
+ "updatedAt": "2026-07-01T00:00:00Z"
804
+ }
805
+ }
806
+ ],
807
+ "expected": []
808
+ },
809
+ {
810
+ "name": "the highest supported version of a bannerId wins, and the others are not rendered",
811
+ "supportedDoctypeVersion": 2,
812
+ "input": [
813
+ {
814
+ "_id": "doc023",
815
+ "_rev": "1-aaa",
816
+ "bannerId": "dual",
817
+ "category": "quota",
818
+ "severity": "info",
819
+ "surface": "banner",
820
+ "text": "Message.",
821
+ "lang": "en",
822
+ "dismissible": true,
823
+ "dismissedAt": null,
824
+ "priority": 50,
825
+ "startsAt": "2026-07-01T00:00:00Z",
826
+ "endsAt": null,
827
+ "source": {
828
+ "trigger": "test",
829
+ "at": "2026-07-01T00:00:00Z"
830
+ },
831
+ "cozyMetadata": {
832
+ "createdAt": "2026-07-01T00:00:00Z",
833
+ "createdByApp": "stack",
834
+ "doctypeVersion": "1",
835
+ "metadataVersion": 1,
836
+ "updatedAt": "2026-07-01T00:00:00Z"
837
+ }
838
+ },
839
+ {
840
+ "_id": "doc024",
841
+ "_rev": "1-aaa",
842
+ "bannerId": "dual",
843
+ "category": "quota",
844
+ "severity": "error",
845
+ "surface": "banner",
846
+ "text": "Message.",
847
+ "lang": "en",
848
+ "dismissible": true,
849
+ "dismissedAt": null,
850
+ "priority": 50,
851
+ "startsAt": "2026-07-01T00:00:00Z",
852
+ "endsAt": null,
853
+ "source": {
854
+ "trigger": "test",
855
+ "at": "2026-07-01T00:00:00Z"
856
+ },
857
+ "cozyMetadata": {
858
+ "createdAt": "2026-07-01T00:00:00Z",
859
+ "createdByApp": "stack",
860
+ "doctypeVersion": "3",
861
+ "metadataVersion": 1,
862
+ "updatedAt": "2026-07-01T00:00:00Z"
863
+ }
864
+ },
865
+ {
866
+ "_id": "doc025",
867
+ "_rev": "1-aaa",
868
+ "bannerId": "dual",
869
+ "category": "quota",
870
+ "severity": "info",
871
+ "surface": "modal",
872
+ "text": "Message.",
873
+ "lang": "en",
874
+ "dismissible": true,
875
+ "dismissedAt": null,
876
+ "priority": 50,
877
+ "startsAt": "2026-07-01T00:00:00Z",
878
+ "endsAt": null,
879
+ "source": {
880
+ "trigger": "test",
881
+ "at": "2026-07-01T00:00:00Z"
882
+ },
883
+ "cozyMetadata": {
884
+ "createdAt": "2026-07-01T00:00:00Z",
885
+ "createdByApp": "stack",
886
+ "doctypeVersion": "2",
887
+ "metadataVersion": 1,
888
+ "updatedAt": "2026-07-01T00:00:00Z"
889
+ }
890
+ }
891
+ ],
892
+ "expected": [
893
+ {
894
+ "bannerId": "dual",
895
+ "severity": "info",
896
+ "surface": "modal",
897
+ "cta": false
898
+ }
899
+ ]
900
+ },
901
+ {
902
+ "name": "at equal versions the most recently updated document wins",
903
+ "supportedDoctypeVersion": 1,
904
+ "input": [
905
+ {
906
+ "_id": "doc026",
907
+ "_rev": "1-aaa",
908
+ "bannerId": "same",
909
+ "category": "quota",
910
+ "severity": "info",
911
+ "surface": "banner",
912
+ "text": "Message.",
913
+ "lang": "en",
914
+ "dismissible": true,
915
+ "dismissedAt": null,
916
+ "priority": 50,
917
+ "startsAt": "2026-07-01T00:00:00Z",
918
+ "endsAt": null,
919
+ "source": {
920
+ "trigger": "test",
921
+ "at": "2026-07-01T00:00:00Z"
922
+ },
923
+ "cozyMetadata": {
924
+ "createdAt": "2026-07-01T00:00:00Z",
925
+ "createdByApp": "stack",
926
+ "doctypeVersion": "1",
927
+ "metadataVersion": 1,
928
+ "updatedAt": "2026-07-02T00:00:00Z"
929
+ }
930
+ },
931
+ {
932
+ "_id": "doc027",
933
+ "_rev": "1-aaa",
934
+ "bannerId": "same",
935
+ "category": "quota",
936
+ "severity": "info",
937
+ "surface": "modal",
938
+ "text": "Message.",
939
+ "lang": "en",
940
+ "dismissible": true,
941
+ "dismissedAt": null,
942
+ "priority": 50,
943
+ "startsAt": "2026-07-01T00:00:00Z",
944
+ "endsAt": null,
945
+ "source": {
946
+ "trigger": "test",
947
+ "at": "2026-07-01T00:00:00Z"
948
+ },
949
+ "cozyMetadata": {
950
+ "createdAt": "2026-07-01T00:00:00Z",
951
+ "createdByApp": "stack",
952
+ "doctypeVersion": "1",
953
+ "metadataVersion": 1,
954
+ "updatedAt": "2026-07-09T00:00:00Z"
955
+ }
956
+ }
957
+ ],
958
+ "expected": [
959
+ {
960
+ "bannerId": "same",
961
+ "severity": "info",
962
+ "surface": "modal",
963
+ "cta": false
964
+ }
965
+ ]
966
+ },
967
+ {
968
+ "name": "at equal versions and equal updatedAt the lowest _id wins",
969
+ "supportedDoctypeVersion": 1,
970
+ "input": [
971
+ {
972
+ "_id": "bbb",
973
+ "_rev": "1-aaa",
974
+ "bannerId": "tied",
975
+ "category": "quota",
976
+ "severity": "error",
977
+ "surface": "banner",
978
+ "text": "Message.",
979
+ "lang": "en",
980
+ "dismissible": true,
981
+ "dismissedAt": null,
982
+ "priority": 50,
983
+ "startsAt": "2026-07-01T00:00:00Z",
984
+ "endsAt": null,
985
+ "source": {
986
+ "trigger": "test",
987
+ "at": "2026-07-01T00:00:00Z"
988
+ },
989
+ "cozyMetadata": {
990
+ "createdAt": "2026-07-01T00:00:00Z",
991
+ "createdByApp": "stack",
992
+ "doctypeVersion": "1",
993
+ "metadataVersion": 1,
994
+ "updatedAt": "2026-07-01T00:00:00Z"
995
+ }
996
+ },
997
+ {
998
+ "_id": "aaa",
999
+ "_rev": "1-aaa",
1000
+ "bannerId": "tied",
1001
+ "category": "quota",
1002
+ "severity": "info",
1003
+ "surface": "modal",
1004
+ "text": "Message.",
1005
+ "lang": "en",
1006
+ "dismissible": true,
1007
+ "dismissedAt": null,
1008
+ "priority": 50,
1009
+ "startsAt": "2026-07-01T00:00:00Z",
1010
+ "endsAt": null,
1011
+ "source": {
1012
+ "trigger": "test",
1013
+ "at": "2026-07-01T00:00:00Z"
1014
+ },
1015
+ "cozyMetadata": {
1016
+ "createdAt": "2026-07-01T00:00:00Z",
1017
+ "createdByApp": "stack",
1018
+ "doctypeVersion": "1",
1019
+ "metadataVersion": 1,
1020
+ "updatedAt": "2026-07-01T00:00:00Z"
1021
+ }
1022
+ }
1023
+ ],
1024
+ "expected": [
1025
+ {
1026
+ "bannerId": "tied",
1027
+ "severity": "info",
1028
+ "surface": "modal",
1029
+ "cta": false
1030
+ }
1031
+ ]
1032
+ },
1033
+ {
1034
+ "name": "a dismissal of one version hides every version of that bannerId",
1035
+ "supportedDoctypeVersion": 2,
1036
+ "input": [
1037
+ {
1038
+ "_id": "doc030",
1039
+ "_rev": "1-aaa",
1040
+ "bannerId": "shared",
1041
+ "category": "quota",
1042
+ "severity": "info",
1043
+ "surface": "banner",
1044
+ "text": "Message.",
1045
+ "lang": "en",
1046
+ "dismissible": true,
1047
+ "dismissedAt": "2026-07-21T08:00:00Z",
1048
+ "priority": 50,
1049
+ "startsAt": "2026-07-01T00:00:00Z",
1050
+ "endsAt": null,
1051
+ "source": {
1052
+ "trigger": "test",
1053
+ "at": "2026-07-01T00:00:00Z"
1054
+ },
1055
+ "cozyMetadata": {
1056
+ "createdAt": "2026-07-01T00:00:00Z",
1057
+ "createdByApp": "stack",
1058
+ "doctypeVersion": "1",
1059
+ "metadataVersion": 1,
1060
+ "updatedAt": "2026-07-01T00:00:00Z"
1061
+ }
1062
+ },
1063
+ {
1064
+ "_id": "doc031",
1065
+ "_rev": "1-aaa",
1066
+ "bannerId": "shared",
1067
+ "category": "quota",
1068
+ "severity": "info",
1069
+ "surface": "banner",
1070
+ "text": "Message.",
1071
+ "lang": "en",
1072
+ "dismissible": true,
1073
+ "dismissedAt": null,
1074
+ "priority": 50,
1075
+ "startsAt": "2026-07-01T00:00:00Z",
1076
+ "endsAt": null,
1077
+ "source": {
1078
+ "trigger": "test",
1079
+ "at": "2026-07-01T00:00:00Z"
1080
+ },
1081
+ "cozyMetadata": {
1082
+ "createdAt": "2026-07-01T00:00:00Z",
1083
+ "createdByApp": "stack",
1084
+ "doctypeVersion": "2",
1085
+ "metadataVersion": 1,
1086
+ "updatedAt": "2026-07-01T00:00:00Z"
1087
+ }
1088
+ }
1089
+ ],
1090
+ "expected": []
1091
+ },
1092
+ {
1093
+ "name": "a dismissal recorded on a version this client cannot read still hides the banner",
1094
+ "supportedDoctypeVersion": 1,
1095
+ "input": [
1096
+ {
1097
+ "_id": "docx01",
1098
+ "_rev": "1-aaa",
1099
+ "bannerId": "crossversion",
1100
+ "category": "quota",
1101
+ "severity": "info",
1102
+ "surface": "banner",
1103
+ "text": "Message.",
1104
+ "lang": "en",
1105
+ "dismissible": true,
1106
+ "dismissedAt": null,
1107
+ "priority": 50,
1108
+ "startsAt": "2026-07-01T00:00:00Z",
1109
+ "endsAt": null,
1110
+ "source": {
1111
+ "trigger": "test",
1112
+ "at": "2026-07-01T00:00:00Z"
1113
+ },
1114
+ "cozyMetadata": {
1115
+ "createdAt": "2026-07-01T00:00:00Z",
1116
+ "createdByApp": "stack",
1117
+ "doctypeVersion": "1",
1118
+ "metadataVersion": 1,
1119
+ "updatedAt": "2026-07-01T00:00:00Z"
1120
+ }
1121
+ },
1122
+ {
1123
+ "_id": "docx02",
1124
+ "_rev": "1-aaa",
1125
+ "bannerId": "crossversion",
1126
+ "category": "quota",
1127
+ "severity": "info",
1128
+ "surface": "banner",
1129
+ "text": "Message.",
1130
+ "lang": "en",
1131
+ "dismissible": true,
1132
+ "dismissedAt": "2026-07-21T08:00:00Z",
1133
+ "priority": 50,
1134
+ "startsAt": "2026-07-01T00:00:00Z",
1135
+ "endsAt": null,
1136
+ "source": {
1137
+ "trigger": "test",
1138
+ "at": "2026-07-01T00:00:00Z"
1139
+ },
1140
+ "cozyMetadata": {
1141
+ "createdAt": "2026-07-01T00:00:00Z",
1142
+ "createdByApp": "stack",
1143
+ "doctypeVersion": "2",
1144
+ "metadataVersion": 1,
1145
+ "updatedAt": "2026-07-01T00:00:00Z"
1146
+ }
1147
+ }
1148
+ ],
1149
+ "expected": []
1150
+ }
1151
+ ]
1152
+ }