@tapflowio/relay 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/RelayServer.d.ts +37 -1
  2. package/dist/RelayServer.d.ts.map +1 -1
  3. package/dist/RelayServer.js +121 -7
  4. package/dist/RelayServer.js.map +1 -1
  5. package/dist/SessionManager.d.ts.map +1 -1
  6. package/dist/SessionManager.js +4 -0
  7. package/dist/SessionManager.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/cert/index.d.ts +1 -1
  13. package/dist/lib/cert/index.d.ts.map +1 -1
  14. package/dist/lib/cert/index.js +1 -1
  15. package/dist/lib/cert/index.js.map +1 -1
  16. package/dist/lib/cert/parseCert.d.ts +4 -0
  17. package/dist/lib/cert/parseCert.d.ts.map +1 -1
  18. package/dist/lib/cert/parseCert.js +68 -0
  19. package/dist/lib/cert/parseCert.js.map +1 -1
  20. package/dist/lib/trailingRequester.d.ts +23 -0
  21. package/dist/lib/trailingRequester.d.ts.map +1 -0
  22. package/dist/lib/trailingRequester.js +56 -0
  23. package/dist/lib/trailingRequester.js.map +1 -0
  24. package/dist/server.js +4 -2
  25. package/dist/server.js.map +1 -1
  26. package/package.json +3 -3
  27. package/public/assets/{AppCenter-DyP0aqfF.js → AppCenter-Dg4dscW-.js} +5 -5
  28. package/public/assets/AppCenter-Dg4dscW-.js.br +0 -0
  29. package/public/assets/{Default-D7ScPE30.js → Default-Dxi8aZ1t.js} +1 -1
  30. package/public/assets/Default-Dxi8aZ1t.js.br +0 -0
  31. package/public/assets/{Invite-UmhV5rAf.js → Invite-0EwoClX6.js} +1 -1
  32. package/public/assets/Invite-0EwoClX6.js.br +0 -0
  33. package/public/assets/{MacResources-MS4E00w3.js → MacResources-Dy1M3EqK.js} +1 -1
  34. package/public/assets/MacResources-Dy1M3EqK.js.br +0 -0
  35. package/public/assets/QASession-DqMj8JL1.js +140 -0
  36. package/public/assets/QASession-DqMj8JL1.js.br +0 -0
  37. package/public/assets/{ResetPassword-CAlB6CfP.js → ResetPassword-CXU2bRry.js} +1 -1
  38. package/public/assets/ResetPassword-CXU2bRry.js.br +0 -0
  39. package/public/assets/{Setup-CPm2-hPJ.js → Setup-XXChRxeL.js} +1 -1
  40. package/public/assets/Setup-XXChRxeL.js.br +0 -0
  41. package/public/assets/{Team-GEIzrM1D.js → Team-D0bXpmEY.js} +2 -2
  42. package/public/assets/Team-D0bXpmEY.js.br +0 -0
  43. package/public/assets/{Tokens-DSeBz_CJ.js → Tokens-D0YNHS5e.js} +1 -1
  44. package/public/assets/Tokens-D0YNHS5e.js.br +0 -0
  45. package/public/assets/{alert-dialog-BsXI9SVV.js → alert-dialog-CgatMXjB.js} +1 -1
  46. package/public/assets/alert-dialog-CgatMXjB.js.br +0 -0
  47. package/public/assets/{badge-BkdYQFsh.js → badge-B6Nf3A0Y.js} +1 -1
  48. package/public/assets/badge-B6Nf3A0Y.js.br +0 -0
  49. package/public/assets/{build-format-CXuQt1X2.js → build-format-BFC8gLoh.js} +3 -3
  50. package/public/assets/build-format-BFC8gLoh.js.br +0 -0
  51. package/public/assets/{dialog-DuXZpbiF.js → dialog-DK9a3b4z.js} +3 -3
  52. package/public/assets/dialog-DK9a3b4z.js.br +0 -0
  53. package/public/assets/{index-bitr6DIC.js → index-9vdYIm7s.js} +66 -71
  54. package/public/assets/index-9vdYIm7s.js.br +0 -0
  55. package/public/assets/index-ClHUQm-F.css +1 -0
  56. package/public/assets/index-ClHUQm-F.css.br +0 -0
  57. package/public/assets/{pencil-iRR275s8.js → pencil-BeLNLEKe.js} +2 -2
  58. package/public/assets/pencil-BeLNLEKe.js.br +0 -0
  59. package/public/assets/{table-CHmhGpHG.js → table-DW57-o1p.js} +1 -1
  60. package/public/assets/table-DW57-o1p.js.br +0 -0
  61. package/public/assets/{tabs-BnbeuAOe.js → tabs-Xlttuqxh.js} +1 -1
  62. package/public/assets/tabs-Xlttuqxh.js.br +0 -0
  63. package/public/assets/{trash-2-QI162w2K.js → trash-2-CGxISX8x.js} +3 -3
  64. package/public/assets/trash-2-CGxISX8x.js.br +0 -0
  65. package/public/index.html +2 -2
  66. package/public/index.html.br +0 -0
  67. package/public/assets/AppCenter-DyP0aqfF.js.br +0 -0
  68. package/public/assets/Default-D7ScPE30.js.br +0 -0
  69. package/public/assets/Invite-UmhV5rAf.js.br +0 -0
  70. package/public/assets/MacResources-MS4E00w3.js.br +0 -0
  71. package/public/assets/QASession-CjgJHDZ3.js +0 -125
  72. package/public/assets/QASession-CjgJHDZ3.js.br +0 -0
  73. package/public/assets/ResetPassword-CAlB6CfP.js.br +0 -0
  74. package/public/assets/Setup-CPm2-hPJ.js.br +0 -0
  75. package/public/assets/Team-GEIzrM1D.js.br +0 -0
  76. package/public/assets/Tokens-DSeBz_CJ.js.br +0 -0
  77. package/public/assets/alert-dialog-BsXI9SVV.js.br +0 -0
  78. package/public/assets/badge-BkdYQFsh.js.br +0 -0
  79. package/public/assets/build-format-CXuQt1X2.js.br +0 -0
  80. package/public/assets/dialog-DuXZpbiF.js.br +0 -0
  81. package/public/assets/index-Bk2hqaHZ.css +0 -1
  82. package/public/assets/index-Bk2hqaHZ.css.br +0 -0
  83. package/public/assets/index-bitr6DIC.js.br +0 -0
  84. package/public/assets/pencil-iRR275s8.js.br +0 -0
  85. package/public/assets/table-CHmhGpHG.js.br +0 -0
  86. package/public/assets/tabs-BnbeuAOe.js.br +0 -0
  87. package/public/assets/trash-2-QI162w2K.js.br +0 -0
@@ -0,0 +1,56 @@
1
+ /** The production scheduler. `unref` keeps a pending request from keeping the relay process alive. */
2
+ export const systemTimerScheduler = {
3
+ now: () => Date.now(),
4
+ schedule(callback, delayMs) {
5
+ const timer = setTimeout(callback, delayMs);
6
+ timer.unref();
7
+ return timer;
8
+ },
9
+ cancel(timer) { clearTimeout(timer); },
10
+ };
11
+ /**
12
+ * Calls `fire` immediately at the leading edge, then coalesces calls inside `windowMs` onto one
13
+ * trailing edge. The scheduler is injected so the timing policy can be tested without faking the
14
+ * relay's WebSocket or heartbeat timers.
15
+ */
16
+ export function createTrailingRequester(options) {
17
+ const { scheduler, windowMs, fire } = options;
18
+ let lastAt = null;
19
+ let pending = null;
20
+ const fireNow = () => {
21
+ lastAt = scheduler.now();
22
+ fire();
23
+ };
24
+ const requester = (() => {
25
+ if (lastAt === null) {
26
+ fireNow();
27
+ return;
28
+ }
29
+ const wait = windowMs - (scheduler.now() - lastAt);
30
+ if (wait <= 0) {
31
+ // A timer that became due while another callback was running must not fire after this leading
32
+ // edge as well. Node normally runs due timers first, but that ordering is not a second budget.
33
+ if (pending !== null) {
34
+ scheduler.cancel(pending);
35
+ pending = null;
36
+ }
37
+ fireNow();
38
+ return;
39
+ }
40
+ // Already coalesced. A second timer here would be the double send the window is for.
41
+ if (pending !== null)
42
+ return;
43
+ pending = scheduler.schedule(() => {
44
+ pending = null;
45
+ fireNow();
46
+ }, wait);
47
+ });
48
+ requester.dispose = () => {
49
+ if (pending !== null) {
50
+ scheduler.cancel(pending);
51
+ pending = null;
52
+ }
53
+ };
54
+ return requester;
55
+ }
56
+ //# sourceMappingURL=trailingRequester.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trailingRequester.js","sourceRoot":"","sources":["../../src/lib/trailingRequester.ts"],"names":[],"mappings":"AAUA,sGAAsG;AACtG,MAAM,CAAC,MAAM,oBAAoB,GAAkD;IACjF,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IACrB,QAAQ,CAAC,QAAQ,EAAE,OAAO;QACxB,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC3C,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,OAAO,KAAK,CAAA;IACd,CAAC;IACD,MAAM,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC;CACtC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAQ,OAI9C;IACC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IAC7C,IAAI,MAAM,GAAkB,IAAI,CAAA;IAChC,IAAI,OAAO,GAAiB,IAAI,CAAA;IAEhC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,CAAA;QACxB,IAAI,EAAE,CAAA;IACR,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE;QACtB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,EAAE,CAAA;YACT,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAA;QAClD,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YACd,8FAA8F;YAC9F,+FAA+F;YAC/F,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;gBACzB,OAAO,GAAG,IAAI,CAAA;YAChB,CAAC;YACD,OAAO,EAAE,CAAA;YACT,OAAM;QACR,CAAC;QAED,qFAAqF;QACrF,IAAI,OAAO,KAAK,IAAI;YAAE,OAAM;QAC5B,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE;YAChC,OAAO,GAAG,IAAI,CAAA;YACd,OAAO,EAAE,CAAA;QACX,CAAC,EAAE,IAAI,CAAC,CAAA;IACV,CAAC,CAAsB,CAAA;IAEvB,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;QACvB,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACzB,OAAO,GAAG,IAAI,CAAA;QAChB,CAAC;IACH,CAAC,CAAA;IAED,OAAO,SAAS,CAAA;AAClB,CAAC"}
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { initDb } from './db.js';
3
3
  import { RelayServer } from './RelayServer.js';
