@conduction/nextcloud-vue 2.56.0-beta.12 → 2.56.0-beta.14

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.
Files changed (119) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +19 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +10 -3
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +101 -5
  6. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +23 -7
  8. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  9. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
  10. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
  11. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
  12. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
  13. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +125 -4
  14. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +439 -381
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  17. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +9 -3
  18. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -1
  19. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +1 -1
  20. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +4 -4
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +142 -26
  25. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +195 -124
  27. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  28. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js +3 -1
  29. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js.map +1 -1
  30. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +144 -4
  31. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  32. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  33. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +84 -11
  34. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  35. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +3 -2
  36. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  37. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +31 -1
  38. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +335 -313
  40. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  41. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +11 -0
  42. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  43. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +2 -1
  44. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  45. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +5 -11
  46. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  47. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  48. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  49. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  50. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +22 -3
  51. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  52. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +10 -3
  53. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  54. package/dist/esm/composables/useDependencyCheck.js +44 -1
  55. package/dist/esm/composables/useDependencyCheck.js.map +1 -1
  56. package/dist/esm/composables/useListView.js +43 -1
  57. package/dist/esm/composables/useListView.js.map +1 -1
  58. package/dist/esm/composables/useSetupStatus.js +26 -3
  59. package/dist/esm/composables/useSetupStatus.js.map +1 -1
  60. package/dist/esm/l10n/en.json.js +7 -1
  61. package/dist/esm/l10n/en.json.js.map +1 -1
  62. package/dist/esm/l10n/nl.json.js +7 -1
  63. package/dist/esm/l10n/nl.json.js.map +1 -1
  64. package/dist/esm/mixins/pageViews.js +400 -0
  65. package/dist/esm/mixins/pageViews.js.map +1 -0
  66. package/dist/esm/nextcloud-vue.css +202 -2
  67. package/dist/esm/store/plugins/liveUpdates.js +19 -9
  68. package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
  69. package/dist/esm/store/useObjectStore.js +138 -42
  70. package/dist/esm/store/useObjectStore.js.map +1 -1
  71. package/dist/esm/utils/actionsDispatcher.js +25 -2
  72. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  73. package/dist/esm/utils/columnFilters.js +27 -3
  74. package/dist/esm/utils/columnFilters.js.map +1 -1
  75. package/dist/esm/utils/schema.js +40 -2
  76. package/dist/esm/utils/schema.js.map +1 -1
  77. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  78. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  79. package/dist/nextcloud-vue.cjs.js +2857 -1335
  80. package/dist/nextcloud-vue.cjs.js.map +2 -2
  81. package/dist/nextcloud-vue.css +202 -2
  82. package/l10n/en.json +7 -1
  83. package/l10n/nl.json +7 -1
  84. package/package.json +1 -1
  85. package/src/components/CnActionsBar/CnActionsBar.md +2 -1
  86. package/src/components/CnActionsBar/CnActionsBar.vue +25 -1
  87. package/src/components/CnAppNav/CnAppNav.vue +150 -9
  88. package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
  89. package/src/components/CnDashboardPage/CnDashboardPage.vue +194 -10
  90. package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
  91. package/src/components/CnDataTable/CnDataTable.md +1 -1
  92. package/src/components/CnDataTable/CnDataTable.vue +4 -4
  93. package/src/components/CnDetailPage/CnDetailPage.md +5 -1
  94. package/src/components/CnDetailPage/CnDetailPage.vue +208 -11
  95. package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
  96. package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
  97. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +100 -13
  98. package/src/components/CnIndexPage/CnIndexPage.md +2 -1
  99. package/src/components/CnIndexPage/CnIndexPage.vue +47 -1
  100. package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
  101. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
  102. package/src/components/CnSetupWizard/CnSetupWizard.vue +5 -11
  103. package/src/components/CnStagesWidget/CnStagesWidget.vue +9 -0
  104. package/src/components/CnStatWidget/CnStatWidget.vue +33 -5
  105. package/src/composables/useDependencyCheck.js +43 -0
  106. package/src/composables/useListView.js +43 -1
  107. package/src/composables/useSetupStatus.js +26 -3
  108. package/src/css/actions-bar.css +20 -2
  109. package/src/css/detail-page.css +27 -0
  110. package/src/css/kpi-card.css +47 -0
  111. package/src/mixins/pageViews.js +396 -0
  112. package/src/schemas/app-manifest-v2.schema.json +53 -4
  113. package/src/schemas/app-manifest.schema.json +1 -1
  114. package/src/store/plugins/liveUpdates.js +19 -9
  115. package/src/store/useObjectStore.js +137 -41
  116. package/src/utils/actionsDispatcher.js +25 -2
  117. package/src/utils/columnFilters.js +29 -2
  118. package/src/utils/schema.js +40 -2
  119. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -1283,6 +1283,53 @@
1283
1283
  font-size: var(--cn-kpi-value-size-stacked, 2rem);
1284
1284
  }
1285
1285
 
1286
+ /* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
1287
+ label, the number at 34px/700 in the text colour, and the caption on a line
1288
+ of its own; CnStatWidget draws no icon circle in this layout. The padding
1289
+ adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
1290
+ Every value is a token so a theme can move it. */
1291
+ .cn-kpi-card--stacked {
1292
+ flex-direction: column;
1293
+ align-items: stretch;
1294
+ justify-content: center;
1295
+ gap: 0;
1296
+ padding: var(--cn-kpi-stacked-padding, 10px 6px);
1297
+ }
1298
+
1299
+ .cn-kpi-card--stacked .cn-kpi-card__body {
1300
+ gap: var(--cn-kpi-stacked-gap, 6px);
1301
+ }
1302
+
1303
+ .cn-kpi-card--stacked .cn-kpi-card__title {
1304
+ font-size: var(--cn-kpi-stacked-title-size, 14px);
1305
+ font-weight: var(--cn-kpi-stacked-title-weight, 400);
1306
+ color: var(--color-text-maxcontrast);
1307
+ }
1308
+
1309
+ .cn-kpi-card--stacked .cn-kpi-card__value {
1310
+ font-size: var(--cn-kpi-stacked-value-size, 34px);
1311
+ font-weight: var(--cn-kpi-value-weight, 700);
1312
+ line-height: 1;
1313
+ letter-spacing: -0.01em;
1314
+ color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
1315
+ }
1316
+
1317
+ .cn-kpi-card--stacked .cn-kpi-card__caption-line {
1318
+ flex: 0 0 auto;
1319
+ max-width: 100%;
1320
+ font-size: var(--cn-kpi-label-size, 13px);
1321
+ font-weight: 500;
1322
+ }
1323
+
1324
+ /* A linked stacked tile reads as a tile, not as underlined link text. The
1325
+ NL Design theme underlines every `a` with `!important`, so the opt-out
1326
+ needs it too; it only applies to this opt-in layout. */
1327
+ a.cn-kpi-card--stacked,
1328
+ a.cn-kpi-card--stacked:hover,
1329
+ a.cn-kpi-card--stacked:focus-visible {
1330
+ text-decoration: none !important;
1331
+ }
1332
+
1286
1333
  /* Filled: the card draws its own grey box, for a KPI that is NOT already
1287
1334
  inside a wrapper that draws one. Opt-in via `content.flat: false`. */
1288
1335
  .cn-kpi-card--filled {
@@ -1893,6 +1940,23 @@
1893
1940
  color: var(--color-text-maxcontrast);
1894
1941
  }
1895
1942
 
1943
+ /* Beside the inline search (`showCountWithSearch`): the search field shrinks
1944
+ first and the counter stays on one line. */
1945
+ .cn-actions-bar__count--beside-search {
1946
+ flex-shrink: 0;
1947
+ white-space: nowrap;
1948
+ }
1949
+
1950
+ /* Taken out of the flex row so it adds no gap, but kept in the accessibility
1951
+ tree so the live region exists before a total appears. */
1952
+ .cn-actions-bar__count--empty {
1953
+ position: absolute;
1954
+ width: 1px;
1955
+ height: 1px;
1956
+ overflow: hidden;
1957
+ clip-path: inset(50%);
1958
+ }
1959
+
1896
1960
  /* Inline search field */
