signalk-questdb 1.9.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ # Contributing
2
+
3
+ Bug reports, feature requests and pull requests are welcome at
4
+ <https://github.com/dirkwa/signalk-questdb>.
5
+
6
+ Before opening a pull request, run the full local chain:
7
+
8
+ ```bash
9
+ npm run format && npm run build:all && npm run ci-lint
10
+ ```
11
+
12
+ ## Contributor license grant
13
+
14
+ By submitting a pull request or patch, you grant Dirk Wahrheit a perpetual,
15
+ worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce,
16
+ modify, publish, sublicense and distribute your contribution, and to relicense
17
+ it under any terms, including as part of signalk-questdb releases. You confirm
18
+ that you have the right to grant this.
@@ -1,3 +1,7 @@
1
+ This MIT license applied to signalk-questdb version 1.9.2 and all earlier
2
+ releases. Those versions remain available under MIT in perpetuity.
3
+ Version 2.0.0 and later are licensed under the terms in LICENSE.md.
4
+
1
5
  MIT License
2
6
 
3
7
  Copyright (c) 2026 Dirk Wahrheit
package/LICENSE.md ADDED
@@ -0,0 +1,122 @@
1
+ # Source-Available License, No Redistribution, Version 1.0
2
+
3
+ ## Notice
4
+
5
+ Copyright 2026 Dirk Wahrheit
6
+
7
+ This license is adapted from a standardized plain-language license template.
8
+ It has been modified and is not endorsed by, or associated with, the authors of
9
+ the template.
10
+
11
+ ## Acceptance
12
+
13
+ In order to get any license under these terms, you must agree to them as both
14
+ strict obligations and conditions to all your licenses.
15
+
16
+ ## Copyright License
17
+
18
+ The licensor grants you a copyright license for the software to do everything
19
+ you might do with the software that would otherwise infringe the licensor's
20
+ copyright in it, for any permitted purpose. However, you may only make changes
21
+ or new works based on the software according to the Changes and New Works
22
+ License, and you may only distribute the software according to the
23
+ Redistribution of Official Releases section.
24
+
25
+ ## Permitted Purposes
26
+
27
+ Any of the following is use for a permitted purpose:
28
+
29
+ 1. Personal use, including use aboard any vessel you own or operate, hobby
30
+ projects, amateur pursuits, private study and private entertainment.
31
+
32
+ 2. Use for the internal operations of you and your company, including
33
+ commercial operations.
34
+
35
+ 3. Non-commercial education and non-commercial research.
36
+
37
+ 4. Professional services that you provide to someone else who is using the
38
+ software in accordance with these terms.
39
+
40
+ ## Changes and New Works License
41
+
42
+ The licensor grants you an additional copyright license to make changes and new
43
+ works based on the software, for any permitted purpose. You may not distribute
44
+ those changes or new works.
45
+
46
+ ## Redistribution of Official Releases
47
+
48
+ You may reproduce and distribute verbatim, unmodified copies of releases
49
+ published by the licensor, provided that you do not remove or alter any
50
+ copyright, license or attribution notices, and that you include a copy of or a
51
+ link to these terms.
52
+
53
+ This permits, among other things, package registries, mirrors, proxies and
54
+ caches to serve official releases, and permits you to keep copies of official
55
+ releases in your own backups, images and deployments.
56
+
57
+ You may not distribute the software, or any changes or new works based on the
58
+ software, in any other way. In particular, you may not publish a modified
59
+ version of the software to any package registry, application store or other
60
+ distribution channel.
61
+
62
+ ## Patent License
63
+
64
+ The licensor grants you a patent license for the software that covers patent
65
+ claims the licensor can license, or becomes able to license, that you would
66
+ infringe by using the software.
67
+
68
+ ## Fair Use
69
+
70
+ You may have "fair use" rights for the software under the law. These terms do
71
+ not limit them.
72
+
73
+ ## No Other Rights
74
+
75
+ These terms do not allow you to sublicense or transfer any of your licenses to
76
+ anyone else, or prevent the licensor from granting licenses to anyone else.
77
+ These terms do not imply any other licenses.
78
+
79
+ ## Patent Defense
80
+
81
+ If you make any written claim that the software infringes or contributes to
82
+ infringement of any patent, your patent license for the software granted under
83
+ these terms ends immediately. If your company makes such a claim, your patent
84
+ license ends immediately for work on behalf of your company.
85
+
86
+ ## Violations
87
+
88
+ The first time you are notified in writing that you have violated any of these
89
+ terms, or done anything with the software not covered by your licenses, your
90
+ licenses can nonetheless continue if you come into full compliance with these
91
+ terms, and take practical steps to correct past violations, within 32 days of
92
+ receiving notice. Otherwise, all your licenses end immediately.
93
+
94
+ ## No Liability
95
+
96
+ _**As far as the law allows, the software comes as is, without any warranty or
97
+ condition, and the licensor will not be liable to you for any damages arising
98
+ out of these terms or the use or nature of the software, under any kind of
99
+ legal claim.**_
100
+
101
+ ## Definitions
102
+
103
+ The **licensor** is the individual or entity offering these terms, and the
104
+ **software** is the software the licensor makes available under these terms.
105
+
106
+ **You** refers to the individual or entity agreeing to these terms.
107
+
108
+ **Your company** is any legal entity, sole proprietorship, or other kind of
109
+ organization that you work for, plus all organizations that have control over,
110
+ are under the control of, or are under common control with that organization.
111
+ **Control** means ownership of substantially all the assets of an entity, or
112
+ the power to direct its management and policies by vote, contract, or
113
+ otherwise.
114
+
115
+ **Your licenses** are all the licenses granted to you for the software under
116
+ these terms.
117
+
118
+ **Use** means anything you do with the software requiring one of your licenses.
119
+
120
+ **Distribute** means to make the software, or any changes or new works based on
121
+ the software, available to anyone other than you and your company, by any
122
+ means, including publication to a package registry or application store.
package/README.md CHANGED
@@ -326,6 +326,14 @@ The plugin is optimized for Raspberry Pi and similar low-power devices:
326
326
 
327
327
  ## Troubleshooting
328
328
 
329
+ ### 'Module "signalk-questdb" is not available' right after install or update
330
+
331
+ Right after installing or updating the plugin, the admin UI can show
332
+ `Module "signalk-questdb" is not available. Make sure the webapp is installed.`
333
+ It is installed — the browser tab is still running the admin UI it loaded
334
+ before the update, which looks for the panel bundle it knew then. A hard
335
+ refresh of the tab (Shift-Reload) fixes it.
336
+
329
337
  ### "QuestDB keeps dropping the write connection — the container may be unhealthy or out of memory"
330
338
 
331
339
  This status appears when the plugin's ILP writer connects to QuestDB, gets
