@tapflowio/relay 0.17.0 → 0.19.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 (99) hide show
  1. package/README.md +1 -1
  2. package/dist/RelayServer.d.ts +313 -2
  3. package/dist/RelayServer.d.ts.map +1 -1
  4. package/dist/RelayServer.js +1245 -211
  5. package/dist/RelayServer.js.map +1 -1
  6. package/dist/SessionManager.d.ts +124 -21
  7. package/dist/SessionManager.d.ts.map +1 -1
  8. package/dist/SessionManager.js +201 -22
  9. package/dist/SessionManager.js.map +1 -1
  10. package/dist/index.d.ts +0 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/types.d.ts +3 -44
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/types.js +13 -0
  15. package/dist/types.js.map +1 -1
  16. package/package.json +10 -8
  17. package/public/assets/{AppCenter-BRmG2FEm.js → AppCenter-DyP0aqfF.js} +2 -2
  18. package/public/assets/AppCenter-DyP0aqfF.js.br +0 -0
  19. package/public/assets/Default-D7ScPE30.js +1 -0
  20. package/public/assets/Default-D7ScPE30.js.br +0 -0
  21. package/public/assets/Invite-UmhV5rAf.js +1 -0
  22. package/public/assets/Invite-UmhV5rAf.js.br +0 -0
  23. package/public/assets/MacResources-MS4E00w3.js +1 -0
  24. package/public/assets/MacResources-MS4E00w3.js.br +0 -0
  25. package/public/assets/NotFound-BoDDivK5.js +1 -0
  26. package/public/assets/NotFound-BoDDivK5.js.br +0 -0
  27. package/public/assets/QASession-CjgJHDZ3.js +125 -0
  28. package/public/assets/QASession-CjgJHDZ3.js.br +0 -0
  29. package/public/assets/ResetPassword-CAlB6CfP.js +1 -0
  30. package/public/assets/ResetPassword-CAlB6CfP.js.br +0 -0
  31. package/public/assets/Setup-CPm2-hPJ.js +1 -0
  32. package/public/assets/Setup-CPm2-hPJ.js.br +0 -0
  33. package/public/assets/{Team-D1iwg2vL.js → Team-GEIzrM1D.js} +2 -2
  34. package/public/assets/Team-GEIzrM1D.js.br +0 -0
  35. package/public/assets/Tokens-DSeBz_CJ.js +1 -0
  36. package/public/assets/Tokens-DSeBz_CJ.js.br +0 -0
  37. package/public/assets/alert-dialog-BsXI9SVV.js +1 -0
  38. package/public/assets/alert-dialog-BsXI9SVV.js.br +0 -0
  39. package/public/assets/badge-BkdYQFsh.js +1 -0
  40. package/public/assets/badge-BkdYQFsh.js.br +0 -0
  41. package/public/assets/{build-format-BZV6gt41.js → build-format-CXuQt1X2.js} +3 -3
  42. package/public/assets/build-format-CXuQt1X2.js.br +0 -0
  43. package/public/assets/dialog-DuXZpbiF.js +11 -0
  44. package/public/assets/dialog-DuXZpbiF.js.br +0 -0
  45. package/public/assets/index-Bk2hqaHZ.css +1 -0
  46. package/public/assets/index-Bk2hqaHZ.css.br +0 -0
  47. package/public/assets/index-bitr6DIC.js +215 -0
  48. package/public/assets/index-bitr6DIC.js.br +0 -0
  49. package/public/assets/{pencil-BGrOEXS6.js → pencil-iRR275s8.js} +1 -1
  50. package/public/assets/pencil-iRR275s8.js.br +0 -0
  51. package/public/assets/table-CHmhGpHG.js +1 -0
  52. package/public/assets/table-CHmhGpHG.js.br +0 -0
  53. package/public/assets/tabs-BnbeuAOe.js +1 -0
  54. package/public/assets/tabs-BnbeuAOe.js.br +0 -0
  55. package/public/assets/{trash-2-CwlFrbEF.js → trash-2-QI162w2K.js} +1 -1
  56. package/public/assets/trash-2-QI162w2K.js.br +0 -0
  57. package/public/assets/vendor-charts-DyX5CBcf.js +5 -0
  58. package/public/assets/vendor-charts-DyX5CBcf.js.br +0 -0
  59. package/public/assets/vendor-react-AJpf4YZ0.js +49 -0
  60. package/public/assets/vendor-react-AJpf4YZ0.js.br +0 -0
  61. package/public/assets/vendor-router-ChFy8CZ1.js +12 -0
  62. package/public/assets/vendor-router-ChFy8CZ1.js.br +0 -0
  63. package/public/index.html +4 -2
  64. package/public/index.html.br +0 -0
  65. package/public/assets/AppCenter-BRmG2FEm.js.br +0 -0
  66. package/public/assets/Default-DTr0wqds.js +0 -1
  67. package/public/assets/Default-DTr0wqds.js.br +0 -0
  68. package/public/assets/Invite-DKsNh2GB.js +0 -1
  69. package/public/assets/Invite-DKsNh2GB.js.br +0 -0
  70. package/public/assets/MacResources-CLDdcibL.js +0 -5
  71. package/public/assets/MacResources-CLDdcibL.js.br +0 -0
  72. package/public/assets/NotFound-BtKq2uv6.js +0 -1
  73. package/public/assets/NotFound-BtKq2uv6.js.br +0 -0
  74. package/public/assets/QASession-B_5aJ67l.js +0 -130
  75. package/public/assets/QASession-B_5aJ67l.js.br +0 -0
  76. package/public/assets/ResetPassword-gp6hVQrf.js +0 -1
  77. package/public/assets/ResetPassword-gp6hVQrf.js.br +0 -0
  78. package/public/assets/Setup-DiG4Nbs7.js +0 -1
  79. package/public/assets/Setup-DiG4Nbs7.js.br +0 -0
  80. package/public/assets/Team-D1iwg2vL.js.br +0 -0
  81. package/public/assets/Tokens-DGtE4Xcy.js +0 -1
  82. package/public/assets/Tokens-DGtE4Xcy.js.br +0 -0
  83. package/public/assets/alert-dialog-CXwkFlF3.js +0 -1
  84. package/public/assets/alert-dialog-CXwkFlF3.js.br +0 -0
  85. package/public/assets/badge-CavXTq2x.js +0 -1
  86. package/public/assets/badge-CavXTq2x.js.br +0 -0
  87. package/public/assets/build-format-BZV6gt41.js.br +0 -0
  88. package/public/assets/dialog-JbKwqqS0.js +0 -11
  89. package/public/assets/dialog-JbKwqqS0.js.br +0 -0
  90. package/public/assets/index-CBnxiD7-.js +0 -274
  91. package/public/assets/index-CBnxiD7-.js.br +0 -0
  92. package/public/assets/index-Ctx3_cYz.css +0 -1
  93. package/public/assets/index-Ctx3_cYz.css.br +0 -0
  94. package/public/assets/pencil-BGrOEXS6.js.br +0 -0
  95. package/public/assets/table-CqOA0Bb1.js +0 -1
  96. package/public/assets/table-CqOA0Bb1.js.br +0 -0
  97. package/public/assets/tabs-BVBbhCFG.js +0 -1
  98. package/public/assets/tabs-BVBbhCFG.js.br +0 -0
  99. package/public/assets/trash-2-CwlFrbEF.js.br +0 -0
@@ -1,35 +1,66 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import { WebSocket } from 'ws';
3
- import { ValidationError } from '@tapflowio/agent-core';
4
3
  const DEFAULT_IDLE_TIMEOUT_MS = parseInt(process.env['IDLE_TIMEOUT_MS'] ?? String(5 * 60 * 1000));