1897
1961
  .cn-actions-bar__search {
1898
1962
  position: relative;
@@ -2152,8 +2216,9 @@
2152
2216
  display: contents;
2153
2217
  }
2154
2218
 
2155
- /* #after-search filter buttons + the view toggle ride beside the
2156
- search field (DOM order — search first via its own order). */
2219
+ /* #after-search filter buttons, the beside-search counter and the view
2220
+ toggle ride beside the search field (DOM order — search first via its
2221
+ own order). */
2157
2222
  .cn-actions-bar__info > * {
2158
2223
  order: 1;
2159
2224
  }
@@ -2790,6 +2855,28 @@
2790
2855
  min-width: 0;
2791
2856
  }
2792
2857
 
2858
+ /* A widget in the header (`config.headerWidget`) takes a row of its own under
2859
+ the title and the actions. */
2860
+ .cn-detail-page__header--with-widget {
2861
+ flex-wrap: wrap;
2862
+ row-gap: var(--cn-detail-header-row-gap, 22px);
2863
+ }
2864
+
2865
+ .cn-detail-page__header-widget {
2866
+ flex: 1 0 100%;
2867
+ min-width: 0;
2868
+ }
2869
+
2870
+ /* The header as a card (`config.headerCard`): the board's case header, a
2871
+ bordered box on the surface colour. The 56px inset that clears the
2872
+ navigation toggle is not needed inside a card that starts below it. */
2873
+ .cn-detail-page__header--card {
2874
+ padding: var(--cn-detail-header-card-padding, 22px 24px);
2875
+ border: 1px solid var(--color-border);
2876
+ border-radius: var(--cn-detail-header-card-radius, 12px);
2877
+ background: var(--color-main-background);
2878
+ }
2879
+
2793
2880
  .cn-detail-page__header-left {
2794
2881
  display: flex;
2795
2882
  align-items: center;
@@ -3210,6 +3297,11 @@
3210
3297
  font-size: 0.9em;
3211
3298
  white-space: nowrap;
3212
3299
  }
3300
+
3301
+ /* A page view the switch shows with nothing to draw (view-switch-containers). */
3302
+ .cn-detail-page .cn-page-view-region--empty {
3303
+ padding: 40px 20px;
3304
+ }
3213
3305
  /* CnReferencePreview — a reference that shows what it points at. */
3214
3306
 
3215
3307
  .cn-reference-preview {
@@ -16875,7 +16967,17 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16875
16967
  text-overflow: ellipsis;
16876
16968
  white-space: nowrap;
16877
16969
  }
16970
+
16971
+ /* A clickable label is a <button>, and Nextcloud's core stylesheet gives
16972
+ every `button:not(.button-vue)` a min-height of the clickable area (34 to
16973
+ 44px) with the text centred in it. That pushed each reachable stage's label
16974
+ about 12px below the current one, which is a <span>. Zeroed here so all
16975
+ labels sit 8px under their bar, as the board draws them. The visually
16976
+ hidden "(current step)" is absolutely positioned and takes no space. */
16878
16977
  button.cn-stages-widget__bar-label[data-v-358fde0f] {
16978
+ min-height: 0;
16979
+ height: auto;
16980
+ line-height: inherit;
16879
16981
  cursor: pointer;
16880
16982
  }
