@conduction/nextcloud-vue 2.132.0 → 2.134.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.
Files changed (107) hide show
  1. package/dist/esm/components/CnActionButtons/CnActionButtons.vue.js +1 -1
  2. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js +14 -0
  3. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +5 -4
  5. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
  6. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue.js +9 -0
  7. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue.js.map +1 -0
  8. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue2.js +237 -0
  9. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue2.js.map +1 -0
  10. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue3.js +103 -0
  11. package/dist/esm/components/CnConditionListEditor/CnConditionListEditor.vue3.js.map +1 -0
  12. package/dist/esm/components/CnConditionListEditor/conditionOperators.js +121 -0
  13. package/dist/esm/components/CnConditionListEditor/conditionOperators.js.map +1 -0
  14. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +12 -0
  15. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  16. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +1 -1
  17. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  18. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
  19. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +85 -10
  20. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  21. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +60 -36
  22. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  23. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +8 -1
  24. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  25. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  26. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue.js +1 -1
  27. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue2.js +10 -0
  28. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue2.js.map +1 -1
  29. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue3.js.map +1 -1
  30. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
  31. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +46 -7
  32. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
  34. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
  35. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
  36. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +258 -6
  37. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +283 -131
  39. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
  40. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  41. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +42 -2
  42. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  43. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  44. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  45. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +1 -1
  46. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  47. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  48. package/dist/esm/dialogs/CnPartyAddDialog.vue.js +9 -0
  49. package/dist/esm/dialogs/CnPartyAddDialog.vue.js.map +1 -0
  50. package/dist/esm/dialogs/CnPartyAddDialog.vue2.js +184 -0
  51. package/dist/esm/dialogs/CnPartyAddDialog.vue2.js.map +1 -0
  52. package/dist/esm/dialogs/CnPartyAddDialog.vue3.js +168 -0
  53. package/dist/esm/dialogs/CnPartyAddDialog.vue3.js.map +1 -0
  54. package/dist/esm/index.js +2 -0
  55. package/dist/esm/index.js.map +1 -1
  56. package/dist/esm/l10n/en.json.js +27 -1
  57. package/dist/esm/l10n/en.json.js.map +1 -1
  58. package/dist/esm/l10n/nl.json.js +27 -1
  59. package/dist/esm/l10n/nl.json.js.map +1 -1
  60. package/dist/esm/library-style.js +1 -1
  61. package/dist/esm/nextcloud-vue.css +353 -217
  62. package/dist/esm/store/plugins/liveUpdates.js +13 -4
  63. package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
  64. package/dist/esm/store/useObjectStore.js +28 -5
  65. package/dist/esm/store/useObjectStore.js.map +1 -1
  66. package/dist/esm/utils/detailActionModel.js +6 -0
  67. package/dist/esm/utils/detailActionModel.js.map +1 -1
  68. package/dist/esm/utils/listLenses.js +20 -1
  69. package/dist/esm/utils/listLenses.js.map +1 -1
  70. package/dist/esm/utils/objectParties.js +79 -1
  71. package/dist/esm/utils/objectParties.js.map +1 -1
  72. package/dist/esm/utils/objectRows.js +59 -0
  73. package/dist/esm/utils/objectRows.js.map +1 -0
  74. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  75. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  76. package/dist/nextcloud-vue.cjs.js +7460 -5803
  77. package/dist/nextcloud-vue.cjs.js.map +2 -2
  78. package/dist/nextcloud-vue.css +353 -217
  79. package/l10n/en.json +27 -1
  80. package/l10n/nl.json +27 -1
  81. package/package.json +1 -1
  82. package/src/components/CnActionButtons/CnActionButtons.vue +15 -0
  83. package/src/components/CnConditionListEditor/CnConditionListEditor.vue +346 -0
  84. package/src/components/CnConditionListEditor/conditionOperators.js +126 -0
  85. package/src/components/CnConditionListEditor/index.js +17 -0
  86. package/src/components/CnDetailPage/CnDetailPage.md +1 -0
  87. package/src/components/CnDetailPage/CnDetailPage.vue +13 -1
  88. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +105 -12
  89. package/src/components/CnIndexPage/CnIndexPage.vue +8 -1
  90. package/src/components/CnIntegrationWidget/CnIntegrationWidget.vue +10 -0
  91. package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +47 -8
  92. package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +401 -3
  93. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +42 -2
  94. package/src/components/CnTabsWidget/CnTabsWidget.vue +1 -1
  95. package/src/components/index.js +1 -0
  96. package/src/css/look-board-index.css +6 -0
  97. package/src/css/look-board.css +35 -7
  98. package/src/dialogs/CnPartyAddDialog.vue +309 -0
  99. package/src/index.js +2 -0
  100. package/src/schemas/app-manifest-v2.schema.json +17 -1
  101. package/src/store/plugins/liveUpdates.js +13 -4
  102. package/src/store/useObjectStore.js +28 -5
  103. package/src/utils/detailActionModel.js +6 -0
  104. package/src/utils/listLenses.js +20 -1
  105. package/src/utils/objectParties.js +78 -0
  106. package/src/utils/objectRows.js +55 -0
  107. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -392,12 +392,15 @@ function liveUpdatesPlugin(opts = {}) {
392
392
 
393
393
  // Detached: the store outlives the component whose setup first
394
394
  // used it, and an attached observer is removed with that scope.
395
- store.$onAction(({ name, args, after }) => {
395
+ // Recorded when the fetch starts, so a hint arriving while it is in
396
+ // flight repeats it rather than the query before. An append page
397
+ // (the board's "Load more") is not a query of its own.
398
+ store.$onAction(({ name, args }) => {
396
399
  if (name === 'fetchCollection') {
397
- const [type, params = {}] = args;
398
- after(() => {
400
+ const [type, params = {}, options = {}] = args;
401
+ if (!(options && options.append === true)) {
399
402
  store.__lastCollectionParams.set(type, params);
400
- });
403
+ }
401
404
  }
402
405
  }, true);
403
406
 
@@ -431,6 +434,12 @@ function liveUpdatesPlugin(opts = {}) {
431
434
  }
432
435
  const key = collectionDedupKey(type, params);
433
436
  let entry = collectionInFlight.get(key);
437
+ if (entry && !(options && options.append === true)) {
438
+ // Joining makes the shared request's query the newest again.
439
+ const currentQuery = store.__currentCollectionQuery || (store.__currentCollectionQuery = {});
440
+ currentQuery[type] = JSON.stringify(params);
441
+ store.__lastCollectionParams.set(type, params);
442
+ }
434
443
  if (!entry) {
435
444
  // The shared request reports into its own sink, copied to
436
445
  // each caller's `options.outcome` below, so a caller that
@@ -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\t// Detached: the store outlives the component whose setup first\n\t\t\t// used it, and an attached observer is removed with that scope.\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}, true)\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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"}
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\t// Detached: the store outlives the component whose setup first\n\t\t\t// used it, and an attached observer is removed with that scope.\n\t\t\t// Recorded when the fetch starts, so a hint arriving while it is in\n\t\t\t// flight repeats it rather than the query before. An append page\n\t\t\t// (the board's \"Load more\") is not a query of its own.\n\t\t\tstore.$onAction(({ name, args }) => {\n\t\t\t\tif (name === 'fetchCollection') {\n\t\t\t\t\tconst [type, params = {}, options = {}] = args\n\t\t\t\t\tif (!(options && options.append === true)) {\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}, true)\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 && !(options && options.append === true)) {\n\t\t\t\t\t// Joining makes the shared request's query the newest again.\n\t\t\t\t\tconst currentQuery = store.__currentCollectionQuery || (store.__currentCollectionQuery = {})\n\t\t\t\t\tcurrentQuery[type] = JSON.stringify(params)\n\t\t\t\t\tstore.__lastCollectionParams.set(type, params)\n\t\t\t\t}\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;AACnB,IAAI,GAAG,GAAE;AACT,IAAI;AACJ,GAAG,EAAE,MAAM,EAAC;AACZ,EAAE;AACF;AACA,CAAC,SAAS,MAAM,GAAG;AACnB,EAAE,IAAI,KAAK,EAAE;AACb,GAAG,YAAY,CAAC,KAAK,EAAC;AACtB,GAAG;AACH,EAAE,KAAK,GAAG,KAAI;AACd,EAAE,OAAO,GAAG,MAAK;AACjB,EAAE;AACF;AACA,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE;AACvB,CAAC;AACD;AACO,SAAS,iBAAiB,CAAC,IAAI,GAAG,EAAE,EAAE;AAC7C,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,sBAAsB,IAAI,MAAK;AAClE,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,kBAAkB,IAAI,MAAK;AAC1D,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,eAAe,KAAK,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,gBAAe;AAC9F;AACA,CAAC,OAAO;AACR,EAAE,IAAI,EAAE,aAAa;AACrB;AACA,EAAE,KAAK,EAAE,OAAO;AAChB;AACA,GAAG,UAAU,EAAE,SAAS;AACxB;AACA,GAAG,iBAAiB,EAAE,CAAC;AACvB;AACA,GAAG,eAAe,EAAE,IAAI;AACxB,GAAG,CAAC;AACJ;AACA,EAAE,OAAO,EAAE;AACX;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,aAAa,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,UAAU;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,oBAAoB,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,iBAAiB;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,kBAAkB,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,eAAe;AACvD,GAAG;AACH;AACA,EAAE,OAAO,EAAE;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,aAAa,GAAG,EAAE,EAAE;AACjD,IAAI,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAC;AAChD,IAAI,IAAI,CAAC,MAAM,EAAE;AACjB,KAAK,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,8CAA8C,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;AACnG,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,iBAAiB,GAAG,KAAI;AACjC;AACA,IAAI,MAAM,WAAW,GAAG,cAAc,CAAC;AACvC,KAAK,sBAAsB,EAAE,oBAAoB;AACjD,KAAK,kBAAkB,EAAE,gBAAgB;AACzC,KAAK,EAAC;AACN;AACA;AACA,IAAI,IAAI,CAAC,IAAI,CAAC,8BAA8B,EAAE;AAC9C,KAAK,IAAI,CAAC,8BAA8B,GAAG,KAAI;AAC/C,KAAK,WAAW,CAAC,cAAc,CAAC,CAAC,SAAS,KAAK;AAC/C,MAAM,IAAI,CAAC,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,GAAE;AACvF;AACA,MAAM,IAAI,CAAC,UAAU,GAAG,UAAS;AACjC,MAAM,EAAC;AACP,KAAK;AACL;AACA,IAAI,IAAI,SAAQ;AAChB,IAAI,IAAI,QAAQ,GAAG,MAAK;AACxB;AACA,IAAI,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,EAAE;AACzC;AACA,KAAK,QAAQ,GAAG,KAAI;AACpB,KAAK,QAAQ,GAAG,cAAc,CAAC,EAAE,EAAC;AAClC,KAAK,MAAM;AACX;AACA,KAAK,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,OAAM;AAC9C;AACA,KAAK,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,EAAE;AACvC;AACA,MAAM,IAAI;AACV,OAAO,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AACpD,QAAQ,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AAChC,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAC9B,QAAQ,EAAC;AACT;AACA,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;AACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,CAAC,qCAAqC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACxE,QAAQ;AACR,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;AACpC,QAAQ,MAAM,IAAI,KAAK,CAAC,CAAC,mCAAmC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AACtE,QAAQ;AACR;AACA,OAAO,YAAY,GAAG,QAAQ,CAAC,KAAI;AACnC,OAAO,UAAU,GAAG,MAAM,CAAC,KAAI;AAC/B;AACA;AACA,OAAO,IAAI,CAAC,kBAAkB,GAAG;AACjC,QAAQ,GAAG,IAAI,CAAC,kBAAkB;AAClC,QAAQ,CAAC,IAAI,GAAG,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE;AACvD,SAAQ;AACR,OAAO,CAAC,OAAO,GAAG,EAAE;AACpB,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,wCAAwC,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACtH,OAAO;AACP,MAAM;AACN;AACA,KAAK,QAAQ,GAAG,kBAAkB,CAAC,YAAY,EAAE,UAAU,EAAC;AAC5D,KAAK;AACL;AACA;AACA,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE;AACvC,KAAK,IAAI,CAAC,UAAU,GAAG,aAAY;AACnC,KAAK;AACL;AACA,IAAI,MAAM,KAAK,GAAG,KAAI;AACtB;AACA;AACA;AACA;AACA,IAAI,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,KAAK,SAAS,GAAG,qBAAqB,GAAG,aAAa,CAAC,SAAQ;AAC5G,IAAI,MAAM,QAAQ,GAAG,QAAQ;AAC7B,OAAO,MAAM;AACb;AACA,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAC;AAClC,OAAO;AACP,OAAO,MAAM;AACb;AACA,OAAO,MAAM,UAAU,GAAG,KAAK,CAAC,sBAAsB,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,GAAE;AACvE,OAAO,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,EAAC;AAC9C,QAAO;AACP,IAAI,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,EAAE,UAAU,EAAC;AAC/D;AACA,IAAI,MAAM,QAAQ,GAAG,MAAM;AAC3B,KAAK,KAAK,CAAC,eAAe,GAAG,IAAI,IAAI,GAAE;AACvC,KAAK,SAAS,CAAC,GAAG,GAAE;AACpB,MAAK;AACL;AACA,IAAI,MAAM,aAAa,GAAG;AAC1B,KAAK,QAAQ;AACb,KAAK,QAAQ,EAAE,aAAa,CAAC,QAAQ,KAAK,QAAQ,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAC7F,MAAK;AACL;AACA,IAAI,MAAM,eAAe,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAC;AACpF;AACA;AACA,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,EAAC;AACvD;AACA;AACA,IAAI,MAAM,eAAe,GAAG,WAAW,CAAC,SAAS,GAAE;AACnD,IAAI,IAAI,eAAe,KAAK,SAAS,EAAE;AACvC,KAAK,IAAI,CAAC,UAAU,GAAG,gBAAe;AACtC,KAAK;AACL;AACA,IAAI,MAAM,MAAM,GAAG;AACnB,KAAK,WAAW,EAAE,IAAI;AACtB,KAAK,IAAI;AACT,KAAK,EAAE;AACP,KAAK,QAAQ;AACb,KAAK,eAAe;AACpB;AACA;AACA,KAAK,qBAAqB,EAAE,SAAS,CAAC,MAAM;AAC5C,MAAK;AACL;AACA;AACA,IAAI,IAAIA,iBAAkB,EAAE;AAC5B,KAAK,IAAI;AACT,MAAMA,iBAAkB,CAAC,MAAM;AAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAC;AAC/B,OAAO,EAAC;AACR,MAAM,CAAC,MAAM;AACb;AACA,MAAM;AACN,KAAK;AACL;AACA,IAAI,OAAO,MAAM;AACjB,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,WAAW,CAAC,MAAM,EAAE;AACvB,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,SAAS,EAAE;AAC5D,KAAK,MAAM;AACX,KAAK;AACL,IAAI,MAAM,CAAC,SAAS,GAAG,KAAI;AAC3B;AACA;AACA;AACA;AACA,IAAI,IAAI,OAAO,MAAM,CAAC,qBAAqB,KAAK,UAAU,EAAE;AAC5D,KAAK,MAAM,CAAC,qBAAqB,GAAE;AACnC,KAAK;AACL;AACA,IAAI,MAAM,WAAW,GAAG,cAAc,GAAE;AACxC,IAAI,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,eAAe,EAAC;AACnD;AACA,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,GAAG,CAAC,EAAC;AACpE,IAAI;AACJ,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,KAAK,CAAC,KAAK,EAAE;AACf;AACA;AACA;AACA;AACA,GAAG,KAAK,CAAC,iBAAiB,GAAG,MAAK;AAClC;AACA;AACA;AACA,GAAG,KAAK,CAAC,sBAAsB,GAAG,IAAI,GAAG,GAAE;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;AACvC,IAAI,IAAI,IAAI,KAAK,iBAAiB,EAAE;AACpC,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,CAAC,GAAG,KAAI;AACnD,KAAK,IAAI,EAAE,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,EAAE;AAChD,MAAM,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAC;AACpD,MAAM;AACN,KAAK;AACL,IAAI,EAAE,IAAI,EAAC;AACX;AACA;AACA;AACA,GAAG,MAAM,cAAc,GAAG,IAAI,GAAG,GAAE;AACnC;AACA,GAAG,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAC;AAC5D,GAAG,KAAK,CAAC,WAAW,GAAG,eAAe,kBAAkB,CAAC,IAAI,EAAE,EAAE,EAAE;AACnE,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE;AAClC,KAAK,OAAO,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC;AACzC,KAAK;AACL,IAAI,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,EAAE,EAAE,EAAC;AACxC,IAAI,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACjC,KAAK,OAAO,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;AACnC,KAAK;AACL,IAAI,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;AAChE,KAAK,cAAc,CAAC,MAAM,CAAC,GAAG,EAAC;AAC/B,KAAK,EAAC;AACN,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAC;AACpC,IAAI,OAAO,OAAO;AAClB,KAAI;AACJ;AACA;AACA,GAAG,MAAM,kBAAkB,GAAG,IAAI,GAAG,GAAE;AACvC;AACA,GAAG,MAAM,uBAAuB,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAC;AACpE,GAAG,KAAK,CAAC,eAAe,GAAG,eAAe,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE;AAClG,IAAI,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE;AAClC,KAAK,OAAO,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;AAC1D,KAAK;AACL,IAAI,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAC;AAChD,IAAI,IAAI,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAC;AAC3C,IAAI,IAAI,KAAK,IAAI,EAAE,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,EAAE;AACxD;AACA,KAAK,MAAM,YAAY,GAAG,KAAK,CAAC,wBAAwB,KAAK,KAAK,CAAC,wBAAwB,GAAG,EAAE,EAAC;AACjG,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAC;AAChD,KAAK,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAC;AACnD,KAAK;AACL,IAAI,IAAI,CAAC,KAAK,EAAE;AAChB;AACA;AACA;AACA,KAAK,MAAM,OAAO,GAAG,GAAE;AACvB,KAAK,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;AAClG,MAAM,kBAAkB,CAAC,MAAM,CAAC,GAAG,EAAC;AACpC,MAAM,EAAC;AACP,KAAK,KAAK,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE;AACjC,KAAK,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAC;AACvC,KAAK;AACL,IAAI,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,QAAO;AACvC,IAAI,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,QAAO;AAC3C,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;AACtE,KAAK,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAK;AACrC,KAAK;AACL,IAAI,OAAO,OAAO;AAClB,KAAI;AACJ,GAAG;AACH,EAAE;AACF;;;;"}
@@ -714,10 +714,20 @@ const baseActions = {
714
714
  * @param {{error?: object|null}} [options.outcome] Opt-in sink for THIS call's own result: `error` is set to the error it records on `errors[type]`, or `null` on success. Unlike `errors[type]`, which every call for the type shares, a later call cannot overwrite it.
715
715
  * @param {boolean} [options.append] Add the fetched page after the rows already stored instead of replacing them. Dropped when the stored rows are no longer the page before it, or when `options.isCurrent()` returns false (the query changed meanwhile).
716
716
  * @param {() => boolean} [options.isCurrent] With `append`: asked once the page arrives; false drops it.
717
- * @return {Promise<Array>} The fetched collection (also stored in state)
717
+ * @return {Promise<Array>} The fetched collection (also stored in state, unless a newer non-append fetch for the type started meanwhile)
718
+ * @spec openspec/changes/list-keeps-its-newest-query/specs/list-keeps-its-newest-query/spec.md#requirement-the-newest-list-query-decides-what-the-list-shows
718
719
  */
719
720
  async fetchCollection(type, params = {}, options = {}) {
720
721
  const outcome = (options && typeof options.outcome === 'object' && options.outcome) || null;
722
+ const append = options?.append === true;
723
+ // Responses can arrive out of order; only the newest query for the
724
+ // type may write the list. An append page belongs to the query before it.
725
+ const currentQuery = this.__currentCollectionQuery || (this.__currentCollectionQuery = {});
726
+ if (!append) {
727
+ currentQuery[type] = JSON.stringify(params);
728
+ }
729
+ const query = currentQuery[type];
730
+ const superseded = () => currentQuery[type] !== query;
721
731
  this.loading = { ...this.loading, [type]: true };
722
732
  this.errors = { ...this.errors, [type]: null };
723
733
 
@@ -746,10 +756,13 @@ const baseActions = {
746
756
 
747
757
  if (!response.ok) {
748
758
  const failure = await parseResponseError(response, type);
749
- this.errors = { ...this.errors, [type]: failure };
750
759
  if (outcome) {
751
760
  outcome.error = failure;
752
761
  }
762
+ if (superseded()) {
763
+ return []
764
+ }
765
+ this.errors = { ...this.errors, [type]: failure };
753
766
  // eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from
754
767
  console.error(`Error fetching ${type} collection:`, failure);
755
768
  return []
@@ -757,8 +770,13 @@ const baseActions = {
757
770
 
758
771
  const data = await response.json();
759
772
  const results = data.results || data;
760
- const append = options?.append === true;
761
773
 
774
+ if (superseded()) {
775
+ if (outcome) {
776
+ outcome.error = null;
777
+ }
778
+ return append ? [] : results
779
+ }
762
780
  const stale = append && (
763
781
  Number(this.pagination[type]?.page || 1) !== Number(params._page || 1) - 1
764
782
  || (typeof options.isCurrent === 'function' && !options.isCurrent())
@@ -797,15 +815,20 @@ const baseActions = {
797
815
  const failure = error.name === 'TypeError'
798
816
  ? networkError(error)
799
817
  : genericError(error);
800
- this.errors = { ...this.errors, [type]: failure };
801
818
  if (outcome) {
802
819
  outcome.error = failure;
803
820
  }
821
+ if (superseded()) {
822
+ return []
823
+ }
824
+ this.errors = { ...this.errors, [type]: failure };
804
825
  // eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from
805
826
  console.error(`Error fetching ${type} collection:`, error);
806
827
  return []
807
828
  } finally {
808
- this.loading = { ...this.loading, [type]: false };
829
+ if (!superseded()) {
830
+ this.loading = { ...this.loading, [type]: false };
831
+ }
809
832
  }
810
833
  },
811
834