5
4
  export class SessionManager {
6
5
  sessions = new Map();
7
6
  agentResources = new Map();
8
7
  agentSocketIndex = new Map();
9
8
  streamSocketIndex = new Map();
9
+ /**
10
+ * Which sessions a browser socket holds. **A set, because the relation is one-to-many** — and it was a
11
+ * single `Session` until #507 was diagnosed, which is the whole of that defect.
12
+ *
13
+ * `mcp-server` opens exactly one socket (`client.ts`, one `new WebSocket`) and sends a `session:start`
14
+ * per device, because an LLM can hold several sessions at once and its waiters are keyed per session.
15
+ * With one slot per socket, the second join silently overwrote the first — `A.browserSocket` still
16
+ * pointed at the socket, so *commands* kept working, and only the reverse lookup lost A. The close
17
+ * handler resolves through that lookup, so **A was never released**: `busy: true` for the life of the
18
+ * relay, no idle timer, and a device left booted with nobody watching it.
19
+ *
20
+ * That is also why the obvious reading of #507 — "release the previous session when a socket joins
21
+ * another" — is a regression rather than a fix. Two independent design reviews reached it separately.
22
+ */
10
23
  browserSocketIndex = new Map();
11
24
  idleTimeoutMs;
12
25
  constructor(options = {}) {
13
26
  this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
14
27
  }
28
+ /**
29
+ * The single place a session's fields are computed from an `agent:register`. `create()` spreads
30
+ * it and `rebind()` assigns it, so neither one names these fields itself — a field added here
31
+ * reaches both paths, and `rebind` is the one that would otherwise be forgotten.
32
+ *
33
+ * What is left out is what a register cannot change: the session's own id and sockets, and
34
+ * `deviceId`, which is the key the rebind matched on in the first place.
35
+ */
36
+ static agentFields(agent, device) {
37
+ return {
38
+ agentId: agent.agentId,
39
+ agentName: agent.agentName,
40
+ agentPlatform: agent.agentPlatform,
41
+ agentCapabilities: agent.agentCapabilities,
42
+ deviceName: device.name,
43
+ devicePlatform: device.platform,
44
+ deviceStatus: device.status,
45
+ deviceOsVersion: device.osVersion,
46
+ };
47
+ }
15
48
  create(agentSocket, devices = [], agentName, agentPlatform, agentId, agentCapabilities) {
16
49
  const agentIds = this.agentSocketIndex.get(agentSocket) ?? new Set();
50
+ const agent = { agentId, agentName, agentPlatform, agentCapabilities };
17
51
  return devices.map((d) => {
18
52
  const id = randomUUID();
19
53
  this.sessions.set(id, {
20
54
  id,
21
- agentId,
22
- agentName,
23
- agentPlatform,
24
- agentCapabilities,
55
+ ...SessionManager.agentFields(agent, d),
25
56
  agentSocket,
26
57
  browserSocket: null,
58
+ owner: null,
59
+ ownerMinted: false,
60
+ ownerUser: null,
27
61
  streamSocket: null,
28
62
  deviceId: d.id,
29
- deviceName: d.name,
30
- devicePlatform: d.platform,
31
- deviceStatus: d.status,
32
- deviceOsVersion: d.osVersion,
63
+ readySent: false,
33
64
  idleTimer: null,
34
65
  });
35
66
  agentIds.add(id);
@@ -63,27 +94,86 @@ export class SessionManager {
63
94
  }
64
95
  return Array.from(sockets);
65
96
  }
97
+ /** Sessions currently claiming a device id. More than one only while a held session (#426) has
98
+ * not yet been reclaimed or given up on. */
99
+ getAllByDeviceId(deviceId) {
100
+ return Array.from(this.sessions.values()).filter((s) => s.deviceId === deviceId);
101
+ }
66
102
  getByStreamSocket(ws) {
67
103
  return this.streamSocketIndex.get(ws);
68
104
  }
105
+ /** Every session this socket holds. **Plural**, and the caller must treat it as such — the close
106
+ * handler releasing only the first is the defect the index comment above describes. */
69
107
  getByBrowserSocket(ws) {
70
- return this.browserSocketIndex.get(ws);
108
+ return [...(this.browserSocketIndex.get(ws) ?? [])];
71
109
  }
72
- join(sessionId, browserSocket) {
110
+ /** Drop `session` from its browser socket's set, and the key with it when the set empties. Leaving an
111
+ * empty `Set` behind would keep a closed socket referenced for the life of the relay. */
112
+ unindexBrowser(session) {
113
+ const ws = session.browserSocket;
114
+ if (!ws)
115
+ return;
116
+ const held = this.browserSocketIndex.get(ws);
117
+ if (!held)
118
+ return;
119
+ held.delete(session);
120
+ if (held.size === 0)
121
+ this.browserSocketIndex.delete(ws);
122
+ }
123
+ /**
124
+ * @returns `not-found` and `held-by-another` rather than throwing them, **so an unexpected failure and
125
+ * an expected one stop sharing a channel.** `session:start` answered both from one `catch`, and
126
+ * the comment there said reaching it meant something the handler did not anticipate — while the
127
+ * most common way to reach it was a socket re-joining the session it already holds (#515). An
128
+ * expected failure that travels as an exception is indistinguishable from a bug by the time it
129
+ * is caught, and the handler then has to guess a `reason`.
130
+ */
131
+ join(sessionId, browserSocket, owner, isAlive) {
73
132
  const session = this.sessions.get(sessionId);
74
133
  if (!session)
75
- throw new ValidationError(`Session not found: ${sessionId}`);
76
- if (session.browserSocket?.readyState === WebSocket.OPEN) {
77
- throw new ValidationError(`Session busy: ${sessionId}`);
134
+ return { ok: false, failure: 'not-found' };
135
+ // **Three conditions, and each one is an issue.** A session is occupied only when someone *else* holds
136
+ // it, on a socket that is open, and that socket is answering.
137
+ //
138
+ // - `owner !== owner` is #527 and #515: a re-join by the same client is idempotent whether or not the
139
+ // socket is the same one, which is what makes a tab's four sockets one holder and an automatic
140
+ // reconnect a takeover rather than a refusal.
141
+ // - `readyState === OPEN` was the whole test, and it is not a liveness signal. A laptop that went to
142
+ // sleep leaves it OPEN until TCP or the heartbeat notices.
143
+ // - `isAlive` is that signal, passed in because liveness lives on the server rather than here — as a
144
+ // predicate over the socket rather than a thunk, so it is applied to *this* session's holder and
145
+ // cannot be closed over a stale one. `list()` below takes the same shape for the same reason.
146
+ // #579 is the gap between `readyState` and this.
147
+ if (session.browserSocket &&
148
+ session.owner !== null &&
149
+ session.owner !== owner.key &&
150
+ session.browserSocket.readyState === WebSocket.OPEN &&
151
+ isAlive(session.browserSocket)) {
152
+ return { ok: false, failure: 'held-by-another' };
78
153
  }
79
154
  if (session.idleTimer) {
80
155
  clearTimeout(session.idleTimer);
81
156
  session.idleTimer = null;
82
157
  }
83
- if (session.browserSocket)
84
- this.browserSocketIndex.delete(session.browserSocket);
158
+ // Unconditional, and **the order is what makes it safe**: this releases the session from whichever
159
+ // socket held it, which on a re-join is the socket joining. Removing and re-adding the same entry is a
160
+ // no-op; doing it *after* the add below would delete the entry this join just made, leaving the
161
+ // session bound for commands and invisible to the close handler — #507 rebuilt one method over.
162
+ //
163
+ // A guard reading `!== browserSocket` stood here with that reasoning written as its justification. It
164
+ // was dead: mutation testing removed the guard and every test still passed, because the add follows.
165
+ this.unindexBrowser(session);
85
166
  session.browserSocket = browserSocket;
86
- this.browserSocketIndex.set(browserSocket, session);
167
+ session.owner = owner.key;
168
+ session.ownerMinted = owner.minted;
169
+ session.ownerUser = owner.user;
170
+ let held = this.browserSocketIndex.get(browserSocket);
171
+ if (!held) {
172
+ held = new Set();
173
+ this.browserSocketIndex.set(browserSocket, held);
174
+ }
175
+ held.add(session);
176
+ return { ok: true };
87
177
  }
88
178
  remove(sessionId) {
89
179
  const session = this.sessions.get(sessionId);
@@ -95,8 +185,7 @@ export class SessionManager {
95
185
  }
96
186
  if (session.streamSocket)
97
187
  this.streamSocketIndex.delete(session.streamSocket);
98
- if (session.browserSocket)
99
- this.browserSocketIndex.delete(session.browserSocket);
188
+ this.unindexBrowser(session);
100
189
  const agentIds = this.agentSocketIndex.get(session.agentSocket);
101
190
  agentIds?.delete(sessionId);
102
191
  if (agentIds?.size === 0)
@@ -108,9 +197,12 @@ export class SessionManager {
108
197
  if (!session)
109
198
  return;
110
199
  if (session.browserSocket) {
111
- this.browserSocketIndex.delete(session.browserSocket);
200
+ this.unindexBrowser(session);
112
201
  session.browserSocket = null;
113
202
  }
203
+ session.owner = null;
204
+ session.ownerMinted = false;
205
+ session.ownerUser = null;
114
206
  if (session.idleTimer) {
115
207
  clearTimeout(session.idleTimer);
116
208
  session.idleTimer = null;
@@ -122,6 +214,51 @@ export class SessionManager {
122
214
  }, this.idleTimeoutMs);
123
215
  }
124
216
  }
217
+ /**
218
+ * Re-point an existing session at the socket of an agent that just restarted, keeping its id.
219
+ *
220
+ * Everything a rebind touches lives here rather than at the call site, and that is deliberate:
221
+ * the index move below has an order requirement that is invisible where it is used, and the
222
+ * field refresh has to stay in step with `create()`. Written inline in `RelayServer`, the next
223
+ * field added to `create()` would be missed on this path alone, and silently.
224
+ */
225
+ rebind(sessionId, agentSocket, device, agent) {
226
+ const session = this.sessions.get(sessionId);
227
+ if (!session)
228
+ return;
229
+ const old = session.agentSocket;
230
+ // Drop from the old socket's set BEFORE reassigning. `remove()` dereferences the index through
231
+ // `session.agentSocket`, and following that idiom here would delete the id from the *new* set
232
+ // and leave the old one holding it — so the old socket's close, which fires late after an
233
+ // unclean drop, would evict the session that was just re-pointed.
234
+ const oldIds = this.agentSocketIndex.get(old);
235
+ oldIds?.delete(sessionId);
236
+ if (oldIds?.size === 0)
237
+ this.agentSocketIndex.delete(old);
238
+ session.agentSocket = agentSocket;
239
+ const ids = this.agentSocketIndex.get(agentSocket) ?? new Set();
240
+ ids.add(sessionId);
241
+ this.agentSocketIndex.set(agentSocket, ids);
242
+ // The stream died with the old process. `old.terminate()` only closes the control socket, so
243
+ // nothing else would clear this.
244
+ this.clearStreamSocket(sessionId);
245
+ // `clearStreamSocket` returns early when there is no stream socket, and a session that was
246
+ // never streamed has none — so this cannot be left to it.
247
+ session.readySent = false;
248
+ // Same argument as `readySent`, two fields over: `handleSessionStart` replays both to a browser
249
+ // that joins now, and both were measured by the process that just died. A viewer's own
250
+ // `device:boot` would clear them a moment later via `device:booting`, but an MCP-attached
251
+ // session never boots on its own and would keep them for as long as it lives.
252
+ session.chromeData = undefined;
253
+ session.deviceInfo = undefined;
254
+ Object.assign(session, SessionManager.agentFields(agent, device));
255
+ // Not a carry-over guard — resources are keyed by socket, so re-pointing the session at a new
256
+ // one already leaves the old reading behind, and every reader goes through
257
+ // `session.agentSocket`. This is the leak: `evictAgentSocket` drops the entry, but it returns
258
+ // early when the socket has no sessions left, which is precisely the case where every one of
259
+ // them was rebound. Without this line the map keeps a dead socket per restart, forever.
260
+ this.agentResources.delete(old);
261
+ }
125
262
  setResources(agentSocket, resources) {
126
263
  this.agentResources.set(agentSocket, resources);
127
264
  }
@@ -138,6 +275,9 @@ export class SessionManager {
138
275
  session.chromeData = undefined;
139
276
  session.deviceInfo = undefined;
140
277
  session.deviceStatus = 'shutdown';
278
+ // Called on `device:booting`: whatever we announced before is no longer true, and replaying it
279
+ // to a browser that joins mid-boot would promise a stream that is being torn down.
280
+ session.readySent = false;
141
281
  }
142
282
  setStreamSocket(sessionId, ws) {
143
283
  const session = this.sessions.get(sessionId);
@@ -148,12 +288,16 @@ export class SessionManager {
148
288
  session.streamSocket = ws;
149
289
  this.streamSocketIndex.set(ws, session);
150
290
  }
291
+ /** The stream socket is the stream. Losing it means whatever we announced is no longer true —
292
+ * and this is the only signal for it on the paths where the agent never reports back, such as a
293
+ * `simctl shutdown` that throws after the streamer has already been torn down. */
151
294
  clearStreamSocket(sessionId) {
152
295
  const session = this.sessions.get(sessionId);
153
296
  if (!session?.streamSocket)
154
297
  return;
155
298
  this.streamSocketIndex.delete(session.streamSocket);
156
299
  session.streamSocket = null;
300
+ session.readySent = false;
157
301
  }
158
302
  setChromeData(sessionId, data) {
159
303
  const session = this.sessions.get(sessionId);
@@ -165,15 +309,42 @@ export class SessionManager {
165
309
  if (session)
166
310
  session.deviceInfo = info;
167
311
  }
312
+ setReadySent(sessionId, value) {
313
+ const session = this.sessions.get(sessionId);
314
+ if (session)
315
+ session.readySent = value;
316
+ }
168
317
  updateDeviceStatus(sessionId, status) {
169
318
  const session = this.sessions.get(sessionId);
170
319
  if (session)
171
320
  session.deviceStatus = status;
172
321
  }
173
- list() {
322
+ /**
323
+ * @param asker the owner key of the socket that asked, so `busy` can mean *busy for you*.
324
+ * @param isAlive whether a holder's socket is answering — the same predicate occupancy uses.
325
+ *
326
+ * **`busy` has to agree with the occupancy test or the UI locks a tester out of their own session.**
327
+ * `browserSocket !== null` said "someone holds it", which is a different question from "you cannot have
328
+ * it": `QASession` renders `disabled={isBusy}`, so a tester whose socket reconnected automatically found
329
+ * their own device greyed out with no way to reach the takeover that would have worked. And a holder
330
+ * that has stopped answering keeps the card locked for everyone until the sweep notices.
331
+ *
332
+ * Passing the same `isAlive` rather than a second liveness rule is the point — two predicates that
333
+ * disagree would flash a device as free while a join for it is still refused.
334
+ */
335
+ list(asker, isAlive) {
174
336
  // Group sessions by agentSocket
175
337
  const agentMap = new Map();
176
338
  for (const session of this.sessions.values()) {
339
+ // A session whose agent socket is closed is being held for a returning agent (#426). It is
340
+ // not something anyone can pick right now, and listing it is worse than leaving it out: the
341
+ // card would render with the dead agent's last CPU/RAM reading and no warning — the `Stale`
342
+ // badge keys off a 30s-old resource sample, far longer than the window. Worse, if the agent
343
+ // comes back under a different identity (adding an agentId is a common reason to upgrade,
344
+ // and upgrading is a common reason to restart) nothing rebinds, and the dashboard groups by
345
+ // `agentName` — two groups, a duplicate React key, and the lookup picking the dead one.
346
+ if (session.agentSocket.readyState !== WebSocket.OPEN)
347
+ continue;
177
348
  const group = agentMap.get(session.agentSocket) ?? [];
178
349
  group.push(session);
179
350
  agentMap.set(session.agentSocket, group);
@@ -189,7 +360,15 @@ export class SessionManager {
189
360
  status: s.deviceStatus,
190
361
  osVersion: s.deviceOsVersion,
191
362
  sessionId: s.id,
192
- busy: s.browserSocket !== null,
363
+ busy: s.owner !== null &&
364
+ s.owner !== asker &&
365
+ s.browserSocket !== null &&
366
+ // The clause that was missing, and its absence was the mirror of the failure the docstring warns
367
+ // about: a socket in CLOSING has not fired `close` yet, so `isAlive` is still true — the card
368
+ // read `busy` while a join for it would have succeeded, locking every other tester out of a
369
+ // device the relay was ready to hand them.
370
+ s.browserSocket.readyState === WebSocket.OPEN &&
371
+ isAlive(s.browserSocket),
193
372
  })),
194
373
  }));
195
374
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../src/SessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../src/SessionManager.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -11,5 +11,4 @@ export { startTlsBackgroundTasks } from './lib/tlsTasks.js';
11
11
  export type { DnsProviderEntry } from './lib/cert/index.js';
12
12
  export type { TlsConfig } from './lib/cert/index.js';
13
13
  export type { Session } from './SessionManager.js';
14
- export type { RelayMessage, MessageType } from './types.js';
15
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAA;AACrF,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACnF,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC/G,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACvD,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAA;AACrF,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACnF,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC/G,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA"}
package/dist/types.d.ts CHANGED
@@ -1,47 +1,6 @@
1
- export type MessageType = 'agent:register' | 'agent:registered' | 'agent:resources' | 'agents:list' | 'agents:listed' | 'session:start' | 'session:joined' | 'session:chrome' | 'session:deviceInfo' | 'session:end' | 'session:leave' | 'stream:register' | 'stream:registered' | 'device:boot' | 'device:booting' | 'device:ready' | 'device:boot-error' | 'device:shutdown' | 'device:shutdown-done' | 'app:install' | 'app:install-done' | 'app:install-error' | 'app:launch' | 'app:launch-done' | 'app:launch-error' | 'open-url' | 'open-url:done' | 'open-url:error' | 'app:clear-state' | 'app:clear-state-done' | 'app:clear-state-error' | 'input:touch:start' | 'input:touch:move' | 'input:touch:end' | 'input:pinch:start' | 'input:pinch:move' | 'input:pinch:end' | 'input:key' | 'input:type' | 'input:type-done' | 'input:type-error' | 'input:done' | 'input:error' | 'input:button' | 'input:rotate' | 'input:keyboard:toggle' | 'keyboard:toggled' | 'screenshot:request' | 'screenshot:done' | 'screenshot:error' | 'ui:tree:request' | 'ui:tree:response' | 'ui:tree:error' | 'clipboard:read' | 'clipboard:write' | 'clipboard:data' | 'clipboard:write-done' | 'clipboard:error' | 'error';
2
1
  import type { AgentResources, UIElement } from '@tapflowio/agent-core';
3
2
  export type { AgentResources, UIElement };
4
- export interface DeviceInfo {
5
- id: string;
6
- name: string;
7
- platform: string;
8
- status: string;
9
- osVersion?: string;
10
- sessionId: string;
11
- busy: boolean;
12
- }
13
- export interface SessionInfo {
14
- agentName?: string;
15
- platform?: string;
16
- resources?: AgentResources;
17
- devices: DeviceInfo[];
18
- }
19
- export interface RelayMessage {
20
- type: MessageType;
21
- sessionId?: string;
22
- payload?: unknown;
23
- message?: string;
24
- agentName?: string;
25
- agentId?: string;
26
- devices?: Array<{
27
- id: string;
28
- name: string;
29
- platform: string;
30
- status: string;
31
- osVersion?: string;
32
- }>;
33
- platform?: string;
34
- capabilities?: string[];
35
- sessions?: SessionInfo[];
36
- registeredSessions?: Array<{
37
- deviceId: string;
38
- sessionId: string;
39
- }>;
40
- buildId?: number;
41
- resources?: AgentResources;
42
- requestId?: string;
43
- data?: string;
44
- format?: 'png' | 'jpeg';
45
- elements?: UIElement[];
46
- }
3
+ import type { DeviceSummary } from '@tapflowio/protocol';
4
+ export type { DeviceDetails, DeviceReport, DeviceSummary, SessionInfo, SessionTerminatedReason } from '@tapflowio/protocol';
5
+ export type DeviceInfo = DeviceSummary;
47
6
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,mBAAmB,GACnB,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,mBAAmB,GACnB,iBAAiB,GACjB,sBAAsB,GACtB,aAAa,GACb,kBAAkB,GAClB,mBAAmB,GACnB,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,UAAU,GACV,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,sBAAsB,GACtB,uBAAuB,GACvB,mBAAmB,GACnB,kBAAkB,GAClB,iBAAiB,GACjB,mBAAmB,GACnB,kBAAkB,GAClB,iBAAiB,GACjB,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,cAAc,GACd,cAAc,GACd,uBAAuB,GACvB,kBAAkB,GAClB,oBAAoB,GACpB,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,sBAAsB,GACtB,iBAAiB,GACjB,OAAO,CAAA;AAEX,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,CAAA;AAEzC,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd;AAGD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,OAAO,EAAE,UAAU,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAGlB,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAA;IAIjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IAEvB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IAExB,kBAAkB,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;IAEvB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAA;CACvB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACtE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,CAAA;AAIzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAE3H,MAAM,MAAM,UAAU,GAAG,aAAa,CAAA"}
package/dist/types.js CHANGED
@@ -1,2 +1,15 @@
1
+ // The wire contract lives in @tapflowio/protocol. This file holds what the relay adds on top of it —
2
+ // today only the re-exports and aliases below.
3
+ //
4
+ // **`RelayMessage` and `MessageType` were removed here (#550).** They were a flat interface where
5
+ // `type` was the only required member and a hand-copied union of 63 literals beside it, and they were
6
+ // the relay's *inbound* type: `route` took a `RelayMessage`, so every field it read was optional by
7
+ // construction and every one it needed came with a `!`. That is why the two type systems could
8
+ // disagree about the same wire field — `format?` here against a required `format` in the protocol —
9
+ // with nothing to report it.
10
+ //
11
+ // What replaced them is not another declaration but a parse: `@tapflowio/protocol/validate` turns an
12
+ // inbound frame into a discriminated union at the door, and the relay's own membership assertions
13
+ // went with the literal list they were holding, because there is no longer a second copy to hold.
1
14
  export {};
2
15
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,+CAA+C;AAC/C,EAAE;AACF,kGAAkG;AAClG,sGAAsG;AACtG,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,6BAA6B;AAC7B,EAAE;AACF,qGAAqG;AACrG,kGAAkG;AAClG,kGAAkG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapflowio/relay",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "WebSocket relay server for tapflow — NAT traversal, session routing, JWT auth, bundled dashboard",
5
5
  "keywords": [
6
6
  "tapflow",
@@ -39,7 +39,7 @@
39
39
  "LICENSE"
40
40
  ],
41
41
  "engines": {
42
- "node": ">=20.12.0"
42
+ "node": ">=22.0.0"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"
@@ -49,24 +49,26 @@
49
49
  "better-sqlite3": "^12.11.1",
50
50
  "busboy": "^1.6.0",
51
51
  "jsonwebtoken": "^9.0.3",
52
- "nodemailer": "^9.0.3",
53
- "ws": "^8.21.1",
52
+ "nodemailer": "^9.0.5",
53
+ "ws": "^8.21.3",
54
54
  "zod": "^4.4.3",
55
- "@tapflowio/agent-core": "0.17.0"
55
+ "@tapflowio/agent-core": "0.19.0",
56
+ "@tapflowio/protocol": "0.19.0"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@types/better-sqlite3": "^7.6.13",
59
60
  "@types/busboy": "^1.5.4",
60
61
  "@types/jsonwebtoken": "^9.0.10",
61
- "@types/node": "^20.19.43",
62
+ "@types/node": "^22.20.1",
62
63
  "@types/nodemailer": "^8.0.1",
63
64
  "@types/ws": "^8.0.0",
64
65
  "typescript": "^5.0.0",
65
- "vitest": "^4.1.10"
66
+ "vitest": "^4.1.10",
67
+ "@tapflowio/test-utils": "0.0.0"
66
68
  },
67
69
  "scripts": {
68
70
  "build": "tsc -b && rm -rf dist/migrations && cp -r src/migrations dist/migrations",
69
- "typecheck": "tsc -b",
71
+ "typecheck": "tsc -b && tsc -p src/__tests__/tsconfig.json",
70
72
  "start": "node dist/server.js",
71
73
  "test": "vitest run",
72
74
  "lint": "eslint src"
@@ -1,4 +1,4 @@
1
- import{W as C,a6 as r,a3 as e,B as y,L as b,a8 as k,J,I as M,S as Q,f as W,ak as Y,al as K}from"./index-CBnxiD7-.js";import{e as X,S as ee,P as se,g as ae,h as te,i as le,b as ne,d as re,s as ce,u as ie}from"./build-format-BZV6gt41.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 oe}from"./dialog-JbKwqqS0.js";import{P as de,T as ue}from"./trash-2-CwlFrbEF.js";import{B as T}from"./badge-CavXTq2x.js";import{A as he,c as xe,f as pe,g as me,d as fe,e as ge,b as je,a as ve}from"./alert-dialog-CXwkFlF3.js";/**
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
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -18,4 +18,4 @@ import{W as C,a6 as r,a3 as e,B as y,L as b,a8 as k,J,I as M,S as Q,f as W,ak as
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.
21
- */const De=[["path",{d:"M12 3v12",key:"1x0j5s"}],["path",{d:"m17 8-5-5-5 5",key:"7q97r8"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}]],Ce=C("upload",De);function Ae({onSuccess:s,appId:l}){const[h,c]=r.useState(!1),[t,g]=r.useState(null),[o,x]=r.useState("none"),j=r.useRef(null);function p(n){if(n.preventDefault(),!t)return;const d=new FormData;d.append("file",t),o!=="none"&&d.append("status",o),l&&d.append("app_id",String(l));const w=fetch("/api/v1/builds",{method:"POST",credentials:"include",body:d}).then(async u=>{if(!u.ok){const m=await u.json().catch(()=>({}));throw new Error(m.error??"Upload failed. Check the file format.")}s()});k.promise(w,{loading:"Uploading build…",success:"Build uploaded",error:u=>u instanceof Error?u.message:"Failed to upload build"}),c(!1),g(null),x("none")}function N(n){c(n),n||(g(null),x("none"))}return e.jsxs(O,{open:h,onOpenChange:N,children:[e.jsx(L,{asChild:!0,children:e.jsxs(y,{size:"sm",children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"}),"Upload build"]})}),e.jsxs(U,{className:"sm:max-w-md",children:[e.jsx(E,{children:e.jsx(V,{children:"Upload build"})}),e.jsxs("form",{onSubmit:p,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"File"}),e.jsx("div",{className:"flex h-24 cursor-pointer items-center justify-center rounded-md border-2 border-dashed text-sm text-muted-foreground hover:border-primary",onClick:()=>{var n;return(n=j.current)==null?void 0:n.click()},onDragOver:n=>n.preventDefault(),onDrop:n=>{n.preventDefault();const d=n.dataTransfer.files[0];d&&g(d)},children:t?t.name:"Click or drag to upload"}),e.jsx("input",{ref:j,type:"file",accept:".zip,.apk,.tgz,.tar.gz,application/gzip,application/x-gzip",className:"hidden",onChange:n=>{var d;return g(((d=n.target.files)==null?void 0:d[0])??null)}}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["iOS: ",e.jsx("code",{children:".app.zip"})," or ",e.jsx("code",{children:".tar.gz"})," / ",e.jsx("code",{children:".tgz"})," (e.g. an EAS simulator build)  · Android: ",e.jsx("code",{children:".apk"})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(b,{children:["Status ",e.jsx("span",{className:"text-muted-foreground",children:"(optional)"})]}),e.jsxs(A,{value:o,onValueChange:x,children:[e.jsx(_,{children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"none",children:"None"}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"outline",className:"w-24",onClick:()=>c(!1),children:"Cancel"}),e.jsx(y,{type:"submit",className:"w-24",disabled:!t,children:"Upload"})]})]})]})]})}function D({className:s,...l}){return e.jsx("span",{className:J("font-mono text-xs tabular-nums tracking-tight",s),...l})}function _e({onSuccess:s}){const[l,h]=r.useState(!1),[c,t]=r.useState(""),[g,o]=r.useState(""),[x,j]=r.useState("ios"),[p,N]=r.useState(""),[n,d]=r.useState(!1);async function w(u){u.preventDefault(),N(""),d(!0);try{const m=await X({name:c.trim(),bundle_id_key:g.trim(),platform:x});if(!m){N("Failed to create app");return}if("error"in m){N(m.error);return}h(!1),t(""),o(""),j("ios"),k.success("App created"),s()}catch{k.error("Failed to create app — check your network")}finally{d(!1)}}return e.jsxs(O,{open:l,onOpenChange:h,children:[e.jsx(L,{asChild:!0,children:e.jsxs("button",{className:"flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-left text-sm text-muted-foreground hover:bg-accent hover:text-foreground transition-colors",children:[e.jsx(de,{className:"size-3.5 shrink-0"}),e.jsx("span",{children:"Add App"})]})}),e.jsxs(U,{className:"sm:max-w-sm",children:[e.jsx(E,{children:e.jsx(V,{children:"Add App"})}),e.jsxs("form",{onSubmit:w,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"app-name",children:"Name"}),e.jsx(M,{id:"app-name",value:c,onChange:u=>t(u.target.value),placeholder:"My App",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"bundle-id",children:"Bundle ID"}),e.jsx(M,{id:"bundle-id",value:g,onChange:u=>o(u.target.value),placeholder:"com.example.myapp",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"platform",children:"Platform"}),e.jsxs(A,{value:x,onValueChange:u=>j(u),children:[e.jsx(_,{id:"platform",children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"ios",children:"iOS"}),e.jsx(i,{value:"android",children:"Android"}),e.jsx(i,{value:"both",children:"Both"})]})]})]}),p&&e.jsx("p",{className:"text-sm text-destructive",children:p}),e.jsx(y,{type:"submit",disabled:n,className:"w-full",children:n?"Creating…":"Create App"})]})]})]})}function Be({apps:s,selectedAppId:l,onSelect:h,onAdd:c}){return e.jsxs("aside",{className:"w-64 shrink-0 border-r flex flex-col gap-1 p-3 overflow-y-auto",children:[e.jsx("span",{className:"px-2 pb-1 font-mono text-xs font-medium text-muted-foreground uppercase tracking-wider",children:"Apps"}),s.length===0&&e.jsx("span",{className:"px-2 text-sm text-muted-foreground",children:"No apps yet"}),s.map(t=>e.jsxs("button",{onClick:()=>h(t.id),className:["flex flex-col gap-0.5 rounded-md px-2 py-2 text-left text-sm hover:bg-accent overflow-hidden",t.id===l?"bg-accent font-medium":""].join(" "),children:[e.jsx("span",{className:"truncate",children:t.name}),e.jsx(D,{className:"text-muted-foreground truncate",children:t.bundle_id_key})]},t.id)),e.jsx("div",{className:"mt-1 border-t pt-1",children:e.jsx(_e,{onSuccess:c})})]})}function ze(s){const l=/[zZ]|[+-]\d{2}:?\d{2}$/.test(s),c=new Date(l?s:s.replace(" ","T")+"Z").getTime()-Date.now();if(c<=0)return{label:"Deleting…",urgent:!0};const t=Math.floor(c/36e5);return t<1?{label:"Deletes in < 1h",urgent:!0}:t<24?{label:`Deletes in ${t}h`,urgent:t<6}:{label:`Deletes in ${Math.floor(t/24)}d`,urgent:!1}}function Ie({build:s,isLast:l,onNavigate:h,onStatusChange:c,onScheduleDeletion:t,onCancelDeletion:g}){const[o,x]=r.useState(!1),j=s.status_label==="Done",p=s.delete_after?ze(s.delete_after):null;function N(n){c(s.id,n==="none"?null:n)}return e.jsxs(e.Fragment,{children:[e.jsx(he,{open:o,onOpenChange:x,children:e.jsxs(xe,{children:[e.jsxs(pe,{children:[e.jsx(me,{children:"Schedule deletion?"}),e.jsx(fe,{children:"Build files will be deleted after 7 days. You can cancel the scheduled deletion anytime before then."})]}),e.jsxs(ge,{children:[e.jsx(je,{children:"Cancel"}),e.jsx(ve,{onClick:()=>{t(s.id),x(!1)},children:"Schedule deletion"})]})]})}),e.jsxs("div",{className:["flex items-center gap-3 px-4 py-3",l?"":"border-b"].join(" "),children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("span",{className:"text-sm font-medium",children:["build ",e.jsx(D,{children:s.build_number??"—"})]}),e.jsx(T,{tone:s.platform==="ios"?"ios":"android",className:"text-xs capitalize",children:s.platform}),s.status_label&&e.jsx(T,{tone:ee[s.status_label],className:"text-xs",children:s.status_label}),p&&e.jsx(T,{tone:p.urgent?"rejected":"backlog",className:"text-xs",children:p.label})]}),e.jsxs("div",{style:{display:"flex",flexDirection:"row",gap:"14px",marginTop:"0.7rem",alignItems:"center"},className:"text-xs text-muted-foreground",children:[s.uploader&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:s.uploader}),e.jsx(Q,{orientation:"vertical",className:"h-3"})]}),e.jsx(D,{children:new Date(s.uploaded_at).toLocaleDateString()})]})]}),e.jsxs(A,{value:s.status_label??"none",onValueChange:N,children:[e.jsx(_,{className:"h-9 w-32 text-xs",children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"none",children:e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]}),p?e.jsx(y,{size:"icon-sm",variant:"outline",onClick:()=>g(s.id),title:"Cancel scheduled deletion",children:e.jsx(ke,{className:"h-3.5 w-3.5"})}):e.jsx(y,{size:"icon-sm",variant:"destructive",onClick:()=>x(!0),title:"Schedule deletion",children:e.jsx(ue,{className:"h-3.5 w-3.5"})}),e.jsxs(y,{size:"sm",onClick:()=>h(s.id),disabled:j,children:[e.jsx(se,{className:"mr-1.5 h-3.5 w-3.5"}),"Start QA"]})]})]})}function Pe({versionName:s,builds:l,isOpen:h,onToggle:c,onNavigate:t,onStatusChange:g,onScheduleDeletion:o,onCancelDeletion:x}){return e.jsxs("div",{className:"rounded-lg shadow-card-2 overflow-hidden",children:[e.jsxs("button",{className:"flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-accent/50 bg-card",onClick:c,children:[h?e.jsx(oe,{className:"h-4 w-4 shrink-0 text-muted-foreground"}):e.jsx(W,{className:"h-4 w-4 shrink-0 text-muted-foreground"}),e.jsx(D,{className:"font-medium text-sm text-foreground",children:s}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["(",l.length," build",l.length>1?"s":"",")"]})]}),h&&e.jsx("div",{className:"border-t bg-card",children:l.map((j,p)=>e.jsx(Ie,{build:j,isLast:p===l.length-1,onNavigate:t,onStatusChange:g,onScheduleDeletion:o,onCancelDeletion:x},j.id))})]})}function Ue(){const s=Y(),[l,h]=K(),[c,t]=r.useState([]),[g,o]=r.useState([]),[x,j]=r.useState(""),[p,N]=r.useState("all"),[n,d]=r.useState(!0),[w,u]=r.useState(new Set),m=l.get("appId")?Number(l.get("appId")):null,F=c.find(a=>a.id===m)??null,I=r.useCallback(async()=>{const a=await ae();t(a),!l.get("appId")&&a.length>0&&h({appId:String(a[0].id)},{replace:!0})},[l,h]),P=r.useCallback(async()=>{if(!m){o([]),d(!1);return}d(!0);try{const a=await te({appId:m,search:x,statusFilter:p});o(a),a.length>0&&w.size===0&&u(new Set([a[0].version_name??"Unversioned"]))}finally{d(!1)}},[m,x,p]);r.useEffect(()=>{I()},[]),r.useEffect(()=>{P()},[P]);function $(a){a!==m&&(o([]),u(new Set)),h({appId:String(a)})}function q(a){u(v=>{const f=new Set(v);return f.has(a)?f.delete(a):f.add(a),f})}async function H(a,v){await ie(a,v),o(f=>f.map(S=>S.id===a?{...S,status_label:v}:S))}async function Z(a){try{const v=await ce(a);o(f=>f.map(S=>S.id===a?{...S,delete_after:v}:S))}catch{k.error("Failed to schedule deletion")}}async function G(a){try{await re(a),o(v=>v.map(f=>f.id===a?{...f,delete_after:null}:f))}catch{k.error("Failed to cancel scheduled deletion")}}const R=le(g);return e.jsxs("div",{className:"flex h-full gap-0",children:[e.jsx(Be,{apps:c,selectedAppId:m,onSelect:$,onAdd:I}),e.jsxs("div",{className:"flex-1 flex flex-col gap-4 p-4 overflow-y-auto min-w-0",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2",children:[e.jsx("h1",{className:"text-xl font-semibold tracking-display-sm",children:F?F.name:"App Center"}),e.jsx(Ae,{onSuccess:()=>{I(),P()},appId:m})]}),m?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(ne,{placeholder:"Search version…",value:x,onChange:j}),e.jsxs(A,{value:p,onValueChange:N,children:[e.jsx(_,{className:"h-8 w-36",children:e.jsx(B,{placeholder:"Status"})}),e.jsxs(z,{children:[e.jsx(i,{value:"all",children:"All statuses"}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]})]}),n?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):R.length===0?e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(we,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No builds yet"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Upload the first build to get started."})]}):e.jsx("div",{className:"flex flex-col gap-2",children:R.map(({versionName:a,builds:v})=>e.jsx(Pe,{versionName:a,builds:v,isOpen:w.has(a),onToggle:()=>q(a),onNavigate:f=>s(`/app-center/build?id=${f}`),onStatusChange:H,onScheduleDeletion:Z,onCancelDeletion:G},a))})]}):e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(Se,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No app selected"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Choose an app from the sidebar to view its builds."})]})]})]})}export{Ue as AppCenter};
21
+ */const De=[["path",{d:"M12 3v12",key:"1x0j5s"}],["path",{d:"m17 8-5-5-5 5",key:"7q97r8"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}]],Ce=C("upload",De);function Ae({onSuccess:s,appId:l}){const[h,c]=r.useState(!1),[t,g]=r.useState(null),[o,x]=r.useState("none"),j=r.useRef(null);function p(n){if(n.preventDefault(),!t)return;const d=new FormData;d.append("file",t),o!=="none"&&d.append("status",o),l&&d.append("app_id",String(l));const w=fetch("/api/v1/builds",{method:"POST",credentials:"include",body:d}).then(async u=>{if(!u.ok){const m=await u.json().catch(()=>({}));throw new Error(m.error??"Upload failed. Check the file format.")}s()});k.promise(w,{loading:"Uploading build…",success:"Build uploaded",error:u=>u instanceof Error?u.message:"Failed to upload build"}),c(!1),g(null),x("none")}function N(n){c(n),n||(g(null),x("none"))}return e.jsxs(O,{open:h,onOpenChange:N,children:[e.jsx(L,{asChild:!0,children:e.jsxs(y,{size:"sm",children:[e.jsx(Ce,{className:"mr-2 h-4 w-4"}),"Upload build"]})}),e.jsxs(U,{className:"sm:max-w-md",children:[e.jsx(E,{children:e.jsx(V,{children:"Upload build"})}),e.jsxs("form",{onSubmit:p,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"grid gap-2",children:[e.jsx(b,{children:"File"}),e.jsx("div",{className:"flex h-24 cursor-pointer items-center justify-center rounded-md border-2 border-dashed text-sm text-muted-foreground hover:border-primary",onClick:()=>{var n;return(n=j.current)==null?void 0:n.click()},onDragOver:n=>n.preventDefault(),onDrop:n=>{n.preventDefault();const d=n.dataTransfer.files[0];d&&g(d)},children:t?t.name:"Click or drag to upload"}),e.jsx("input",{ref:j,type:"file",accept:".zip,.apk,.tgz,.tar.gz,application/gzip,application/x-gzip",className:"hidden",onChange:n=>{var d;return g(((d=n.target.files)==null?void 0:d[0])??null)}}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["iOS: ",e.jsx("code",{children:".app.zip"})," or ",e.jsx("code",{children:".tar.gz"})," / ",e.jsx("code",{children:".tgz"})," (e.g. an EAS simulator build)  · Android: ",e.jsx("code",{children:".apk"})]})]}),e.jsxs("div",{className:"grid gap-2",children:[e.jsxs(b,{children:["Status ",e.jsx("span",{className:"text-muted-foreground",children:"(optional)"})]}),e.jsxs(A,{value:o,onValueChange:x,children:[e.jsx(_,{children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"none",children:"None"}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"outline",className:"w-24",onClick:()=>c(!1),children:"Cancel"}),e.jsx(y,{type:"submit",className:"w-24",disabled:!t,children:"Upload"})]})]})]})]})}function D({className:s,...l}){return e.jsx("span",{className:J("font-mono text-xs tabular-nums tracking-tight",s),...l})}function _e({onSuccess:s}){const[l,h]=r.useState(!1),[c,t]=r.useState(""),[g,o]=r.useState(""),[x,j]=r.useState("ios"),[p,N]=r.useState(""),[n,d]=r.useState(!1);async function w(u){u.preventDefault(),N(""),d(!0);try{const m=await Y({name:c.trim(),bundle_id_key:g.trim(),platform:x});if(!m){N("Failed to create app");return}if("error"in m){N(m.error);return}h(!1),t(""),o(""),j("ios"),k.success("App created"),s()}catch{k.error("Failed to create app — check your network")}finally{d(!1)}}return e.jsxs(O,{open:l,onOpenChange:h,children:[e.jsx(L,{asChild:!0,children:e.jsxs("button",{className:"flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-left text-sm text-muted-foreground hover:bg-accent hover:text-foreground transition-colors",children:[e.jsx(ie,{className:"size-3.5 shrink-0"}),e.jsx("span",{children:"Add App"})]})}),e.jsxs(U,{className:"sm:max-w-sm",children:[e.jsx(E,{children:e.jsx(V,{children:"Add App"})}),e.jsxs("form",{onSubmit:w,className:"flex flex-col gap-4 pt-2",children:[e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"app-name",children:"Name"}),e.jsx(M,{id:"app-name",value:c,onChange:u=>t(u.target.value),placeholder:"My App",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"bundle-id",children:"Bundle ID"}),e.jsx(M,{id:"bundle-id",value:g,onChange:u=>o(u.target.value),placeholder:"com.example.myapp",required:!0})]}),e.jsxs("div",{className:"flex flex-col gap-1.5",children:[e.jsx(b,{htmlFor:"platform",children:"Platform"}),e.jsxs(A,{value:x,onValueChange:u=>j(u),children:[e.jsx(_,{id:"platform",children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"ios",children:"iOS"}),e.jsx(i,{value:"android",children:"Android"}),e.jsx(i,{value:"both",children:"Both"})]})]})]}),p&&e.jsx("p",{className:"text-sm text-destructive",children:p}),e.jsx(y,{type:"submit",disabled:n,className:"w-full",children:n?"Creating…":"Create App"})]})]})]})}function Be({apps:s,selectedAppId:l,onSelect:h,onAdd:c}){return e.jsxs("aside",{className:"w-64 shrink-0 border-r flex flex-col gap-1 p-3 overflow-y-auto",children:[e.jsx("span",{className:"px-2 pb-1 font-mono text-xs font-medium text-muted-foreground uppercase tracking-wider",children:"Apps"}),s.length===0&&e.jsx("span",{className:"px-2 text-sm text-muted-foreground",children:"No apps yet"}),s.map(t=>e.jsxs("button",{onClick:()=>h(t.id),className:["flex flex-col gap-0.5 rounded-md px-2 py-2 text-left text-sm hover:bg-accent overflow-hidden",t.id===l?"bg-accent font-medium":""].join(" "),children:[e.jsx("span",{className:"truncate",children:t.name}),e.jsx(D,{className:"text-muted-foreground truncate",children:t.bundle_id_key})]},t.id)),e.jsx("div",{className:"mt-1 border-t pt-1",children:e.jsx(_e,{onSuccess:c})})]})}function ze(s){const l=/[zZ]|[+-]\d{2}:?\d{2}$/.test(s),c=new Date(l?s:s.replace(" ","T")+"Z").getTime()-Date.now();if(c<=0)return{label:"Deleting…",urgent:!0};const t=Math.floor(c/36e5);return t<1?{label:"Deletes in < 1h",urgent:!0}:t<24?{label:`Deletes in ${t}h`,urgent:t<6}:{label:`Deletes in ${Math.floor(t/24)}d`,urgent:!1}}function Ie({build:s,isLast:l,onNavigate:h,onStatusChange:c,onScheduleDeletion:t,onCancelDeletion:g}){const[o,x]=r.useState(!1),j=s.status_label==="Done",p=s.delete_after?ze(s.delete_after):null;function N(n){c(s.id,n==="none"?null:n)}return e.jsxs(e.Fragment,{children:[e.jsx(de,{open:o,onOpenChange:x,children:e.jsxs(ue,{children:[e.jsxs(he,{children:[e.jsx(xe,{children:"Schedule deletion?"}),e.jsx(pe,{children:"Build files will be deleted after 7 days. You can cancel the scheduled deletion anytime before then."})]}),e.jsxs(me,{children:[e.jsx(fe,{children:"Cancel"}),e.jsx(ge,{onClick:()=>{t(s.id),x(!1)},children:"Schedule deletion"})]})]})}),e.jsxs("div",{className:["flex items-center gap-3 px-4 py-3",l?"":"border-b"].join(" "),children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("span",{className:"text-sm font-medium",children:["build ",e.jsx(D,{children:s.build_number??"—"})]}),e.jsx(T,{tone:s.platform==="ios"?"ios":"android",className:"text-xs capitalize",children:s.platform}),s.status_label&&e.jsx(T,{tone:K[s.status_label],className:"text-xs",children:s.status_label}),p&&e.jsx(T,{tone:p.urgent?"rejected":"backlog",className:"text-xs",children:p.label})]}),e.jsxs("div",{style:{display:"flex",flexDirection:"row",gap:"14px",marginTop:"0.7rem",alignItems:"center"},className:"text-xs text-muted-foreground",children:[s.uploader&&e.jsxs(e.Fragment,{children:[e.jsx("span",{children:s.uploader}),e.jsx(Q,{orientation:"vertical",className:"h-3"})]}),e.jsx(D,{children:new Date(s.uploaded_at).toLocaleDateString()})]})]}),e.jsxs(A,{value:s.status_label??"none",onValueChange:N,children:[e.jsx(_,{className:"h-9 w-32 text-xs",children:e.jsx(B,{})}),e.jsxs(z,{children:[e.jsx(i,{value:"none",children:e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]}),p?e.jsx(y,{size:"icon-sm",variant:"outline",onClick:()=>g(s.id),title:"Cancel scheduled deletion",children:e.jsx(ke,{className:"h-3.5 w-3.5"})}):e.jsx(y,{size:"icon-sm",variant:"destructive",onClick:()=>x(!0),title:"Schedule deletion",children:e.jsx(oe,{className:"h-3.5 w-3.5"})}),e.jsxs(y,{size:"sm",onClick:()=>h(s.id),disabled:j,children:[e.jsx(X,{className:"mr-1.5 h-3.5 w-3.5"}),"Start QA"]})]})]})}function Pe({versionName:s,builds:l,isOpen:h,onToggle:c,onNavigate:t,onStatusChange:g,onScheduleDeletion:o,onCancelDeletion:x}){return e.jsxs("div",{className:"rounded-lg shadow-card-2 overflow-hidden",children:[e.jsxs("button",{className:"flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-accent/50 bg-card",onClick:c,children:[h?e.jsx(ce,{className:"h-4 w-4 shrink-0 text-muted-foreground"}):e.jsx(W,{className:"h-4 w-4 shrink-0 text-muted-foreground"}),e.jsx(D,{className:"font-medium text-sm text-foreground",children:s}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["(",l.length," build",l.length>1?"s":"",")"]})]}),h&&e.jsx("div",{className:"border-t bg-card",children:l.map((j,p)=>e.jsx(Ie,{build:j,isLast:p===l.length-1,onNavigate:t,onStatusChange:g,onScheduleDeletion:o,onCancelDeletion:x},j.id))})]})}function Ve(){const s=je(),[l,h]=ve(),[c,t]=r.useState([]),[g,o]=r.useState([]),[x,j]=r.useState(""),[p,N]=r.useState("all"),[n,d]=r.useState(!0),[w,u]=r.useState(new Set),m=l.get("appId")?Number(l.get("appId")):null,F=c.find(a=>a.id===m)??null,I=r.useCallback(async()=>{const a=await ee();t(a),!l.get("appId")&&a.length>0&&h({appId:String(a[0].id)},{replace:!0})},[l,h]),P=r.useCallback(async()=>{if(!m){o([]),d(!1);return}d(!0);try{const a=await se({appId:m,search:x,statusFilter:p});o(a),a.length>0&&w.size===0&&u(new Set([a[0].version_name??"Unversioned"]))}finally{d(!1)}},[m,x,p]);r.useEffect(()=>{I()},[]),r.useEffect(()=>{P()},[P]);function $(a){a!==m&&(o([]),u(new Set)),h({appId:String(a)})}function q(a){u(v=>{const f=new Set(v);return f.has(a)?f.delete(a):f.add(a),f})}async function H(a,v){await re(a,v),o(f=>f.map(S=>S.id===a?{...S,status_label:v}:S))}async function Z(a){try{const v=await ne(a);o(f=>f.map(S=>S.id===a?{...S,delete_after:v}:S))}catch{k.error("Failed to schedule deletion")}}async function G(a){try{await le(a),o(v=>v.map(f=>f.id===a?{...f,delete_after:null}:f))}catch{k.error("Failed to cancel scheduled deletion")}}const R=ae(g);return e.jsxs("div",{className:"flex h-full gap-0",children:[e.jsx(Be,{apps:c,selectedAppId:m,onSelect:$,onAdd:I}),e.jsxs("div",{className:"flex-1 flex flex-col gap-4 p-4 overflow-y-auto min-w-0",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-2",children:[e.jsx("h1",{className:"text-xl font-semibold tracking-display-sm",children:F?F.name:"App Center"}),e.jsx(Ae,{onSuccess:()=>{I(),P()},appId:m})]}),m?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(te,{placeholder:"Search version…",value:x,onChange:j}),e.jsxs(A,{value:p,onValueChange:N,children:[e.jsx(_,{className:"h-8 w-36",children:e.jsx(B,{placeholder:"Status"})}),e.jsxs(z,{children:[e.jsx(i,{value:"all",children:"All statuses"}),e.jsx(i,{value:"Backlog",children:"Backlog"}),e.jsx(i,{value:"In Progress",children:"In Progress"}),e.jsx(i,{value:"Done",children:"Done"}),e.jsx(i,{value:"Rejected",children:"Rejected"})]})]})]}),n?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):R.length===0?e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(we,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No builds yet"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Upload the first build to get started."})]}):e.jsx("div",{className:"flex flex-col gap-2",children:R.map(({versionName:a,builds:v})=>e.jsx(Pe,{versionName:a,builds:v,isOpen:w.has(a),onToggle:()=>q(a),onNavigate:f=>s(`/app-center/build?id=${f}`),onStatusChange:H,onScheduleDeletion:Z,onCancelDeletion:G},a))})]}):e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 text-center",children:[e.jsx(Se,{className:"w-8 h-8 text-muted-foreground/40"}),e.jsx("p",{className:"text-sm font-medium",children:"No app selected"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Choose an app from the sidebar to view its builds."})]})]})]})}export{Ve as AppCenter};