@@ -426,6 +434,92 @@ This takes effect immediately — no container or host restart needed. See
426
434
  [QuestDB capacity planning](https://questdb.com/docs/getting-started/capacity-planning/#max-virtual-memory-areas-limit)
427
435
  for background.
428
436
 
437
+ ### QuestDB container never starts on macOS (podman machine)
438
+
439
+ On macOS the QuestDB container is created but may never start. What you
440
+ see depends on the signalk-container version: with signalk-container 1.26
441
+ or later, the manager names the problem outright (an open-files limit the
442
+ host refuses) and starts the container on the runtime's default limits
443
+ instead, with this plugin's config panel showing a **"request rejected by
444
+ the host"** banner — the remediation below applies unchanged. Older
445
+ versions never start the container at all and show either
446
+ a misleading **"Permission denied"** (the runtime's error text contains
447
+ "operation not permitted") or only a generic **"Unexpected error. See logs
448
+ for details."** — and the container log view stays empty, because a
449
+ container that never started has no logs.
450
+
451
+ The cause is the plugin's open-files request. On macOS, Signal K runs on the
452
+ Mac while podman runs inside a Fedora CoreOS VM ("podman machine"). The
453
+ plugin asks for 1048576 open files, and signalk-container normally clamps
454
+ that request to what the host can grant — but from macOS it cannot read the
455
+ VM's limits, so the full request reaches the VM, exceeds its default hard
456
+ limit (524288), and the OCI runtime refuses to start the container. On
457
+ current Fedora CoreOS the VM's `vm.max_map_count` already meets QuestDB's
458
+ 1048576, so usually only the file-descriptor limit needs raising — but an
459
+ older machine image may sit lower, so check it first:
460
+
461
+ ```bash
462
+ podman machine ssh -- sysctl -n vm.max_map_count
463
+ ```
464
+
465
+ If that prints less than 1048576, raise it inside the VM before relying on
466
+ the file-descriptor fix alone (`podman machine ssh`, then
467
+ `sudo tee /etc/sysctl.d/99-signalk-questdb.conf <<< 'vm.max_map_count=1048576'`
468
+ and `sudo sysctl --system`).
469
+
470
+ Raise it inside the VM. From a macOS terminal:
471
+
472
+ ```bash
473
+ podman machine ssh
474
+ ```
475
+
476
+ Inside the VM, add a systemd drop-in for every user manager (the
477
+ `user@.service` template covers each user instance, including the machine's
478
+ `core` user, whose session runs rootless containers) and the same drop-in
479
+ for `podman.service` to cover the rootful connection:
480
+
481
+ ```bash
482
+ sudo mkdir -p /etc/systemd/system/user@.service.d /etc/systemd/system/podman.service.d
483
+ sudo tee /etc/systemd/system/user@.service.d/nofile.conf >/dev/null <<'EOF'
484
+ [Service]
485
+ LimitNOFILE=1048576
486
+ EOF
487
+ sudo cp /etc/systemd/system/user@.service.d/nofile.conf /etc/systemd/system/podman.service.d/nofile.conf
488
+ sudo systemctl daemon-reload
489
+ exit
490
+ ```
491
+
492
+ Back on macOS, restart the VM:
493
+
494
+ ```bash
495
+ podman machine stop && podman machine start
496
+ ```
497
+
498
+ and verify the new limit is grantable:
499
+
500
+ ```bash
501
+ podman run --rm --ulimit nofile=1048576:1048576 docker.io/library/alpine sh -c 'ulimit -n -H'
502
+ ```
503
+
504
+ This should print `1048576`. Finally, remove the half-created container so it
505
+ is recreated with the full limit — the limit is set at create time, so a
506
+ restart is not enough:
507
+
508
+ ```bash
509
+ podman rm -f sk-signalk-questdb
510
+ ```
511
+
512
+ then restart Signal K — on the next plugin start the container is recreated
513
+ with the full limit. (The container manager's **Start** button only starts an
514
+ existing container, so it cannot replace this step.)
515
+
516
+ The verify and `rm` commands run on podman's default connection — normally
517
+ the rootless one the plugin uses. Rootless and rootful connections keep
518
+ separate container stores, so on a setup with a non-default connection add
519
+ the same `--connection <name>` (list them with
520
+ `podman system connection list`) to both commands, so they hit the store
521
+ where `sk-signalk-questdb` actually lives (`podman ps -a` shows it).
522
+
429
523
  ## History API Provider
430
524
 
431
525
  QuestDB automatically registers as the **default** Signal K v2 History API provider. Any app or Grafana plugin that queries `/signalk/v2/api/history/` uses QuestDB.
@@ -468,8 +562,24 @@ SAMPLE BY $__interval
468
562
 
469
563
  - Node.js >= 22
470
564
  - [signalk-container](https://github.com/dirkwa/signalk-container) >= 1.14.0 plugin (for managed mode; older versions still work but fall back to loopback connectivity)
565
+ - Podman >= 5.4 (the version Debian 13 "trixie" ships) or Docker, for managed mode. On rootless Podman below 5.5 the plugin's open-files request is inherited from the podman service rather than granted per container ([containers/podman#25881](https://github.com/containers/podman/issues/25881)); signalk-container accounts for this.
471
566
  - Signal K server
472
567
 
473
568
  ## License
474
569
 
475
- MIT
570
+ signalk-questdb 2.0.0 and later is **source available, not open source**.
571
+ See [LICENSE.md](LICENSE.md).
572
+
573
+ **You may**, free of charge: run it on your own boat or fleet, private or
574
+ commercial; use it for internal company operations; modify it for your own use;
575
+ use it in education and research; and provide professional services around it.
576
+
577
+ **You may not**: redistribute it, or publish a modified version of it to npm or
578
+ anywhere else. Verbatim copies of official releases may be mirrored and cached.
579
+
580
+ Versions 1.9.2 and earlier remain available under the MIT license, see
581
+ [LICENSE-MIT-through-v1.x.txt](LICENSE-MIT-through-v1.x.txt).
582
+
583
+ ## Contributing
584
+
585
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-questdb",
3
- "version": "1.9.1",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "QuestDB history provider for Signal K — replaces signalk-to-influxdb",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "node": ">=22"
40
40
  },
41
41
  "author": "Dirk Wahrheit <dirkwahrheit@gmail.com>",
42
- "license": "MIT",
42
+ "license": "SEE LICENSE IN LICENSE.md",
43
43
  "repository": {
44
44
  "type": "git",
45
45
  "url": "https://github.com/dirkwa/signalk-questdb"
@@ -47,7 +47,7 @@
47
47
  "dependencies": {
48
48
  "@js-temporal/polyfill": "^0.5.0",
49
49
  "minimatch": "^10.2.3",
50
- "signalk-container-helper": "^0.4.3",
50
+ "signalk-container-helper": "^0.6.1",
51
51
  "typebox": "^1.3.11"
52
52
  },
53
53
  "devDependencies": {
@@ -0,0 +1,9 @@
1
+ import{a as e,i as t,n,r,t as i}from"./_virtual_mf___mfe_internal__signalk_questdb__mf_owner__1__loadShare__react__loadShare__.js-DzhF4wXp.js";var a={root:{fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,color:`#333`,padding:`16px 0`},sectionToggle:{color:`#555`,display:`flex`,alignItems:`center`,gap:6,width:`100%`,textAlign:`left`,background:`none`,border:`none`,padding:0,cursor:`pointer`,userSelect:`none`},sectionMarker:{fontSize:11,transition:`transform 0.15s`},sectionTitle:{fontSize:13,fontWeight:600,color:`#888`,textTransform:`uppercase`,letterSpacing:`0.05em`,marginBottom:10,marginTop:24},btn:{display:`inline-flex`,alignItems:`center`,gap:8,padding:`8px 16px`,border:`none`,borderRadius:6,fontSize:13,fontWeight:600,cursor:`pointer`},btnPrimary:{background:`#3b82f6`,color:`#fff`},btnSecondary:{background:`#f1f5f9`,color:`#475569`,border:`1px solid #e2e8f0`},btnWarn:{background:`#f59e0b`,color:`#fff`},btnDanger:{background:`#ef4444`,color:`#fff`},btnDisabled:{opacity:.5,cursor:`not-allowed`},btnSmall:{padding:`4px 12px`,fontSize:12},status:{marginTop:8,fontSize:12,minHeight:18},card:{display:`flex`,alignItems:`center`,gap:14,padding:`14px 18px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,marginBottom:12},cardIcon:{width:44,height:44,borderRadius:10,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:20,fontWeight:700,flexShrink:0},cardInfo:{flex:1},cardTitle:{fontSize:15,fontWeight:600,color:`#333`},cardMeta:{fontSize:12,color:`#888`},stateIndicator:{width:10,height:10,borderRadius:`50%`,flexShrink:0},fieldRow:{display:`flex`,alignItems:`center`,gap:12,marginBottom:10},label:{fontSize:13,fontWeight:500,color:`#555`,width:180,flexShrink:0},select:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,minWidth:200},input:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,width:200},inputSmall:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,width:80},checkbox:{width:16,height:16,accentColor:`#3b82f6`},hint:{fontSize:11,color:`#aaa`,marginLeft:8},link:{color:`#3b82f6`,textDecoration:`none`,fontSize:13,fontWeight:600},textarea:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,fontFamily:`monospace`,background:`#fff`,color:`#333`,width:`100%`,minHeight:70,boxSizing:`border-box`,resize:`vertical`},empty:{textAlign:`center`,padding:`30px 16px`,color:`#999`,fontSize:13},tag:{display:`inline-block`,padding:`2px 8px`,borderRadius:4,fontSize:10,fontWeight:600,marginLeft:8},tagPre:{background:`#fef3c7`,color:`#92400e`},tagLatest:{background:`#dcfce7`,color:`#166534`},warnBanner:{padding:`12px 16px`,background:`#fef2f2`,border:`1px solid #fecaca`,borderRadius:10,marginBottom:12,fontSize:13,color:`#991b1b`,lineHeight:1.5},warnBannerTitle:{fontWeight:700,marginBottom:4},infoBanner:{padding:`12px 16px`,background:`#fffbeb`,border:`1px solid #fde68a`,borderRadius:10,marginBottom:12,fontSize:13,color:`#92400e`,lineHeight:1.5},bannerCode:{display:`block`,marginTop:8,padding:`8px 10px`,background:`#fff`,border:`1px solid #fecaca`,borderRadius:6,fontFamily:`monospace`,fontSize:12,color:`#7f1d1d`,whiteSpace:`pre-wrap`,wordBreak:`break-word`},statsGrid:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(140px, 1fr))`,gap:10,marginBottom:12},statCard:{padding:`12px 16px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,textAlign:`center`},statValue:{fontSize:22,fontWeight:700,color:`#333`},statLabel:{fontSize:11,color:`#888`,marginTop:2}},o={ok:`#10b981`,warn:`#f59e0b`,error:`#ef4444`};function s(e,t){if(!e)return{versions:null,versionsError:`⚠ Could not reach GitHub — showing last known versions, retry`};let n=t&&typeof t==`object`?t:{},r=Array.isArray(n)?n:Array.isArray(n.versions)?n.versions:[],i=!Array.isArray(n)&&n.sources&&typeof n.sources==`object`?n.sources:{},a=``;return i.prImages===`rate-limited`?a=`⚠ GitHub rate-limited — PR test images temporarily unavailable, retry shortly`:i.releases===`rate-limited`?a=`⚠ GitHub rate-limited — some versions temporarily unavailable, retry shortly`:(i.prImages===`error`||i.releases===`error`)&&(a=`⚠ Could not fetch some versions from GitHub, retry`),{versions:r,versionsError:a}}function c(e,t={}){let{stableCount:n=5,preCount:r=3}=t,i=e.filter(e=>typeof e.pr==`number`),a=e.filter(e=>typeof e.pr!=`number`);return{prVersions:i,stableVersions:a.filter(e=>!e.prerelease).slice(0,n),preVersions:a.filter(e=>e.prerelease).slice(0,r)}}function l(e,t=[`latest`],n={}){let{prVersions:r,stableVersions:i,preVersions:a}=c(e,n);return new Set([...t,...a.map(e=>e.tag),...i.map(e=>e.tag),...r.map(e=>e.tag)])}function u(e,t,n=[`latest`],r={}){return e?l(t,n,r).has(e)?null:e:null}function d(e){return e==null?`—`:e>=1e6?(e/1e6).toFixed(1)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:String(e)}function f(i,a={}){let{intervalMs:o=5e3}=a,[s,c]=e(null),[l,u]=e(!0),d=t(0),f=t(a.fallback??null),p=n(async e=>{let t=++d.current,n=f.current;try{let t=await(await fetch(i,{signal:e})).json().catch(()=>null);t&&typeof t==`object`&&(n=t)}catch{}t===d.current&&(c(n),u(!1))},[i]);return r(()=>{let e=!1,t=null,n=new AbortController,r=async()=>{await p(n.signal),!e&&o>0&&(t=setTimeout(()=>void r(),o))};return r(),()=>{e=!0,n.abort(),t&&clearTimeout(t)}},[p,o]),{status:s,loading:l,refresh:()=>p()}}function p(i){let[a,o]=e([]),[c,l]=e(``),[u,d]=e(!1),f=t(0),p=n(async()=>{let e=++f.current;d(!0);try{let t=await fetch(i),n=await t.json().catch(()=>null),r=s(t.ok,n);if(e!==f.current)return;r.versions!==null&&o(r.versions),l(r.versionsError)}catch{if(e!==f.current)return;l(`⚠ Offline — showing last known versions`)}d(!1)},[i]);return r(()=>{p()},[p]),{versions:a,versionsError:c,loading:u,refresh:p}}function m({children:e,color:t}){return i.createElement(`span`,{style:{...a.hint,...t?{color:t}:{}}},e)}function h({state:e=`ok`,color:t,title:n,style:r}){return i.createElement(`div`,{style:{...a.stateIndicator,background:t??o[e],...r},title:n})}function g({icon:e,iconBackground:t,iconColor:n,title:r,meta:s,state:c=`ok`,stateTitle:l,link:u,children:d}){let f=c===`error`&&!t;return i.createElement(`div`,{style:a.card},i.createElement(`div`,{style:{...a.cardIcon,background:f?`#fef2f2`:t??`#3b82f6`,color:f?o.error:n??`#fff`}},e),i.createElement(`div`,{style:a.cardInfo},i.createElement(`div`,{style:a.cardTitle},r),s!=null&&i.createElement(`div`,{style:a.cardMeta},s)),d,u&&i.createElement(`a`,{href:u.href,target:`_blank`,rel:`noopener noreferrer`,style:a.link},u.label),i.createElement(h,{state:c,title:l}))}function _({title:t,defaultOpen:n=!1,children:r}){let[o,s]=e(n);return i.createElement(`div`,null,i.createElement(`button`,{type:`button`,"aria-expanded":o,style:{...a.sectionTitle,...a.sectionToggle},onClick:()=>s(!o)},i.createElement(`span`,{style:{...a.sectionMarker,transform:o?`rotate(90deg)`:`rotate(0deg)`}},`▶`),t),o&&i.createElement(`div`,{style:{marginBottom:16}},r))}var v={primary:a.btnPrimary,secondary:a.btnSecondary,warn:a.btnWarn,danger:a.btnDanger};function y({variant:e=`primary`,small:t=!1,busy:n=!1,busyLabel:r,disabled:o=!1,onClick:s,title:c,style:l,children:u}){let d=o||n;return i.createElement(`button`,{type:`button`,style:{...a.btn,...v[e],...t?a.btnSmall:{},...d?a.btnDisabled:{},...l},onClick:s,disabled:d,title:c},n?r??u:u)}function ee({message:e,error:t=!1,style:n}){return e?i.createElement(`div`,{style:{...a.status,color:t?o.error:o.ok,marginTop:16,...n}},e):null}var b=[{tag:`latest`,label:`latest (recommended)`}];function te({value:e,onChange:t,versions:n,floatingOptions:r=b,stableCount:s,preCount:l,loading:d=!1,error:f,onRefresh:p,disabled:h=!1,style:g}){let _={stableCount:s,preCount:l},{prVersions:v,stableVersions:ee,preVersions:te}=c(n,_),x=u(e,n,r.map(e=>e.tag),_);return i.createElement(i.Fragment,null,i.createElement(`select`,{style:{...a.select,...g},value:e,onChange:e=>t(e.target.value),disabled:h},r.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.label??e.tag)),te.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,` (pre-release)`)),ee.map((e,t)=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,t===0?` (current stable)`:``)),v.length>0&&i.createElement(`optgroup`,{label:`PR test images`},v.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,e.title?` — ${e.title}`:``))),x&&i.createElement(`option`,{value:x},x,` (running)`)),d&&i.createElement(m,null,`loading releases...`),p&&i.createElement(y,{small:!0,style:{padding:`4px 10px`,fontSize:11},onClick:p,title:`Refresh available versions`},`↻`),f&&i.createElement(m,{color:o.error},f))}var x={...a,warnBannerCode:{display:`block`,marginTop:8,padding:`8px 10px`,background:`#fff`,border:`1px solid #fecaca`,borderRadius:6,fontFamily:`monospace`,fontSize:12,color:`#7f1d1d`,whiteSpace:`pre-wrap`,wordBreak:`break-word`},fieldHelp:{fontSize:12,color:`#666`,marginTop:6,lineHeight:1.5},migrationItem:{display:`flex`,alignItems:`center`,gap:12,padding:`12px 16px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,marginBottom:8},migrationActions:{display:`flex`,gap:8,alignItems:`center`}},S=e=>typeof e==`object`&&!!e;function ne(e){let t=S(e)?e.sources:void 0;return Array.isArray(t)?t.filter(e=>S(e)&&typeof e.type==`string`&&typeof e.url==`string`&&typeof e.status==`string`&&(e.version===void 0||typeof e.version==`string`)):[]}function C(e){return e instanceof Error?e.message:String(e)}function w(e,t){return e??t}var T=[`none`,`lz4`,`zstd`],re={padding:`4px 12px`,fontSize:12};function ie(e){return T.includes(e)?e:`lz4`}function E({configuration:a,save:o}){let s=a||{},[c,l]=e(s.questdbHost||`127.0.0.1`),[u,m]=e(s.questdbIlpPort||9009),[h,v]=e(s.questdbHttpPort||9e3),[b,S]=e(s.questdbPgPort||8812),[T,E]=e(s.questdbVersion||`latest`),[D,ae]=e(s.managedContainer!==!1),[oe,se]=e(s.recordSelf!==!1),[ce,le]=e(s.recordOthers!==!1),[O,ue]=e(s.restoreOnStart===!0),[de,fe]=e(s.enableConsole!==!1),[pe,me]=e((s.restoreMaxAgeMinutes??0)>0?s.restoreMaxAgeMinutes:9),[he,ge]=e(s.defaultSamplingRate??2e3),[k,_e]=e(String(s.ilpFlushIntervalMs??5e3)),[ve,ye]=e(s.retentionDays||0),[A,be]=e(s.pathFilter?.mode===`include`?`include`:`exclude`),[j,xe]=e((Array.isArray(s.pathFilter?.paths)?s.pathFilter.paths:[]).join(`
2
+ `)),[Se,Ce]=e(s.compression||`lz4`),[we,Te]=e(s.compressionLevel||3),[Ee,De]=e(s.networkName||`sk-network`),[M,Oe]=e(s.exposeToContainers||!1),{versions:ke,versionsError:Ae,loading:je,refresh:Me}=p(`/plugins/signalk-questdb/api/versions`),{status:N,loading:Ne,refresh:P}=f(`/plugins/signalk-questdb/api/status`,{fallback:{status:`not_running`},intervalMs:5e3}),[F,Pe]=e(null),[Fe,Ie]=e(!1),[I,Le]=e(``),[Re,L]=e(``),[ze,R]=e(!1),[z,Be]=e(null),[Ve,He]=e(!1),[Ue,We]=e(!1),[Ge,Ke]=e(!1),[qe,Je]=e(!1),[Ye,B]=e(``),[V,Xe]=e(null),[H,U]=e(!1),W=t(0),[Ze,Qe]=e(!1),G=n(async e=>{let t=++W.current;try{let n=await fetch(`/plugins/signalk-questdb/api/wal-diagnosis`,{signal:e});if(t!==W.current)return;if(n.ok){let e=await n.json();if(t!==W.current)return;Xe(e),U(!1)}else U(!0)}catch{t===W.current&&U(!0)}},[]),$e=!!(N&&N.status===`running`&&(N.suspendedTables||[]).length>0);r(()=>{if(!$e){Xe(null),U(!1);return}let e=!1,t=null,n=new AbortController,r=async()=>{await G(n.signal),e||(t=setTimeout(r,15e3))};return r(),()=>{e=!0,n.abort(),t&&clearTimeout(t)}},[$e,G]);let et=async(e,t)=>{let n=t.tailSkip?`
3
+
4
+ WARNING: this is the newest pending segment — skipping it drops the ENTIRE pending backlog.`:``;if(window.confirm(`Skip the unreadable WAL segment on ${e}?\n\nThis permanently loses ${d(t.skippedTxns)} transaction(s) recorded between ${t.skipWindowStart} and ${t.skipWindowEnd}. Everything after the skipped segment is replayed without loss.`+n)){Qe(!0),B(``);try{let n=await fetch(`/plugins/signalk-questdb/api/resume-wal/skip`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({table:e,confirmPlan:t})}),r=await n.json().catch(()=>({error:n.statusText}));n.ok?B(r.message??``):B(`Skip failed: ${w(r.error,`unknown error`)}`),P(),G()}catch(e){B(`Skip failed: ${C(e)}`)}Qe(!1)}},tt=async()=>{He(!0);try{let e=await fetch(`/plugins/signalk-questdb/api/update/check`);e.ok&&Be(await e.json())}catch{}He(!1)},nt=async()=>{We(!0),L(`Pulling new image and restarting...`),R(!1);try{let e=await fetch(`/plugins/signalk-questdb/api/update/apply`,{method:`POST`});if(e.ok){let t=await e.json();L(t.message??``),Be(null),t.newVersion&&E(t.newVersion),P()}else{let t=await e.json().catch(()=>({error:e.statusText}));L(`Update failed: ${w(t.error,`unknown error`)}`),R(!0)}}catch(e){L(`Update failed: ${C(e)}`),R(!0)}We(!1)},rt=async()=>{if(window.confirm(`Remove the QuestDB container and DELETE ALL recorded data? This cannot be undone.`)){Ke(!0),L(`Removing QuestDB container and data...`),R(!1);try{let e=await fetch(`/plugins/signalk-questdb/api/purge-data`,{method:`POST`}),t=await e.json().catch(()=>({error:e.statusText}));e.ok?(L(t.message??``),P()):(L(`Remove failed: ${w(t.error,`unknown error`)}`),R(!0))}catch(e){L(`Remove failed: ${C(e)}`),R(!0)}Ke(!1)}},it=async()=>{Je(!0),B(``);try{let e=await fetch(`/plugins/signalk-questdb/api/resume-wal`,{method:`POST`}),t=await e.json().catch(()=>({error:e.statusText}));if(e.ok){let e=(t.results||[]).filter(e=>!e.ok);B(e.length===0?`${w(t.message,`Resume requested`)}. Recording resumes as the backlog drains — the banner clears once tables catch up.`:`${w(t.message,`Resume requested`)}. `+e.map(e=>`${e.table}: ${e.error}`).join(` · `)),P(),G()}else B(`Resume failed: ${w(t.error,`unknown error`)}`)}catch(e){B(`Resume failed: ${C(e)}`)}Je(!1)},at=async()=>{Ie(!0),L(``);try{let e=I?`?url=${encodeURIComponent(I)}`:``,t=await fetch(`/plugins/signalk-questdb/api/migration/detect${e}`);if(t.ok){let e=ne(await t.json().catch(()=>null));Pe(e),e.length===0&&(L(I?`No InfluxDB found at ${I}.`:`No InfluxDB instances detected on localhost:8086.`),R(!1))}}catch(e){L(`Detection failed: `+C(e)),R(!0)}Ie(!1)},[K,ot]=e(``),[q,st]=e(``),[J,ct]=e(`parquet`),[lt,ut]=e(!1),dt=()=>{let e=Number(k);if(k===``||!Number.isFinite(e)||e<500||e>3e5){L(`Write batch interval must be 500–300000 ms.`),R(!0);return}o({...s,questdbHost:c,questdbIlpPort:u,questdbHttpPort:h,questdbPgPort:b,questdbVersion:T,managedContainer:D,defaultSamplingRate:he,ilpFlushIntervalMs:e,recordSelf:oe,recordOthers:ce,restoreOnStart:O,enableConsole:de,restoreMaxAgeMinutes:pe,retentionDays:ve,compression:Se,compressionLevel:we,networkName:Ee,exposeToContainers:M,pathFilter:{mode:A,paths:j.split(`
5
+ `).map(e=>e.trim()).filter(Boolean)},samplingRates:s.samplingRates||{}}),L(`Saved! Plugin will restart with new configuration.`),R(!1)},ft=async()=>{if(!K||!q){L(`Set both from and to dates for export.`),R(!0);return}ut(!0),L(`Exporting ${J.toUpperCase()}...`),R(!1);try{let e=`/plugins/signalk-questdb/api/export?from=${encodeURIComponent(K)}&to=${encodeURIComponent(q)}&format=${J}`,t=await fetch(e);if(!t.ok){let e=await t.json().catch(()=>({error:t.statusText}));L(`Export failed: ${w(e.error,`unknown error`)}`),R(!0),ut(!1);return}let n=await t.blob(),r=J===`parquet`?`parquet`:`csv`,i=document.createElement(`a`);i.href=URL.createObjectURL(n),i.download=`signalk-export-${K.slice(0,10)}.${r}`,i.click(),URL.revokeObjectURL(i.href),L(`Exported ${(n.size/1024/1024).toFixed(1)} MB`)}catch(e){L(`Export failed: ${C(e)}`),R(!0)}ut(!1)},Y=N&&N.status===`running`,X=Y&&N.suspendedTables||[],Z=X.length>0,pt=Y&&N.schemaMismatch||!1,Q=Y&&N.ulimitClamp||null,mt=Q!==null&&Q.granted<=0,$=N?.hostMaxMapCount?.tooLow&&N.hostMaxMapCount||null;return i.createElement(`div`,{style:x.root},i.createElement(`div`,{style:x.sectionTitle},`QuestDB Status`),$&&i.createElement(`div`,{style:x.infoBanner},i.createElement(`div`,{style:x.warnBannerTitle},`Host vm.max_map_count is low — `,d($.current),` `,`(QuestDB recommends `,d($.recommended),`)`),`QuestDB memory-maps every partition and WAL segment it touches. As the database grows, this kernel limit can run out — mmap then fails with out-of-memory errors even though RAM is free, which shows up as slow or failing history queries, can suspend recording, and can take QuestDB down entirely. Run this in a shell on the host machine — not inside the QuestDB container, which can neither change the kernel-global limit nor has sudo (takes effect immediately, no restart needed):`,i.createElement(`code`,{style:x.warnBannerCode},`echo 'vm.max_map_count=${$.recommended}' | sudo tee /etc/sysctl.d/99-questdb.conf && sudo sysctl --system`)),Ne?i.createElement(`div`,{style:x.empty},`Checking QuestDB...`):Y?i.createElement(i.Fragment,null,Z&&i.createElement(`div`,{style:x.warnBanner},i.createElement(`div`,{style:x.warnBannerTitle},`QuestDB WAL suspended — recording stalled`),`Rows are arriving but no longer commit, so the counts below have stopped advancing. This follows an error while QuestDB applied the write-ahead log — see the reason reported per table below. Resuming replays every pending transaction, so no data is lost.`,i.createElement(`code`,{style:x.warnBannerCode},X.map(e=>{let t=String(e.errorMessage||e.errorTag||`reason not reported`).replace(/[\r\n]+/g,` `),n=(V?.tables||[]).find(t=>t.name===e.name),r=n?.suspendedSince?` — frozen since ${n.suspendedSince}`:``;return`${e.name}: ${d(e.txnLag)} txns behind — ${t}${r}`}).join(`
6
+ `)),(V?.tables||[]).filter(e=>e.applyError).map(e=>i.createElement(`div`,{key:e.name,style:{marginTop:8,fontSize:12}},`QuestDB's own log reports the apply failure on`,` `,i.createElement(`code`,null,e.name),` as:`,i.createElement(`code`,{style:x.warnBannerCode},e.applyError))),i.createElement(`div`,{style:{marginTop:10}},i.createElement(y,{variant:`primary`,busy:qe,busyLabel:`Resuming...`,disabled:Ze,onClick:it},`Resume recording`)),X.filter(e=>e.autoResume===`failed`).map(e=>{let t=(V?.tables||[]).find(t=>t.name===e.name);if(t?.partitionOpenFailure)return i.createElement(`div`,{key:e.name,style:{marginTop:12}},i.createElement(`div`,{style:x.warnBannerTitle},e.name,`: table data damaged — automatic repair not possible`),`QuestDB fails while opening this table's stored data, before it reaches any pending transaction. That means the commit record on disk describes rows whose data never made it to storage — the signature of a power loss during a write. Skipping transactions cannot fix this (the failure happens before them) and would discard the `,d(e.txnLag),` pending transactions for nothing, so no repair button is offered. Recovering this table means repairing its commit record by hand; please open an issue with the error above. Recording continues into the other tables, and “Resume recording” will re-suspend this one within milliseconds — it is safe to press, but it cannot repair this damage.`);let n=t?.skipPlan;return n?i.createElement(`div`,{key:e.name,style:{marginTop:12}},i.createElement(`div`,{style:x.warnBannerTitle},e.name,`: automatic resume failed — WAL segment unreadable`),`A lossless resume was attempted and the table re-suspended at the same transaction: the write-ahead-log segment at the stall point cannot be read back (typically corrupted by an unclean shutdown mid-write). Replaying can never get past it. The only repair is to skip the unreadable segment, losing`,` `,i.createElement(`b`,null,d(n.skippedTxns),` transaction(s)`),` `,`recorded between `,i.createElement(`b`,null,n.skipWindowStart),` and`,` `,i.createElement(`b`,null,n.skipWindowEnd),n.tailSkip?` — and this is the newest pending segment, so skipping it drops the ENTIRE pending backlog`:` — everything after the skipped segment (${d(Math.max(0,e.txnLag-n.skippedTxns))} txns) is replayed without loss`,`.`,i.createElement(`div`,{style:{marginTop:8}},i.createElement(y,{variant:`danger`,busy:Ze,busyLabel:`Skipping...`,disabled:qe||H,onClick:()=>et(e.name,n)},`Skip unreadable segment (loses data)`),H&&i.createElement(`div`,{style:{marginTop:6,fontSize:12}},`The diagnosis could not be refreshed — the numbers above may be stale. The skip re-enables once a refresh succeeds.`))):null}),i.createElement(`div`,{style:{marginTop:8,fontSize:12}},`Manual fallback in the QuestDB SQL console (`,i.createElement(`code`,null,`:9000`),`), one statement at a time — avoid running it from several tabs, the console retries a busy statement forever:`,i.createElement(`code`,{style:x.warnBannerCode},X.map(e=>{let t=`"${String(e.name).replace(/"/g,`""`)}"`,n=(V?.tables||[]).find(t=>t.name===e.name),r=[`ALTER TABLE ${t} RESUME WAL;`];return e.autoResume===`failed`&&n?.skipPlan&&!H&&r.push(`-- if the resume re-suspends: skip the unreadable segment (loses ${d(n.skipPlan.skippedTxns)} txns)`,`ALTER TABLE ${t} RESUME WAL FROM TXN ${n.skipPlan.skipToTxn};`),r.join(`
7
+ `)}).join(`
8
+ `)))),Ye&&i.createElement(`div`,{style:x.infoBanner},Ye),pt&&i.createElement(`div`,{style:x.warnBanner},i.createElement(`div`,{style:x.warnBannerTitle},`QuestDB table schema mismatch — data not readable`),`A QuestDB table was re-created by ILP ingestion with the wrong timestamp column, so rows are being stored but reads filtering on time (history, Grafana, and the counts above) return nothing. The plugin rebuilds the affected table with the correct schema automatically within a minute; if this persists, restart the plugin. (The few rows written into the wrong-schema table are lost — they were unreadable anyway.)`),Q&&i.createElement(`div`,{style:x.infoBanner},i.createElement(`div`,{style:x.warnBannerTitle},mt?`QuestDB open-files request rejected by the host`:`QuestDB open-files limit capped by the host`),mt?i.createElement(i.Fragment,null,`QuestDB requested a `,i.createElement(`code`,null,Q.ulimit),` limit of`,` `,d(Q.requested),`, but the container host rejected it, so QuestDB is running with the runtime's default limits. This is typical for podman machine on macOS, where the limits live inside the VM and cannot be read from here. Raise the limits of the service that runs the container runtime (on macOS: inside the VM, via`,` `,i.createElement(`code`,null,`podman machine ssh`),`), then remove the container once with `,i.createElement(`code`,null,`podman rm -f sk-signalk-questdb`),` and restart Signal K — a restart alone cannot re-grant a rejected ask.`):i.createElement(i.Fragment,null,`QuestDB requested a `,i.createElement(`code`,null,Q.ulimit),` limit of`,` `,d(Q.requested),`, but this host only allows `,d(Q.granted),`, so it was capped. QuestDB is running on the lower limit. To grant the full value, raise the host limit for the user running the container runtime — under rootless Podman that means a systemd`,` `,i.createElement(`code`,null,`user@.service`),` `,i.createElement(`code`,null,`LimitNOFILE`),` drop-in (editing `,i.createElement(`code`,null,`/etc/security/limits.conf`),` alone is usually not enough) — then restart the Signal K server so the plugin can re-create the QuestDB container with the raised limit (signalk-container 1.25.3+; on older versions remove the container once with`,` `,i.createElement(`code`,null,`podman rm -f sk-signalk-questdb`),` instead).`),` `,`This warning clears itself once the container is running with the full value.`,` `,i.createElement(`a`,{href:mt?`https://github.com/dirkwa/signalk-questdb#questdb-container-never-starts-on-macos-podman-machine`:`https://github.com/dirkwa/signalk-container#raising-the-open-files-limit-nofile`,target:`_blank`,rel:`noreferrer`,style:{color:`#92400e`,textDecoration:`underline`}},`Step-by-step instructions`),`.`),i.createElement(g,{icon:`Q`,iconBackground:`#7c3aed`,iconColor:`#fff`,title:`QuestDB`,meta:i.createElement(i.Fragment,null,N?.endpoint||`${c}:${h}`,` `,`· `,Z?`WAL suspended`:`Recording`),state:Z?`error`:`ok`,stateTitle:Z?`WAL suspended`:`Running`}),i.createElement(`div`,{style:x.statsGrid},i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},d(N.totalRows)),i.createElement(`div`,{style:x.statLabel},`Total Rows`)),i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},d(N.activePathsToday)),i.createElement(`div`,{style:x.statLabel},`Active Paths Today`)),N.restore&&i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},N.restore.failed?`—`:d(N.restore.contexts)),i.createElement(`div`,{style:x.statLabel},N.restore.failed?`Restore failed`:`Vessels Restored`))),i.createElement(`div`,{style:{display:`flex`,alignItems:`center`,gap:10,marginBottom:12}},z&&z.updateAvailable?i.createElement(i.Fragment,null,i.createElement(`span`,{style:{fontSize:13}},`v`,z.currentVersion,` →`,` `,i.createElement(`strong`,null,`v`,z.latestVersion),` available`),i.createElement(y,{variant:`primary`,busy:Ue,busyLabel:`Updating...`,onClick:nt,style:re},`Update QuestDB`)):z&&!z.updateAvailable?i.createElement(`span`,{style:{fontSize:12,color:`#888`}},`v`,z.currentVersion,` (up to date)`):i.createElement(y,{variant:`secondary`,busy:Ve,busyLabel:`Checking...`,onClick:tt,style:re},`Check for updates`))):i.createElement(g,{icon:`Q`,title:`QuestDB`,meta:i.createElement(i.Fragment,null,N?.status===`unhealthy`?`Not responding`:`Not running`,D?` — enable plugin to start container`:``),state:`error`}),i.createElement(`div`,{style:x.sectionTitle},`Image Version`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB version`),i.createElement(te,{value:T,onChange:E,versions:ke,loading:je,onRefresh:()=>void Me(),error:Ae,stableCount:3,preCount:2})),i.createElement(`div`,{style:x.sectionTitle},`Connection`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Managed container`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:D,onChange:e=>ae(e.target.checked)}),i.createElement(`span`,{style:x.hint},D?`signalk-container manages QuestDB`:`Connect to external QuestDB`)),!D&&i.createElement(i.Fragment,null,i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB host`),i.createElement(`input`,{style:x.input,value:c,onChange:e=>l(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`HTTP port (queries)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:h,onChange:e=>v(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ILP port (writes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:u,onChange:e=>m(Number(e.target.value))}))),D&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Bind to 0.0.0.0`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:M,onChange:e=>Oe(e.target.checked)}),i.createElement(`span`,{style:{...x.hint,color:M?`#ef4444`:void 0}},M?`Caution! This exposes your data to the network`:`Signal K reaches QuestDB automatically — only enable to reach it from another machine or a separate-Docker Grafana`)),D&&M&&i.createElement(i.Fragment,null,i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`HTTP port (queries)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:h,onChange:e=>v(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ILP port (writes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:u,onChange:e=>m(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`PostgreSQL wire port`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:b,onChange:e=>S(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`for Grafana`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Container network`),i.createElement(`input`,{style:x.input,value:Ee,onChange:e=>De(e.target.value)}),i.createElement(`span`,{style:x.hint},`shared with signalk-grafana`))),i.createElement(`div`,{style:x.sectionTitle},`Recording`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Default sampling rate (ms)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:he,onChange:e=>ge(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`1000 = max 1 write/sec per path (0 = every update)`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Write batch interval (ms)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:500,max:3e5,"aria-label":`Write batch interval in milliseconds`,value:k,onChange:e=>_e(e.target.value)}),i.createElement(`span`,{style:x.hint},`one QuestDB transaction per table per interval; longer = bigger batches, but up to this many ms lost on a hard crash (default 5000)`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Record own vessel`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:oe,onChange:e=>se(e.target.checked)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Record AIS targets`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:ce,onChange:e=>le(e.target.checked)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Restore vessels on startup`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,"aria-label":`Restore vessels on startup`,checked:O,onChange:e=>ue(e.target.checked)}),i.createElement(`span`,{style:x.hint},`replay each vessel's last recorded position after a restart, so AIS targets appear at once instead of only when they next transmit`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB console webapp`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,"aria-label":`QuestDB console webapp`,checked:de,onChange:e=>fe(e.target.checked)}),i.createElement(`span`,{style:x.hint},`serve QuestDB's own console inside the Signal K admin UI (admin only). It is a full SQL client — unlike the read-only query endpoint it can modify and delete recorded data`)),O&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Restore max age (minutes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:1,"aria-label":`Restore max age (minutes)`,value:pe,onChange:e=>{let t=Number(e.target.value);Number.isFinite(t)&&t>=1&&me(t)}}),i.createElement(`span`,{style:x.hint},`only replay values this recent (default 9, matching Freeboard's AIS expiry); higher puts staler positions on the chart`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Retention (days)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:ve,onChange:e=>ye(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`0 = keep forever`)),i.createElement(_,{title:`Path filtering`,defaultOpen:j.trim()!==``},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Filter mode`),i.createElement(`select`,{style:x.select,value:A,onChange:e=>be(e.target.value===`include`?`include`:`exclude`)},i.createElement(`option`,{value:`exclude`},`Exclude matching paths`),i.createElement(`option`,{value:`include`},`Include only matching paths`))),i.createElement(`div`,{style:{marginBottom:10}},i.createElement(`div`,{style:{...x.label,width:`auto`,marginBottom:6}},`Path patterns (one per line, glob supported) — optional`),i.createElement(`textarea`,{style:x.textarea,value:j,onChange:e=>xe(e.target.value),placeholder:`notifications.*
9
+ environment.wind.*`}),i.createElement(`div`,{style:x.fieldHelp},`Empty = record everything (the default). Nothing is filtered out unless you list a pattern here.`),i.createElement(`div`,{style:{...x.hint,marginLeft:0}},A===`exclude`?`These paths are NOT recorded; everything else is.`:`ONLY these paths are recorded; everything else is dropped.`))),i.createElement(_,{title:`Compression (on-disk)`},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Compression codec`),i.createElement(`select`,{style:x.select,value:Se,onChange:e=>Ce(ie(e.target.value))},i.createElement(`option`,{value:`none`},`None`),i.createElement(`option`,{value:`lz4`},`LZ4 (fast)`),i.createElement(`option`,{value:`zstd`},`ZSTD (smaller)`)),i.createElement(`span`,{style:x.hint},`applies to new data after save`)),Se===`zstd`&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ZSTD level`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:`1`,max:`22`,value:we,onChange:e=>Te(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`1 (fast) to 22 (smallest)`))),i.createElement(_,{title:`InfluxDB Migration`},i.createElement(`div`,{style:{display:`flex`,gap:10,alignItems:`center`,marginBottom:10}},i.createElement(y,{variant:`primary`,busy:Fe,busyLabel:`Detecting...`,onClick:at},`Detect InfluxDB`),i.createElement(`span`,{style:x.hint},`Checks localhost:8086 for InfluxDB 1.x and 2.x`)),F&&F.length>0&&i.createElement(`div`,null,F.map((e,t)=>i.createElement(`div`,{key:t,style:x.migrationItem},i.createElement(`div`,{style:{...x.cardIcon,width:36,height:36,fontSize:16,background:e.type===`influxdb2`?`#020a47`:`#22adf6`,color:`#fff`}},e.type===`influxdb2`?`2`:`1`),i.createElement(`div`,{style:x.cardInfo},i.createElement(`div`,{style:x.cardTitle},`InfluxDB `,e.type===`influxdb2`?`2.x`:`1.x`,i.createElement(`span`,{style:{...x.tag,...x.tagLatest}},e.status)),i.createElement(`div`,{style:x.cardMeta},e.url,` · v`,e.version))))),i.createElement(`div`,{style:{...x.fieldRow,marginTop:10}},i.createElement(`span`,{style:x.label},`Manual InfluxDB URL`),i.createElement(`input`,{style:x.input,placeholder:`http://192.168.1.100:8086`,value:I,onChange:e=>Le(e.target.value)}),i.createElement(`span`,{style:x.hint},`for remote instances`)),F&&F.length===0&&!Fe&&i.createElement(`div`,{style:{...x.empty,padding:`16px`,textAlign:`left`}},`No InfluxDB found on localhost. Use manual URL above for remote instances.`)),i.createElement(_,{title:`Data Export`},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`From`),i.createElement(`input`,{style:x.input,type:`datetime-local`,value:K,onChange:e=>ot(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`To`),i.createElement(`input`,{style:x.input,type:`datetime-local`,value:q,onChange:e=>st(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Format`),i.createElement(`select`,{style:x.select,value:J,onChange:e=>ct(e.target.value)},i.createElement(`option`,{value:`parquet`},`Parquet`),i.createElement(`option`,{value:`csv`},`CSV`))),i.createElement(y,{variant:`primary`,busy:lt,busyLabel:`Exporting...`,onClick:ft},`Export Data`)),s.managedContainer!==!1&&i.createElement(_,{title:`Danger zone`},i.createElement(`div`,{style:{fontSize:13,color:`#555`,marginBottom:10}},`Remove the QuestDB container and permanently delete all recorded data. Use this to fully reset QuestDB — Signal K's plugin-uninstall cannot delete this data on rootless Podman. This cannot be undone.`),i.createElement(y,{variant:`danger`,busy:Ge,busyLabel:`Removing...`,onClick:rt},`Remove container & all data`)),i.createElement(ee,{message:Re,error:ze,style:{marginTop:16}}),i.createElement(`div`,{style:{marginTop:24}},i.createElement(y,{onClick:dt},`Save Configuration`)))}export{E as default};
@@ -1 +1 @@
1
- import{t as e}from"./vite-preload-helper-HclGiUj8.js";import"./virtualExposes-pKhk7rm8.js";var t=`__mf_module_cache__`;globalThis[t]||={share:{},remote:{}},globalThis[t].share||={},globalThis[t].remote||={};var n=globalThis[t];for(let e of Object.keys(n.share))if(e.startsWith(`default:`)){let t=e.slice(8);n.share[t]===void 0&&(n.share[t]=n.share[e])}else if(!e.includes(`:`)){let t=`default:`+e;n.share[t]===void 0&&(n.share[t]=n.share[e])}(async()=>{let t=await e(()=>import(`./hostInit-CUx4ptQ-.js`),[],import.meta.url);await t.__tla;let{initHost:r}=t;await r(),n.pendingShareLoads&&await Promise.all(n.pendingShareLoads);let i=globalThis.__mf_module_cache_react_server__;i?.pendingShareLoads&&await Promise.all(i.pendingShareLoads)})().then(()=>e(()=>import(`./configpanel-BvRk9kiK.js`),[],import.meta.url));
1
+ import{t as e}from"./vite-preload-helper-HclGiUj8.js";import"./virtualExposes-CyrNon4j.js";var t=`__mf_module_cache__`;globalThis[t]||={share:{},remote:{}},globalThis[t].share||={},globalThis[t].remote||={};var n=globalThis[t];for(let e of Object.keys(n.share))if(e.startsWith(`default:`)){let t=e.slice(8);n.share[t]===void 0&&(n.share[t]=n.share[e])}else if(!e.includes(`:`)){let t=`default:`+e;n.share[t]===void 0&&(n.share[t]=n.share[e])}(async()=>{let t=await e(()=>import(`./hostInit-CUx4ptQ-.js`),[],import.meta.url);await t.__tla;let{initHost:r}=t;await r(),n.pendingShareLoads&&await Promise.all(n.pendingShareLoads);let i=globalThis.__mf_module_cache_react_server__;i?.pendingShareLoads&&await Promise.all(i.pendingShareLoads)})().then(()=>e(()=>import(`./configpanel-BvRk9kiK.js`),[],import.meta.url));
@@ -1 +1 @@
1
- import{t as e}from"./vite-preload-helper-HclGiUj8.js";var t={},n=new Set,r=new Map;function i(e,t){let n=r.get(e);return n||(n=Promise.resolve().then(t).catch(t=>{throw r.delete(e),t}),r.set(e,n)),n}async function a(e){if(typeof document>`u`)return;let r=t[e]||[];await Promise.all(r.map(e=>{let t=new URL(e,import.meta.url).href;return n.has(t)||(n.add(t),document.querySelector(`link[rel="stylesheet"][href="${t}"]`))?Promise.resolve():new Promise((e,n)=>{let r=document.createElement(`link`);r.rel=`stylesheet`,r.href=t,r.onload=()=>e(),r.onerror=()=>n(Error(`[Module Federation] Failed to load CSS asset: ${t}`)),document.head.appendChild(r)})}))}var o={"./PluginConfigurationPanel":async()=>{await a(`./PluginConfigurationPanel`),await Promise.all([]);let t=await i(`./PluginConfigurationPanel`,()=>e(()=>import(`./PluginConfigurationPanel-Wr6ovJk-.js`),[],import.meta.url)),n=t&&t.__mf_remote_dependency_pending;n&&typeof n.then==`function`&&await n;let r={};return Object.assign(r,t),Object.defineProperty(r,"__esModule",{value:!0,enumerable:!1}),r},"./AppPanel":async()=>{await a(`./AppPanel`),await Promise.all([]);let t=await i(`./AppPanel`,()=>e(()=>import(`./AppPanel-CNFtJpeq.js`),[],import.meta.url)),n=t&&t.__mf_remote_dependency_pending;n&&typeof n.then==`function`&&await n;let r={};return Object.assign(r,t),Object.defineProperty(r,"__esModule",{value:!0,enumerable:!1}),r}};export{o as default};
1
+ import{t as e}from"./vite-preload-helper-HclGiUj8.js";var t={},n=new Set,r=new Map;function i(e,t){let n=r.get(e);return n||(n=Promise.resolve().then(t).catch(t=>{throw r.delete(e),t}),r.set(e,n)),n}async function a(e){if(typeof document>`u`)return;let r=t[e]||[];await Promise.all(r.map(e=>{let t=new URL(e,import.meta.url).href;return n.has(t)||(n.add(t),document.querySelector(`link[rel="stylesheet"][href="${t}"]`))?Promise.resolve():new Promise((e,n)=>{let r=document.createElement(`link`);r.rel=`stylesheet`,r.href=t,r.onload=()=>e(),r.onerror=()=>n(Error(`[Module Federation] Failed to load CSS asset: ${t}`)),document.head.appendChild(r)})}))}var o={"./PluginConfigurationPanel":async()=>{await a(`./PluginConfigurationPanel`),await Promise.all([]);let t=await i(`./PluginConfigurationPanel`,()=>e(()=>import(`./PluginConfigurationPanel-CyS3A7gD.js`),[],import.meta.url)),n=t&&t.__mf_remote_dependency_pending;n&&typeof n.then==`function`&&await n;let r={};return Object.assign(r,t),Object.defineProperty(r,"__esModule",{value:!0,enumerable:!1}),r},"./AppPanel":async()=>{await a(`./AppPanel`),await Promise.all([]);let t=await i(`./AppPanel`,()=>e(()=>import(`./AppPanel-CNFtJpeq.js`),[],import.meta.url)),n=t&&t.__mf_remote_dependency_pending;n&&typeof n.then==`function`&&await n;let r={};return Object.assign(r,t),Object.defineProperty(r,"__esModule",{value:!0,enumerable:!1}),r}};export{o as default};
@@ -1 +1 @@
1
- import{t as e}from"./assets/vite-preload-helper-HclGiUj8.js";import{r as t,t as n}from"./assets/dist-BxwXn66h.js";({...t.global});var r=t.share;t.utils,typeof __VUE_HMR_RUNTIME__>`u`&&(globalThis.__VUE_HMR_RUNTIME__={createRecord(){},rerender(){},reload(){}});var i=`__mf_init__virtual:mf:__mfe_internal__signalk_questdb__mf_owner__1__mf_v__runtimeInit__mf_v__.js__`,a=globalThis[i];if(!a){let e,t,n=new Promise((n,r)=>{e=n,t=r});a=globalThis[i]={initPromise:n,initResolve:e,initReject:t}}var o=a.initResolve,s=`__mf_module_cache__`;globalThis[s]||={share:{},remote:{}},globalThis[s].share||={},globalThis[s].remote||={};var c=globalThis[s];for(let e of Object.keys(c.share))if(e.startsWith(`default:`)){let t=e.slice(8);c.share[t]===void 0&&(c.share[t]=c.share[e])}else if(!e.includes(`:`)){let t=`default:`+e;c.share[t]===void 0&&(c.share[t]=c.share[e])}var l={},u=Array.isArray(`default`)?`default`:[`default`],d=`default`,f=`signalk_questdb`,p=[[`react`]],m,h,g;async function _(e){for(let t=0;;t++)try{return await e()}catch(e){throw e}}var v=Symbol(`mf.originalSharedProvider`),y={emit:e=>e},b=(e,t)=>{if(t!==`version-first`)return e;let n={};for(let[t,r]of Object.entries(e))n[t]=Object.assign({},r,{[v]:r});return n},x=(e,t)=>{if(!t)return;let n=Object.entries(e||{}),r=n.find(([,e])=>e===t);if(r)return{version:r[0],provider:t,registered:!0};if(typeof t.version==`string`&&t.version)return{version:t.version,provider:t,registered:!1};let i=n.filter(([,e])=>e===t||!!(t.from&&e?.from===t.from));if(i.length===1)return{version:i[0][0],provider:t,registered:!1}},S=(e,t,n,i)=>{if(!e||!n)return;let a=Array.isArray(n.scope)?n.scope:[n.scope||`default`],o=b(e,i),s={};for(let e of a)s[e||`default`]={[t]:o};let c=r.getRegisteredShare(s,t,{...n,scope:a,strategy:i},y)?.shared;return c?.[v]||c},C=(e,t,n,r)=>{let i=e=>w(e,n),a=Object.fromEntries(Object.entries(e||{}).filter(([,e])=>!i(e)));n?.version&&n.shareConfig?.import!==!1&&(a[n.version]||(a[n.version]=n));let o=S(a,t,n,r);return i(o)?void 0:o},w=(e,t)=>e===t||!!(t?.from&&e?.from===t.from),T=(e,t,n,r,i,a,o,s,c)=>{if(c!==`version-first`||!s)return;let l=t?.options?.shared?.[i],u=Array.isArray(l)?l.find(e=>e?.version===a):void 0,d=(s?.from===t?.options?.name?s:void 0)||(w(u,s)?u:t?void 0:s);if(d)return e.some(e=>e!==t&&e?.options?.name===o?.from&&e?.shareScopeMap?.[r]===n)?d:void 0},ee=(e,t,n,r,i,a,o,s,c)=>{let l=a.registered?T(e,t,n,r,i,a.version,a.provider,s,c):void 0,u=l||o;if(u&&!(a.registered&&!w(u,s)))return{provider:u,scopeRootProvider:l}};async function E(){return m||=_(()=>e(()=>import(`./assets/_virtual_mf-localSharedImportMap___mfe_internal__signalk_questdb__mf_owner__1-I2PEpnTA.js`),[],import.meta.url)).catch(e=>{throw m=void 0,e}),m}async function D(){return h||=_(()=>e(()=>import(`./assets/virtualExposes-pKhk7rm8.js`),[],import.meta.url)).then(e=>e.default??e).catch(e=>{throw h=void 0,e}),h}async function O(e={},t=[]){let r=(e,t,n,r)=>{let i=(Array.isArray(r)?r[0]:r)||`default`,a=t||!n?e:e+`@`+n,o={canonical:i+`:`+a};return i==="default"&&(o.aliases=[a]),o},i=(e,t)=>{let n=e[t.canonical];if(n!==void 0)return n;let r=t.aliases||[];for(let n of r){if(!Object.prototype.hasOwnProperty.call(e,n))continue;let r=e[n];if(r!==void 0)return e[t.canonical]=r,r}},a=Symbol.for(`module-federation.shared-cache-listeners`),s=Symbol.for(`module-federation.shared-cache-owners`),m=e=>{let t=e[s];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,s,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},h=(e,t)=>e[s]?.[t.canonical],v=(e,t,n,r)=>{e[t.canonical]=n;let i=t.aliases||[];for(let t of i)Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0});let o=e[s];r===void 0?o&&delete o[t.canonical]:m(e)[t.canonical]=r;let c=e[a]?.[t.canonical];if(c)for(let e of c)e(n);return n},y=Symbol.for(`module-federation.tree-shaking-shared-cache`),b=e=>{let t=e[y];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,y,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},T=(e,t,n,r)=>{if(!Array.isArray(n))return r;let i=[...new Set(n)].sort(),a=b(e),o=a[t.canonical]||=[],s=o.find(e=>e.providedExports.length===i.length&&e.providedExports.every((e,t)=>e===i[t]));return s?s.value=r:o.push({providedExports:i,value:r}),r},D=Symbol.for(`module-federation.tree-shaking-shared-selection-cache`),O=e=>{let t=e[D];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,D,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},k=(e,t,n)=>{let r=i(e,t);return r===void 0?e[D]?.[t.canonical]?.[n]:r},A=(e,t,n,r)=>{let i=O(e),a=i[t.canonical]||=Object.create(null);return a[n]=r,r},j=globalThis.__FEDERATION__?.__INSTANCES__||[],M=t.find(e=>e?.from)?.from,N=j.find(t=>t?.options?.name===M&&t?.shareScopeMap?.default===e)||j.find(t=>t?.options?.name!==f&&t?.shareScopeMap?.default===e),P=Object.create(null),F=e=>{let t=Object.create(null);for(let[n,r]of Object.entries(e||{}))t[n]=Object.assign(Object.create(null),r);return t},I=(e,t)=>{let n=!N&&Object.values(t||{}).some(e=>Object.values(e||{}).some(B)),r=n?F(t):t;return P[e]={host:t,runtime:r,isWebpackScope:n},r},L=()=>{let e=Object.values(P).filter(({isWebpackScope:e})=>e);if(e.length!==0)for(let{host:t,runtime:n}of e)for(let[e,r]of Object.entries(t||{})){let t=n[e]||=Object.create(null);for(let[e,n]of Object.entries(r||{}))t[e]=n}},R=Object.create(null);for(let[t,n]of Object.entries(e)){let e=R[t]=Object.create(null);for(let[t,r]of Object.entries(n))e[t]=Object.assign({},r)}let{usedShared:z,usedRemotes:te}=await E();function B(e){return typeof e?.get==`function`&&Function.prototype.toString.call(e.get).includes(`__webpack_require__`)}let ne=Object.values(R).some(e=>Object.values(e||{}).some(B)),re=e=>{let t=e.split(`/`);return e.startsWith(`@`)?t.slice(0,2).join(`/`):t[0]},V=(t,n,r)=>{if(typeof C!=`function`)return;let i=re(t),a=i===t?[[t,n]]:[[t,n],[i,z[i]]];for(let[n,i]of a){if(!i)continue;let a=C(r?n===t?r:R[n]:e[n],n,i,`version-first`);if(a&&B(a)&&!a.lib&&!a.loaded)return a}};var H=l[d];if(H||=l[d]={from:f},t.indexOf(H)>=0)return;t.push(H);let U=e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t},ie=[],ae=globalThis.window===void 0?await Promise.all([]):[],W=`__mf_vite_runtime_share_load_id__`,oe=0,G=new Map,K=new Map,q=n({name:f,remotes:te,shared:z,plugins:[se(),...ie,...ae],shareStrategy:`version-first`});q.initShareScopeMap(`default`,I(`default`,e));function se(){return{name:`vite-share-pin-lifecycle-plugin`,resolveShare(e){let t=e.shareInfo?.[W],n=t===void 0?void 0:K.get(t);if(!n)return e;let r=e.resolver;return e.resolver=(...e)=>(n.pinned.reapply(),r(...e)),n.pinned.reveal(),e}}}let ce=q.sharedHandler.hooks.lifecycle.resolveShare,J=new WeakMap;ce.on(e=>{let t=e.shareInfo?.[W],n=e.resolver;return typeof n==`function`&&(e.resolver=(...e)=>{let r=n(...e),i=r?.shared;return i&&(typeof i==`object`||typeof i==`function`)&&!J.has(i)&&J.set(i,{from:i.from}),t!==void 0&&i&&G.set(t,i),r}),e});let le=(e,t,n,r)=>{if(!e||e[t]!==n)return;let i=Object.assign({},r,{version:r.version??t,scope:r.scope??n?.scope??[`default`],strategy:`loaded-first`}),a=r.from;e[t]=i;let o=()=>n===void 0?e[t]===void 0:e[t]===n;return{provider:i,reveal(){return e[t]===i&&(n===void 0?delete e[t]:e[t]=n,!0)},reapply(){return o()?(e[t]=i,!0):!1},release(s,c=!0){return r.from=a,e[t]===i?c?s?(i.from=a,s&&i.lib&&(i.loaded=!0),r.strategy===void 0?delete i.strategy:i.strategy=r.strategy,!0):(n===void 0?delete e[t]:e[t]=n,!1):(n===void 0?delete e[t]:e[t]=n,!0):!c&&o()}}},ue=e=>Object.entries(e||{}).map(([e,t])=>({provider:t,version:e,from:t.from,registered:!0})),de=(e,t)=>{if(t===void 0)return;let n;for(let r of e){let e=r.provider,i=e.treeShaking||e;if(r.loadedFactory===t||e.lib===t||i.lib===t){if(n)return;n=r}}return n},fe=async(e,t,n)=>{let r=++oe;K.set(r,{pinned:n});try{let n=await q.loadShare(e,{customShareInfo:{shareConfig:t,[W]:r}});return{factory:n===!1?void 0:n,selectedProvider:G.get(r)}}finally{G.delete(r),K.delete(r)}},Y=async(e,t,n,r,i,a,o=!0)=>{let s=a.from,c=le(n,r,i,a);if(!c)return;let l;try{l=await fe(e,t,c)}catch(e){throw c.release(!1),e}let u=l?.factory;if(u===void 0){c.release(!1);return}let d=ue(n),f=c.provider.treeShaking||c.provider,p=c.provider.lib===u||f.lib===u;if(!o&&p){let e=d.findIndex(e=>e.provider===c.provider);e!==-1&&d.splice(e,1)}!o&&!d.some(e=>e.provider===a)&&d.push({provider:a,version:r,from:s,registered:!1,loadedFactory:p?u:void 0});let m=!o&&l.selectedProvider===c.provider&&p?a:l.selectedProvider;if(m&&!d.some(e=>e.provider===m)){let e=J.get(m),t=typeof m.version==`string`&&m.version?m.version:r;d.push({provider:m,version:t,from:e?e.from:m.from,registered:n?.[t]===m,loadedFactory:u})}let h=d.find(e=>e.provider===m)??de(d,u);if(!c.release(!0,h?.provider===c.provider)||!h)return;let g=J.get(h.provider);h.from=h.provider===a?s:g?g.from:h.provider.from,g&&(h.provider.from=g.from);let _=typeof u==`function`?u():u,v=await Promise.resolve(_);if(!(h.registered&&n?.[h.version]!==h.provider))return{provider:h.provider,selection:h,resolved:v}},X=new Set,Z=new Map,pe=async(t,n,a)=>{let o=!!n.shareConfig?.singleton;if(!o&&n.canLiveRebind!==!1)try{let s=C(a,t,n,`version-first`),l=x(a,s);if(!l)return;let{version:u}=l;if(!o&&u!==n.version||!s.lib&&!s.loading&&!(s.loaded&&typeof s.get==`function`))return;let d=r(t,o,n.version,n.scope);if(i(c.share,d)!==void 0)return;let f=e[t],p=f?.[u];if(l.registered&&!w(p,s))return;let m,h=s.lib;if(!h&&B(s)||(!h&&s.loading&&(h=await s.loading),!h&&s.loaded&&typeof s.get==`function`&&(h=await s.get()),!h))return;let g=typeof h==`function`?h():h,_=await Promise.resolve(g),y=l.registered?p:s;m={provider:y,selection:{provider:y,version:u,from:s.from,registered:l.registered},resolved:_};let b=m?.provider,S=m?.selection;if(!S)return;let T=m?.resolved;if(T===void 0||i(c.share,d)!==void 0||S.registered&&f?.[S.version]!==b)return;v(c.share,d,U(T),S.from),X.add(b)}catch(e){console.error(`[Module Federation] Failed to bridge materialized shared module "`+t+`"`,e)}},me=async(t,n,a,o,s)=>{try{if(V(t,n))return;let l=r(t,n.shareConfig?.singleton,n.version,n.scope),u=i(c.share,l),d=h(c.share,l),p=C(a,t,n,`version-first`),m=p||S(a,t,n,`version-first`)||n,g=x(a,m);if(!g)return;let _=w(m,n),{version:y}=g;if(!n.shareConfig?.singleton&&y!==n.version)return;let b=o?.[y],T=ee(j,N,e,`default`,t,g,p,b,`version-first`);if(!T&&!_)return;let{provider:E,scopeRootProvider:D}=T||{provider:m,scopeRootProvider:void 0};if(n.canLiveRebind===!1||u!==void 0&&d!==f)return;let O=e[t],k=O?.[y];if(g.registered&&!D&&!w(k,E)||!_&&B(E)&&!E.lib&&!E.loaded)return;let A=await Y(t,n.shareConfig,O,y,k,E,g.registered&&!_),M=A?.provider,P=A?.selection;if(!P||w(M,n)||s&&(s.version!==P.version||!w({from:P.from},s.provider))||X.has(M))return;let F=A?.resolved;if(F===void 0)return;let I=i(c.share,l),L=h(c.share,l);if(I!==void 0&&L!==f||P.registered&&O?.[P.version]!==M)return;s||Z.set(t,{version:P.version,provider:{from:P.from}}),X.add(M);let R=U(F);v(c.share,l,R,P.from)}catch(e){console.error(`[Module Federation] Failed to bridge external shared module "`+t+`"`,e)}};for(let e of p)await Promise.all(e.map(async e=>{let t=z[e];!t||t.materialize===!1||t.treeShaking||await pe(e,t,R[e])}));for(let[e,t]of Object.entries(z)){if(t.treeShaking)continue;let n=r(e,t.shareConfig?.singleton,t.version,t.scope);if(i(c.share,n)!==void 0)continue;let a=r(e,!0,t.version,t.scope),o=i(c.share,a);o!==void 0&&v(c.share,n,o,h(c.share,a))}let he=[`react`],ge=[[`react`]],Q=he.filter(e=>z[e]&&z[e].materialize!==!1);c.providerInit||=new Map;let _e=(e,t)=>{let n=c.providerInit.get(e);if(n)return n;let r=Promise.resolve().then(t);return c.providerInit.set(e,r),r.catch(()=>c.providerInit.delete(e)),r};var ve=async e=>{let t=new Set(e);for(let e of ge)await Promise.all(e.filter(e=>t.has(e)).map(async e=>{let t=z[e],n=r(e,t.shareConfig?.singleton,t.version,t.scope);if(t.shareConfig?.import===!1||t.treeShaking||i(c.share,n)!==void 0)return;let a=r(e,!0,t.version,t.scope),o=i(c.share,a);if(o!==void 0){v(c.share,n,o,h(c.share,a));return}let s=typeof V==`function`?V(e,t):void 0;if(s&&!s.lib&&!s.loaded)return;let l=n.canonical,u=await _e(l,async()=>{let e=await t.get(),n=typeof e==`function`?e():e;return Promise.resolve(n)}),d=(e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t})(u),p=d===u?{...u}:d;p.__esModule!==!0&&Object.defineProperty(p,"__esModule",{value:!0,enumerable:!1}),v(c.share,n,p,f)}))};let ye=e=>{let t=z[e];if(!t.treeShaking&&t.shareConfig?.import!==!1)return!1;let n=r(e,t.shareConfig?.singleton,t.version,t.scope);return t.treeShaking?k(c.share,n,f)===void 0&&i(c.share,n)===void 0:i(c.share,n)===void 0},$=Q.findIndex(e=>{let t=z[e],n=r(e,t.shareConfig?.singleton,t.version,t.scope);return(t.treeShaking?k(c.share,n,f)??i(c.share,n):i(c.share,n))===void 0?t.treeShaking||t.shareConfig?.import===!1?!0:typeof C==`function`&&!!C(R[e],e,t,`version-first`):!1}),be=$===-1?Q:Q.slice(0,$);var xe=$===-1?[]:Q.slice($);await ve(be);try{await _(async()=>{await Promise.all(await q.initializeSharing(`default`,{strategy:`version-first`,from:`build`,initScope:t}))})}catch(e){console.error(`[Module Federation]`,e)}L();let Se=async()=>{for(let t of p)await Promise.all(t.map(async t=>{let n=z[t];!n||n.materialize===!1||n.treeShaking||await me(t,n,e[t],R[t],void 0)}))};await Se(),ne&&(g=Se);try{let e=globalThis.__FEDERATION__?.__SHARE__,t=Object.create(null);if(e)for(let[,n]of Object.entries(e))for(let e of u){let r=n?.[e];if(r)for(let[e,n]of Object.entries(r)){let r=z?.[e],i=R[e],a=Z.get(e);if(!r||!i||!a||r.treeShaking)continue;let o=t[e]||(t[e]=Object.create(null));for(let[e,t]of Object.entries(n)){if(!t.lib||a.version!==e||!w(t,a.provider))continue;let n=i[e];(t===n||n?.from&&t.from===n.from)&&(t===r||r.from&&t.from===r.from||o[e]===void 0&&(o[e]=t))}}}for(let e of p)await Promise.all(e.map(async e=>{let n=t[e];n&&await me(e,z[e],n,R[e],Z.get(e))}))}catch(e){console.error(`[Module Federation] Failed to bridge external shared modules`,e)}let Ce=async()=>{},we=async(t,n)=>{let a=r(t,n.shareConfig?.singleton,n.version,n.scope),o=n.treeShaking?k(c.share,a,f):i(c.share,a);if(n.shareConfig?.import!==!1||o!==void 0||V(t,n,R[t]))return;let s=e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t},l=e?.[t],u=S(l,t,n,`version-first`)||n,d=x(l,u);if(!d)return;let{version:p}=d,m=l?.[p],h=await Y(t,n.shareConfig,l,p,m,u,d.registered&&!w(u,n)),g=h?.selection,_=h?.provider,y=h?.resolved;if(!g||w(_,n)||y===void 0||(n.treeShaking?k(c.share,a,f):i(c.share,a))!==void 0||g.registered&&l?.[g.version]!==_)return;let b=s(y);if(n.treeShaking){let e=n.treeShaking.providedExports??n.treeShaking.usedExports??[];T(c.share,a,e,b),A(c.share,a,f,b)}else v(c.share,a,b,g.from)},Te=[];for(let e of xe){let t=z[e];if(ye(e))try{t.treeShaking?await Ce(e,t):t.shareConfig?.import===!1&&await we(e,t)}catch(t){console.error(`[Module Federation] Failed to resolve runtime-only shared module "${e}"`,t);break}if(ye(e))break;Te.push(e)}return await ve(Te),o(q),q}async function k(e){let t=await D();if(!(e in t))throw Error(`[Module Federation] Module ${e} does not exist in container.`);return g&&await g(),c.pendingShareLoads&&await Promise.all(c.pendingShareLoads),t[e]().then(e=>()=>e)}export{k as get,O as init};
1
+ import{t as e}from"./assets/vite-preload-helper-HclGiUj8.js";import{r as t,t as n}from"./assets/dist-BxwXn66h.js";({...t.global});var r=t.share;t.utils,typeof __VUE_HMR_RUNTIME__>`u`&&(globalThis.__VUE_HMR_RUNTIME__={createRecord(){},rerender(){},reload(){}});var i=`__mf_init__virtual:mf:__mfe_internal__signalk_questdb__mf_owner__1__mf_v__runtimeInit__mf_v__.js__`,a=globalThis[i];if(!a){let e,t,n=new Promise((n,r)=>{e=n,t=r});a=globalThis[i]={initPromise:n,initResolve:e,initReject:t}}var o=a.initResolve,s=`__mf_module_cache__`;globalThis[s]||={share:{},remote:{}},globalThis[s].share||={},globalThis[s].remote||={};var c=globalThis[s];for(let e of Object.keys(c.share))if(e.startsWith(`default:`)){let t=e.slice(8);c.share[t]===void 0&&(c.share[t]=c.share[e])}else if(!e.includes(`:`)){let t=`default:`+e;c.share[t]===void 0&&(c.share[t]=c.share[e])}var l={},u=Array.isArray(`default`)?`default`:[`default`],d=`default`,f=`signalk_questdb`,p=[[`react`]],m,h,g;async function _(e){for(let t=0;;t++)try{return await e()}catch(e){throw e}}var v=Symbol(`mf.originalSharedProvider`),y={emit:e=>e},b=(e,t)=>{if(t!==`version-first`)return e;let n={};for(let[t,r]of Object.entries(e))n[t]=Object.assign({},r,{[v]:r});return n},x=(e,t)=>{if(!t)return;let n=Object.entries(e||{}),r=n.find(([,e])=>e===t);if(r)return{version:r[0],provider:t,registered:!0};if(typeof t.version==`string`&&t.version)return{version:t.version,provider:t,registered:!1};let i=n.filter(([,e])=>e===t||!!(t.from&&e?.from===t.from));if(i.length===1)return{version:i[0][0],provider:t,registered:!1}},S=(e,t,n,i)=>{if(!e||!n)return;let a=Array.isArray(n.scope)?n.scope:[n.scope||`default`],o=b(e,i),s={};for(let e of a)s[e||`default`]={[t]:o};let c=r.getRegisteredShare(s,t,{...n,scope:a,strategy:i},y)?.shared;return c?.[v]||c},C=(e,t,n,r)=>{let i=e=>w(e,n),a=Object.fromEntries(Object.entries(e||{}).filter(([,e])=>!i(e)));n?.version&&n.shareConfig?.import!==!1&&(a[n.version]||(a[n.version]=n));let o=S(a,t,n,r);return i(o)?void 0:o},w=(e,t)=>e===t||!!(t?.from&&e?.from===t.from),T=(e,t,n,r,i,a,o,s,c)=>{if(c!==`version-first`||!s)return;let l=t?.options?.shared?.[i],u=Array.isArray(l)?l.find(e=>e?.version===a):void 0,d=(s?.from===t?.options?.name?s:void 0)||(w(u,s)?u:t?void 0:s);if(d)return e.some(e=>e!==t&&e?.options?.name===o?.from&&e?.shareScopeMap?.[r]===n)?d:void 0},ee=(e,t,n,r,i,a,o,s,c)=>{let l=a.registered?T(e,t,n,r,i,a.version,a.provider,s,c):void 0,u=l||o;if(u&&!(a.registered&&!w(u,s)))return{provider:u,scopeRootProvider:l}};async function E(){return m||=_(()=>e(()=>import(`./assets/_virtual_mf-localSharedImportMap___mfe_internal__signalk_questdb__mf_owner__1-I2PEpnTA.js`),[],import.meta.url)).catch(e=>{throw m=void 0,e}),m}async function D(){return h||=_(()=>e(()=>import(`./assets/virtualExposes-CyrNon4j.js`),[],import.meta.url)).then(e=>e.default??e).catch(e=>{throw h=void 0,e}),h}async function O(e={},t=[]){let r=(e,t,n,r)=>{let i=(Array.isArray(r)?r[0]:r)||`default`,a=t||!n?e:e+`@`+n,o={canonical:i+`:`+a};return i==="default"&&(o.aliases=[a]),o},i=(e,t)=>{let n=e[t.canonical];if(n!==void 0)return n;let r=t.aliases||[];for(let n of r){if(!Object.prototype.hasOwnProperty.call(e,n))continue;let r=e[n];if(r!==void 0)return e[t.canonical]=r,r}},a=Symbol.for(`module-federation.shared-cache-listeners`),s=Symbol.for(`module-federation.shared-cache-owners`),m=e=>{let t=e[s];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,s,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},h=(e,t)=>e[s]?.[t.canonical],v=(e,t,n,r)=>{e[t.canonical]=n;let i=t.aliases||[];for(let t of i)Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0});let o=e[s];r===void 0?o&&delete o[t.canonical]:m(e)[t.canonical]=r;let c=e[a]?.[t.canonical];if(c)for(let e of c)e(n);return n},y=Symbol.for(`module-federation.tree-shaking-shared-cache`),b=e=>{let t=e[y];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,y,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},T=(e,t,n,r)=>{if(!Array.isArray(n))return r;let i=[...new Set(n)].sort(),a=b(e),o=a[t.canonical]||=[],s=o.find(e=>e.providedExports.length===i.length&&e.providedExports.every((e,t)=>e===i[t]));return s?s.value=r:o.push({providedExports:i,value:r}),r},D=Symbol.for(`module-federation.tree-shaking-shared-selection-cache`),O=e=>{let t=e[D];return t===void 0&&(t=Object.create(null),Object.defineProperty(e,D,{value:t,enumerable:!1,configurable:!1,writable:!1})),t},k=(e,t,n)=>{let r=i(e,t);return r===void 0?e[D]?.[t.canonical]?.[n]:r},A=(e,t,n,r)=>{let i=O(e),a=i[t.canonical]||=Object.create(null);return a[n]=r,r},j=globalThis.__FEDERATION__?.__INSTANCES__||[],M=t.find(e=>e?.from)?.from,N=j.find(t=>t?.options?.name===M&&t?.shareScopeMap?.default===e)||j.find(t=>t?.options?.name!==f&&t?.shareScopeMap?.default===e),P=Object.create(null),F=e=>{let t=Object.create(null);for(let[n,r]of Object.entries(e||{}))t[n]=Object.assign(Object.create(null),r);return t},I=(e,t)=>{let n=!N&&Object.values(t||{}).some(e=>Object.values(e||{}).some(B)),r=n?F(t):t;return P[e]={host:t,runtime:r,isWebpackScope:n},r},L=()=>{let e=Object.values(P).filter(({isWebpackScope:e})=>e);if(e.length!==0)for(let{host:t,runtime:n}of e)for(let[e,r]of Object.entries(t||{})){let t=n[e]||=Object.create(null);for(let[e,n]of Object.entries(r||{}))t[e]=n}},R=Object.create(null);for(let[t,n]of Object.entries(e)){let e=R[t]=Object.create(null);for(let[t,r]of Object.entries(n))e[t]=Object.assign({},r)}let{usedShared:z,usedRemotes:te}=await E();function B(e){return typeof e?.get==`function`&&Function.prototype.toString.call(e.get).includes(`__webpack_require__`)}let ne=Object.values(R).some(e=>Object.values(e||{}).some(B)),re=e=>{let t=e.split(`/`);return e.startsWith(`@`)?t.slice(0,2).join(`/`):t[0]},V=(t,n,r)=>{if(typeof C!=`function`)return;let i=re(t),a=i===t?[[t,n]]:[[t,n],[i,z[i]]];for(let[n,i]of a){if(!i)continue;let a=C(r?n===t?r:R[n]:e[n],n,i,`version-first`);if(a&&B(a)&&!a.lib&&!a.loaded)return a}};var H=l[d];if(H||=l[d]={from:f},t.indexOf(H)>=0)return;t.push(H);let U=e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t},ie=[],ae=globalThis.window===void 0?await Promise.all([]):[],W=`__mf_vite_runtime_share_load_id__`,oe=0,G=new Map,K=new Map,q=n({name:f,remotes:te,shared:z,plugins:[se(),...ie,...ae],shareStrategy:`version-first`});q.initShareScopeMap(`default`,I(`default`,e));function se(){return{name:`vite-share-pin-lifecycle-plugin`,resolveShare(e){let t=e.shareInfo?.[W],n=t===void 0?void 0:K.get(t);if(!n)return e;let r=e.resolver;return e.resolver=(...e)=>(n.pinned.reapply(),r(...e)),n.pinned.reveal(),e}}}let ce=q.sharedHandler.hooks.lifecycle.resolveShare,J=new WeakMap;ce.on(e=>{let t=e.shareInfo?.[W],n=e.resolver;return typeof n==`function`&&(e.resolver=(...e)=>{let r=n(...e),i=r?.shared;return i&&(typeof i==`object`||typeof i==`function`)&&!J.has(i)&&J.set(i,{from:i.from}),t!==void 0&&i&&G.set(t,i),r}),e});let le=(e,t,n,r)=>{if(!e||e[t]!==n)return;let i=Object.assign({},r,{version:r.version??t,scope:r.scope??n?.scope??[`default`],strategy:`loaded-first`}),a=r.from;e[t]=i;let o=()=>n===void 0?e[t]===void 0:e[t]===n;return{provider:i,reveal(){return e[t]===i&&(n===void 0?delete e[t]:e[t]=n,!0)},reapply(){return o()?(e[t]=i,!0):!1},release(s,c=!0){return r.from=a,e[t]===i?c?s?(i.from=a,s&&i.lib&&(i.loaded=!0),r.strategy===void 0?delete i.strategy:i.strategy=r.strategy,!0):(n===void 0?delete e[t]:e[t]=n,!1):(n===void 0?delete e[t]:e[t]=n,!0):!c&&o()}}},ue=e=>Object.entries(e||{}).map(([e,t])=>({provider:t,version:e,from:t.from,registered:!0})),de=(e,t)=>{if(t===void 0)return;let n;for(let r of e){let e=r.provider,i=e.treeShaking||e;if(r.loadedFactory===t||e.lib===t||i.lib===t){if(n)return;n=r}}return n},fe=async(e,t,n)=>{let r=++oe;K.set(r,{pinned:n});try{let n=await q.loadShare(e,{customShareInfo:{shareConfig:t,[W]:r}});return{factory:n===!1?void 0:n,selectedProvider:G.get(r)}}finally{G.delete(r),K.delete(r)}},Y=async(e,t,n,r,i,a,o=!0)=>{let s=a.from,c=le(n,r,i,a);if(!c)return;let l;try{l=await fe(e,t,c)}catch(e){throw c.release(!1),e}let u=l?.factory;if(u===void 0){c.release(!1);return}let d=ue(n),f=c.provider.treeShaking||c.provider,p=c.provider.lib===u||f.lib===u;if(!o&&p){let e=d.findIndex(e=>e.provider===c.provider);e!==-1&&d.splice(e,1)}!o&&!d.some(e=>e.provider===a)&&d.push({provider:a,version:r,from:s,registered:!1,loadedFactory:p?u:void 0});let m=!o&&l.selectedProvider===c.provider&&p?a:l.selectedProvider;if(m&&!d.some(e=>e.provider===m)){let e=J.get(m),t=typeof m.version==`string`&&m.version?m.version:r;d.push({provider:m,version:t,from:e?e.from:m.from,registered:n?.[t]===m,loadedFactory:u})}let h=d.find(e=>e.provider===m)??de(d,u);if(!c.release(!0,h?.provider===c.provider)||!h)return;let g=J.get(h.provider);h.from=h.provider===a?s:g?g.from:h.provider.from,g&&(h.provider.from=g.from);let _=typeof u==`function`?u():u,v=await Promise.resolve(_);if(!(h.registered&&n?.[h.version]!==h.provider))return{provider:h.provider,selection:h,resolved:v}},X=new Set,Z=new Map,pe=async(t,n,a)=>{let o=!!n.shareConfig?.singleton;if(!o&&n.canLiveRebind!==!1)try{let s=C(a,t,n,`version-first`),l=x(a,s);if(!l)return;let{version:u}=l;if(!o&&u!==n.version||!s.lib&&!s.loading&&!(s.loaded&&typeof s.get==`function`))return;let d=r(t,o,n.version,n.scope);if(i(c.share,d)!==void 0)return;let f=e[t],p=f?.[u];if(l.registered&&!w(p,s))return;let m,h=s.lib;if(!h&&B(s)||(!h&&s.loading&&(h=await s.loading),!h&&s.loaded&&typeof s.get==`function`&&(h=await s.get()),!h))return;let g=typeof h==`function`?h():h,_=await Promise.resolve(g),y=l.registered?p:s;m={provider:y,selection:{provider:y,version:u,from:s.from,registered:l.registered},resolved:_};let b=m?.provider,S=m?.selection;if(!S)return;let T=m?.resolved;if(T===void 0||i(c.share,d)!==void 0||S.registered&&f?.[S.version]!==b)return;v(c.share,d,U(T),S.from),X.add(b)}catch(e){console.error(`[Module Federation] Failed to bridge materialized shared module "`+t+`"`,e)}},me=async(t,n,a,o,s)=>{try{if(V(t,n))return;let l=r(t,n.shareConfig?.singleton,n.version,n.scope),u=i(c.share,l),d=h(c.share,l),p=C(a,t,n,`version-first`),m=p||S(a,t,n,`version-first`)||n,g=x(a,m);if(!g)return;let _=w(m,n),{version:y}=g;if(!n.shareConfig?.singleton&&y!==n.version)return;let b=o?.[y],T=ee(j,N,e,`default`,t,g,p,b,`version-first`);if(!T&&!_)return;let{provider:E,scopeRootProvider:D}=T||{provider:m,scopeRootProvider:void 0};if(n.canLiveRebind===!1||u!==void 0&&d!==f)return;let O=e[t],k=O?.[y];if(g.registered&&!D&&!w(k,E)||!_&&B(E)&&!E.lib&&!E.loaded)return;let A=await Y(t,n.shareConfig,O,y,k,E,g.registered&&!_),M=A?.provider,P=A?.selection;if(!P||w(M,n)||s&&(s.version!==P.version||!w({from:P.from},s.provider))||X.has(M))return;let F=A?.resolved;if(F===void 0)return;let I=i(c.share,l),L=h(c.share,l);if(I!==void 0&&L!==f||P.registered&&O?.[P.version]!==M)return;s||Z.set(t,{version:P.version,provider:{from:P.from}}),X.add(M);let R=U(F);v(c.share,l,R,P.from)}catch(e){console.error(`[Module Federation] Failed to bridge external shared module "`+t+`"`,e)}};for(let e of p)await Promise.all(e.map(async e=>{let t=z[e];!t||t.materialize===!1||t.treeShaking||await pe(e,t,R[e])}));for(let[e,t]of Object.entries(z)){if(t.treeShaking)continue;let n=r(e,t.shareConfig?.singleton,t.version,t.scope);if(i(c.share,n)!==void 0)continue;let a=r(e,!0,t.version,t.scope),o=i(c.share,a);o!==void 0&&v(c.share,n,o,h(c.share,a))}let he=[`react`],ge=[[`react`]],Q=he.filter(e=>z[e]&&z[e].materialize!==!1);c.providerInit||=new Map;let _e=(e,t)=>{let n=c.providerInit.get(e);if(n)return n;let r=Promise.resolve().then(t);return c.providerInit.set(e,r),r.catch(()=>c.providerInit.delete(e)),r};var ve=async e=>{let t=new Set(e);for(let e of ge)await Promise.all(e.filter(e=>t.has(e)).map(async e=>{let t=z[e],n=r(e,t.shareConfig?.singleton,t.version,t.scope);if(t.shareConfig?.import===!1||t.treeShaking||i(c.share,n)!==void 0)return;let a=r(e,!0,t.version,t.scope),o=i(c.share,a);if(o!==void 0){v(c.share,n,o,h(c.share,a));return}let s=typeof V==`function`?V(e,t):void 0;if(s&&!s.lib&&!s.loaded)return;let l=n.canonical,u=await _e(l,async()=>{let e=await t.get(),n=typeof e==`function`?e():e;return Promise.resolve(n)}),d=(e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t})(u),p=d===u?{...u}:d;p.__esModule!==!0&&Object.defineProperty(p,"__esModule",{value:!0,enumerable:!1}),v(c.share,n,p,f)}))};let ye=e=>{let t=z[e];if(!t.treeShaking&&t.shareConfig?.import!==!1)return!1;let n=r(e,t.shareConfig?.singleton,t.version,t.scope);return t.treeShaking?k(c.share,n,f)===void 0&&i(c.share,n)===void 0:i(c.share,n)===void 0},$=Q.findIndex(e=>{let t=z[e],n=r(e,t.shareConfig?.singleton,t.version,t.scope);return(t.treeShaking?k(c.share,n,f)??i(c.share,n):i(c.share,n))===void 0?t.treeShaking||t.shareConfig?.import===!1?!0:typeof C==`function`&&!!C(R[e],e,t,`version-first`):!1}),be=$===-1?Q:Q.slice(0,$);var xe=$===-1?[]:Q.slice($);await ve(be);try{await _(async()=>{await Promise.all(await q.initializeSharing(`default`,{strategy:`version-first`,from:`build`,initScope:t}))})}catch(e){console.error(`[Module Federation]`,e)}L();let Se=async()=>{for(let t of p)await Promise.all(t.map(async t=>{let n=z[t];!n||n.materialize===!1||n.treeShaking||await me(t,n,e[t],R[t],void 0)}))};await Se(),ne&&(g=Se);try{let e=globalThis.__FEDERATION__?.__SHARE__,t=Object.create(null);if(e)for(let[,n]of Object.entries(e))for(let e of u){let r=n?.[e];if(r)for(let[e,n]of Object.entries(r)){let r=z?.[e],i=R[e],a=Z.get(e);if(!r||!i||!a||r.treeShaking)continue;let o=t[e]||(t[e]=Object.create(null));for(let[e,t]of Object.entries(n)){if(!t.lib||a.version!==e||!w(t,a.provider))continue;let n=i[e];(t===n||n?.from&&t.from===n.from)&&(t===r||r.from&&t.from===r.from||o[e]===void 0&&(o[e]=t))}}}for(let e of p)await Promise.all(e.map(async e=>{let n=t[e];n&&await me(e,z[e],n,R[e],Z.get(e))}))}catch(e){console.error(`[Module Federation] Failed to bridge external shared modules`,e)}let Ce=async()=>{},we=async(t,n)=>{let a=r(t,n.shareConfig?.singleton,n.version,n.scope),o=n.treeShaking?k(c.share,a,f):i(c.share,a);if(n.shareConfig?.import!==!1||o!==void 0||V(t,n,R[t]))return;let s=e=>{let t=e;for(let e=0;e<5;e++){let e=t?.default;if(!e||typeof e!=`object`||Object.keys(e).length===0)break;let n=Object.keys(t).filter(e=>e!=="default").map(e=>t[e]);if(n.length>0&&n.some(e=>e!==void 0))break;t=e}return t},l=e?.[t],u=S(l,t,n,`version-first`)||n,d=x(l,u);if(!d)return;let{version:p}=d,m=l?.[p],h=await Y(t,n.shareConfig,l,p,m,u,d.registered&&!w(u,n)),g=h?.selection,_=h?.provider,y=h?.resolved;if(!g||w(_,n)||y===void 0||(n.treeShaking?k(c.share,a,f):i(c.share,a))!==void 0||g.registered&&l?.[g.version]!==_)return;let b=s(y);if(n.treeShaking){let e=n.treeShaking.providedExports??n.treeShaking.usedExports??[];T(c.share,a,e,b),A(c.share,a,f,b)}else v(c.share,a,b,g.from)},Te=[];for(let e of xe){let t=z[e];if(ye(e))try{t.treeShaking?await Ce(e,t):t.shareConfig?.import===!1&&await we(e,t)}catch(t){console.error(`[Module Federation] Failed to resolve runtime-only shared module "${e}"`,t);break}if(ye(e))break;Te.push(e)}return await ve(Te),o(q),q}async function k(e){let t=await D();if(!(e in t))throw Error(`[Module Federation] Module ${e} does not exist in container.`);return g&&await g(),c.pendingShareLoads&&await Promise.all(c.pendingShareLoads),t[e]().then(e=>()=>e)}export{k as get,O as init};
@@ -1,9 +0,0 @@
1
- import{a as e,i as t,n,r,t as i}from"./_virtual_mf___mfe_internal__signalk_questdb__mf_owner__1__loadShare__react__loadShare__.js-DzhF4wXp.js";var a={root:{fontFamily:`-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,color:`#333`,padding:`16px 0`},sectionToggle:{color:`#555`,display:`flex`,alignItems:`center`,gap:6,width:`100%`,textAlign:`left`,background:`none`,border:`none`,padding:0,cursor:`pointer`,userSelect:`none`},sectionMarker:{fontSize:11,transition:`transform 0.15s`},sectionTitle:{fontSize:13,fontWeight:600,color:`#888`,textTransform:`uppercase`,letterSpacing:`0.05em`,marginBottom:10,marginTop:24},btn:{display:`inline-flex`,alignItems:`center`,gap:8,padding:`8px 16px`,border:`none`,borderRadius:6,fontSize:13,fontWeight:600,cursor:`pointer`},btnPrimary:{background:`#3b82f6`,color:`#fff`},btnSecondary:{background:`#f1f5f9`,color:`#475569`,border:`1px solid #e2e8f0`},btnWarn:{background:`#f59e0b`,color:`#fff`},btnDanger:{background:`#ef4444`,color:`#fff`},btnDisabled:{opacity:.5,cursor:`not-allowed`},btnSmall:{padding:`4px 12px`,fontSize:12},status:{marginTop:8,fontSize:12,minHeight:18},card:{display:`flex`,alignItems:`center`,gap:14,padding:`14px 18px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,marginBottom:12},cardIcon:{width:44,height:44,borderRadius:10,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:20,fontWeight:700,flexShrink:0},cardInfo:{flex:1},cardTitle:{fontSize:15,fontWeight:600,color:`#333`},cardMeta:{fontSize:12,color:`#888`},stateIndicator:{width:10,height:10,borderRadius:`50%`,flexShrink:0},fieldRow:{display:`flex`,alignItems:`center`,gap:12,marginBottom:10},label:{fontSize:13,fontWeight:500,color:`#555`,width:180,flexShrink:0},select:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,minWidth:200},input:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,width:200},inputSmall:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,background:`#fff`,color:`#333`,width:80},checkbox:{width:16,height:16,accentColor:`#3b82f6`},hint:{fontSize:11,color:`#aaa`,marginLeft:8},link:{color:`#3b82f6`,textDecoration:`none`,fontSize:13,fontWeight:600},textarea:{padding:`6px 10px`,borderRadius:6,border:`1px solid #ccc`,fontSize:13,fontFamily:`monospace`,background:`#fff`,color:`#333`,width:`100%`,minHeight:70,boxSizing:`border-box`,resize:`vertical`},empty:{textAlign:`center`,padding:`30px 16px`,color:`#999`,fontSize:13},tag:{display:`inline-block`,padding:`2px 8px`,borderRadius:4,fontSize:10,fontWeight:600,marginLeft:8},tagPre:{background:`#fef3c7`,color:`#92400e`},tagLatest:{background:`#dcfce7`,color:`#166534`},warnBanner:{padding:`12px 16px`,background:`#fef2f2`,border:`1px solid #fecaca`,borderRadius:10,marginBottom:12,fontSize:13,color:`#991b1b`,lineHeight:1.5},warnBannerTitle:{fontWeight:700,marginBottom:4},infoBanner:{padding:`12px 16px`,background:`#fffbeb`,border:`1px solid #fde68a`,borderRadius:10,marginBottom:12,fontSize:13,color:`#92400e`,lineHeight:1.5},bannerCode:{display:`block`,marginTop:8,padding:`8px 10px`,background:`#fff`,border:`1px solid #fecaca`,borderRadius:6,fontFamily:`monospace`,fontSize:12,color:`#7f1d1d`,whiteSpace:`pre-wrap`,wordBreak:`break-word`},statsGrid:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(140px, 1fr))`,gap:10,marginBottom:12},statCard:{padding:`12px 16px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,textAlign:`center`},statValue:{fontSize:22,fontWeight:700,color:`#333`},statLabel:{fontSize:11,color:`#888`,marginTop:2}},o={ok:`#10b981`,warn:`#f59e0b`,error:`#ef4444`};function s(e,t){if(!e)return{versions:null,versionsError:`⚠ Could not reach GitHub — showing last known versions, retry`};let n=t&&typeof t==`object`?t:{},r=Array.isArray(n)?n:Array.isArray(n.versions)?n.versions:[],i=!Array.isArray(n)&&n.sources&&typeof n.sources==`object`?n.sources:{},a=``;return i.prImages===`rate-limited`?a=`⚠ GitHub rate-limited — PR test images temporarily unavailable, retry shortly`:i.releases===`rate-limited`?a=`⚠ GitHub rate-limited — some versions temporarily unavailable, retry shortly`:(i.prImages===`error`||i.releases===`error`)&&(a=`⚠ Could not fetch some versions from GitHub, retry`),{versions:r,versionsError:a}}function c(e,t={}){let{stableCount:n=5,preCount:r=3}=t,i=e.filter(e=>typeof e.pr==`number`),a=e.filter(e=>typeof e.pr!=`number`);return{prVersions:i,stableVersions:a.filter(e=>!e.prerelease).slice(0,n),preVersions:a.filter(e=>e.prerelease).slice(0,r)}}function l(e,t=[`latest`],n={}){let{prVersions:r,stableVersions:i,preVersions:a}=c(e,n);return new Set([...t,...a.map(e=>e.tag),...i.map(e=>e.tag),...r.map(e=>e.tag)])}function u(e,t,n=[`latest`],r={}){return e?l(t,n,r).has(e)?null:e:null}function d(e){return e==null?`—`:e>=1e6?(e/1e6).toFixed(1)+`M`:e>=1e3?(e/1e3).toFixed(1)+`K`:String(e)}function f(i,a={}){let{intervalMs:o=5e3}=a,[s,c]=e(null),[l,u]=e(!0),d=t(0),f=t(a.fallback??null),p=n(async e=>{let t=++d.current,n=f.current;try{let t=await(await fetch(i,{signal:e})).json().catch(()=>null);t&&typeof t==`object`&&(n=t)}catch{}t===d.current&&(c(n),u(!1))},[i]);return r(()=>{let e=!1,t=null,n=new AbortController,r=async()=>{await p(n.signal),!e&&o>0&&(t=setTimeout(()=>void r(),o))};return r(),()=>{e=!0,n.abort(),t&&clearTimeout(t)}},[p,o]),{status:s,loading:l,refresh:()=>p()}}function p(i){let[a,o]=e([]),[c,l]=e(``),[u,d]=e(!1),f=t(0),p=n(async()=>{let e=++f.current;d(!0);try{let t=await fetch(i),n=await t.json().catch(()=>null),r=s(t.ok,n);if(e!==f.current)return;r.versions!==null&&o(r.versions),l(r.versionsError)}catch{if(e!==f.current)return;l(`⚠ Offline — showing last known versions`)}d(!1)},[i]);return r(()=>{p()},[p]),{versions:a,versionsError:c,loading:u,refresh:p}}function m({children:e,color:t}){return i.createElement(`span`,{style:{...a.hint,...t?{color:t}:{}}},e)}function h({state:e=`ok`,color:t,title:n,style:r}){return i.createElement(`div`,{style:{...a.stateIndicator,background:t??o[e],...r},title:n})}function g({icon:e,iconBackground:t,iconColor:n,title:r,meta:s,state:c=`ok`,stateTitle:l,link:u,children:d}){let f=c===`error`&&!t;return i.createElement(`div`,{style:a.card},i.createElement(`div`,{style:{...a.cardIcon,background:f?`#fef2f2`:t??`#3b82f6`,color:f?o.error:n??`#fff`}},e),i.createElement(`div`,{style:a.cardInfo},i.createElement(`div`,{style:a.cardTitle},r),s!=null&&i.createElement(`div`,{style:a.cardMeta},s)),d,u&&i.createElement(`a`,{href:u.href,target:`_blank`,rel:`noopener noreferrer`,style:a.link},u.label),i.createElement(h,{state:c,title:l}))}function _({title:t,defaultOpen:n=!1,children:r}){let[o,s]=e(n);return i.createElement(`div`,null,i.createElement(`button`,{type:`button`,"aria-expanded":o,style:{...a.sectionTitle,...a.sectionToggle},onClick:()=>s(!o)},i.createElement(`span`,{style:{...a.sectionMarker,transform:o?`rotate(90deg)`:`rotate(0deg)`}},`▶`),t),o&&i.createElement(`div`,{style:{marginBottom:16}},r))}var v={primary:a.btnPrimary,secondary:a.btnSecondary,warn:a.btnWarn,danger:a.btnDanger};function y({variant:e=`primary`,small:t=!1,busy:n=!1,busyLabel:r,disabled:o=!1,onClick:s,title:c,style:l,children:u}){let d=o||n;return i.createElement(`button`,{type:`button`,style:{...a.btn,...v[e],...t?a.btnSmall:{},...d?a.btnDisabled:{},...l},onClick:s,disabled:d,title:c},n?r??u:u)}function ee({message:e,error:t=!1,style:n}){return e?i.createElement(`div`,{style:{...a.status,color:t?o.error:o.ok,marginTop:16,...n}},e):null}var b=[{tag:`latest`,label:`latest (recommended)`}];function te({value:e,onChange:t,versions:n,floatingOptions:r=b,stableCount:s,preCount:l,loading:d=!1,error:f,onRefresh:p,disabled:h=!1,style:g}){let _={stableCount:s,preCount:l},{prVersions:v,stableVersions:ee,preVersions:te}=c(n,_),x=u(e,n,r.map(e=>e.tag),_);return i.createElement(i.Fragment,null,i.createElement(`select`,{style:{...a.select,...g},value:e,onChange:e=>t(e.target.value),disabled:h},r.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.label??e.tag)),te.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,` (pre-release)`)),ee.map((e,t)=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,t===0?` (current stable)`:``)),v.length>0&&i.createElement(`optgroup`,{label:`PR test images`},v.map(e=>i.createElement(`option`,{key:e.tag,value:e.tag},e.tag,e.title?` — ${e.title}`:``))),x&&i.createElement(`option`,{value:x},x,` (running)`)),d&&i.createElement(m,null,`loading releases...`),p&&i.createElement(y,{small:!0,style:{padding:`4px 10px`,fontSize:11},onClick:p,title:`Refresh available versions`},`↻`),f&&i.createElement(m,{color:o.error},f))}var x={...a,warnBannerCode:{display:`block`,marginTop:8,padding:`8px 10px`,background:`#fff`,border:`1px solid #fecaca`,borderRadius:6,fontFamily:`monospace`,fontSize:12,color:`#7f1d1d`,whiteSpace:`pre-wrap`,wordBreak:`break-word`},fieldHelp:{fontSize:12,color:`#666`,marginTop:6,lineHeight:1.5},migrationItem:{display:`flex`,alignItems:`center`,gap:12,padding:`12px 16px`,background:`#f8f9fa`,border:`1px solid #e0e0e0`,borderRadius:10,marginBottom:8},migrationActions:{display:`flex`,gap:8,alignItems:`center`}},S=e=>typeof e==`object`&&!!e;function ne(e){let t=S(e)?e.sources:void 0;return Array.isArray(t)?t.filter(e=>S(e)&&typeof e.type==`string`&&typeof e.url==`string`&&typeof e.status==`string`&&(e.version===void 0||typeof e.version==`string`)):[]}function C(e){return e instanceof Error?e.message:String(e)}function w(e,t){return e??t}var T=[`none`,`lz4`,`zstd`],re={padding:`4px 12px`,fontSize:12};function ie(e){return T.includes(e)?e:`lz4`}function E({configuration:a,save:o}){let s=a||{},[c,l]=e(s.questdbHost||`127.0.0.1`),[u,m]=e(s.questdbIlpPort||9009),[h,v]=e(s.questdbHttpPort||9e3),[b,S]=e(s.questdbPgPort||8812),[T,E]=e(s.questdbVersion||`latest`),[D,ae]=e(s.managedContainer!==!1),[oe,se]=e(s.recordSelf!==!1),[ce,le]=e(s.recordOthers!==!1),[O,ue]=e(s.restoreOnStart===!0),[de,fe]=e(s.enableConsole!==!1),[pe,me]=e((s.restoreMaxAgeMinutes??0)>0?s.restoreMaxAgeMinutes:9),[he,ge]=e(s.defaultSamplingRate??2e3),[k,_e]=e(String(s.ilpFlushIntervalMs??5e3)),[ve,ye]=e(s.retentionDays||0),[A,be]=e(s.pathFilter?.mode===`include`?`include`:`exclude`),[j,xe]=e((Array.isArray(s.pathFilter?.paths)?s.pathFilter.paths:[]).join(`
2
- `)),[M,Se]=e(s.compression||`lz4`),[Ce,we]=e(s.compressionLevel||3),[Te,Ee]=e(s.networkName||`sk-network`),[N,De]=e(s.exposeToContainers||!1),{versions:Oe,versionsError:ke,loading:Ae,refresh:je}=p(`/plugins/signalk-questdb/api/versions`),{status:P,loading:Me,refresh:F}=f(`/plugins/signalk-questdb/api/status`,{fallback:{status:`not_running`},intervalMs:5e3}),[I,Ne]=e(null),[Pe,Fe]=e(!1),[L,Ie]=e(``),[Le,R]=e(``),[Re,z]=e(!1),[B,ze]=e(null),[Be,Ve]=e(!1),[He,Ue]=e(!1),[We,Ge]=e(!1),[Ke,qe]=e(!1),[Je,V]=e(``),[H,Ye]=e(null),[U,W]=e(!1),G=t(0),[Xe,Ze]=e(!1),K=n(async e=>{let t=++G.current;try{let n=await fetch(`/plugins/signalk-questdb/api/wal-diagnosis`,{signal:e});if(t!==G.current)return;if(n.ok){let e=await n.json();if(t!==G.current)return;Ye(e),W(!1)}else W(!0)}catch{t===G.current&&W(!0)}},[]),Qe=!!(P&&P.status===`running`&&(P.suspendedTables||[]).length>0);r(()=>{if(!Qe){Ye(null),W(!1);return}let e=!1,t=null,n=new AbortController,r=async()=>{await K(n.signal),e||(t=setTimeout(r,15e3))};return r(),()=>{e=!0,n.abort(),t&&clearTimeout(t)}},[Qe,K]);let $e=async(e,t)=>{let n=t.tailSkip?`
3
-
4
- WARNING: this is the newest pending segment — skipping it drops the ENTIRE pending backlog.`:``;if(window.confirm(`Skip the unreadable WAL segment on ${e}?\n\nThis permanently loses ${d(t.skippedTxns)} transaction(s) recorded between ${t.skipWindowStart} and ${t.skipWindowEnd}. Everything after the skipped segment is replayed without loss.`+n)){Ze(!0),V(``);try{let n=await fetch(`/plugins/signalk-questdb/api/resume-wal/skip`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({table:e,confirmPlan:t})}),r=await n.json().catch(()=>({error:n.statusText}));n.ok?V(r.message??``):V(`Skip failed: ${w(r.error,`unknown error`)}`),F(),K()}catch(e){V(`Skip failed: ${C(e)}`)}Ze(!1)}},et=async()=>{Ve(!0);try{let e=await fetch(`/plugins/signalk-questdb/api/update/check`);e.ok&&ze(await e.json())}catch{}Ve(!1)},tt=async()=>{Ue(!0),R(`Pulling new image and restarting...`),z(!1);try{let e=await fetch(`/plugins/signalk-questdb/api/update/apply`,{method:`POST`});if(e.ok){let t=await e.json();R(t.message??``),ze(null),t.newVersion&&E(t.newVersion),F()}else{let t=await e.json().catch(()=>({error:e.statusText}));R(`Update failed: ${w(t.error,`unknown error`)}`),z(!0)}}catch(e){R(`Update failed: ${C(e)}`),z(!0)}Ue(!1)},nt=async()=>{if(window.confirm(`Remove the QuestDB container and DELETE ALL recorded data? This cannot be undone.`)){Ge(!0),R(`Removing QuestDB container and data...`),z(!1);try{let e=await fetch(`/plugins/signalk-questdb/api/purge-data`,{method:`POST`}),t=await e.json().catch(()=>({error:e.statusText}));e.ok?(R(t.message??``),F()):(R(`Remove failed: ${w(t.error,`unknown error`)}`),z(!0))}catch(e){R(`Remove failed: ${C(e)}`),z(!0)}Ge(!1)}},rt=async()=>{qe(!0),V(``);try{let e=await fetch(`/plugins/signalk-questdb/api/resume-wal`,{method:`POST`}),t=await e.json().catch(()=>({error:e.statusText}));if(e.ok){let e=(t.results||[]).filter(e=>!e.ok);V(e.length===0?`${w(t.message,`Resume requested`)}. Recording resumes as the backlog drains — the banner clears once tables catch up.`:`${w(t.message,`Resume requested`)}. `+e.map(e=>`${e.table}: ${e.error}`).join(` · `)),F(),K()}else V(`Resume failed: ${w(t.error,`unknown error`)}`)}catch(e){V(`Resume failed: ${C(e)}`)}qe(!1)},it=async()=>{Fe(!0),R(``);try{let e=L?`?url=${encodeURIComponent(L)}`:``,t=await fetch(`/plugins/signalk-questdb/api/migration/detect${e}`);if(t.ok){let e=ne(await t.json().catch(()=>null));Ne(e),e.length===0&&(R(L?`No InfluxDB found at ${L}.`:`No InfluxDB instances detected on localhost:8086.`),z(!1))}}catch(e){R(`Detection failed: `+C(e)),z(!0)}Fe(!1)},[q,at]=e(``),[ot,st]=e(``),[J,ct]=e(`parquet`),[lt,ut]=e(!1),dt=()=>{let e=Number(k);if(k===``||!Number.isFinite(e)||e<500||e>3e5){R(`Write batch interval must be 500–300000 ms.`),z(!0);return}o({...s,questdbHost:c,questdbIlpPort:u,questdbHttpPort:h,questdbPgPort:b,questdbVersion:T,managedContainer:D,defaultSamplingRate:he,ilpFlushIntervalMs:e,recordSelf:oe,recordOthers:ce,restoreOnStart:O,enableConsole:de,restoreMaxAgeMinutes:pe,retentionDays:ve,compression:M,compressionLevel:Ce,networkName:Te,exposeToContainers:N,pathFilter:{mode:A,paths:j.split(`
5
- `).map(e=>e.trim()).filter(Boolean)},samplingRates:s.samplingRates||{}}),R(`Saved! Plugin will restart with new configuration.`),z(!1)},ft=async()=>{if(!q||!ot){R(`Set both from and to dates for export.`),z(!0);return}ut(!0),R(`Exporting ${J.toUpperCase()}...`),z(!1);try{let e=`/plugins/signalk-questdb/api/export?from=${encodeURIComponent(q)}&to=${encodeURIComponent(ot)}&format=${J}`,t=await fetch(e);if(!t.ok){let e=await t.json().catch(()=>({error:t.statusText}));R(`Export failed: ${w(e.error,`unknown error`)}`),z(!0),ut(!1);return}let n=await t.blob(),r=J===`parquet`?`parquet`:`csv`,i=document.createElement(`a`);i.href=URL.createObjectURL(n),i.download=`signalk-export-${q.slice(0,10)}.${r}`,i.click(),URL.revokeObjectURL(i.href),R(`Exported ${(n.size/1024/1024).toFixed(1)} MB`)}catch(e){R(`Export failed: ${C(e)}`),z(!0)}ut(!1)},Y=P&&P.status===`running`,X=Y&&P.suspendedTables||[],Z=X.length>0,pt=Y&&P.schemaMismatch||!1,Q=Y&&P.ulimitClamp||null,$=P?.hostMaxMapCount?.tooLow&&P.hostMaxMapCount||null;return i.createElement(`div`,{style:x.root},i.createElement(`div`,{style:x.sectionTitle},`QuestDB Status`),$&&i.createElement(`div`,{style:x.infoBanner},i.createElement(`div`,{style:x.warnBannerTitle},`Host vm.max_map_count is low — `,d($.current),` `,`(QuestDB recommends `,d($.recommended),`)`),`QuestDB memory-maps every partition and WAL segment it touches. As the database grows, this kernel limit can run out — mmap then fails with out-of-memory errors even though RAM is free, which shows up as slow or failing history queries, can suspend recording, and can take QuestDB down entirely. Run this in a shell on the host machine — not inside the QuestDB container, which can neither change the kernel-global limit nor has sudo (takes effect immediately, no restart needed):`,i.createElement(`code`,{style:x.warnBannerCode},`echo 'vm.max_map_count=${$.recommended}' | sudo tee /etc/sysctl.d/99-questdb.conf && sudo sysctl --system`)),Me?i.createElement(`div`,{style:x.empty},`Checking QuestDB...`):Y?i.createElement(i.Fragment,null,Z&&i.createElement(`div`,{style:x.warnBanner},i.createElement(`div`,{style:x.warnBannerTitle},`QuestDB WAL suspended — recording stalled`),`Rows are arriving but no longer commit, so the counts below have stopped advancing. This follows an error while QuestDB applied the write-ahead log — see the reason reported per table below. Resuming replays every pending transaction, so no data is lost.`,i.createElement(`code`,{style:x.warnBannerCode},X.map(e=>{let t=String(e.errorMessage||e.errorTag||`reason not reported`).replace(/[\r\n]+/g,` `),n=(H?.tables||[]).find(t=>t.name===e.name),r=n?.suspendedSince?` — frozen since ${n.suspendedSince}`:``;return`${e.name}: ${d(e.txnLag)} txns behind — ${t}${r}`}).join(`
6
- `)),(H?.tables||[]).filter(e=>e.applyError).map(e=>i.createElement(`div`,{key:e.name,style:{marginTop:8,fontSize:12}},`QuestDB's own log reports the apply failure on`,` `,i.createElement(`code`,null,e.name),` as:`,i.createElement(`code`,{style:x.warnBannerCode},e.applyError))),i.createElement(`div`,{style:{marginTop:10}},i.createElement(y,{variant:`primary`,busy:Ke,busyLabel:`Resuming...`,disabled:Xe,onClick:rt},`Resume recording`)),X.filter(e=>e.autoResume===`failed`).map(e=>{let t=(H?.tables||[]).find(t=>t.name===e.name);if(t?.partitionOpenFailure)return i.createElement(`div`,{key:e.name,style:{marginTop:12}},i.createElement(`div`,{style:x.warnBannerTitle},e.name,`: table data damaged — automatic repair not possible`),`QuestDB fails while opening this table's stored data, before it reaches any pending transaction. That means the commit record on disk describes rows whose data never made it to storage — the signature of a power loss during a write. Skipping transactions cannot fix this (the failure happens before them) and would discard the `,d(e.txnLag),` pending transactions for nothing, so no repair button is offered. Recovering this table means repairing its commit record by hand; please open an issue with the error above. Recording continues into the other tables, and “Resume recording” will re-suspend this one within milliseconds — it is safe to press, but it cannot repair this damage.`);let n=t?.skipPlan;return n?i.createElement(`div`,{key:e.name,style:{marginTop:12}},i.createElement(`div`,{style:x.warnBannerTitle},e.name,`: automatic resume failed — WAL segment unreadable`),`A lossless resume was attempted and the table re-suspended at the same transaction: the write-ahead-log segment at the stall point cannot be read back (typically corrupted by an unclean shutdown mid-write). Replaying can never get past it. The only repair is to skip the unreadable segment, losing`,` `,i.createElement(`b`,null,d(n.skippedTxns),` transaction(s)`),` `,`recorded between `,i.createElement(`b`,null,n.skipWindowStart),` and`,` `,i.createElement(`b`,null,n.skipWindowEnd),n.tailSkip?` — and this is the newest pending segment, so skipping it drops the ENTIRE pending backlog`:` — everything after the skipped segment (${d(Math.max(0,e.txnLag-n.skippedTxns))} txns) is replayed without loss`,`.`,i.createElement(`div`,{style:{marginTop:8}},i.createElement(y,{variant:`danger`,busy:Xe,busyLabel:`Skipping...`,disabled:Ke||U,onClick:()=>$e(e.name,n)},`Skip unreadable segment (loses data)`),U&&i.createElement(`div`,{style:{marginTop:6,fontSize:12}},`The diagnosis could not be refreshed — the numbers above may be stale. The skip re-enables once a refresh succeeds.`))):null}),i.createElement(`div`,{style:{marginTop:8,fontSize:12}},`Manual fallback in the QuestDB SQL console (`,i.createElement(`code`,null,`:9000`),`), one statement at a time — avoid running it from several tabs, the console retries a busy statement forever:`,i.createElement(`code`,{style:x.warnBannerCode},X.map(e=>{let t=`"${String(e.name).replace(/"/g,`""`)}"`,n=(H?.tables||[]).find(t=>t.name===e.name),r=[`ALTER TABLE ${t} RESUME WAL;`];return e.autoResume===`failed`&&n?.skipPlan&&!U&&r.push(`-- if the resume re-suspends: skip the unreadable segment (loses ${d(n.skipPlan.skippedTxns)} txns)`,`ALTER TABLE ${t} RESUME WAL FROM TXN ${n.skipPlan.skipToTxn};`),r.join(`
7
- `)}).join(`
8
- `)))),Je&&i.createElement(`div`,{style:x.infoBanner},Je),pt&&i.createElement(`div`,{style:x.warnBanner},i.createElement(`div`,{style:x.warnBannerTitle},`QuestDB table schema mismatch — data not readable`),`A QuestDB table was re-created by ILP ingestion with the wrong timestamp column, so rows are being stored but reads filtering on time (history, Grafana, and the counts above) return nothing. The plugin rebuilds the affected table with the correct schema automatically within a minute; if this persists, restart the plugin. (The few rows written into the wrong-schema table are lost — they were unreadable anyway.)`),Q&&i.createElement(`div`,{style:x.infoBanner},i.createElement(`div`,{style:x.warnBannerTitle},`QuestDB open-files limit capped by the host`),`QuestDB requested a `,i.createElement(`code`,null,Q.ulimit),` limit of`,` `,d(Q.requested),`, but this host only allows`,` `,d(Q.granted),`, so it was capped. QuestDB is running on the lower limit. To grant the full value, raise the host limit for the user running the container runtime — under rootless Podman that means a systemd `,i.createElement(`code`,null,`user@.service`),` `,i.createElement(`code`,null,`LimitNOFILE`),` drop-in (editing`,` `,i.createElement(`code`,null,`/etc/security/limits.conf`),` alone is usually not enough) — then restart the Signal K server so the plugin can re-create the QuestDB container with the raised limit (signalk-container 1.25.3+; on older versions remove the container once with `,i.createElement(`code`,null,`podman rm -f sk-signalk-questdb`),` instead). This warning clears itself once the container is running with the full value.`,` `,i.createElement(`a`,{href:`https://github.com/dirkwa/signalk-container#raising-the-open-files-limit-nofile`,target:`_blank`,rel:`noreferrer`,style:{color:`#92400e`,textDecoration:`underline`}},`Step-by-step instructions`),`.`),i.createElement(g,{icon:`Q`,iconBackground:`#7c3aed`,iconColor:`#fff`,title:`QuestDB`,meta:i.createElement(i.Fragment,null,P?.endpoint||`${c}:${h}`,` `,`· `,Z?`WAL suspended`:`Recording`),state:Z?`error`:`ok`,stateTitle:Z?`WAL suspended`:`Running`}),i.createElement(`div`,{style:x.statsGrid},i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},d(P.totalRows)),i.createElement(`div`,{style:x.statLabel},`Total Rows`)),i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},d(P.activePathsToday)),i.createElement(`div`,{style:x.statLabel},`Active Paths Today`)),P.restore&&i.createElement(`div`,{style:x.statCard},i.createElement(`div`,{style:x.statValue},P.restore.failed?`—`:d(P.restore.contexts)),i.createElement(`div`,{style:x.statLabel},P.restore.failed?`Restore failed`:`Vessels Restored`))),i.createElement(`div`,{style:{display:`flex`,alignItems:`center`,gap:10,marginBottom:12}},B&&B.updateAvailable?i.createElement(i.Fragment,null,i.createElement(`span`,{style:{fontSize:13}},`v`,B.currentVersion,` →`,` `,i.createElement(`strong`,null,`v`,B.latestVersion),` available`),i.createElement(y,{variant:`primary`,busy:He,busyLabel:`Updating...`,onClick:tt,style:re},`Update QuestDB`)):B&&!B.updateAvailable?i.createElement(`span`,{style:{fontSize:12,color:`#888`}},`v`,B.currentVersion,` (up to date)`):i.createElement(y,{variant:`secondary`,busy:Be,busyLabel:`Checking...`,onClick:et,style:re},`Check for updates`))):i.createElement(g,{icon:`Q`,title:`QuestDB`,meta:i.createElement(i.Fragment,null,P?.status===`unhealthy`?`Not responding`:`Not running`,D?` — enable plugin to start container`:``),state:`error`}),i.createElement(`div`,{style:x.sectionTitle},`Image Version`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB version`),i.createElement(te,{value:T,onChange:E,versions:Oe,loading:Ae,onRefresh:()=>void je(),error:ke,stableCount:3,preCount:2})),i.createElement(`div`,{style:x.sectionTitle},`Connection`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Managed container`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:D,onChange:e=>ae(e.target.checked)}),i.createElement(`span`,{style:x.hint},D?`signalk-container manages QuestDB`:`Connect to external QuestDB`)),!D&&i.createElement(i.Fragment,null,i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB host`),i.createElement(`input`,{style:x.input,value:c,onChange:e=>l(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`HTTP port (queries)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:h,onChange:e=>v(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ILP port (writes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:u,onChange:e=>m(Number(e.target.value))}))),D&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Bind to 0.0.0.0`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:N,onChange:e=>De(e.target.checked)}),i.createElement(`span`,{style:{...x.hint,color:N?`#ef4444`:void 0}},N?`Caution! This exposes your data to the network`:`Signal K reaches QuestDB automatically — only enable to reach it from another machine or a separate-Docker Grafana`)),D&&N&&i.createElement(i.Fragment,null,i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`HTTP port (queries)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:h,onChange:e=>v(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ILP port (writes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:u,onChange:e=>m(Number(e.target.value))})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`PostgreSQL wire port`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:b,onChange:e=>S(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`for Grafana`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Container network`),i.createElement(`input`,{style:x.input,value:Te,onChange:e=>Ee(e.target.value)}),i.createElement(`span`,{style:x.hint},`shared with signalk-grafana`))),i.createElement(`div`,{style:x.sectionTitle},`Recording`),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Default sampling rate (ms)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:he,onChange:e=>ge(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`1000 = max 1 write/sec per path (0 = every update)`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Write batch interval (ms)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:500,max:3e5,"aria-label":`Write batch interval in milliseconds`,value:k,onChange:e=>_e(e.target.value)}),i.createElement(`span`,{style:x.hint},`one QuestDB transaction per table per interval; longer = bigger batches, but up to this many ms lost on a hard crash (default 5000)`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Record own vessel`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:oe,onChange:e=>se(e.target.checked)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Record AIS targets`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,checked:ce,onChange:e=>le(e.target.checked)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Restore vessels on startup`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,"aria-label":`Restore vessels on startup`,checked:O,onChange:e=>ue(e.target.checked)}),i.createElement(`span`,{style:x.hint},`replay each vessel's last recorded position after a restart, so AIS targets appear at once instead of only when they next transmit`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`QuestDB console webapp`),i.createElement(`input`,{type:`checkbox`,style:x.checkbox,"aria-label":`QuestDB console webapp`,checked:de,onChange:e=>fe(e.target.checked)}),i.createElement(`span`,{style:x.hint},`serve QuestDB's own console inside the Signal K admin UI (admin only). It is a full SQL client — unlike the read-only query endpoint it can modify and delete recorded data`)),O&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Restore max age (minutes)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:1,"aria-label":`Restore max age (minutes)`,value:pe,onChange:e=>{let t=Number(e.target.value);Number.isFinite(t)&&t>=1&&me(t)}}),i.createElement(`span`,{style:x.hint},`only replay values this recent (default 9, matching Freeboard's AIS expiry); higher puts staler positions on the chart`)),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Retention (days)`),i.createElement(`input`,{style:x.inputSmall,type:`number`,value:ve,onChange:e=>ye(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`0 = keep forever`)),i.createElement(_,{title:`Path filtering`,defaultOpen:j.trim()!==``},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Filter mode`),i.createElement(`select`,{style:x.select,value:A,onChange:e=>be(e.target.value===`include`?`include`:`exclude`)},i.createElement(`option`,{value:`exclude`},`Exclude matching paths`),i.createElement(`option`,{value:`include`},`Include only matching paths`))),i.createElement(`div`,{style:{marginBottom:10}},i.createElement(`div`,{style:{...x.label,width:`auto`,marginBottom:6}},`Path patterns (one per line, glob supported) — optional`),i.createElement(`textarea`,{style:x.textarea,value:j,onChange:e=>xe(e.target.value),placeholder:`notifications.*
9
- environment.wind.*`}),i.createElement(`div`,{style:x.fieldHelp},`Empty = record everything (the default). Nothing is filtered out unless you list a pattern here.`),i.createElement(`div`,{style:{...x.hint,marginLeft:0}},A===`exclude`?`These paths are NOT recorded; everything else is.`:`ONLY these paths are recorded; everything else is dropped.`))),i.createElement(_,{title:`Compression (on-disk)`},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Compression codec`),i.createElement(`select`,{style:x.select,value:M,onChange:e=>Se(ie(e.target.value))},i.createElement(`option`,{value:`none`},`None`),i.createElement(`option`,{value:`lz4`},`LZ4 (fast)`),i.createElement(`option`,{value:`zstd`},`ZSTD (smaller)`)),i.createElement(`span`,{style:x.hint},`applies to new data after save`)),M===`zstd`&&i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`ZSTD level`),i.createElement(`input`,{style:x.inputSmall,type:`number`,min:`1`,max:`22`,value:Ce,onChange:e=>we(Number(e.target.value))}),i.createElement(`span`,{style:x.hint},`1 (fast) to 22 (smallest)`))),i.createElement(_,{title:`InfluxDB Migration`},i.createElement(`div`,{style:{display:`flex`,gap:10,alignItems:`center`,marginBottom:10}},i.createElement(y,{variant:`primary`,busy:Pe,busyLabel:`Detecting...`,onClick:it},`Detect InfluxDB`),i.createElement(`span`,{style:x.hint},`Checks localhost:8086 for InfluxDB 1.x and 2.x`)),I&&I.length>0&&i.createElement(`div`,null,I.map((e,t)=>i.createElement(`div`,{key:t,style:x.migrationItem},i.createElement(`div`,{style:{...x.cardIcon,width:36,height:36,fontSize:16,background:e.type===`influxdb2`?`#020a47`:`#22adf6`,color:`#fff`}},e.type===`influxdb2`?`2`:`1`),i.createElement(`div`,{style:x.cardInfo},i.createElement(`div`,{style:x.cardTitle},`InfluxDB `,e.type===`influxdb2`?`2.x`:`1.x`,i.createElement(`span`,{style:{...x.tag,...x.tagLatest}},e.status)),i.createElement(`div`,{style:x.cardMeta},e.url,` · v`,e.version))))),i.createElement(`div`,{style:{...x.fieldRow,marginTop:10}},i.createElement(`span`,{style:x.label},`Manual InfluxDB URL`),i.createElement(`input`,{style:x.input,placeholder:`http://192.168.1.100:8086`,value:L,onChange:e=>Ie(e.target.value)}),i.createElement(`span`,{style:x.hint},`for remote instances`)),I&&I.length===0&&!Pe&&i.createElement(`div`,{style:{...x.empty,padding:`16px`,textAlign:`left`}},`No InfluxDB found on localhost. Use manual URL above for remote instances.`)),i.createElement(_,{title:`Data Export`},i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`From`),i.createElement(`input`,{style:x.input,type:`datetime-local`,value:q,onChange:e=>at(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`To`),i.createElement(`input`,{style:x.input,type:`datetime-local`,value:ot,onChange:e=>st(e.target.value)})),i.createElement(`div`,{style:x.fieldRow},i.createElement(`span`,{style:x.label},`Format`),i.createElement(`select`,{style:x.select,value:J,onChange:e=>ct(e.target.value)},i.createElement(`option`,{value:`parquet`},`Parquet`),i.createElement(`option`,{value:`csv`},`CSV`))),i.createElement(y,{variant:`primary`,busy:lt,busyLabel:`Exporting...`,onClick:ft},`Export Data`)),s.managedContainer!==!1&&i.createElement(_,{title:`Danger zone`},i.createElement(`div`,{style:{fontSize:13,color:`#555`,marginBottom:10}},`Remove the QuestDB container and permanently delete all recorded data. Use this to fully reset QuestDB — Signal K's plugin-uninstall cannot delete this data on rootless Podman. This cannot be undone.`),i.createElement(y,{variant:`danger`,busy:We,busyLabel:`Removing...`,onClick:nt},`Remove container & all data`)),i.createElement(ee,{message:Le,error:Re,style:{marginTop:16}}),i.createElement(`div`,{style:{marginTop:24}},i.createElement(y,{onClick:dt},`Save Configuration`)))}export{E as default};