4
4
  import { config, loadedEnvPath } from './lib/config.js';
5
5
  import { buildCorsOrigins, proxyWithoutPublicUrlWarning } from './lib/proxyConfig.js';
6
- import { createCertProvider } from './lib/cert/index.js';
6
+ import { createCertProvider, resolveRelayDisplayHost } from './lib/cert/index.js';
7
7
  import { startTlsBackgroundTasks } from './lib/tlsTasks.js';
8
8
  import { createLogger } from '@tapflowio/agent-core';
9
9
  const logger = createLogger('relay');
@@ -21,10 +21,12 @@ if (proxyWarning)
21
21
  async function main() {
22
22
  let tls;
23
23
  let provider = null;
24
+ let displayHost = 'localhost';
24
25
  if (config.tls) {
25
26
  provider = createCertProvider(config.tls, { dataDir });
26
27
  const material = await provider.ensureCert();
27
28
  tls = { cert: material.cert, key: material.key };
29
+ displayHost = resolveRelayDisplayHost(config.tls, material.cert, (message) => logger.warn(message));
28
30
  }
29
31
  else {
30
32
  logger.info('TLS disabled — serving HTTP. Secure-context features (e.g. WebCodecs hardware decode) require HTTPS; ' +
@@ -32,7 +34,7 @@ async function main() {
32
34
  }
33
35
  const server = new RelayServer({ port, uploadsDir, wsBackpressureBytes: config.local.wsBackpressureBytes, trustedProxies: config.local.trustedProxies, corsOrigins, tls });
34
36
  await server.start();
35
- logger.info(`tapflow relay running on port ${port} (${tls ? 'https' : 'http'})`);
37
+ logger.info(`tapflow relay running at ${tls ? 'https' : 'http'}://${displayHost}:${port}`);
36
38
  const stopTls = provider ? startTlsBackgroundTasks(provider, server, config.tls) : null;
37
39
  const shutdown = () => {
38
40
  stopTls?.();
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapflowio/relay",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "WebSocket relay server for tapflow — NAT traversal, session routing, JWT auth, bundled dashboard",
5
5
  "keywords": [
6
6
  "tapflow",
@@ -52,8 +52,8 @@
52
52
  "nodemailer": "^9.0.5",
53
53
  "ws": "^8.21.3",
54
54
  "zod": "^4.4.3",
55
- "@tapflowio/agent-core": "0.19.0",
56
- "@tapflowio/protocol": "0.19.0"
55
+ "@tapflowio/agent-core": "0.20.0",
56
+ "@tapflowio/protocol": "0.20.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/better-sqlite3": "^7.6.13",
@@ -1,20 +1,20 @@
1
- import{i as r,j as e}from"./vendor-react-AJpf4YZ0.js";import{W as C,B as y,L as b,a4 as k,J,I as M,S as Q,f as W}from"./index-bitr6DIC.js";import{e as Y,S as K,P as X,g as ee,h as se,i as ae,b as te,d as le,s as ne,u as re}from"./build-format-CXuQt1X2.js";import{D as O,f as L,a as U,d as E,e as V,S as A,i as _,j as B,g as z,h as i,C as ce}from"./dialog-DuXZpbiF.js";import{P as ie,T as oe}from"./trash-2-QI162w2K.js";import{B as T}from"./badge-BkdYQFsh.js";import{A as de,c as ue,f as he,g as xe,d as pe,e as me,b as fe,a as ge}from"./alert-dialog-BsXI9SVV.js";import{b as je,c as ve}from"./vendor-router-ChFy8CZ1.js";/**
2
- * @license lucide-react v0.577.0 - ISC
1
+ import{i as r,j as e}from"./vendor-react-AJpf4YZ0.js";import{W as C,B as y,L as b,a4 as k,J,I as M,S as Q,f as W}from"./index-9vdYIm7s.js";import{e as Y,S as K,P as X,g as ee,h as se,i as ae,b as te,d as le,s as ne,u as re}from"./build-format-BFC8gLoh.js";import{D as O,f as L,a as U,d as E,e as V,S as A,i as _,j as B,g as z,h as i,C as ce}from"./dialog-DK9a3b4z.js";import{P as ie,T as oe}from"./trash-2-CGxISX8x.js";import{B as T}from"./badge-B6Nf3A0Y.js";import{A as de,c as ue,f as he,g as xe,d as pe,e as me,b as fe,a as ge}from"./alert-dialog-CgatMXjB.js";import{b as je,c as ve}from"./vendor-router-ChFy8CZ1.js";/**
2
+ * @license lucide-react v1.33.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
5
5
  * See the LICENSE file in the root directory of this source tree.
6
6
  */const Ne=[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]],Se=C("layers",Ne);/**
7
- * @license lucide-react v0.577.0 - ISC
7
+ * @license lucide-react v1.33.0 - ISC
8
8
  *
9
9
  * This source code is licensed under the ISC license.
10
10
  * See the LICENSE file in the root directory of this source tree.
11
11
  */const ye=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]],we=C("package",ye);/**
12
- * @license lucide-react v0.577.0 - ISC
12
+ * @license lucide-react v1.33.0 - ISC
13
13
  *
14
14
  * This source code is licensed under the ISC license.
15
15
  * See the LICENSE file in the root directory of this source tree.
16
16
  */const be=[["path",{d:"M10 2h4",key:"n1abiw"}],["path",{d:"M4.6 11a8 8 0 0 0 1.7 8.7 8 8 0 0 0 8.7 1.7",key:"10he05"}],["path",{d:"M7.4 7.4a8 8 0 0 1 10.3 1 8 8 0 0 1 .9 10.2",key:"15f7sh"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M12 12v-2",key:"fwoke6"}]],ke=C("timer-off",be);/**
17
- * @license lucide-react v0.577.0 - ISC
17
+ * @license lucide-react v1.33.0 - ISC
18
18
  *
19
19
  * This source code is licensed under the ISC license.
20
20
  * See the LICENSE file in the root directory of this source tree.
@@ -1 +1 @@
1
- import{i,j as e}from"./vendor-react-AJpf4YZ0.js";import{ai as X,a6 as Z,ad as S,a5 as y,ah as I,C as g,c as j,d as v,a as w,L as m,I as h,S as M,h as O,a4 as n,B as u,E as ee,J as se,H as ae,a2 as C,_ as $,a3 as p}from"./index-bitr6DIC.js";import{B as re}from"./badge-BkdYQFsh.js";import{A as te,h as oe,c as ne,f as ie,g as le,d as ce,e as de,b as me,a as he}from"./alert-dialog-BsXI9SVV.js";import{P as W}from"./pencil-iRR275s8.js";import"./vendor-router-ChFy8CZ1.js";const ue=C({teamName:p().min(1),logo:$(File).nullable().optional()}),pe=C({displayName:p().min(1),avatar:$(File).nullable().optional()}),fe=C({currentPassword:p().min(1),newPassword:p().min(8),confirmPassword:p()}).refine(f=>f.newPassword===f.confirmPassword,{message:"Passwords do not match",path:["confirmPassword"]});function Ne(){const{resolvedTheme:f}=X(),J=f==="dark"?"/logo-dark.svg":"/logo.svg",{user:o}=Z(),b=(o==null?void 0:o.role)==="Admin",N=(o==null?void 0:o.role)==="Admin"||(o==null?void 0:o.role)==="Developer",[V,P]=i.useState(null),A=i.useRef(null),d=S({resolver:y(ue),mode:"onBlur",defaultValues:{teamName:"",logo:null}});i.useEffect(()=>{b&&fetch("/api/v1/settings",{credentials:"include"}).then(s=>s.ok?s.json():null).then(s=>{s&&(d.reset({teamName:s.team_name,logo:null}),P(s.logo_url))})},[b]);async function Q(s){const a=new FormData;a.append("team_name",s.teamName),s.logo&&a.append("logo",s.logo);try{if(!(await fetch("/api/v1/settings",{method:"PATCH",credentials:"include",body:a})).ok){n.error("Failed to update workspace");return}n.success("Workspace updated")}catch{n.error("Failed to update workspace")}}const[k,F]=i.useState(null),D=i.useRef(null),c=S({resolver:y(pe),mode:"onBlur",defaultValues:{displayName:"",avatar:null}});i.useEffect(()=>{o&&(c.reset({displayName:o.displayName??"",avatar:null}),F(o.avatarUrl??null))},[o]);async function Y(s){const a=new FormData;a.append("display_name",s.displayName),s.avatar&&a.append("avatar",s.avatar);try{if(!(await fetch("/api/v1/profile",{method:"PATCH",credentials:"include",body:a})).ok){n.error("Failed to update profile");return}n.success("Profile updated")}catch{n.error("Failed to update profile")}}const t=S({resolver:y(fe),mode:"onBlur"});async function q(s){try{const a=await fetch("/api/v1/auth/change-password",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPassword:s.currentPassword,newPassword:s.newPassword})});if(!a.ok){const r=await a.json();t.setError("root",{message:r.error??"Failed to change password"});return}t.reset(),n.success("Password changed")}catch{t.setError("root",{message:"Network error"})}}const[T,E]=i.useState([]),[B,L]=i.useState({}),[U,z]=i.useState({}),[R,_]=i.useState({});i.useEffect(()=>{N&&fetch("/api/v1/apps",{credentials:"include"}).then(s=>s.ok?s.json():null).then(s=>{if(!s)return;E(s.items);const a={};s.items.forEach(r=>{a[r.id]=r.name}),L(a)})},[N]);async function G(s){_(a=>({...a,[s]:!0}));try{if(!(await fetch(`/api/v1/apps/${s}`,{method:"DELETE",credentials:"include"})).ok){n.error("Failed to delete app");return}E(r=>r.filter(l=>l.id!==s)),n.success("App deleted")}catch{n.error("Failed to delete app")}finally{_(a=>({...a,[s]:!1}))}}async function K(s){z(a=>({...a,[s]:!0}));try{if(!(await fetch(`/api/v1/apps/${s}`,{method:"PATCH",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B[s]})})).ok){n.error("Failed to update app");return}n.success("App updated")}catch{n.error("Failed to update app")}finally{z(a=>({...a,[s]:!1}))}}const x=I({control:c.control,name:"displayName"});return e.jsxs("div",{className:"flex flex-col gap-6 max-w-[900px] mx-auto w-full p-6",children:[e.jsx("h1",{className:"text-xl font-semibold tracking-display-sm",children:"Settings"}),b&&e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Workspace"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:d.handleSubmit(Q),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"team-name",children:"Team name"}),e.jsx(h,{id:"team-name",placeholder:"My QA Team",...d.register("teamName")}),d.formState.errors.teamName&&e.jsx("p",{className:"text-sm text-destructive",children:d.formState.errors.teamName.message})]}),e.jsx(M,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(m,{children:["Logo ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(png · jpg, max 2MB)"})]}),e.jsx(O,{name:"logo",control:d.control,render:({field:s})=>e.jsxs("div",{className:"relative w-16 h-16",children:[e.jsx("img",{src:V??J,alt:"Workspace logo",className:"w-16 h-16 rounded-lg object-contain"}),e.jsx("button",{type:"button","aria-label":"Change logo",onClick:()=>{var a;return(a=A.current)==null?void 0:a.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(W,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:A,type:"file",accept:".png,.jpg,.jpeg",className:"hidden",onChange:a=>{var l;const r=(l=a.target.files)==null?void 0:l[0];if(r&&r.size>2*1024*1024){n.error("Image must be 2MB or less");return}r&&(s.onChange(r),P(URL.createObjectURL(r)))}})]})})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:d.formState.isSubmitting,children:d.formState.isSubmitting?"Saving…":"Save changes"})})]})})]}),e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Profile"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:c.handleSubmit(Y),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"display-name",children:"Nickname"}),e.jsx(h,{id:"display-name",placeholder:"Your name",...c.register("displayName")}),c.formState.errors.displayName&&e.jsx("p",{className:"text-sm text-destructive",children:c.formState.errors.displayName.message})]}),e.jsx(M,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(m,{children:["Avatar ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(png · jpg, max 2MB)"})]}),e.jsx(O,{name:"avatar",control:c.control,render:({field:s})=>{var a;return e.jsxs("div",{className:"relative w-14 h-14",children:[k?e.jsx("img",{src:k,alt:"Profile avatar",className:"w-14 h-14 rounded-full object-cover border"}):e.jsx("div",{className:"w-14 h-14 rounded-full flex items-center justify-center text-lg font-medium",style:(()=>{const r=ee(x||(o==null?void 0:o.email)||"");return{backgroundColor:r.bg,color:r.fg}})(),children:((a=x==null?void 0:x[0])==null?void 0:a.toUpperCase())??"?"}),e.jsx("button",{type:"button","aria-label":"Change avatar",onClick:()=>{var r;return(r=D.current)==null?void 0:r.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(W,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:D,type:"file",accept:".png,.jpg,.jpeg",className:"hidden",onChange:r=>{var H;const l=(H=r.target.files)==null?void 0:H[0];if(l&&l.size>2*1024*1024){n.error("Image must be 2MB or less");return}l&&(s.onChange(l),F(URL.createObjectURL(l)))}})]})}})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:c.formState.isSubmitting,children:c.formState.isSubmitting?"Saving…":"Save changes"})})]})})]}),e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Password"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:t.handleSubmit(q),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"current-password",children:"Current password"}),e.jsx(h,{id:"current-password",type:"password",...t.register("currentPassword")}),t.formState.errors.currentPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.currentPassword.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"new-password",children:"New password"}),e.jsx(h,{id:"new-password",type:"password",...t.register("newPassword")}),t.formState.errors.newPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.newPassword.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"confirm-password",children:"Confirm new password"}),e.jsx(h,{id:"confirm-password",type:"password",...t.register("confirmPassword")}),t.formState.errors.confirmPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.confirmPassword.message})]}),t.formState.errors.root&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.root.message}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:t.formState.isSubmitting,children:t.formState.isSubmitting?"Saving…":"Change password"})})]})})]}),N&&T.length>0&&e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Apps"})}),e.jsx(w,{children:e.jsx("div",{className:"flex flex-col divide-y divide-border",children:T.map(s=>e.jsxs("div",{className:"flex flex-col gap-2 py-4 first:pt-0 last:pb-0",children:[e.jsx(m,{htmlFor:`app-${s.id}`,children:"App Name"}),e.jsx(h,{id:`app-${s.id}`,value:B[s.id]??"",onChange:a=>L(r=>({...r,[s.id]:a.target.value}))}),e.jsxs("div",{className:"flex flex-col gap-1.5 mt-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground font-mono",children:s.bundle_id_key}),e.jsx(re,{tone:s.platform==="ios"?"ios":s.platform==="android"?"android":void 0,variant:s.platform==="both"?"secondary":void 0,className:"capitalize",children:s.platform})]}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(u,{size:"sm",variant:"outline",disabled:U[s.id],onClick:()=>K(s.id),children:U[s.id]?"Saving…":"Save"}),e.jsxs(te,{children:[e.jsx(oe,{asChild:!0,children:e.jsx(u,{size:"sm",variant:"destructive",disabled:R[s.id],children:R[s.id]?"Deleting…":"Delete"})}),e.jsxs(ne,{children:[e.jsxs(ie,{children:[e.jsx(le,{children:"Delete app?"}),e.jsxs(ce,{children:["This will permanently delete ",e.jsx("strong",{children:s.name})," and all its builds. This action cannot be undone."]})]}),e.jsxs(de,{children:[e.jsx(me,{className:"w-24",children:"Cancel"}),e.jsx(he,{className:se(ae({variant:"destructive"}),"w-24"),onClick:()=>G(s.id),children:"Delete"})]})]})]})]})]})]},s.id))})})]})]})}export{Ne as DefaultSettings};
1
+ import{i,j as e}from"./vendor-react-AJpf4YZ0.js";import{ai as X,a6 as Z,ad as S,a5 as y,ah as I,C as g,c as j,d as v,a as w,L as m,I as h,S as M,h as O,a4 as n,B as u,E as ee,J as se,H as ae,a2 as C,_ as $,a3 as p}from"./index-9vdYIm7s.js";import{B as re}from"./badge-B6Nf3A0Y.js";import{A as te,h as oe,c as ne,f as ie,g as le,d as ce,e as de,b as me,a as he}from"./alert-dialog-CgatMXjB.js";import{P as W}from"./pencil-BeLNLEKe.js";import"./vendor-router-ChFy8CZ1.js";const ue=C({teamName:p().min(1),logo:$(File).nullable().optional()}),pe=C({displayName:p().min(1),avatar:$(File).nullable().optional()}),fe=C({currentPassword:p().min(1),newPassword:p().min(8),confirmPassword:p()}).refine(f=>f.newPassword===f.confirmPassword,{message:"Passwords do not match",path:["confirmPassword"]});function Ne(){const{resolvedTheme:f}=X(),J=f==="dark"?"/logo-dark.svg":"/logo.svg",{user:o}=Z(),b=(o==null?void 0:o.role)==="Admin",N=(o==null?void 0:o.role)==="Admin"||(o==null?void 0:o.role)==="Developer",[V,P]=i.useState(null),A=i.useRef(null),d=S({resolver:y(ue),mode:"onBlur",defaultValues:{teamName:"",logo:null}});i.useEffect(()=>{b&&fetch("/api/v1/settings",{credentials:"include"}).then(s=>s.ok?s.json():null).then(s=>{s&&(d.reset({teamName:s.team_name,logo:null}),P(s.logo_url))})},[b]);async function Q(s){const a=new FormData;a.append("team_name",s.teamName),s.logo&&a.append("logo",s.logo);try{if(!(await fetch("/api/v1/settings",{method:"PATCH",credentials:"include",body:a})).ok){n.error("Failed to update workspace");return}n.success("Workspace updated")}catch{n.error("Failed to update workspace")}}const[k,F]=i.useState(null),D=i.useRef(null),c=S({resolver:y(pe),mode:"onBlur",defaultValues:{displayName:"",avatar:null}});i.useEffect(()=>{o&&(c.reset({displayName:o.displayName??"",avatar:null}),F(o.avatarUrl??null))},[o]);async function Y(s){const a=new FormData;a.append("display_name",s.displayName),s.avatar&&a.append("avatar",s.avatar);try{if(!(await fetch("/api/v1/profile",{method:"PATCH",credentials:"include",body:a})).ok){n.error("Failed to update profile");return}n.success("Profile updated")}catch{n.error("Failed to update profile")}}const t=S({resolver:y(fe),mode:"onBlur"});async function q(s){try{const a=await fetch("/api/v1/auth/change-password",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({currentPassword:s.currentPassword,newPassword:s.newPassword})});if(!a.ok){const r=await a.json();t.setError("root",{message:r.error??"Failed to change password"});return}t.reset(),n.success("Password changed")}catch{t.setError("root",{message:"Network error"})}}const[T,E]=i.useState([]),[B,L]=i.useState({}),[U,z]=i.useState({}),[R,_]=i.useState({});i.useEffect(()=>{N&&fetch("/api/v1/apps",{credentials:"include"}).then(s=>s.ok?s.json():null).then(s=>{if(!s)return;E(s.items);const a={};s.items.forEach(r=>{a[r.id]=r.name}),L(a)})},[N]);async function G(s){_(a=>({...a,[s]:!0}));try{if(!(await fetch(`/api/v1/apps/${s}`,{method:"DELETE",credentials:"include"})).ok){n.error("Failed to delete app");return}E(r=>r.filter(l=>l.id!==s)),n.success("App deleted")}catch{n.error("Failed to delete app")}finally{_(a=>({...a,[s]:!1}))}}async function K(s){z(a=>({...a,[s]:!0}));try{if(!(await fetch(`/api/v1/apps/${s}`,{method:"PATCH",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:B[s]})})).ok){n.error("Failed to update app");return}n.success("App updated")}catch{n.error("Failed to update app")}finally{z(a=>({...a,[s]:!1}))}}const x=I({control:c.control,name:"displayName"});return e.jsxs("div",{className:"flex flex-col gap-6 max-w-[900px] mx-auto w-full p-6",children:[e.jsx("h1",{className:"text-xl font-semibold tracking-display-sm",children:"Settings"}),b&&e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Workspace"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:d.handleSubmit(Q),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"team-name",children:"Team name"}),e.jsx(h,{id:"team-name",placeholder:"My QA Team",...d.register("teamName")}),d.formState.errors.teamName&&e.jsx("p",{className:"text-sm text-destructive",children:d.formState.errors.teamName.message})]}),e.jsx(M,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(m,{children:["Logo ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(png · jpg, max 2MB)"})]}),e.jsx(O,{name:"logo",control:d.control,render:({field:s})=>e.jsxs("div",{className:"relative w-16 h-16",children:[e.jsx("img",{src:V??J,alt:"Workspace logo",className:"w-16 h-16 rounded-lg object-contain"}),e.jsx("button",{type:"button","aria-label":"Change logo",onClick:()=>{var a;return(a=A.current)==null?void 0:a.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(W,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:A,type:"file",accept:".png,.jpg,.jpeg",className:"hidden",onChange:a=>{var l;const r=(l=a.target.files)==null?void 0:l[0];if(r&&r.size>2*1024*1024){n.error("Image must be 2MB or less");return}r&&(s.onChange(r),P(URL.createObjectURL(r)))}})]})})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:d.formState.isSubmitting,children:d.formState.isSubmitting?"Saving…":"Save changes"})})]})})]}),e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Profile"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:c.handleSubmit(Y),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"display-name",children:"Nickname"}),e.jsx(h,{id:"display-name",placeholder:"Your name",...c.register("displayName")}),c.formState.errors.displayName&&e.jsx("p",{className:"text-sm text-destructive",children:c.formState.errors.displayName.message})]}),e.jsx(M,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(m,{children:["Avatar ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(png · jpg, max 2MB)"})]}),e.jsx(O,{name:"avatar",control:c.control,render:({field:s})=>{var a;return e.jsxs("div",{className:"relative w-14 h-14",children:[k?e.jsx("img",{src:k,alt:"Profile avatar",className:"w-14 h-14 rounded-full object-cover border"}):e.jsx("div",{className:"w-14 h-14 rounded-full flex items-center justify-center text-lg font-medium",style:(()=>{const r=ee(x||(o==null?void 0:o.email)||"");return{backgroundColor:r.bg,color:r.fg}})(),children:((a=x==null?void 0:x[0])==null?void 0:a.toUpperCase())??"?"}),e.jsx("button",{type:"button","aria-label":"Change avatar",onClick:()=>{var r;return(r=D.current)==null?void 0:r.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(W,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:D,type:"file",accept:".png,.jpg,.jpeg",className:"hidden",onChange:r=>{var H;const l=(H=r.target.files)==null?void 0:H[0];if(l&&l.size>2*1024*1024){n.error("Image must be 2MB or less");return}l&&(s.onChange(l),F(URL.createObjectURL(l)))}})]})}})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:c.formState.isSubmitting,children:c.formState.isSubmitting?"Saving…":"Save changes"})})]})})]}),e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Password"})}),e.jsx(w,{children:e.jsxs("form",{onSubmit:t.handleSubmit(q),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"current-password",children:"Current password"}),e.jsx(h,{id:"current-password",type:"password",...t.register("currentPassword")}),t.formState.errors.currentPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.currentPassword.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"new-password",children:"New password"}),e.jsx(h,{id:"new-password",type:"password",...t.register("newPassword")}),t.formState.errors.newPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.newPassword.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(m,{htmlFor:"confirm-password",children:"Confirm new password"}),e.jsx(h,{id:"confirm-password",type:"password",...t.register("confirmPassword")}),t.formState.errors.confirmPassword&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.confirmPassword.message})]}),t.formState.errors.root&&e.jsx("p",{className:"text-sm text-destructive",children:t.formState.errors.root.message}),e.jsx("div",{className:"flex justify-end",children:e.jsx(u,{type:"submit",size:"sm",disabled:t.formState.isSubmitting,children:t.formState.isSubmitting?"Saving…":"Change password"})})]})})]}),N&&T.length>0&&e.jsxs(g,{children:[e.jsx(j,{children:e.jsx(v,{children:"Apps"})}),e.jsx(w,{children:e.jsx("div",{className:"flex flex-col divide-y divide-border",children:T.map(s=>e.jsxs("div",{className:"flex flex-col gap-2 py-4 first:pt-0 last:pb-0",children:[e.jsx(m,{htmlFor:`app-${s.id}`,children:"App Name"}),e.jsx(h,{id:`app-${s.id}`,value:B[s.id]??"",onChange:a=>L(r=>({...r,[s.id]:a.target.value}))}),e.jsxs("div",{className:"flex flex-col gap-1.5 mt-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-muted-foreground font-mono",children:s.bundle_id_key}),e.jsx(re,{tone:s.platform==="ios"?"ios":s.platform==="android"?"android":void 0,variant:s.platform==="both"?"secondary":void 0,className:"capitalize",children:s.platform})]}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(u,{size:"sm",variant:"outline",disabled:U[s.id],onClick:()=>K(s.id),children:U[s.id]?"Saving…":"Save"}),e.jsxs(te,{children:[e.jsx(oe,{asChild:!0,children:e.jsx(u,{size:"sm",variant:"destructive",disabled:R[s.id],children:R[s.id]?"Deleting…":"Delete"})}),e.jsxs(ne,{children:[e.jsxs(ie,{children:[e.jsx(le,{children:"Delete app?"}),e.jsxs(ce,{children:["This will permanently delete ",e.jsx("strong",{children:s.name})," and all its builds. This action cannot be undone."]})]}),e.jsxs(de,{children:[e.jsx(me,{className:"w-24",children:"Cancel"}),e.jsx(he,{className:se(ae({variant:"destructive"}),"w-24"),onClick:()=>G(s.id),children:"Delete"})]})]})]})]})]})]},s.id))})})]})]})}export{Ne as DefaultSettings};
@@ -1 +1 @@
1
- import{i as n,j as e}from"./vendor-react-AJpf4YZ0.js";import{ad as I,a5 as A,ah as L,C as b,c as y,d as C,b as k,a as M,L as d,I as h,h as T,E as U,S as _,B as D,a2 as O,a3 as x,_ as Y}from"./index-bitr6DIC.js";import{b as z,c as H}from"./vendor-router-ChFy8CZ1.js";import{P as V}from"./pencil-iRR275s8.js";const W=O({displayName:x().optional(),avatar:Y(File).nullable().optional(),password:x().min(8),confirm:x()}).refine(o=>o.password===o.confirm,{message:"Passwords do not match",path:["confirm"]});function K(){const o=z(),[S]=H(),c=S.get("token")??"",[f,m]=n.useState("loading"),[P,F]=n.useState(""),[v,R]=n.useState(null),j=n.useRef(null),{register:p,handleSubmit:B,control:g,setError:u,formState:{errors:t,isSubmitting:w}}=I({resolver:A(W),mode:"onBlur",defaultValues:{displayName:"",avatar:null}}),l=L({control:g,name:"displayName"})??"";n.useEffect(()=>{if(!c){m("invalid");return}fetch(`/api/v1/invitations/verify?token=${c}`).then(a=>a.ok?a.json():Promise.reject()).then(a=>{F(a.role),m("valid")}).catch(()=>m("invalid"))},[c]);async function E(a){var r;try{const s=new FormData;if(s.append("token",c),s.append("password",a.password),(r=a.displayName)!=null&&r.trim()&&s.append("display_name",a.displayName.trim()),a.avatar&&s.append("avatar",a.avatar),!(await fetch("/api/v1/invitations/accept",{method:"POST",body:s})).ok){u("root",{message:"Failed to accept invitation"});return}o("/app-center",{replace:!0})}catch{u("root",{message:"Network error. Please try again."})}}return f==="loading"?e.jsx("div",{className:"flex min-h-svh items-center justify-center"}):f==="invalid"?e.jsx("div",{className:"bg-mesh-gradient flex min-h-svh items-center justify-center overflow-hidden p-4",children:e.jsx(b,{level:4,className:"w-full max-w-sm text-center",children:e.jsxs(y,{children:[e.jsx(C,{children:"Invitation expired"}),e.jsx(k,{children:"This invite link is invalid or has expired. Ask your admin for a new one."})]})})}):e.jsx("div",{className:"bg-mesh-gradient flex min-h-svh items-center justify-center overflow-hidden p-4",children:e.jsxs(b,{level:4,className:"w-full max-w-sm",children:[e.jsxs(y,{className:"text-center",children:[e.jsx(C,{children:"Set up your account"}),e.jsxs(k,{children:["You're joining as ",e.jsx("strong",{children:P})]})]}),e.jsx(M,{children:e.jsxs("form",{onSubmit:B(E),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(d,{htmlFor:"display-name",children:["Nickname ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(optional)"})]}),e.jsx(h,{id:"display-name",placeholder:"Your name",...p("displayName")})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(d,{children:["Avatar ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(optional, png · jpg, max 2MB)"})]}),e.jsx(T,{name:"avatar",control:g,render:({field:a})=>{var r;return e.jsxs("div",{className:"relative w-14 h-14",children:[v?e.jsx("img",{src:v,alt:"Avatar preview",className:"w-14 h-14 rounded-full object-cover border"}):e.jsx("div",{className:"w-14 h-14 rounded-full flex items-center justify-center text-lg font-medium",style:(()=>{const s=U(l);return{backgroundColor:s.bg,color:s.fg}})(),children:((r=l==null?void 0:l[0])==null?void 0:r.toUpperCase())??"?"}),e.jsx("button",{type:"button","aria-label":"Change avatar",onClick:()=>{var s;return(s=j.current)==null?void 0:s.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(V,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:j,type:"file",accept:"image/png,image/jpeg",className:"hidden",onChange:s=>{var N;const i=(N=s.target.files)==null?void 0:N[0];if(i){if(i.size>2*1024*1024){u("avatar",{message:"Max 2MB for avatar"});return}a.onChange(i),R(URL.createObjectURL(i))}}})]})}}),t.avatar&&e.jsx("p",{className:"text-sm text-destructive",children:t.avatar.message})]}),e.jsx(_,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(d,{htmlFor:"password",children:"Password"}),e.jsx(h,{id:"password",type:"password",...p("password")}),t.password&&e.jsx("p",{className:"text-sm text-destructive",children:t.password.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(d,{htmlFor:"confirm",children:"Confirm password"}),e.jsx(h,{id:"confirm",type:"password",...p("confirm")}),t.confirm&&e.jsx("p",{className:"text-sm text-destructive",children:t.confirm.message})]}),t.root&&e.jsx("p",{className:"text-sm text-destructive",children:t.root.message}),e.jsx(D,{type:"submit",disabled:w,className:"w-full",children:w?"Creating account…":"Create account"})]})})]})})}export{K as Invite};
1
+ import{i as n,j as e}from"./vendor-react-AJpf4YZ0.js";import{ad as I,a5 as A,ah as L,C as b,c as y,d as C,b as k,a as M,L as d,I as h,h as T,E as U,S as _,B as D,a2 as O,a3 as x,_ as Y}from"./index-9vdYIm7s.js";import{b as z,c as H}from"./vendor-router-ChFy8CZ1.js";import{P as V}from"./pencil-BeLNLEKe.js";const W=O({displayName:x().optional(),avatar:Y(File).nullable().optional(),password:x().min(8),confirm:x()}).refine(o=>o.password===o.confirm,{message:"Passwords do not match",path:["confirm"]});function K(){const o=z(),[S]=H(),c=S.get("token")??"",[f,m]=n.useState("loading"),[P,F]=n.useState(""),[v,R]=n.useState(null),j=n.useRef(null),{register:p,handleSubmit:B,control:g,setError:u,formState:{errors:t,isSubmitting:w}}=I({resolver:A(W),mode:"onBlur",defaultValues:{displayName:"",avatar:null}}),l=L({control:g,name:"displayName"})??"";n.useEffect(()=>{if(!c){m("invalid");return}fetch(`/api/v1/invitations/verify?token=${c}`).then(a=>a.ok?a.json():Promise.reject()).then(a=>{F(a.role),m("valid")}).catch(()=>m("invalid"))},[c]);async function E(a){var r;try{const s=new FormData;if(s.append("token",c),s.append("password",a.password),(r=a.displayName)!=null&&r.trim()&&s.append("display_name",a.displayName.trim()),a.avatar&&s.append("avatar",a.avatar),!(await fetch("/api/v1/invitations/accept",{method:"POST",body:s})).ok){u("root",{message:"Failed to accept invitation"});return}o("/app-center",{replace:!0})}catch{u("root",{message:"Network error. Please try again."})}}return f==="loading"?e.jsx("div",{className:"flex min-h-svh items-center justify-center"}):f==="invalid"?e.jsx("div",{className:"bg-mesh-gradient flex min-h-svh items-center justify-center overflow-hidden p-4",children:e.jsx(b,{level:4,className:"w-full max-w-sm text-center",children:e.jsxs(y,{children:[e.jsx(C,{children:"Invitation expired"}),e.jsx(k,{children:"This invite link is invalid or has expired. Ask your admin for a new one."})]})})}):e.jsx("div",{className:"bg-mesh-gradient flex min-h-svh items-center justify-center overflow-hidden p-4",children:e.jsxs(b,{level:4,className:"w-full max-w-sm",children:[e.jsxs(y,{className:"text-center",children:[e.jsx(C,{children:"Set up your account"}),e.jsxs(k,{children:["You're joining as ",e.jsx("strong",{children:P})]})]}),e.jsx(M,{children:e.jsxs("form",{onSubmit:B(E),className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(d,{htmlFor:"display-name",children:["Nickname ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(optional)"})]}),e.jsx(h,{id:"display-name",placeholder:"Your name",...p("displayName")})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(d,{children:["Avatar ",e.jsx("span",{className:"text-muted-foreground text-xs",children:"(optional, png · jpg, max 2MB)"})]}),e.jsx(T,{name:"avatar",control:g,render:({field:a})=>{var r;return e.jsxs("div",{className:"relative w-14 h-14",children:[v?e.jsx("img",{src:v,alt:"Avatar preview",className:"w-14 h-14 rounded-full object-cover border"}):e.jsx("div",{className:"w-14 h-14 rounded-full flex items-center justify-center text-lg font-medium",style:(()=>{const s=U(l);return{backgroundColor:s.bg,color:s.fg}})(),children:((r=l==null?void 0:l[0])==null?void 0:r.toUpperCase())??"?"}),e.jsx("button",{type:"button","aria-label":"Change avatar",onClick:()=>{var s;return(s=j.current)==null?void 0:s.click()},className:"absolute bottom-0 right-0 w-6 h-6 rounded-full bg-background border border-border shadow-sm flex items-center justify-center hover:bg-accent transition-colors",children:e.jsx(V,{className:"w-3 h-3","aria-hidden":"true"})}),e.jsx("input",{ref:j,type:"file",accept:"image/png,image/jpeg",className:"hidden",onChange:s=>{var N;const i=(N=s.target.files)==null?void 0:N[0];if(i){if(i.size>2*1024*1024){u("avatar",{message:"Max 2MB for avatar"});return}a.onChange(i),R(URL.createObjectURL(i))}}})]})}}),t.avatar&&e.jsx("p",{className:"text-sm text-destructive",children:t.avatar.message})]}),e.jsx(_,{}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(d,{htmlFor:"password",children:"Password"}),e.jsx(h,{id:"password",type:"password",...p("password")}),t.password&&e.jsx("p",{className:"text-sm text-destructive",children:t.password.message})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsx(d,{htmlFor:"confirm",children:"Confirm password"}),e.jsx(h,{id:"confirm",type:"password",...p("confirm")}),t.confirm&&e.jsx("p",{className:"text-sm text-destructive",children:t.confirm.message})]}),t.root&&e.jsx("p",{className:"text-sm text-destructive",children:t.root.message}),e.jsx(D,{type:"submit",disabled:w,className:"w-full",children:w?"Creating account…":"Create account"})]})})]})})}export{K as Invite};
@@ -1 +1 @@
1
- import{i,j as e}from"./vendor-react-AJpf4YZ0.js";import{u as Q,T as Z,b as K,c as ee}from"./tabs-BnbeuAOe.js";import{a7 as te,M as se}from"./index-bitr6DIC.js";import{u as ne,h as oe,g as re,e as ae,c as ie,G as le,A as ce,m as V,d as de,a as ue,b as he,L as me,B as fe,l as xe,P as pe,f as ge}from"./vendor-charts-DyX5CBcf.js";import"./vendor-router-ChFy8CZ1.js";const je={cpu:{label:"CPU",color:"#60a5fa"},mem:{label:"RAM",color:"#a78bfa"}},W={"1h":"1h","6h":"6h","24h":"24h","7d":"7d"},z={"1h":36e5,"6h":216e5,"24h":864e5,"7d":6048e5},ve={"1h":6e5,"6h":36e5,"24h":108e5,"7d":864e5};function be(o,x){const n=new Date(o);return x==="7d"?`${n.getMonth()+1}/${n.getDate()}`:`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}function $e(){const[o,x]=i.useState([]),[n,l]=i.useState([]),[a,c]=i.useState(null),[u,h]=i.useState("24h"),[k,v]=i.useState([]),[b,$]=i.useState(()=>Date.now()),[C,T]=i.useState(!1),{setNode:w}=te();i.useEffect(()=>(w(e.jsx("span",{className:"text-sm font-medium",children:"Mac Resources"})),()=>w(null)),[w]);const R=i.useCallback(t=>{t.type==="agents:listed"&&x(t.sessions??[])},[]),{send:N,connected:m}=Q(R);i.useEffect(()=>{if(!m)return;N({type:"agents:list"});const t=setInterval(()=>N({type:"agents:list"}),1e4);return()=>clearInterval(t)},[m,N]),i.useEffect(()=>{fetch("/api/v1/agents",{credentials:"include"}).then(t=>t.ok?t.json():[]).then(l)},[]);const p=o.map(t=>t.agentName).filter(Boolean),d=[...new Set([...p,...n])],S=new Set(p);i.useEffect(()=>{!a&&d.length>0&&c(d[0])},[d.join(",")]),i.useEffect(()=>{a&&(T(!0),fetch(`/api/v1/agents/${encodeURIComponent(a)}/resources?range=${u}`,{credentials:"include"}).then(t=>t.ok?t.json():[]).then(t=>{v(t),$(Date.now())}).finally(()=>T(!1)))},[a,u]);const M=k.map(t=>({time:t.recorded_at,cpu:Math.round(t.cpu_percent*10)/10,mem:Math.round(t.mem_percent*10)/10}));return e.jsxs("div",{className:"flex h-full min-h-0",children:[e.jsxs("aside",{"aria-labelledby":"macs-heading",className:"w-64 shrink-0 border-r flex flex-col gap-1 p-3 overflow-y-auto",children:[e.jsx("h2",{id:"macs-heading",className:"px-2 pb-1 font-mono text-xs font-medium text-muted-foreground uppercase tracking-wider",children:"Macs"}),d.length===0?e.jsx("span",{className:"px-2 text-sm text-muted-foreground",children:m?"No agents yet.":"Connecting…"}):d.map(t=>{const y=S.has(t),g=a===t;return e.jsxs("button",{onClick:()=>c(t),className:["flex items-center gap-2 rounded-md px-2 py-2 text-left text-sm hover:bg-accent transition-colors",g?"bg-accent font-medium":""].join(" "),children:[e.jsx("span",{className:`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${y?"bg-emerald-400":"bg-muted-foreground/40"}`}),e.jsx("span",{className:"truncate min-w-0",children:t})]},t)})]}),e.jsx("div",{className:"flex-1 min-w-0 overflow-auto",children:a?e.jsxs("div",{className:"flex flex-col gap-6 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-base font-semibold",children:a}),e.jsx(Z,{value:u,onValueChange:t=>h(t),children:e.jsx(K,{children:Object.keys(W).map(t=>e.jsx(ee,{value:t,children:W[t]},t))})})]}),C?e.jsx("div",{className:"flex h-40 items-center justify-center text-sm text-muted-foreground",children:"Loading…"}):M.length===0?e.jsx("div",{className:"flex h-40 items-center justify-center text-sm text-muted-foreground",children:"No data yet for this range. Data is collected every minute while the agent is connected."}):e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(X,{title:"CPU %",color:"cpu",data:M,dataKey:"cpu",range:u,now:b}),e.jsx(X,{title:"RAM %",color:"mem",data:M,dataKey:"mem",range:u,now:b})]})]}):e.jsxs("div",{className:"flex h-full items-center justify-center gap-2 text-muted-foreground",children:[e.jsx(se,{className:"h-8 w-8"}),e.jsx("p",{className:"text-sm",children:"Select a Mac to view resource history."})]})})]})}const A=o=>new Date(o.time).getTime(),H=o=>new Date(o.time).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),P=o=>`${Math.round(o*10)/10}%`,ye=ge(A).left,f={top:8,right:24,bottom:24,left:40},L=16;function X({title:o,color:x,data:n,dataKey:l,range:a,now:c}){const u=je[x].color;return e.jsxs("div",{className:"rounded-lg border p-4 flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-full",style:{background:u}}),e.jsx("h2",{className:"text-sm font-medium",children:o})]}),e.jsx("div",{className:"relative h-[220px] w-full",children:e.jsx(pe,{children:({width:h,height:k})=>h>0&&k>0?e.jsx(ke,{width:h,height:k,data:n,dataKey:l,hex:u,range:a,now:c,label:o}):null})})]})}function ke({width:o,height:x,data:n,dataKey:l,hex:a,range:c,now:u,label:h}){const{showTooltip:k,hideTooltip:v,tooltipData:b,tooltipLeft:$,tooltipTop:C}=ne(),T=`chart-hint-${l}`,[w,R]=i.useState(null),N=Math.max(0,n.length-1),m=w===null?N:Math.min(w,N),p=o-f.left-f.right,d=x-f.top-f.bottom,S=ve[c],M=Math.ceil(u/S)*S,t=M-z[c],y=oe({domain:[t,M],range:[L,Math.max(L,p-L)]}),g=re({domain:[0,100],range:[d,L]}),Y=Array.from({length:z[c]/S+1},(s,r)=>new Date(t+r*S)),O=`fill-${l}`,_=`plot-${l}`,I=s=>{const r=n[s];r&&(R(s),k({tooltipData:r,tooltipLeft:y(A(r)),tooltipTop:g(r[l])}))},q=s=>{if(n.length===0)return;if(s.key==="Escape"){v();return}const r=m,j=s.key==="ArrowLeft"||s.key==="ArrowDown"?Math.max(0,r-1):s.key==="ArrowRight"||s.key==="ArrowUp"?Math.min(n.length-1,r+1):s.key==="Home"?0:s.key==="End"?n.length-1:null;j!==null&&(s.preventDefault(),I(j))},B=s=>{const r=xe(s);if(!r)return;const j=y.invert(r.x-f.left).getTime(),F=ye(n,j),D=n[F-1],E=n[F],U=D&&E?j-A(D)<A(E)-j?D:E:D??E;U&&I(n.indexOf(U))},G=n[n.length-1],J=s=>`${h}, ${H(s)}, ${P(s[l])}`;return e.jsxs(e.Fragment,{children:[e.jsxs("svg",{width:o,height:x,role:"group","aria-label":G?`${h}, last ${c}. Latest ${P(G[l])}.`:`${h}, last ${c}. No samples.`,children:[e.jsx(ae,{id:O,from:a,to:a,fromOpacity:.3,toOpacity:0,fromOffset:"5%",toOffset:"95%"}),e.jsx("clipPath",{id:_,children:e.jsx("rect",{x:0,y:0,width:Math.max(0,p),height:Math.max(0,d)})}),e.jsxs(ie,{left:f.left,top:f.top,children:[e.jsx(le,{scale:g,width:p,tickValues:[0,25,50,75,100],strokeDasharray:"3 3",stroke:"hsl(var(--border))"}),e.jsxs("g",{clipPath:`url(#${_})`,children:[e.jsx(ce,{data:n,x:s=>y(A(s)),y:s=>g(s[l]),yScale:g,curve:V,fill:`url(#${O})`}),e.jsx(de,{data:n,x:s=>y(A(s)),y:s=>g(s[l]),curve:V,stroke:a,strokeWidth:1.5})]}),e.jsx(ue,{top:d,scale:y,tickValues:Y,tickFormat:s=>be(new Date(+s).toISOString(),c),hideAxisLine:!0,hideTicks:!0,tickLength:0,tickLabelProps:(s,r,j)=>({fontSize:11,fill:"currentColor",textAnchor:r===0?"start":r===j.length-1?"end":"middle",dy:6,className:"fill-muted-foreground"})}),e.jsx(he,{scale:g,tickValues:[0,25,50,75,100],tickFormat:s=>`${s}%`,hideAxisLine:!0,hideTicks:!0,tickLabelProps:()=>({fontSize:11,fill:"currentColor",textAnchor:"end",dx:-4,dy:3,className:"fill-muted-foreground"})}),b&&e.jsxs("g",{style:{transition:"transform 0.25s ease-out",transform:`translateX(${$??0}px)`},pointerEvents:"none",children:[e.jsx(me,{from:{x:0,y:L},to:{x:0,y:d},stroke:"hsl(var(--border))",strokeWidth:1}),e.jsx("circle",{cx:0,cy:0,r:3,fill:a,stroke:"hsl(var(--background))",strokeWidth:1.5,style:{transition:"transform 0.25s ease-out",transform:`translateY(${C??0}px)`}})]}),e.jsx(fe,{x:0,y:0,width:Math.max(0,p),height:Math.max(0,d),fill:"transparent",tabIndex:0,role:"slider","aria-label":`${h} samples`,"aria-valuemin":0,"aria-valuemax":Math.max(0,n.length-1),"aria-valuenow":m,"aria-valuetext":n[m]?J(n[m]):void 0,"aria-describedby":T,className:"outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",onFocus:()=>I(m),onBlur:v,onKeyDown:q,onMouseMove:B,onMouseLeave:v,onTouchMove:B,onTouchEnd:v,onTouchCancel:v})]})]}),e.jsx("p",{id:T,className:"sr-only",children:"Use the arrow keys to read individual samples. Escape hides the reading."}),b&&e.jsxs("div",{"aria-hidden":"true",className:"pointer-events-none absolute top-0 left-0 whitespace-nowrap rounded-lg border bg-background px-3 py-2 text-xs text-foreground shadow-md",style:{transform:`translate(${($??0)+f.left}px, ${(C??0)+f.top}px) translate(${($??0)>p*.6?"calc(-100% - 12px)":"12px"}, -50%)`,transition:"transform 0.25s ease-out"},children:[e.jsxs("p",{className:"mb-1",children:["Date:"," ",H(b)]}),e.jsxs("p",{children:[h,": ",P(b[l])]})]})]})}export{ke as AreaChartInner,$e as MacResources};
1
+ import{i,j as e}from"./vendor-react-AJpf4YZ0.js";import{u as Q,T as Z,b as K,c as ee}from"./tabs-Xlttuqxh.js";import{a7 as te,M as se}from"./index-9vdYIm7s.js";import{u as ne,h as oe,g as re,e as ae,c as ie,G as le,A as ce,m as V,d as de,a as ue,b as he,L as me,B as fe,l as xe,P as pe,f as ge}from"./vendor-charts-DyX5CBcf.js";import"./vendor-router-ChFy8CZ1.js";const je={cpu:{label:"CPU",color:"#60a5fa"},mem:{label:"RAM",color:"#a78bfa"}},W={"1h":"1h","6h":"6h","24h":"24h","7d":"7d"},z={"1h":36e5,"6h":216e5,"24h":864e5,"7d":6048e5},ve={"1h":6e5,"6h":36e5,"24h":108e5,"7d":864e5};function be(o,x){const n=new Date(o);return x==="7d"?`${n.getMonth()+1}/${n.getDate()}`:`${String(n.getHours()).padStart(2,"0")}:${String(n.getMinutes()).padStart(2,"0")}`}function $e(){const[o,x]=i.useState([]),[n,l]=i.useState([]),[a,c]=i.useState(null),[u,h]=i.useState("24h"),[k,v]=i.useState([]),[b,$]=i.useState(()=>Date.now()),[C,T]=i.useState(!1),{setNode:w}=te();i.useEffect(()=>(w(e.jsx("span",{className:"text-sm font-medium",children:"Mac Resources"})),()=>w(null)),[w]);const R=i.useCallback(t=>{t.type==="agents:listed"&&x(t.sessions??[])},[]),{send:N,connected:m}=Q(R);i.useEffect(()=>{if(!m)return;N({type:"agents:list"});const t=setInterval(()=>N({type:"agents:list"}),1e4);return()=>clearInterval(t)},[m,N]),i.useEffect(()=>{fetch("/api/v1/agents",{credentials:"include"}).then(t=>t.ok?t.json():[]).then(l)},[]);const p=o.map(t=>t.agentName).filter(Boolean),d=[...new Set([...p,...n])],S=new Set(p);i.useEffect(()=>{!a&&d.length>0&&c(d[0])},[d.join(",")]),i.useEffect(()=>{a&&(T(!0),fetch(`/api/v1/agents/${encodeURIComponent(a)}/resources?range=${u}`,{credentials:"include"}).then(t=>t.ok?t.json():[]).then(t=>{v(t),$(Date.now())}).finally(()=>T(!1)))},[a,u]);const M=k.map(t=>({time:t.recorded_at,cpu:Math.round(t.cpu_percent*10)/10,mem:Math.round(t.mem_percent*10)/10}));return e.jsxs("div",{className:"flex h-full min-h-0",children:[e.jsxs("aside",{"aria-labelledby":"macs-heading",className:"w-64 shrink-0 border-r flex flex-col gap-1 p-3 overflow-y-auto",children:[e.jsx("h2",{id:"macs-heading",className:"px-2 pb-1 font-mono text-xs font-medium text-muted-foreground uppercase tracking-wider",children:"Macs"}),d.length===0?e.jsx("span",{className:"px-2 text-sm text-muted-foreground",children:m?"No agents yet.":"Connecting…"}):d.map(t=>{const y=S.has(t),g=a===t;return e.jsxs("button",{onClick:()=>c(t),className:["flex items-center gap-2 rounded-md px-2 py-2 text-left text-sm hover:bg-accent transition-colors",g?"bg-accent font-medium":""].join(" "),children:[e.jsx("span",{className:`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${y?"bg-emerald-400":"bg-muted-foreground/40"}`}),e.jsx("span",{className:"truncate min-w-0",children:t})]},t)})]}),e.jsx("div",{className:"flex-1 min-w-0 overflow-auto",children:a?e.jsxs("div",{className:"flex flex-col gap-6 p-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h1",{className:"text-base font-semibold",children:a}),e.jsx(Z,{value:u,onValueChange:t=>h(t),children:e.jsx(K,{children:Object.keys(W).map(t=>e.jsx(ee,{value:t,children:W[t]},t))})})]}),C?e.jsx("div",{className:"flex h-40 items-center justify-center text-sm text-muted-foreground",children:"Loading…"}):M.length===0?e.jsx("div",{className:"flex h-40 items-center justify-center text-sm text-muted-foreground",children:"No data yet for this range. Data is collected every minute while the agent is connected."}):e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx(X,{title:"CPU %",color:"cpu",data:M,dataKey:"cpu",range:u,now:b}),e.jsx(X,{title:"RAM %",color:"mem",data:M,dataKey:"mem",range:u,now:b})]})]}):e.jsxs("div",{className:"flex h-full items-center justify-center gap-2 text-muted-foreground",children:[e.jsx(se,{className:"h-8 w-8"}),e.jsx("p",{className:"text-sm",children:"Select a Mac to view resource history."})]})})]})}const A=o=>new Date(o.time).getTime(),H=o=>new Date(o.time).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),P=o=>`${Math.round(o*10)/10}%`,ye=ge(A).left,f={top:8,right:24,bottom:24,left:40},L=16;function X({title:o,color:x,data:n,dataKey:l,range:a,now:c}){const u=je[x].color;return e.jsxs("div",{className:"rounded-lg border p-4 flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-full",style:{background:u}}),e.jsx("h2",{className:"text-sm font-medium",children:o})]}),e.jsx("div",{className:"relative h-[220px] w-full",children:e.jsx(pe,{children:({width:h,height:k})=>h>0&&k>0?e.jsx(ke,{width:h,height:k,data:n,dataKey:l,hex:u,range:a,now:c,label:o}):null})})]})}function ke({width:o,height:x,data:n,dataKey:l,hex:a,range:c,now:u,label:h}){const{showTooltip:k,hideTooltip:v,tooltipData:b,tooltipLeft:$,tooltipTop:C}=ne(),T=`chart-hint-${l}`,[w,R]=i.useState(null),N=Math.max(0,n.length-1),m=w===null?N:Math.min(w,N),p=o-f.left-f.right,d=x-f.top-f.bottom,S=ve[c],M=Math.ceil(u/S)*S,t=M-z[c],y=oe({domain:[t,M],range:[L,Math.max(L,p-L)]}),g=re({domain:[0,100],range:[d,L]}),Y=Array.from({length:z[c]/S+1},(s,r)=>new Date(t+r*S)),O=`fill-${l}`,_=`plot-${l}`,I=s=>{const r=n[s];r&&(R(s),k({tooltipData:r,tooltipLeft:y(A(r)),tooltipTop:g(r[l])}))},q=s=>{if(n.length===0)return;if(s.key==="Escape"){v();return}const r=m,j=s.key==="ArrowLeft"||s.key==="ArrowDown"?Math.max(0,r-1):s.key==="ArrowRight"||s.key==="ArrowUp"?Math.min(n.length-1,r+1):s.key==="Home"?0:s.key==="End"?n.length-1:null;j!==null&&(s.preventDefault(),I(j))},B=s=>{const r=xe(s);if(!r)return;const j=y.invert(r.x-f.left).getTime(),F=ye(n,j),D=n[F-1],E=n[F],U=D&&E?j-A(D)<A(E)-j?D:E:D??E;U&&I(n.indexOf(U))},G=n[n.length-1],J=s=>`${h}, ${H(s)}, ${P(s[l])}`;return e.jsxs(e.Fragment,{children:[e.jsxs("svg",{width:o,height:x,role:"group","aria-label":G?`${h}, last ${c}. Latest ${P(G[l])}.`:`${h}, last ${c}. No samples.`,children:[e.jsx(ae,{id:O,from:a,to:a,fromOpacity:.3,toOpacity:0,fromOffset:"5%",toOffset:"95%"}),e.jsx("clipPath",{id:_,children:e.jsx("rect",{x:0,y:0,width:Math.max(0,p),height:Math.max(0,d)})}),e.jsxs(ie,{left:f.left,top:f.top,children:[e.jsx(le,{scale:g,width:p,tickValues:[0,25,50,75,100],strokeDasharray:"3 3",stroke:"hsl(var(--border))"}),e.jsxs("g",{clipPath:`url(#${_})`,children:[e.jsx(ce,{data:n,x:s=>y(A(s)),y:s=>g(s[l]),yScale:g,curve:V,fill:`url(#${O})`}),e.jsx(de,{data:n,x:s=>y(A(s)),y:s=>g(s[l]),curve:V,stroke:a,strokeWidth:1.5})]}),e.jsx(ue,{top:d,scale:y,tickValues:Y,tickFormat:s=>be(new Date(+s).toISOString(),c),hideAxisLine:!0,hideTicks:!0,tickLength:0,tickLabelProps:(s,r,j)=>({fontSize:11,fill:"currentColor",textAnchor:r===0?"start":r===j.length-1?"end":"middle",dy:6,className:"fill-muted-foreground"})}),e.jsx(he,{scale:g,tickValues:[0,25,50,75,100],tickFormat:s=>`${s}%`,hideAxisLine:!0,hideTicks:!0,tickLabelProps:()=>({fontSize:11,fill:"currentColor",textAnchor:"end",dx:-4,dy:3,className:"fill-muted-foreground"})}),b&&e.jsxs("g",{style:{transition:"transform 0.25s ease-out",transform:`translateX(${$??0}px)`},pointerEvents:"none",children:[e.jsx(me,{from:{x:0,y:L},to:{x:0,y:d},stroke:"hsl(var(--border))",strokeWidth:1}),e.jsx("circle",{cx:0,cy:0,r:3,fill:a,stroke:"hsl(var(--background))",strokeWidth:1.5,style:{transition:"transform 0.25s ease-out",transform:`translateY(${C??0}px)`}})]}),e.jsx(fe,{x:0,y:0,width:Math.max(0,p),height:Math.max(0,d),fill:"transparent",tabIndex:0,role:"slider","aria-label":`${h} samples`,"aria-valuemin":0,"aria-valuemax":Math.max(0,n.length-1),"aria-valuenow":m,"aria-valuetext":n[m]?J(n[m]):void 0,"aria-describedby":T,className:"outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",onFocus:()=>I(m),onBlur:v,onKeyDown:q,onMouseMove:B,onMouseLeave:v,onTouchMove:B,onTouchEnd:v,onTouchCancel:v})]})]}),e.jsx("p",{id:T,className:"sr-only",children:"Use the arrow keys to read individual samples. Escape hides the reading."}),b&&e.jsxs("div",{"aria-hidden":"true",className:"pointer-events-none absolute top-0 left-0 whitespace-nowrap rounded-lg border bg-background px-3 py-2 text-xs text-foreground shadow-md",style:{transform:`translate(${($??0)+f.left}px, ${(C??0)+f.top}px) translate(${($??0)>p*.6?"calc(-100% - 12px)":"12px"}, -50%)`,transition:"transform 0.25s ease-out"},children:[e.jsxs("p",{className:"mb-1",children:["Date:"," ",H(b)]}),e.jsxs("p",{children:[h,": ",P(b[l])]})]})]})}export{ke as AreaChartInner,$e as MacResources};