16881
16983
  button.cn-stages-widget__bar-label[aria-disabled="true"][data-v-358fde0f] {
@@ -17310,6 +17412,53 @@ button.cn-stages-widget__bar-label[data-v-358fde0f]:focus-visible {
17310
17412
  font-size: var(--cn-kpi-value-size-stacked, 2rem);
17311
17413
  }
17312
17414
 
17415
+ /* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
17416
+ label, the number at 34px/700 in the text colour, and the caption on a line
17417
+ of its own; CnStatWidget draws no icon circle in this layout. The padding
17418
+ adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
17419
+ Every value is a token so a theme can move it. */
17420
+ .cn-kpi-card--stacked {
17421
+ flex-direction: column;
17422
+ align-items: stretch;
17423
+ justify-content: center;
17424
+ gap: 0;
17425
+ padding: var(--cn-kpi-stacked-padding, 10px 6px);
17426
+ }
17427
+
17428
+ .cn-kpi-card--stacked .cn-kpi-card__body {
17429
+ gap: var(--cn-kpi-stacked-gap, 6px);
17430
+ }
17431
+
17432
+ .cn-kpi-card--stacked .cn-kpi-card__title {
17433
+ font-size: var(--cn-kpi-stacked-title-size, 14px);
17434
+ font-weight: var(--cn-kpi-stacked-title-weight, 400);
17435
+ color: var(--color-text-maxcontrast);
17436
+ }
17437
+
17438
+ .cn-kpi-card--stacked .cn-kpi-card__value {
17439
+ font-size: var(--cn-kpi-stacked-value-size, 34px);
17440
+ font-weight: var(--cn-kpi-value-weight, 700);
17441
+ line-height: 1;
17442
+ letter-spacing: -0.01em;
17443
+ color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
17444
+ }
17445
+
17446
+ .cn-kpi-card--stacked .cn-kpi-card__caption-line {
17447
+ flex: 0 0 auto;
17448
+ max-width: 100%;
17449
+ font-size: var(--cn-kpi-label-size, 13px);
17450
+ font-weight: 500;
17451
+ }
17452
+
17453
+ /* A linked stacked tile reads as a tile, not as underlined link text. The
17454
+ NL Design theme underlines every `a` with `!important`, so the opt-out
17455
+ needs it too; it only applies to this opt-in layout. */
17456
+ a.cn-kpi-card--stacked,
17457
+ a.cn-kpi-card--stacked:hover,
17458
+ a.cn-kpi-card--stacked:focus-visible {
17459
+ text-decoration: none !important;
17460
+ }
17461
+
17313
17462
  /* Filled: the card draws its own grey box, for a KPI that is NOT already
17314
17463
  inside a wrapper that draws one. Opt-in via `content.flat: false`. */
17315
17464
  .cn-kpi-card--filled {
@@ -18262,6 +18411,16 @@ to { background-position: -200% 0;
18262
18411
  flex: 0 0 auto;
18263
18412
  padding: 16px;
18264
18413
  }
18414
+
18415
+ /* On the page ground (`content.ground`): no card, so no inset around the
18416
+ view switch, and the heading at the board's 32px. */
18417
+ .cn-header-widget--ground .cn-header-widget__views[data-v-1b97430f] {
18418
+ padding: 0;
18419
+ }
18420
+ .cn-header-widget--ground .cn-header-widget__title[data-v-1b97430f] {
18421
+ font-size: var(--cn-header-ground-title-size, 32px);
18422
+ letter-spacing: -0.01em;
18423
+ }
18265
18424
  .cn-header-widget__date[data-v-1b97430f] {
18266
18425
  font-size: 14px;
18267
18426
  line-height: 1.4;
@@ -30431,6 +30590,19 @@ to {
30431
30590
  .cn-dashboard-page__empty[data-v-824052fe] {
30432
30591
  padding: 60px 20px;
30433
30592
  }
30593
+
30594
+ /* The page's view switch on a page without a header row: at the end of its
30595
+ own row, above the grids, where the header would have put it. */
30596
+ .cn-dashboard-page__view-switch[data-v-824052fe] {
30597
+ display: flex;
30598
+ justify-content: flex-end;
30599
+ margin-bottom: 12px;
30600
+ }
30601
+
30602
+ /* A view the switch shows with nothing to draw. */
30603
+ .cn-page-view-region--empty[data-v-824052fe] {
30604
+ padding: 40px 20px;
30605
+ }
30434
30606
  .cn-dashboard-page__page-filters[data-v-824052fe] {
30435
30607
  display: flex;
30436
30608
  flex-wrap: wrap;
@@ -33247,6 +33419,21 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
33247
33419
  padding: calc(var(--default-grid-baseline, 4px) * 2);
33248
33420
  }
33249
33421
 
33422
+ /*
33423
+ * The primary action never shrinks out of sight. NcAppNavigation renders it in
33424
+ * `.app-navigation__body`, a flex child with `overflow-y: scroll` (so its
33425
+ * minimum height is 0) beside a list of `height: 100%` and the footer. With a
33426
+ * card and footer entries below the list, the column overflows and the body
33427
+ * gives up its share of the shrink: "New case" showed as a 24px sliver of a
33428
+ * 42px button. All three forms carry `.app-navigation-new` (the solid and
33429
+ * link wrappers mirror NcAppNavigationNew's class), and the rule is scoped to
33430
+ * this component's navigation, so a navigation without a primary action lays
33431
+ * out exactly as before.
33432
+ */
33433
+ .app-navigation[data-testid="cn-nav"] .app-navigation__body:has(> .app-navigation-new) {
33434
+ flex-shrink: 0;
33435
+ }
33436
+
33250
33437
  /*
33251
33438
  * Footer-section items (section: "footer") render in NcAppNavigation's
33252
33439
  * #footer slot, outside the scroll container, so they stay visible above
@@ -33270,6 +33457,19 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
33270
33457
  overflow: visible !important;
33271
33458
  }
33272
33459
 
33460
+ /*
33461
+ * A declared footer that names `settings` first (`nav.footer`) puts the
33462
+ * foldout above the footer list. The two are siblings in NcAppNavigation's
33463
+ * flex column, so `order` moves them without changing either's markup; the
33464
+ * card above keeps order 0 and stays first.
33465
+ */
33466
+ .cn-app-nav__settings--first {
33467
+ order: 1;
33468
+ }
33469
+ .cn-app-nav__footer-list--after-settings {
33470
+ order: 2;
33471
+ }
33472
+
33273
33473
  /*
33274
33474
  * Align the settings foldout's items with the main/footer list items,
33275
33475
  * whose icons sit at a 16px inset. The foldout's items live in a bare
@@ -423,19 +423,29 @@ function liveUpdatesPlugin(opts = {}) {
423
423
  const collectionInFlight = new Map();
424
424
 
425
425
  const originalFetchCollection = store.fetchCollection.bind(store);
426
- store.fetchCollection = async function dedupedFetchCollection(type, params = {}) {
426
+ store.fetchCollection = async function dedupedFetchCollection(type, params = {}, options = {}) {
427
427
  if (!store.__liveDedupActive) {
428
- return originalFetchCollection(type, params)
428
+ return originalFetchCollection(type, params, options)
429
429
  }
430
430
  const key = collectionDedupKey(type, params);
431
- if (collectionInFlight.has(key)) {
432
- return collectionInFlight.get(key)
431
+ let entry = collectionInFlight.get(key);
432
+ if (!entry) {
433
+ // The shared request reports into its own sink, copied to
434
+ // each caller's `options.outcome` below, so a caller that
435
+ // joined it learns that request's result too.
436
+ const outcome = {};
437
+ const promise = originalFetchCollection(type, params, { ...options, outcome }).finally(() => {
438
+ collectionInFlight.delete(key);
439
+ });
440
+ entry = { promise, outcome };
441
+ collectionInFlight.set(key, entry);
433
442
  }
434
- const promise = originalFetchCollection(type, params).finally(() => {
435
- collectionInFlight.delete(key);
436
- });
437
- collectionInFlight.set(key, promise);
438
- return promise
443
+ const results = await entry.promise;
444
+ const sink = options && options.outcome;
445
+ if (sink && typeof sink === 'object' && 'error' in entry.outcome) {
446
+ sink.error = entry.outcome.error;
447
+ }
448
+ return results
439
449
  };
440
450
  },
441
451
  }
@@ -1 +1 @@
1
- {"version":3,"file":"liveUpdates.js","sources":["../../../../src/store/plugins/liveUpdates.js"],"sourcesContent":["/**\n * liveUpdatesPlugin — Pinia plugin factory for OpenRegister real-time updates.\n *\n * Adds live-update subscription support to any store created via createObjectStore().\n * Uses @nextcloud/notify_push via the transport singleton, with automatic polling\n * fallback when push is unavailable.\n *\n * Contributed state:\n * - `liveStatus` — current transport status string (`'offline'|'connecting'|'live'|'reconnecting'|'polling'`)\n * - `liveSubscriptions` — number of active subscriptions\n * - `liveLastEventAt` — Date of last received event, or null\n *\n * Contributed getters:\n * - `getLiveStatus`, `getLiveSubscriptions`, `getLiveLastEventAt`\n *\n * Contributed actions:\n * - `subscribe(type, id?, opts?)` — subscribe to live updates; returns a handle\n * - `unsubscribe(handle)` — tear down a subscription\n *\n * Usage note (Options API):\n * `tryOnScopeDispose` auto-registers cleanup when called from a Vue setup()\n * or Options API mounted() with an active effect scope. In Options API mounted()\n * without Vue 2.7 scope tracking, manual `unsubscribe(handle)` in beforeDestroy\n * is required. Document this at the call site.\n *\n * In-flight dedup:\n * Concurrent calls to fetchObject(type, id) or fetchCollection(type, params)\n * for the same key are coalesced into one HTTP request. The dedup maps live as\n * plain (non-reactive) Maps on the store instance to avoid Vue 2 overhead.\n * Dedup activates on the FIRST `subscribe()` call — before that, fetch actions\n * pass straight through to the base implementations. This keeps the plugin\n * fully inert (zero behaviour change) on stores that never subscribe, which\n * matters now that createObjectStore installs this plugin by default\n * (live-updates-default-on).\n *\n * Laziness guarantee:\n * Installing the plugin causes NO transport activity. The transport singleton\n * (and therefore the notify_push `listen()` probe / websocket connection /\n * polling timers) is only created inside the `subscribe()` action.\n *\n * Event coalescing:\n * Live events are HINTS (\"something changed\"), not payloads — each one\n * triggers a refetch. A burst of events (mass import, bulk save, another\n * user's rapid edits) would fire a refetch per event, so the dispatch is\n * coalesced per subscription: the FIRST event refetches immediately, and\n * any further events inside the `refetchDebounce` window (default 750 ms)\n * collapse into ONE trailing refetch when the window closes. Pending\n * trailing refetches are cancelled by `unsubscribe()`.\n *\n * @param {object} [opts] Plugin options\n * @param {number} [opts.pollIntervalCollection=30000] Collection poll interval (ms)\n * @param {number} [opts.pollIntervalObject=60000] Object poll interval (ms)\n * @param {number} [opts.refetchDebounce=750] Event-burst coalescing window (ms); 0 disables\n * @return {object} Plugin definition for use with createObjectStore\n *\n * @example\n * import { createObjectStore, liveUpdatesPlugin } from '@conduction/nextcloud-vue'\n *\n * const useStore = createObjectStore('myStore', {\n * plugins: [liveUpdatesPlugin({ pollIntervalCollection: 15000 })],\n * })\n *\n * // In a Vue component:\n * const store = useStore()\n * const handle = await store.subscribe('melding') // collection\n * const handle2 = await store.subscribe('melding', id) // object\n * // In beforeDestroy (Options API without scope):\n * store.unsubscribe(handle)\n */\n\n// `tryOnScopeDispose` comes from @vueuse/core, a DECLARED (non-optional) peer\n// dependency, so it is imported statically.\n//\n// It used to be pulled in through a CommonJS call inside a try/catch \"to avoid\n// a hard failure if @vueuse/core is absent\". That could not work: this module\n// ships to `dist/esm/**` where that function is not defined, and @vueuse/core's\n// own `exports` map resolves \".\" to a single ESM file with no CommonJS\n// condition. The catch therefore fired every time, `_tryOnScopeDispose` was\n// permanently null, and auto-cleanup on scope dispose silently never happened —\n// subscriptions leaked with no warning anywhere.\nimport { tryOnScopeDispose as _tryOnScopeDispose } from '@vueuse/core'\nimport { buildCollectionKey, buildObjectKey } from '../liveUpdates/eventKeys.js'\nimport { getLiveUpdates } from '../liveUpdates/transport.js'\n\n/**\n * Compute a stable cache key for dedup of fetchCollection calls.\n *\n * @param {string} type Object type slug\n * @param {object} params Query params\n * @return {string}\n */\nfunction collectionDedupKey(type, params) {\n\treturn `${type}:${JSON.stringify(params)}`\n}\n\n/**\n * Compute the cache key for dedup of fetchObject calls.\n *\n * @param {string} type Object type slug\n * @param {string} id Object ID\n * @return {string}\n */\nfunction objectDedupKey(type, id) {\n\treturn `${type}:${id}`\n}\n\n/**\n * Wrap a refetch dispatcher in a leading+trailing burst coalescer.\n *\n * Events are hints, so the exact invocation count doesn't matter — only\n * that the data ends up fresh. The first `run()` dispatches immediately\n * (snappy single-event case); further `run()`s inside the `waitMs` window\n * collapse into one trailing dispatch when the window closes (which opens\n * a new window, so a sustained burst dispatches at most once per window).\n * `cancel()` clears any pending trailing dispatch — called on\n * unsubscribe so a torn-down subscription never fires a late refetch.\n *\n * @param {() => void} fn The refetch dispatcher.\n * @param {number} waitMs Coalescing window in ms; `<= 0` disables (every run dispatches).\n * @return {{run: () => void, cancel: () => void}} The coalesced dispatcher.\n */\nfunction createHintCoalescer(fn, waitMs) {\n\tlet timer = null\n\tlet pending = false\n\n\tfunction run() {\n\t\tif (!(waitMs > 0)) {\n\t\t\tfn()\n\t\t\treturn\n\t\t}\n\t\tif (timer) {\n\t\t\tpending = true\n\t\t\treturn\n\t\t}\n\t\tfn()\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = null\n\t\t\tif (pending) {\n\t\t\t\tpending = false\n\t\t\t\trun()\n\t\t\t}\n\t\t}, waitMs)\n\t}\n\n\tfunction cancel() {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer)\n\t\t}\n\t\ttimer = null\n\t\tpending = false\n\t}\n\n\treturn { run, cancel }\n}\n\nexport function liveUpdatesPlugin(opts = {}) {\n\tconst pluginPollCollection = opts.pollIntervalCollection || 30000\n\tconst pluginPollObject = opts.pollIntervalObject || 60000\n\tconst pluginRefetchDebounce = opts.refetchDebounce === undefined ? 750 : opts.refetchDebounce\n\n\treturn {\n\t\tname: 'liveUpdates',\n\n\t\tstate: () => ({\n\t\t\t/** @type {'offline'|'connecting'|'live'|'reconnecting'|'polling'} */\n\t\t\tliveStatus: 'offline',\n\t\t\t/** @type {number} */\n\t\t\tliveSubscriptions: 0,\n\t\t\t/** @type {Date|null} */\n\t\t\tliveLastEventAt: null,\n\t\t}),\n\n\t\tgetters: {\n\t\t\t/**\n\t\t\t * Get the current transport status.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {string}\n\t\t\t */\n\t\t\tgetLiveStatus: (state) => state.liveStatus,\n\n\t\t\t/**\n\t\t\t * Get the number of active subscriptions.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {number}\n\t\t\t */\n\t\t\tgetLiveSubscriptions: (state) => state.liveSubscriptions,\n\n\t\t\t/**\n\t\t\t * Get the timestamp of the last received live event.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {Date|null}\n\t\t\t */\n\t\t\tgetLiveLastEventAt: (state) => state.liveLastEventAt,\n\t\t},\n\n\t\tactions: {\n\t\t\t/**\n\t\t\t * Subscribe to live updates for an object type.\n\t\t\t *\n\t\t\t * When `id` is provided: subscribes to `or-object-{id}` (per-object events).\n\t\t\t * When `id` is omitted: subscribes to `or-collection-{registerSlug}-{schemaSlug}`\n\t\t\t * derived from objectTypeRegistry. Slugs are lazy-fetched if not already cached.\n\t\t\t *\n\t\t\t * **Options API note**: In `mounted()` without an active Vue scope,\n\t\t\t * `tryOnScopeDispose` cannot auto-register cleanup. Call `unsubscribe(handle)`\n\t\t\t * manually in `beforeDestroy`.\n\t\t\t *\n\t\t\t * @param {string} type Registered object type slug\n\t\t\t * @param {string} [id] Object UUID (omit for collection subscription)\n\t\t\t * @param {object} [subscribeOpts] Options\n\t\t\t * @param {number} [subscribeOpts.interval] Override poll interval (ms)\n\t\t\t * @return {Promise<object>} Opaque handle for unsubscribe()\n\t\t\t * @throws {Error} If type is not registered, or if lazy slug fetch fails (collection form)\n\t\t\t */\n\t\t\tasync subscribe(type, id, subscribeOpts = {}) {\n\t\t\t\tconst config = this.objectTypeRegistry[type]\n\t\t\t\tif (!config) {\n\t\t\t\t\tthrow new Error(`\"${type}\" is not registered. Call registerObjectType('${type}', ...) first.`)\n\t\t\t\t}\n\n\t\t\t\t// First subscribe() activates the in-flight dedup wrappers set\n\t\t\t\t// up in the plugin's setup() hook. Before this point the store\n\t\t\t\t// behaves exactly as if the plugin were not installed.\n\t\t\t\tthis.__liveDedupActive = true\n\n\t\t\t\tconst liveUpdates = getLiveUpdates({\n\t\t\t\t\tpollIntervalCollection: pluginPollCollection,\n\t\t\t\t\tpollIntervalObject: pluginPollObject,\n\t\t\t\t})\n\n\t\t\t\t// Register transport status observer (idempotent: only once per store instance)\n\t\t\t\tif (!this.__liveStatusObserverRegistered) {\n\t\t\t\t\tthis.__liveStatusObserverRegistered = true\n\t\t\t\t\tliveUpdates.onStatusChange((newStatus) => {\n\t\t\t\t\t\tthis.liveStatus = { ...this.liveStatus, valueOf: undefined, toString: undefined }\n\t\t\t\t\t\t// Vue 2 spread pattern for primitive reactive update\n\t\t\t\t\t\tthis.liveStatus = newStatus\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tlet eventKey\n\t\t\t\tlet isObject = false\n\n\t\t\t\tif (id !== undefined && id !== null) {\n\t\t\t\t\t// Object subscription — no slug lookup needed\n\t\t\t\t\tisObject = true\n\t\t\t\t\teventKey = buildObjectKey(id)\n\t\t\t\t} else {\n\t\t\t\t\t// Collection subscription — need registerSlug + schemaSlug\n\t\t\t\t\tlet { registerSlug, schemaSlug } = config\n\n\t\t\t\t\tif (!registerSlug || !schemaSlug) {\n\t\t\t\t\t\t// Lazy fetch slugs via existing store actions\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst [register, schema] = await Promise.all([\n\t\t\t\t\t\t\t\tthis.fetchRegister(type),\n\t\t\t\t\t\t\t\tthis.fetchSchema(type),\n\t\t\t\t\t\t\t])\n\n\t\t\t\t\t\t\tif (!register || !register.slug) {\n\t\t\t\t\t\t\t\tthrow new Error(`Failed to resolve register slug for \"${type}\"`)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!schema || !schema.slug) {\n\t\t\t\t\t\t\t\tthrow new Error(`Failed to resolve schema slug for \"${type}\"`)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tregisterSlug = register.slug\n\t\t\t\t\t\t\tschemaSlug = schema.slug\n\n\t\t\t\t\t\t\t// Cache slugs in registry (Vue 2 spread pattern)\n\t\t\t\t\t\t\tthis.objectTypeRegistry = {\n\t\t\t\t\t\t\t\t...this.objectTypeRegistry,\n\t\t\t\t\t\t\t\t[type]: { ...config, registerSlug, schemaSlug },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tthrow new Error(`liveUpdatesPlugin: cannot subscribe to \"${type}\" collection — ${err.message}`, { cause: err })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\teventKey = buildCollectionKey(registerSlug, schemaSlug)\n\t\t\t\t}\n\n\t\t\t\t// Set status to 'connecting' on first subscribe (before transport sets it)\n\t\t\t\tif (this.liveStatus === 'offline') {\n\t\t\t\t\tthis.liveStatus = 'connecting'\n\t\t\t\t}\n\n\t\t\t\tconst store = this\n\n\t\t\t\t// Events are hints — coalesce refetch bursts per subscription\n\t\t\t\t// (see \"Event coalescing\" in the module docblock). A per-call\n\t\t\t\t// `subscribeOpts.debounce` overrides the plugin default; 0 disables.\n\t\t\t\tconst debounceMs = subscribeOpts.debounce === undefined ? pluginRefetchDebounce : subscribeOpts.debounce\n\t\t\t\tconst dispatch = isObject\n\t\t\t\t\t? () => {\n\t\t\t\t\t\t// Dispatch fetchObject with dedup\n\t\t\t\t\t\t\tstore.fetchObject(type, id)\n\t\t\t\t\t\t}\n\t\t\t\t\t: () => {\n\t\t\t\t\t\t// Dispatch fetchCollection with last stashed params + dedup\n\t\t\t\t\t\t\tconst lastParams = store.__lastCollectionParams?.get(type) || {}\n\t\t\t\t\t\t\tstore.fetchCollection(type, lastParams)\n\t\t\t\t\t\t}\n\t\t\t\tconst coalesced = createHintCoalescer(dispatch, debounceMs)\n\n\t\t\t\tconst callback = () => {\n\t\t\t\t\tstore.liveLastEventAt = new Date()\n\t\t\t\t\tcoalesced.run()\n\t\t\t\t}\n\n\t\t\t\tconst transportOpts = {\n\t\t\t\t\tisObject,\n\t\t\t\t\tinterval: subscribeOpts.interval || (isObject ? pluginPollObject : pluginPollCollection),\n\t\t\t\t}\n\n\t\t\t\tconst transportHandle = liveUpdates.subscribe(eventKey, callback, transportOpts)\n\n\t\t\t\t// Update reactive subscriptions count (Vue 2 spread)\n\t\t\t\tthis.liveSubscriptions = this.liveSubscriptions + 1\n\n\t\t\t\t// Update liveStatus from transport now that we've subscribed\n\t\t\t\tconst transportStatus = liveUpdates.getStatus()\n\t\t\t\tif (transportStatus !== 'offline') {\n\t\t\t\t\tthis.liveStatus = transportStatus\n\t\t\t\t}\n\n\t\t\t\tconst handle = {\n\t\t\t\t\t_livePlugin: true,\n\t\t\t\t\ttype,\n\t\t\t\t\tid,\n\t\t\t\t\teventKey,\n\t\t\t\t\ttransportHandle,\n\t\t\t\t\t// Cancels a pending coalesced (trailing) refetch — called by\n\t\t\t\t\t// unsubscribe() so a torn-down subscription never fires late.\n\t\t\t\t\t_cancelPendingRefetch: coalesced.cancel,\n\t\t\t\t}\n\n\t\t\t\t// Auto-cleanup via tryOnScopeDispose (Vue 2.7 composition API scopes)\n\t\t\t\tif (_tryOnScopeDispose) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t_tryOnScopeDispose(() => {\n\t\t\t\t\t\t\tthis.unsubscribe(handle)\n\t\t\t\t\t\t})\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Not in a scope — manual unsubscribe required in beforeDestroy\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn handle\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Unsubscribe from live updates. Idempotent — releasing the same\n\t\t\t * handle twice (e.g. the plugin's own scope-dispose cleanup racing\n\t\t\t * a composable's explicit detach) is a no-op the second time, so\n\t\t\t * `liveSubscriptions` never double-decrements.\n\t\t\t *\n\t\t\t * @param {object} handle Handle returned by subscribe()\n\t\t\t */\n\t\t\tunsubscribe(handle) {\n\t\t\t\tif (!handle || !handle._livePlugin || handle._released) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\thandle._released = true\n\n\t\t\t\t// Cancel any pending coalesced refetch before tearing down the\n\t\t\t\t// transport subscription — a late trailing dispatch after\n\t\t\t\t// unsubscribe would refetch for a scope nobody renders anymore.\n\t\t\t\tif (typeof handle._cancelPendingRefetch === 'function') {\n\t\t\t\t\thandle._cancelPendingRefetch()\n\t\t\t\t}\n\n\t\t\t\tconst liveUpdates = getLiveUpdates()\n\t\t\t\tliveUpdates.unsubscribe(handle.transportHandle)\n\n\t\t\t\tthis.liveSubscriptions = Math.max(0, this.liveSubscriptions - 1)\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Plugin setup hook — called once per store instance.\n\t\t * Sets up:\n\t\t * 1. `$onAction` observer for fetchCollection → stash last params\n\t\t * 2. In-flight dedup Maps for fetchObject and fetchCollection\n\t\t *\n\t\t * @param {object} store The Pinia store instance\n\t\t */\n\t\tsetup(store) {\n\t\t\t// Dedup activation flag — flipped to true by the first subscribe()\n\t\t\t// call. Until then the fetch wrappers below pass straight through,\n\t\t\t// so a default-installed plugin causes zero behaviour change on\n\t\t\t// stores that never subscribe (live-updates-default-on).\n\t\t\tstore.__liveDedupActive = false\n\n\t\t\t// -- Last-params stash for collection re-fetch on events --\n\t\t\t// Plain (non-reactive) Map: type → last params object\n\t\t\tstore.__lastCollectionParams = new Map()\n\n\t\t\tstore.$onAction(({ name, args, after }) => {\n\t\t\t\tif (name === 'fetchCollection') {\n\t\t\t\t\tconst [type, params = {}] = args\n\t\t\t\t\tafter(() => {\n\t\t\t\t\t\tstore.__lastCollectionParams.set(type, params)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// -- In-flight dedup for fetchObject --\n\t\t\t// Plain Map: dedupKey → Promise\n\t\t\tconst objectInFlight = new Map()\n\n\t\t\tconst originalFetchObject = store.fetchObject.bind(store)\n\t\t\tstore.fetchObject = async function dedupedFetchObject(type, id) {\n\t\t\t\tif (!store.__liveDedupActive) {\n\t\t\t\t\treturn originalFetchObject(type, id)\n\t\t\t\t}\n\t\t\t\tconst key = objectDedupKey(type, id)\n\t\t\t\tif (objectInFlight.has(key)) {\n\t\t\t\t\treturn objectInFlight.get(key)\n\t\t\t\t}\n\t\t\t\tconst promise = originalFetchObject(type, id).finally(() => {\n\t\t\t\t\tobjectInFlight.delete(key)\n\t\t\t\t})\n\t\t\t\tobjectInFlight.set(key, promise)\n\t\t\t\treturn promise\n\t\t\t}\n\n\t\t\t// -- In-flight dedup for fetchCollection --\n\t\t\tconst collectionInFlight = new Map()\n\n\t\t\tconst originalFetchCollection = store.fetchCollection.bind(store)\n\t\t\tstore.fetchCollection = async function dedupedFetchCollection(type, params = {}) {\n\t\t\t\tif (!store.__liveDedupActive) {\n\t\t\t\t\treturn originalFetchCollection(type, params)\n\t\t\t\t}\n\t\t\t\tconst key = collectionDedupKey(type, params)\n\t\t\t\tif (collectionInFlight.has(key)) {\n\t\t\t\t\treturn collectionInFlight.get(key)\n\t\t\t\t}\n\t\t\t\tconst promise = originalFetchCollection(type, params).finally(() => {\n\t\t\t\t\tcollectionInFlight.delete(key)\n\t\t\t\t})\n\t\t\t\tcollectionInFlight.set(key, promise)\n\t\t\t\treturn promise\n\t\t\t}\n\t\t},\n\t}\n}\n"],"names":["_tryOnScopeDispose"],"mappings":";;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE;AAC1C,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3C,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,cAAc,CAAC,IAAI,EAAE,EAAE,EAAE;AAClC,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE;AACzC,CAAC,IAAI,KAAK,GAAG,KAAI;AACjB,CAAC,IAAI,OAAO,GAAG,MAAK;AACpB;AACA,CAAC,SAAS,GAAG,GAAG;AAChB,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE;AACrB,GAAG,EAAE,GAAE;AACP,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,KAAK,EAAE;AACb,GAAG,OAAO,GAAG,KAAI;AACjB,GAAG,MAAM;AACT,GAAG;AACH,EAAE,EAAE,GAAE;AACN,EAAE,KAAK,GAAG,UAAU,CAAC,MAAM;AAC3B,GAAG,KAAK,GAAG,KAAI;AACf,GAAG,IAAI,OAAO,EAAE;AAChB,IAAI,OAAO,GAAG,MAAK;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"}
1
+ {"version":3,"file":"liveUpdates.js","sources":["../../../../src/store/plugins/liveUpdates.js"],"sourcesContent":["/**\n * liveUpdatesPlugin — Pinia plugin factory for OpenRegister real-time updates.\n *\n * Adds live-update subscription support to any store created via createObjectStore().\n * Uses @nextcloud/notify_push via the transport singleton, with automatic polling\n * fallback when push is unavailable.\n *\n * Contributed state:\n * - `liveStatus` — current transport status string (`'offline'|'connecting'|'live'|'reconnecting'|'polling'`)\n * - `liveSubscriptions` — number of active subscriptions\n * - `liveLastEventAt` — Date of last received event, or null\n *\n * Contributed getters:\n * - `getLiveStatus`, `getLiveSubscriptions`, `getLiveLastEventAt`\n *\n * Contributed actions:\n * - `subscribe(type, id?, opts?)` — subscribe to live updates; returns a handle\n * - `unsubscribe(handle)` — tear down a subscription\n *\n * Usage note (Options API):\n * `tryOnScopeDispose` auto-registers cleanup when called from a Vue setup()\n * or Options API mounted() with an active effect scope. In Options API mounted()\n * without Vue 2.7 scope tracking, manual `unsubscribe(handle)` in beforeDestroy\n * is required. Document this at the call site.\n *\n * In-flight dedup:\n * Concurrent calls to fetchObject(type, id) or fetchCollection(type, params)\n * for the same key are coalesced into one HTTP request. The dedup maps live as\n * plain (non-reactive) Maps on the store instance to avoid Vue 2 overhead.\n * Dedup activates on the FIRST `subscribe()` call — before that, fetch actions\n * pass straight through to the base implementations. This keeps the plugin\n * fully inert (zero behaviour change) on stores that never subscribe, which\n * matters now that createObjectStore installs this plugin by default\n * (live-updates-default-on).\n *\n * Laziness guarantee:\n * Installing the plugin causes NO transport activity. The transport singleton\n * (and therefore the notify_push `listen()` probe / websocket connection /\n * polling timers) is only created inside the `subscribe()` action.\n *\n * Event coalescing:\n * Live events are HINTS (\"something changed\"), not payloads — each one\n * triggers a refetch. A burst of events (mass import, bulk save, another\n * user's rapid edits) would fire a refetch per event, so the dispatch is\n * coalesced per subscription: the FIRST event refetches immediately, and\n * any further events inside the `refetchDebounce` window (default 750 ms)\n * collapse into ONE trailing refetch when the window closes. Pending\n * trailing refetches are cancelled by `unsubscribe()`.\n *\n * @param {object} [opts] Plugin options\n * @param {number} [opts.pollIntervalCollection=30000] Collection poll interval (ms)\n * @param {number} [opts.pollIntervalObject=60000] Object poll interval (ms)\n * @param {number} [opts.refetchDebounce=750] Event-burst coalescing window (ms); 0 disables\n * @return {object} Plugin definition for use with createObjectStore\n *\n * @example\n * import { createObjectStore, liveUpdatesPlugin } from '@conduction/nextcloud-vue'\n *\n * const useStore = createObjectStore('myStore', {\n * plugins: [liveUpdatesPlugin({ pollIntervalCollection: 15000 })],\n * })\n *\n * // In a Vue component:\n * const store = useStore()\n * const handle = await store.subscribe('melding') // collection\n * const handle2 = await store.subscribe('melding', id) // object\n * // In beforeDestroy (Options API without scope):\n * store.unsubscribe(handle)\n */\n\n// `tryOnScopeDispose` comes from @vueuse/core, a DECLARED (non-optional) peer\n// dependency, so it is imported statically.\n//\n// It used to be pulled in through a CommonJS call inside a try/catch \"to avoid\n// a hard failure if @vueuse/core is absent\". That could not work: this module\n// ships to `dist/esm/**` where that function is not defined, and @vueuse/core's\n// own `exports` map resolves \".\" to a single ESM file with no CommonJS\n// condition. The catch therefore fired every time, `_tryOnScopeDispose` was\n// permanently null, and auto-cleanup on scope dispose silently never happened —\n// subscriptions leaked with no warning anywhere.\nimport { tryOnScopeDispose as _tryOnScopeDispose } from '@vueuse/core'\nimport { buildCollectionKey, buildObjectKey } from '../liveUpdates/eventKeys.js'\nimport { getLiveUpdates } from '../liveUpdates/transport.js'\n\n/**\n * Compute a stable cache key for dedup of fetchCollection calls.\n *\n * @param {string} type Object type slug\n * @param {object} params Query params\n * @return {string}\n */\nfunction collectionDedupKey(type, params) {\n\treturn `${type}:${JSON.stringify(params)}`\n}\n\n/**\n * Compute the cache key for dedup of fetchObject calls.\n *\n * @param {string} type Object type slug\n * @param {string} id Object ID\n * @return {string}\n */\nfunction objectDedupKey(type, id) {\n\treturn `${type}:${id}`\n}\n\n/**\n * Wrap a refetch dispatcher in a leading+trailing burst coalescer.\n *\n * Events are hints, so the exact invocation count doesn't matter — only\n * that the data ends up fresh. The first `run()` dispatches immediately\n * (snappy single-event case); further `run()`s inside the `waitMs` window\n * collapse into one trailing dispatch when the window closes (which opens\n * a new window, so a sustained burst dispatches at most once per window).\n * `cancel()` clears any pending trailing dispatch — called on\n * unsubscribe so a torn-down subscription never fires a late refetch.\n *\n * @param {() => void} fn The refetch dispatcher.\n * @param {number} waitMs Coalescing window in ms; `<= 0` disables (every run dispatches).\n * @return {{run: () => void, cancel: () => void}} The coalesced dispatcher.\n */\nfunction createHintCoalescer(fn, waitMs) {\n\tlet timer = null\n\tlet pending = false\n\n\tfunction run() {\n\t\tif (!(waitMs > 0)) {\n\t\t\tfn()\n\t\t\treturn\n\t\t}\n\t\tif (timer) {\n\t\t\tpending = true\n\t\t\treturn\n\t\t}\n\t\tfn()\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = null\n\t\t\tif (pending) {\n\t\t\t\tpending = false\n\t\t\t\trun()\n\t\t\t}\n\t\t}, waitMs)\n\t}\n\n\tfunction cancel() {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer)\n\t\t}\n\t\ttimer = null\n\t\tpending = false\n\t}\n\n\treturn { run, cancel }\n}\n\nexport function liveUpdatesPlugin(opts = {}) {\n\tconst pluginPollCollection = opts.pollIntervalCollection || 30000\n\tconst pluginPollObject = opts.pollIntervalObject || 60000\n\tconst pluginRefetchDebounce = opts.refetchDebounce === undefined ? 750 : opts.refetchDebounce\n\n\treturn {\n\t\tname: 'liveUpdates',\n\n\t\tstate: () => ({\n\t\t\t/** @type {'offline'|'connecting'|'live'|'reconnecting'|'polling'} */\n\t\t\tliveStatus: 'offline',\n\t\t\t/** @type {number} */\n\t\t\tliveSubscriptions: 0,\n\t\t\t/** @type {Date|null} */\n\t\t\tliveLastEventAt: null,\n\t\t}),\n\n\t\tgetters: {\n\t\t\t/**\n\t\t\t * Get the current transport status.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {string}\n\t\t\t */\n\t\t\tgetLiveStatus: (state) => state.liveStatus,\n\n\t\t\t/**\n\t\t\t * Get the number of active subscriptions.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {number}\n\t\t\t */\n\t\t\tgetLiveSubscriptions: (state) => state.liveSubscriptions,\n\n\t\t\t/**\n\t\t\t * Get the timestamp of the last received live event.\n\t\t\t *\n\t\t\t * @param {object} state Pinia state\n\t\t\t * @return {Date|null}\n\t\t\t */\n\t\t\tgetLiveLastEventAt: (state) => state.liveLastEventAt,\n\t\t},\n\n\t\tactions: {\n\t\t\t/**\n\t\t\t * Subscribe to live updates for an object type.\n\t\t\t *\n\t\t\t * When `id` is provided: subscribes to `or-object-{id}` (per-object events).\n\t\t\t * When `id` is omitted: subscribes to `or-collection-{registerSlug}-{schemaSlug}`\n\t\t\t * derived from objectTypeRegistry. Slugs are lazy-fetched if not already cached.\n\t\t\t *\n\t\t\t * **Options API note**: In `mounted()` without an active Vue scope,\n\t\t\t * `tryOnScopeDispose` cannot auto-register cleanup. Call `unsubscribe(handle)`\n\t\t\t * manually in `beforeDestroy`.\n\t\t\t *\n\t\t\t * @param {string} type Registered object type slug\n\t\t\t * @param {string} [id] Object UUID (omit for collection subscription)\n\t\t\t * @param {object} [subscribeOpts] Options\n\t\t\t * @param {number} [subscribeOpts.interval] Override poll interval (ms)\n\t\t\t * @return {Promise<object>} Opaque handle for unsubscribe()\n\t\t\t * @throws {Error} If type is not registered, or if lazy slug fetch fails (collection form)\n\t\t\t */\n\t\t\tasync subscribe(type, id, subscribeOpts = {}) {\n\t\t\t\tconst config = this.objectTypeRegistry[type]\n\t\t\t\tif (!config) {\n\t\t\t\t\tthrow new Error(`\"${type}\" is not registered. Call registerObjectType('${type}', ...) first.`)\n\t\t\t\t}\n\n\t\t\t\t// First subscribe() activates the in-flight dedup wrappers set\n\t\t\t\t// up in the plugin's setup() hook. Before this point the store\n\t\t\t\t// behaves exactly as if the plugin were not installed.\n\t\t\t\tthis.__liveDedupActive = true\n\n\t\t\t\tconst liveUpdates = getLiveUpdates({\n\t\t\t\t\tpollIntervalCollection: pluginPollCollection,\n\t\t\t\t\tpollIntervalObject: pluginPollObject,\n\t\t\t\t})\n\n\t\t\t\t// Register transport status observer (idempotent: only once per store instance)\n\t\t\t\tif (!this.__liveStatusObserverRegistered) {\n\t\t\t\t\tthis.__liveStatusObserverRegistered = true\n\t\t\t\t\tliveUpdates.onStatusChange((newStatus) => {\n\t\t\t\t\t\tthis.liveStatus = { ...this.liveStatus, valueOf: undefined, toString: undefined }\n\t\t\t\t\t\t// Vue 2 spread pattern for primitive reactive update\n\t\t\t\t\t\tthis.liveStatus = newStatus\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tlet eventKey\n\t\t\t\tlet isObject = false\n\n\t\t\t\tif (id !== undefined && id !== null) {\n\t\t\t\t\t// Object subscription — no slug lookup needed\n\t\t\t\t\tisObject = true\n\t\t\t\t\teventKey = buildObjectKey(id)\n\t\t\t\t} else {\n\t\t\t\t\t// Collection subscription — need registerSlug + schemaSlug\n\t\t\t\t\tlet { registerSlug, schemaSlug } = config\n\n\t\t\t\t\tif (!registerSlug || !schemaSlug) {\n\t\t\t\t\t\t// Lazy fetch slugs via existing store actions\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst [register, schema] = await Promise.all([\n\t\t\t\t\t\t\t\tthis.fetchRegister(type),\n\t\t\t\t\t\t\t\tthis.fetchSchema(type),\n\t\t\t\t\t\t\t])\n\n\t\t\t\t\t\t\tif (!register || !register.slug) {\n\t\t\t\t\t\t\t\tthrow new Error(`Failed to resolve register slug for \"${type}\"`)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!schema || !schema.slug) {\n\t\t\t\t\t\t\t\tthrow new Error(`Failed to resolve schema slug for \"${type}\"`)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tregisterSlug = register.slug\n\t\t\t\t\t\t\tschemaSlug = schema.slug\n\n\t\t\t\t\t\t\t// Cache slugs in registry (Vue 2 spread pattern)\n\t\t\t\t\t\t\tthis.objectTypeRegistry = {\n\t\t\t\t\t\t\t\t...this.objectTypeRegistry,\n\t\t\t\t\t\t\t\t[type]: { ...config, registerSlug, schemaSlug },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tthrow new Error(`liveUpdatesPlugin: cannot subscribe to \"${type}\" collection — ${err.message}`, { cause: err })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\teventKey = buildCollectionKey(registerSlug, schemaSlug)\n\t\t\t\t}\n\n\t\t\t\t// Set status to 'connecting' on first subscribe (before transport sets it)\n\t\t\t\tif (this.liveStatus === 'offline') {\n\t\t\t\t\tthis.liveStatus = 'connecting'\n\t\t\t\t}\n\n\t\t\t\tconst store = this\n\n\t\t\t\t// Events are hints — coalesce refetch bursts per subscription\n\t\t\t\t// (see \"Event coalescing\" in the module docblock). A per-call\n\t\t\t\t// `subscribeOpts.debounce` overrides the plugin default; 0 disables.\n\t\t\t\tconst debounceMs = subscribeOpts.debounce === undefined ? pluginRefetchDebounce : subscribeOpts.debounce\n\t\t\t\tconst dispatch = isObject\n\t\t\t\t\t? () => {\n\t\t\t\t\t\t// Dispatch fetchObject with dedup\n\t\t\t\t\t\t\tstore.fetchObject(type, id)\n\t\t\t\t\t\t}\n\t\t\t\t\t: () => {\n\t\t\t\t\t\t// Dispatch fetchCollection with last stashed params + dedup\n\t\t\t\t\t\t\tconst lastParams = store.__lastCollectionParams?.get(type) || {}\n\t\t\t\t\t\t\tstore.fetchCollection(type, lastParams)\n\t\t\t\t\t\t}\n\t\t\t\tconst coalesced = createHintCoalescer(dispatch, debounceMs)\n\n\t\t\t\tconst callback = () => {\n\t\t\t\t\tstore.liveLastEventAt = new Date()\n\t\t\t\t\tcoalesced.run()\n\t\t\t\t}\n\n\t\t\t\tconst transportOpts = {\n\t\t\t\t\tisObject,\n\t\t\t\t\tinterval: subscribeOpts.interval || (isObject ? pluginPollObject : pluginPollCollection),\n\t\t\t\t}\n\n\t\t\t\tconst transportHandle = liveUpdates.subscribe(eventKey, callback, transportOpts)\n\n\t\t\t\t// Update reactive subscriptions count (Vue 2 spread)\n\t\t\t\tthis.liveSubscriptions = this.liveSubscriptions + 1\n\n\t\t\t\t// Update liveStatus from transport now that we've subscribed\n\t\t\t\tconst transportStatus = liveUpdates.getStatus()\n\t\t\t\tif (transportStatus !== 'offline') {\n\t\t\t\t\tthis.liveStatus = transportStatus\n\t\t\t\t}\n\n\t\t\t\tconst handle = {\n\t\t\t\t\t_livePlugin: true,\n\t\t\t\t\ttype,\n\t\t\t\t\tid,\n\t\t\t\t\teventKey,\n\t\t\t\t\ttransportHandle,\n\t\t\t\t\t// Cancels a pending coalesced (trailing) refetch — called by\n\t\t\t\t\t// unsubscribe() so a torn-down subscription never fires late.\n\t\t\t\t\t_cancelPendingRefetch: coalesced.cancel,\n\t\t\t\t}\n\n\t\t\t\t// Auto-cleanup via tryOnScopeDispose (Vue 2.7 composition API scopes)\n\t\t\t\tif (_tryOnScopeDispose) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t_tryOnScopeDispose(() => {\n\t\t\t\t\t\t\tthis.unsubscribe(handle)\n\t\t\t\t\t\t})\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Not in a scope — manual unsubscribe required in beforeDestroy\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn handle\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Unsubscribe from live updates. Idempotent — releasing the same\n\t\t\t * handle twice (e.g. the plugin's own scope-dispose cleanup racing\n\t\t\t * a composable's explicit detach) is a no-op the second time, so\n\t\t\t * `liveSubscriptions` never double-decrements.\n\t\t\t *\n\t\t\t * @param {object} handle Handle returned by subscribe()\n\t\t\t */\n\t\t\tunsubscribe(handle) {\n\t\t\t\tif (!handle || !handle._livePlugin || handle._released) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\thandle._released = true\n\n\t\t\t\t// Cancel any pending coalesced refetch before tearing down the\n\t\t\t\t// transport subscription — a late trailing dispatch after\n\t\t\t\t// unsubscribe would refetch for a scope nobody renders anymore.\n\t\t\t\tif (typeof handle._cancelPendingRefetch === 'function') {\n\t\t\t\t\thandle._cancelPendingRefetch()\n\t\t\t\t}\n\n\t\t\t\tconst liveUpdates = getLiveUpdates()\n\t\t\t\tliveUpdates.unsubscribe(handle.transportHandle)\n\n\t\t\t\tthis.liveSubscriptions = Math.max(0, this.liveSubscriptions - 1)\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Plugin setup hook — called once per store instance.\n\t\t * Sets up:\n\t\t * 1. `$onAction` observer for fetchCollection → stash last params\n\t\t * 2. In-flight dedup Maps for fetchObject and fetchCollection\n\t\t *\n\t\t * @param {object} store The Pinia store instance\n\t\t */\n\t\tsetup(store) {\n\t\t\t// Dedup activation flag — flipped to true by the first subscribe()\n\t\t\t// call. Until then the fetch wrappers below pass straight through,\n\t\t\t// so a default-installed plugin causes zero behaviour change on\n\t\t\t// stores that never subscribe (live-updates-default-on).\n\t\t\tstore.__liveDedupActive = false\n\n\t\t\t// -- Last-params stash for collection re-fetch on events --\n\t\t\t// Plain (non-reactive) Map: type → last params object\n\t\t\tstore.__lastCollectionParams = new Map()\n\n\t\t\tstore.$onAction(({ name, args, after }) => {\n\t\t\t\tif (name === 'fetchCollection') {\n\t\t\t\t\tconst [type, params = {}] = args\n\t\t\t\t\tafter(() => {\n\t\t\t\t\t\tstore.__lastCollectionParams.set(type, params)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// -- In-flight dedup for fetchObject --\n\t\t\t// Plain Map: dedupKey → Promise\n\t\t\tconst objectInFlight = new Map()\n\n\t\t\tconst originalFetchObject = store.fetchObject.bind(store)\n\t\t\tstore.fetchObject = async function dedupedFetchObject(type, id) {\n\t\t\t\tif (!store.__liveDedupActive) {\n\t\t\t\t\treturn originalFetchObject(type, id)\n\t\t\t\t}\n\t\t\t\tconst key = objectDedupKey(type, id)\n\t\t\t\tif (objectInFlight.has(key)) {\n\t\t\t\t\treturn objectInFlight.get(key)\n\t\t\t\t}\n\t\t\t\tconst promise = originalFetchObject(type, id).finally(() => {\n\t\t\t\t\tobjectInFlight.delete(key)\n\t\t\t\t})\n\t\t\t\tobjectInFlight.set(key, promise)\n\t\t\t\treturn promise\n\t\t\t}\n\n\t\t\t// -- In-flight dedup for fetchCollection --\n\t\t\tconst collectionInFlight = new Map()\n\n\t\t\tconst originalFetchCollection = store.fetchCollection.bind(store)\n\t\t\tstore.fetchCollection = async function dedupedFetchCollection(type, params = {}, options = {}) {\n\t\t\t\tif (!store.__liveDedupActive) {\n\t\t\t\t\treturn originalFetchCollection(type, params, options)\n\t\t\t\t}\n\t\t\t\tconst key = collectionDedupKey(type, params)\n\t\t\t\tlet entry = collectionInFlight.get(key)\n\t\t\t\tif (!entry) {\n\t\t\t\t\t// The shared request reports into its own sink, copied to\n\t\t\t\t\t// each caller's `options.outcome` below, so a caller that\n\t\t\t\t\t// joined it learns that request's result too.\n\t\t\t\t\tconst outcome = {}\n\t\t\t\t\tconst promise = originalFetchCollection(type, params, { ...options, outcome }).finally(() => {\n\t\t\t\t\t\tcollectionInFlight.delete(key)\n\t\t\t\t\t})\n\t\t\t\t\tentry = { promise, outcome }\n\t\t\t\t\tcollectionInFlight.set(key, entry)\n\t\t\t\t}\n\t\t\t\tconst results = await entry.promise\n\t\t\t\tconst sink = options && options.outcome\n\t\t\t\tif (sink && typeof sink === 'object' && 'error' in entry.outcome) {\n\t\t\t\t\tsink.error = entry.outcome.error\n\t\t\t\t}\n\t\t\t\treturn results\n\t\t\t}\n\t\t},\n\t}\n}\n"],"names":["_tryOnScopeDispose"],"mappings":";;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE;AAC1C,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3C,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,cAAc,CAAC,IAAI,EAAE,EAAE,EAAE;AAClC,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE;AACzC,CAAC,IAAI,KAAK,GAAG,KAAI;AACjB,CAAC,IAAI,OAAO,GAAG,MAAK;AACpB;AACA,CAAC,SAAS,GAAG,GAAG;AAChB,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE;AACrB,GAAG,EAAE,GAAE;AACP,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,KAAK,EAAE;AACb,GAAG,OAAO,GAAG,KAAI;AACjB,GAAG,MAAM;AACT,GAAG;AACH,EAAE,EAAE,GAAE;AACN,EAAE,KAAK,GAAG,UAAU,CAAC,MAAM;AAC3B,GAAG,KAAK,GAAG,KAAI;AACf,GAAG,IAAI,OAAO,EAAE;AAChB,IAAI,OAAO,GAAG,MAAK;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"}