@tapflowio/relay 0.27.0 → 0.28.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 (266) hide show
  1. package/dist/RelayServer.d.ts +74 -0
  2. package/dist/RelayServer.d.ts.map +1 -1
  3. package/dist/RelayServer.js +482 -43
  4. package/dist/RelayServer.js.map +1 -1
  5. package/dist/SessionManager.d.ts +63 -2
  6. package/dist/SessionManager.d.ts.map +1 -1
  7. package/dist/SessionManager.js +123 -1
  8. package/dist/SessionManager.js.map +1 -1
  9. package/dist/api/apps.d.ts +2 -1
  10. package/dist/api/apps.d.ts.map +1 -1
  11. package/dist/api/apps.js +20 -7
  12. package/dist/api/apps.js.map +1 -1
  13. package/dist/api/builds.d.ts +2 -1
  14. package/dist/api/builds.d.ts.map +1 -1
  15. package/dist/api/builds.js +23 -45
  16. package/dist/api/builds.js.map +1 -1
  17. package/dist/api/comments.d.ts.map +1 -1
  18. package/dist/api/comments.js +5 -7
  19. package/dist/api/comments.js.map +1 -1
  20. package/dist/api/invitations.d.ts.map +1 -1
  21. package/dist/api/invitations.js +3 -0
  22. package/dist/api/invitations.js.map +1 -1
  23. package/dist/api/profile.d.ts.map +1 -1
  24. package/dist/api/profile.js +28 -9
  25. package/dist/api/profile.js.map +1 -1
  26. package/dist/api/recordings.d.ts.map +1 -1
  27. package/dist/api/recordings.js +5 -6
  28. package/dist/api/recordings.js.map +1 -1
  29. package/dist/api/runVideos.d.ts +85 -0
  30. package/dist/api/runVideos.d.ts.map +1 -0
  31. package/dist/api/runVideos.js +494 -0
  32. package/dist/api/runVideos.js.map +1 -0
  33. package/dist/api/runs.d.ts +77 -0
  34. package/dist/api/runs.d.ts.map +1 -0
  35. package/dist/api/runs.js +579 -0
  36. package/dist/api/runs.js.map +1 -0
  37. package/dist/api/settings.d.ts +1 -1
  38. package/dist/api/settings.d.ts.map +1 -1
  39. package/dist/api/settings.js +67 -10
  40. package/dist/api/settings.js.map +1 -1
  41. package/dist/db.d.ts +2 -0
  42. package/dist/db.d.ts.map +1 -1
  43. package/dist/db.js +4 -0
  44. package/dist/db.js.map +1 -1
  45. package/dist/lib/buildDeletion.d.ts +21 -0
  46. package/dist/lib/buildDeletion.d.ts.map +1 -0
  47. package/dist/lib/buildDeletion.js +58 -0
  48. package/dist/lib/buildDeletion.js.map +1 -0
  49. package/dist/lib/clientAddress.d.ts +12 -0
  50. package/dist/lib/clientAddress.d.ts.map +1 -1
  51. package/dist/lib/clientAddress.js +22 -0
  52. package/dist/lib/clientAddress.js.map +1 -1
  53. package/dist/lib/uploads.d.ts +13 -0
  54. package/dist/lib/uploads.d.ts.map +1 -1
  55. package/dist/lib/uploads.js +41 -0
  56. package/dist/lib/uploads.js.map +1 -1
  57. package/dist/lib/watchActions.d.ts +10 -0
  58. package/dist/lib/watchActions.d.ts.map +1 -0
  59. package/dist/lib/watchActions.js +27 -0
  60. package/dist/lib/watchActions.js.map +1 -0
  61. package/dist/middleware/auth.d.ts +1 -0
  62. package/dist/middleware/auth.d.ts.map +1 -1
  63. package/dist/middleware/auth.js +1 -1
  64. package/dist/middleware/auth.js.map +1 -1
  65. package/dist/migrations/015_flow_runs.sql +59 -0
  66. package/dist/migrations/016_flow_run_videos.sql +51 -0
  67. package/dist/router.d.ts +5 -0
  68. package/dist/router.d.ts.map +1 -1
  69. package/dist/router.js +24 -0
  70. package/dist/router.js.map +1 -1
  71. package/package.json +9 -9
  72. package/public/assets/AISessionWatch-Bxew762e.js +36 -0
  73. package/public/assets/AISessionWatch-Bxew762e.js.br +0 -0
  74. package/public/assets/AISessionWatch-Bxew762e.js.gz +0 -0
  75. package/public/assets/AndroidDeviceScreen-C55msKfh.js +35 -0
  76. package/public/assets/AndroidDeviceScreen-C55msKfh.js.br +0 -0
  77. package/public/assets/AndroidDeviceScreen-C55msKfh.js.gz +0 -0
  78. package/public/assets/AppCenter-93hnrrdy.js +26 -0
  79. package/public/assets/AppCenter-93hnrrdy.js.br +0 -0
  80. package/public/assets/AppCenter-93hnrrdy.js.gz +0 -0
  81. package/public/assets/Default-BhgcUKBm.js +6 -0
  82. package/public/assets/Default-BhgcUKBm.js.br +0 -0
  83. package/public/assets/Default-BhgcUKBm.js.gz +0 -0
  84. package/public/assets/Invite-DQBwLaOl.js +1 -0
  85. package/public/assets/Invite-DQBwLaOl.js.br +0 -0
  86. package/public/assets/Invite-DQBwLaOl.js.gz +0 -0
  87. package/public/assets/MacResources-D4LMGxgV.js +1 -0
  88. package/public/assets/MacResources-D4LMGxgV.js.br +0 -0
  89. package/public/assets/MacResources-D4LMGxgV.js.gz +0 -0
  90. package/public/assets/{NotFound-wHOnT2Fl.js → NotFound-DVq_rCKc.js} +1 -1
  91. package/public/assets/NotFound-DVq_rCKc.js.br +0 -0
  92. package/public/assets/NotFound-DVq_rCKc.js.gz +0 -0
  93. package/public/assets/QASession-Dnuq0yrN.js +81 -0
  94. package/public/assets/QASession-Dnuq0yrN.js.br +0 -0
  95. package/public/assets/QASession-Dnuq0yrN.js.gz +0 -0
  96. package/public/assets/ResetPassword-inTbbral.js +1 -0
  97. package/public/assets/ResetPassword-inTbbral.js.br +0 -0
  98. package/public/assets/ResetPassword-inTbbral.js.gz +0 -0
  99. package/public/assets/RunDetail-B3dw8_U0.js +16 -0
  100. package/public/assets/RunDetail-B3dw8_U0.js.br +0 -0
  101. package/public/assets/RunDetail-B3dw8_U0.js.gz +0 -0
  102. package/public/assets/Runs-DqZl9Y6M.js +6 -0
  103. package/public/assets/Runs-DqZl9Y6M.js.br +0 -0
  104. package/public/assets/Runs-DqZl9Y6M.js.gz +0 -0
  105. package/public/assets/Setup-CPa_UWpa.js +1 -0
  106. package/public/assets/Setup-CPa_UWpa.js.br +0 -0
  107. package/public/assets/Setup-CPa_UWpa.js.gz +0 -0
  108. package/public/assets/Team-DZie8W7R.js +6 -0
  109. package/public/assets/Team-DZie8W7R.js.br +0 -0
  110. package/public/assets/Team-DZie8W7R.js.gz +0 -0
  111. package/public/assets/Tokens-u3-uRAwd.js +1 -0
  112. package/public/assets/Tokens-u3-uRAwd.js.br +0 -0
  113. package/public/assets/Tokens-u3-uRAwd.js.gz +0 -0
  114. package/public/assets/WatchedDevice-CpaKHa1x.js +1 -0
  115. package/public/assets/WatchedDevice-CpaKHa1x.js.br +0 -0
  116. package/public/assets/WatchedDevice-CpaKHa1x.js.gz +0 -0
  117. package/public/assets/aiSession-BsmDnyV1.js +31 -0
  118. package/public/assets/aiSession-BsmDnyV1.js.br +0 -0
  119. package/public/assets/aiSession-BsmDnyV1.js.gz +0 -0
  120. package/public/assets/alert-dialog-Bq_Ln5bp.js +1 -0
  121. package/public/assets/alert-dialog-Bq_Ln5bp.js.br +0 -0
  122. package/public/assets/alert-dialog-Bq_Ln5bp.js.gz +0 -0
  123. package/public/assets/{badge-B3vaBVIQ.js → badge-D-bt97WR.js} +1 -1
  124. package/public/assets/badge-D-bt97WR.js.br +0 -0
  125. package/public/assets/badge-D-bt97WR.js.gz +0 -0
  126. package/public/assets/build-format-ofd2iIzf.js +1 -0
  127. package/public/assets/build-format-ofd2iIzf.js.br +0 -0
  128. package/public/assets/build-format-ofd2iIzf.js.gz +0 -0
  129. package/public/assets/dialog-CtzPkg0O.js +1 -0
  130. package/public/assets/dialog-CtzPkg0O.js.br +0 -0
  131. package/public/assets/dialog-CtzPkg0O.js.gz +0 -0
  132. package/public/assets/field-hint-B774BIWK.js +1 -0
  133. package/public/assets/field-hint-B774BIWK.js.br +1 -0
  134. package/public/assets/field-hint-B774BIWK.js.gz +0 -0
  135. package/public/assets/index-D17hSi50.js +1 -0
  136. package/public/assets/index-D17hSi50.js.br +0 -0
  137. package/public/assets/index-D17hSi50.js.gz +0 -0
  138. package/public/assets/index-EPyP3g9A.css +1 -0
  139. package/public/assets/index-EPyP3g9A.css.br +0 -0
  140. package/public/assets/index-EPyP3g9A.css.gz +0 -0
  141. package/public/assets/index-cgl1yEKu.js +223 -0
  142. package/public/assets/index-cgl1yEKu.js.br +0 -0
  143. package/public/assets/index-cgl1yEKu.js.gz +0 -0
  144. package/public/assets/list-view-BcjDCJy5.js +1 -0
  145. package/public/assets/list-view-BcjDCJy5.js.br +0 -0
  146. package/public/assets/list-view-BcjDCJy5.js.gz +0 -0
  147. package/public/assets/{pencil-CycAOoC_.js → pencil-1XSs32nb.js} +2 -2
  148. package/public/assets/pencil-1XSs32nb.js.br +0 -0
  149. package/public/assets/pencil-1XSs32nb.js.gz +0 -0
  150. package/public/assets/play-DCvrorIC.js +6 -0
  151. package/public/assets/play-DCvrorIC.js.br +0 -0
  152. package/public/assets/play-DCvrorIC.js.gz +0 -0
  153. package/public/assets/resource-health-oWJ8hy9X.js +1 -0
  154. package/public/assets/resource-health-oWJ8hy9X.js.br +0 -0
  155. package/public/assets/resource-health-oWJ8hy9X.js.gz +0 -0
  156. package/public/assets/runs-CInQb6v1.js +1 -0
  157. package/public/assets/runs-CInQb6v1.js.br +0 -0
  158. package/public/assets/runs-CInQb6v1.js.gz +0 -0
  159. package/public/assets/search-input-CFWgLcKA.js +6 -0
  160. package/public/assets/search-input-CFWgLcKA.js.br +0 -0
  161. package/public/assets/search-input-CFWgLcKA.js.gz +0 -0
  162. package/public/assets/select-5ZtzWRYG.js +11 -0
  163. package/public/assets/select-5ZtzWRYG.js.br +0 -0
  164. package/public/assets/select-5ZtzWRYG.js.gz +0 -0
  165. package/public/assets/slider-DHuMDXcP.js +1 -0
  166. package/public/assets/slider-DHuMDXcP.js.br +0 -0
  167. package/public/assets/slider-DHuMDXcP.js.gz +0 -0
  168. package/public/assets/tabs-CmgV_sSI.js +1 -0
  169. package/public/assets/tabs-CmgV_sSI.js.br +0 -0
  170. package/public/assets/tabs-CmgV_sSI.js.gz +0 -0
  171. package/public/assets/tech-label-qLodPeUI.js +1 -0
  172. package/public/assets/tech-label-qLodPeUI.js.br +0 -0
  173. package/public/assets/tech-label-qLodPeUI.js.gz +0 -0
  174. package/public/assets/{trash-BXQnOI5U.js → trash-CXjB9oU1.js} +3 -3
  175. package/public/assets/trash-CXjB9oU1.js.br +0 -0
  176. package/public/assets/trash-CXjB9oU1.js.gz +0 -0
  177. package/public/assets/{useFocusAfterSwap-BY3N9f9v.js → useFocusAfterSwap-BdItkQCu.js} +1 -1
  178. package/public/assets/useFocusAfterSwap-BdItkQCu.js.br +0 -0
  179. package/public/assets/useFocusAfterSwap-BdItkQCu.js.gz +0 -0
  180. package/public/assets/useRelay-CES3I1Mt.js +1 -0
  181. package/public/assets/useRelay-CES3I1Mt.js.br +0 -0
  182. package/public/assets/useRelay-CES3I1Mt.js.gz +0 -0
  183. package/public/assets/useShownAfter-By1Yxysz.js +1 -0
  184. package/public/assets/useShownAfter-By1Yxysz.js.br +0 -0
  185. package/public/assets/useShownAfter-By1Yxysz.js.gz +0 -0
  186. package/public/assets/{vendor-charts-BykzUV2D.js → vendor-charts-BE7R_8yA.js} +2 -2
  187. package/public/assets/vendor-charts-BE7R_8yA.js.br +0 -0
  188. package/public/assets/vendor-charts-BE7R_8yA.js.gz +0 -0
  189. package/public/assets/{vendor-react-BlPSzrEe.js → vendor-react-DTSdA8m-.js} +4 -4
  190. package/public/assets/vendor-react-DTSdA8m-.js.br +0 -0
  191. package/public/assets/{vendor-react-BlPSzrEe.js.gz → vendor-react-DTSdA8m-.js.gz} +0 -0
  192. package/public/assets/{vendor-router-B_lVHrKl.js → vendor-router-B1pQim9Z.js} +3 -3
  193. package/public/assets/vendor-router-B1pQim9Z.js.br +0 -0
  194. package/public/assets/vendor-router-B1pQim9Z.js.gz +0 -0
  195. package/public/assets/video-CK2q3-0B.js +6 -0
  196. package/public/assets/video-CK2q3-0B.js.br +0 -0
  197. package/public/assets/video-CK2q3-0B.js.gz +0 -0
  198. package/public/index.html +18 -4
  199. package/public/index.html.br +0 -0
  200. package/public/index.html.gz +0 -0
  201. package/public/assets/AppCenter-BMdYtQbV.js +0 -26
  202. package/public/assets/AppCenter-BMdYtQbV.js.br +0 -0
  203. package/public/assets/AppCenter-BMdYtQbV.js.gz +0 -0
  204. package/public/assets/Default-0DHHVGaN.js +0 -1
  205. package/public/assets/Default-0DHHVGaN.js.br +0 -0
  206. package/public/assets/Default-0DHHVGaN.js.gz +0 -0
  207. package/public/assets/Invite-C0ZB_HiU.js +0 -1
  208. package/public/assets/Invite-C0ZB_HiU.js.br +0 -0
  209. package/public/assets/Invite-C0ZB_HiU.js.gz +0 -0
  210. package/public/assets/MacResources-DmY5pRV2.js +0 -1
  211. package/public/assets/MacResources-DmY5pRV2.js.br +0 -0
  212. package/public/assets/MacResources-DmY5pRV2.js.gz +0 -0
  213. package/public/assets/NotFound-wHOnT2Fl.js.br +0 -0
  214. package/public/assets/NotFound-wHOnT2Fl.js.gz +0 -0
  215. package/public/assets/QASession-2QogWEX7.js +0 -150
  216. package/public/assets/QASession-2QogWEX7.js.br +0 -0
  217. package/public/assets/QASession-2QogWEX7.js.gz +0 -0
  218. package/public/assets/ResetPassword-jNRuertx.js +0 -1
  219. package/public/assets/ResetPassword-jNRuertx.js.br +0 -0
  220. package/public/assets/ResetPassword-jNRuertx.js.gz +0 -0
  221. package/public/assets/Setup-CF_FN9Dt.js +0 -1
  222. package/public/assets/Setup-CF_FN9Dt.js.br +0 -0
  223. package/public/assets/Setup-CF_FN9Dt.js.gz +0 -0
  224. package/public/assets/Team-BbiyOGau.js +0 -6
  225. package/public/assets/Team-BbiyOGau.js.br +0 -0
  226. package/public/assets/Team-BbiyOGau.js.gz +0 -0
  227. package/public/assets/Tokens-CZo4sPTx.js +0 -1
  228. package/public/assets/Tokens-CZo4sPTx.js.br +0 -0
  229. package/public/assets/Tokens-CZo4sPTx.js.gz +0 -0
  230. package/public/assets/alert-dialog-DFz8G_zu.js +0 -1
  231. package/public/assets/alert-dialog-DFz8G_zu.js.br +0 -0
  232. package/public/assets/alert-dialog-DFz8G_zu.js.gz +0 -0
  233. package/public/assets/badge-B3vaBVIQ.js.br +0 -0
  234. package/public/assets/badge-B3vaBVIQ.js.gz +0 -0
  235. package/public/assets/build-format-dbQPU3A4.js +0 -11
  236. package/public/assets/build-format-dbQPU3A4.js.br +0 -0
  237. package/public/assets/build-format-dbQPU3A4.js.gz +0 -0
  238. package/public/assets/dialog-DeBPk-I3.js +0 -11
  239. package/public/assets/dialog-DeBPk-I3.js.br +0 -0
  240. package/public/assets/dialog-DeBPk-I3.js.gz +0 -0
  241. package/public/assets/field-hint-CMKmbVpy.js +0 -1
  242. package/public/assets/field-hint-CMKmbVpy.js.br +0 -0
  243. package/public/assets/field-hint-CMKmbVpy.js.gz +0 -0
  244. package/public/assets/index-B4w4Lh3e.js +0 -218
  245. package/public/assets/index-B4w4Lh3e.js.br +0 -0
  246. package/public/assets/index-B4w4Lh3e.js.gz +0 -0
  247. package/public/assets/index-CDWu0GQL.css +0 -1
  248. package/public/assets/index-CDWu0GQL.css.br +0 -0
  249. package/public/assets/index-CDWu0GQL.css.gz +0 -0
  250. package/public/assets/list-view-BvINA5t4.js +0 -1
  251. package/public/assets/list-view-BvINA5t4.js.br +0 -0
  252. package/public/assets/list-view-BvINA5t4.js.gz +0 -0
  253. package/public/assets/pencil-CycAOoC_.js.br +0 -0
  254. package/public/assets/pencil-CycAOoC_.js.gz +0 -0
  255. package/public/assets/resource-health-C1qSG3MK.js +0 -1
  256. package/public/assets/resource-health-C1qSG3MK.js.br +0 -0
  257. package/public/assets/resource-health-C1qSG3MK.js.gz +0 -0
  258. package/public/assets/trash-BXQnOI5U.js.br +0 -0
  259. package/public/assets/trash-BXQnOI5U.js.gz +0 -0
  260. package/public/assets/useFocusAfterSwap-BY3N9f9v.js.br +0 -0
  261. package/public/assets/useFocusAfterSwap-BY3N9f9v.js.gz +0 -0
  262. package/public/assets/vendor-charts-BykzUV2D.js.br +0 -0
  263. package/public/assets/vendor-charts-BykzUV2D.js.gz +0 -0
  264. package/public/assets/vendor-react-BlPSzrEe.js.br +0 -0
  265. package/public/assets/vendor-router-B_lVHrKl.js.br +0 -0
  266. package/public/assets/vendor-router-B_lVHrKl.js.gz +0 -0
@@ -1,18 +1,35 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import busboy from 'busboy';
4
+ import { randomUUID } from 'crypto';
4
5
  import { getDb } from '../db.js';
5
6
  import { requireRole, requireAuth } from '../middleware/auth.js';
6
7
  import { json } from '../router.js';
7
- export function handleGetSettings(req, res) {
8
+ import { pipeUpload, unlinkSafe } from '../lib/uploads.js';
9
+ import { diskRoomFor, videoSettings, videoUsageBytes } from './runVideos.js';
10
+ /** Bounds for the video policy fields: 0 days keeps no passed video; the cap is at least 100 MB. */
11
+ const MAX_RETENTION_DAYS = 365;
12
+ const MIN_CAP_MB = 100;
13
+ const MAX_CAP_MB = 10 * 1024 * 1024;
14
+ export function handleGetSettings(req, res, videosDir) {
8
15
  const auth = requireAuth(req, res);
9
16
  if (!auth)
10
17
  return;
11
18
  const db = getDb();
12
19
  const settings = db.prepare('SELECT team_name, logo_path FROM team_settings WHERE id = 1').get();
20
+ // The video policy and what it is using. **The effective cap is the smaller of the setting and the disk's
21
+ // room**, because a cap larger than the volume is a promise the disk cannot keep — the floor the relay keeps for
22
+ // itself comes off first.
23
+ const video = videoSettings();
24
+ const usage = videoUsageBytes();
25
+ const room = videosDir ? diskRoomFor(videosDir) : { free: Number.MAX_SAFE_INTEGER, floor: 0 };
13
26
  json(res, 200, {
14
27
  team_name: settings?.team_name ?? 'tapflow',
15
28
  logo_url: settings?.logo_path ? `/uploads/team/${path.basename(settings.logo_path)}` : null,
29
+ video_pass_retention_days: video.passRetentionDays,
30
+ video_storage_cap_mb: Math.round(video.storageCapBytes / (1024 * 1024)),
31
+ video_usage_bytes: usage,
32
+ video_effective_cap_bytes: Math.min(video.storageCapBytes, usage + Math.max(0, room.free - room.floor)),
16
33
  });
17
34
  }
18
35
  export function handleUpdateSettings(req, res, uploadsDir) {
@@ -22,9 +39,14 @@ export function handleUpdateSettings(req, res, uploadsDir) {
22
39
  const bb = busboy({ headers: req.headers, limits: { fileSize: 2 * 1024 * 1024 } });
23
40
  const fields = {};
24
41
  let logoPath = '';
42
+ let stagedPath = '';
43
+ let written = null;
25
44
  let sizeError = false;
26
45
  bb.on('field', (name, val) => { fields[name] = val; });
27
46
  bb.on('file', (_field, stream, info) => {
47
+ // busboy destroys a file's stream with an error when the body ends inside it, and a stream with no
48
+ // `'error'` listener throws. The response is `bb`'s own `'error'` handler's job.
49
+ stream.on('error', () => { });
28
50
  const allowed = ['image/png', 'image/jpeg'];
29
51
  if (!allowed.includes(info.mimeType)) {
30
52
  stream.resume();
@@ -33,17 +55,48 @@ export function handleUpdateSettings(req, res, uploadsDir) {
33
55
  const ext = info.mimeType === 'image/png' ? '.png' : '.jpg';
34
56
  logoPath = path.join(uploadsDir, 'team', `logo${ext}`);
35
57
  fs.mkdirSync(path.dirname(logoPath), { recursive: true });
36
- let size = 0;
37
- stream.on('data', (chunk) => {
38
- size += chunk.length;
39
- if (size > 2 * 1024 * 1024)
40
- sizeError = true;
41
- });
42
- stream.pipe(fs.createWriteStream(logoPath));
58
+ // **Staged, then renamed into place.** It used to be written straight over the live image, so an upload
59
+ // that failed partway left the current one empty or truncated. busboy also stops at the size limit
60
+ // rather than erroring, which `'limit'` reports.
61
+ stagedPath = `${logoPath}.${randomUUID()}.part`;
62
+ stream.on('limit', () => { sizeError = true; });
63
+ written = pipeUpload(stream, stagedPath, 'staged team logo');
43
64
  });
44
- bb.on('finish', () => {
45
- if (sizeError)
65
+ bb.on('finish', async () => {
66
+ // The policy fields are checked before the logo is put in place, so a refused update changes nothing.
67
+ const videoFields = [];
68
+ for (const [field, min, max] of [
69
+ ['video_pass_retention_days', 0, MAX_RETENTION_DAYS],
70
+ ['video_storage_cap_mb', MIN_CAP_MB, MAX_CAP_MB],
71
+ ]) {
72
+ const raw = fields[field];
73
+ if (raw === undefined)
74
+ continue;
75
+ const n = Number(raw);
76
+ if (!/^\d+$/.test(raw) || n < min || n > max) {
77
+ if (stagedPath) {
78
+ await written?.catch(() => { });
79
+ unlinkSafe(stagedPath, 'staged team logo');
80
+ }
81
+ return json(res, 400, { error: `${field} must be an integer from ${min} to ${max}` });
82
+ }
83
+ videoFields.push([field, n]);
84
+ }
85
+ if (sizeError) {
86
+ if (stagedPath)
87
+ unlinkSafe(stagedPath, 'oversized team logo');
46
88
  return json(res, 400, { error: 'Max 2MB for logo' });
89
+ }
90
+ if (written) {
91
+ try {
92
+ await written;
93
+ fs.renameSync(stagedPath, logoPath);
94
+ }
95
+ catch {
96
+ unlinkSafe(stagedPath, 'staged team logo');
97
+ return json(res, 500, { error: 'Update failed' });
98
+ }
99
+ }
47
100
  const db = getDb();
48
101
  const updates = ['updated_at = datetime(\'now\')'];
49
102
  const params = [];
@@ -51,6 +104,10 @@ export function handleUpdateSettings(req, res, uploadsDir) {
51
104
  updates.push('team_name = ?');
52
105
  params.push(fields.team_name);
53
106
  }
107
+ for (const [field, n] of videoFields) {
108
+ updates.push(`${field} = ?`);
109
+ params.push(n);
110
+ }
54
111
  if (logoPath) {
55
112
  updates.push('logo_path = ?');
56
113
  params.push(logoPath);
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/api/settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/api/settings.ts"],"names":[],"mappings":"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"}
package/dist/db.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import Database from 'better-sqlite3';
2
2
  export declare function getDb(): Database.Database;
3
+ /** Whether `initDb` has run — for a socket handler that touches the database when one is there. */
4
+ export declare function isDbOpen(): boolean;
3
5
  export declare function closeDb(): void;
4
6
  export declare function initDb(dbPath: string): void;
5
7
  //# sourceMappingURL=db.d.ts.map
package/dist/db.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAOrC,wBAAgB,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAGzC;AAED,wBAAgB,OAAO,IAAI,IAAI,CAG9B;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAM3C"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AAOrC,wBAAgB,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAGzC;AAED,mGAAmG;AACnG,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED,wBAAgB,OAAO,IAAI,IAAI,CAG9B;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAM3C"}
package/dist/db.js CHANGED
@@ -8,6 +8,10 @@ export function getDb() {
8
8
  throw new PlatformError('DB not initialized — call initDb() first');
9
9
  return db;
10
10
  }
11
+ /** Whether `initDb` has run — for a socket handler that touches the database when one is there. */
12
+ export function isDbOpen() {
13
+ return db !== null;
14
+ }
11
15
  export function closeDb() {
12
16
  db?.close();
13
17
  db = null;
package/dist/db.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAErD,IAAI,EAAE,GAA6B,IAAI,CAAA;AAEvC,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,aAAa,CAAC,0CAA0C,CAAC,CAAA;IAC5E,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,EAAE,EAAE,KAAK,EAAE,CAAA;IACX,EAAE,GAAG,IAAI,CAAA;AACX,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;IACzB,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAC/B,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC9B,aAAa,EAAE,CAAA;AACjB,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,CAAC,GAAG,KAAK,EAAE,CAAA;IACjB,CAAC,CAAC,IAAI,CAAC;;;;;;GAMN,CAAC,CAAA;IAEF,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAEpF,MAAM,GAAG,GAAG,IAAI,GAAG,CAChB,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,GAAG,EAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC3F,CAAA;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC3B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;QACpE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE;YACjB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACX,CAAC,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAClE,CAAC,CAAC,EAAE,CAAA;IACN,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAA;AACrC,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAErD,IAAI,EAAE,GAA6B,IAAI,CAAA;AAEvC,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,aAAa,CAAC,0CAA0C,CAAC,CAAA;IAC5E,OAAO,EAAE,CAAA;AACX,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,QAAQ;IACtB,OAAO,EAAE,KAAK,IAAI,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,EAAE,EAAE,KAAK,EAAE,CAAA;IACX,EAAE,GAAG,IAAI,CAAA;AACX,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAA;IACzB,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAC/B,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAC9B,aAAa,EAAE,CAAA;AACjB,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,CAAC,GAAG,KAAK,EAAE,CAAA;IACjB,CAAC,CAAC,IAAI,CAAC;;;;;;GAMN,CAAC,CAAA;IAEF,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IAClE,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAEpF,MAAM,GAAG,GAAG,IAAI,GAAG,CAChB,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,GAAG,EAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC3F,CAAA;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC3B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;QACpE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE;YACjB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACX,CAAC,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAClE,CAAC,CAAC,EAAE,CAAA;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /** Where a build's dependents keep their files. All three are this install's, not the stored paths'. */
2
+ export interface BuildFileDirs {
3
+ uploadsDir: string;
4
+ recordingsDir: string;
5
+ runScreenshotsDir: string;
6
+ runVideosDir: string;
7
+ }
8
+ /**
9
+ * Delete builds together with every row that points at them, then their files.
10
+ *
11
+ * **One path for both ways a build goes**, the daily purge and deleting its app. They had drifted: the purge
12
+ * removed recordings first, and app deletion removed nothing — so an app with a recorded build failed its
13
+ * delete on the recordings foreign key (`foreign_keys = ON`), and one without left every build file on disk.
14
+ * Run records are a third dependent, and adding them to one path only would have rebuilt the same drift.
15
+ *
16
+ * Rows go in one transaction and files after it commits: a failed transaction leaves rows pointing at files
17
+ * that still exist, where the opposite order could leave rows pointing at nothing. `alsoInTransaction` runs
18
+ * inside it, for a caller whose own delete (the app row) must land with the builds or not at all.
19
+ */
20
+ export declare function deleteBuildsWithDependents(buildIds: number[], dirs: BuildFileDirs, alsoInTransaction?: () => void): void;
21
+ //# sourceMappingURL=buildDeletion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildDeletion.d.ts","sourceRoot":"","sources":["../../src/lib/buildDeletion.ts"],"names":[],"mappings":"AAKA,wGAAwG;AACxG,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;CACrB;AAUD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,aAAa,EACnB,iBAAiB,GAAE,MAAM,IAAe,GACvC,IAAI,CAkCN"}
@@ -0,0 +1,58 @@
1
+ import path from 'path';
2
+ import { getDb } from '../db.js';
3
+ import { unlinkSafe } from './uploads.js';
4
+ import { resolveBuildFile } from './buildFiles.js';
5
+ const SQLITE_MAX_PARAMS = 999;
6
+ function chunked(arr) {
7
+ const chunks = [];
8
+ for (let i = 0; i < arr.length; i += SQLITE_MAX_PARAMS)
9
+ chunks.push(arr.slice(i, i + SQLITE_MAX_PARAMS));
10
+ return chunks;
11
+ }
12
+ /**
13
+ * Delete builds together with every row that points at them, then their files.
14
+ *
15
+ * **One path for both ways a build goes**, the daily purge and deleting its app. They had drifted: the purge
16
+ * removed recordings first, and app deletion removed nothing — so an app with a recorded build failed its
17
+ * delete on the recordings foreign key (`foreign_keys = ON`), and one without left every build file on disk.
18
+ * Run records are a third dependent, and adding them to one path only would have rebuilt the same drift.
19
+ *
20
+ * Rows go in one transaction and files after it commits: a failed transaction leaves rows pointing at files
21
+ * that still exist, where the opposite order could leave rows pointing at nothing. `alsoInTransaction` runs
22
+ * inside it, for a caller whose own delete (the app row) must land with the builds or not at all.
23
+ */
24
+ export function deleteBuildsWithDependents(buildIds, dirs, alsoInTransaction = () => { }) {
25
+ const db = getDb();
26
+ const chunks = chunked(buildIds);
27
+ const select = (sql) => chunks.flatMap((chunk) => db.prepare(sql(chunk.map(() => '?').join(','))).all(...chunk));
28
+ const builds = select((ph) => `SELECT file_path FROM builds WHERE id IN (${ph})`);
29
+ const recordings = select((ph) => `SELECT filename FROM recordings WHERE build_id IN (${ph})`);
30
+ const screenshots = select((ph) => `
31
+ SELECT f.screenshot_file FROM flow_run_flows f JOIN flow_runs r ON r.seq = f.run_seq
32
+ WHERE r.build_id IN (${ph}) AND f.screenshot_file IS NOT NULL`);
33
+ const videos = select((ph) => `
34
+ SELECT v.file FROM flow_run_videos v JOIN flow_runs r ON r.seq = v.run_seq
35
+ WHERE r.build_id IN (${ph}) AND v.evicted_at IS NULL`);
36
+ db.transaction(() => {
37
+ for (const chunk of chunks) {
38
+ const ph = chunk.map(() => '?').join(',');
39
+ db.prepare(`DELETE FROM recordings WHERE build_id IN (${ph})`).run(...chunk);
40
+ // `flow_run_flows` and the run's videos go with it (ON DELETE CASCADE).
41
+ db.prepare(`DELETE FROM flow_runs WHERE build_id IN (${ph})`).run(...chunk);
42
+ db.prepare(`DELETE FROM builds WHERE id IN (${ph})`).run(...chunk);
43
+ }
44
+ alsoInTransaction();
45
+ })();
46
+ for (const { filename } of recordings)
47
+ unlinkSafe(path.join(dirs.recordingsDir, filename), 'recording');
48
+ for (const { screenshot_file } of screenshots)
49
+ unlinkSafe(path.join(dirs.runScreenshotsDir, screenshot_file), 'run screenshot');
50
+ for (const { file } of videos)
51
+ unlinkSafe(path.join(dirs.runVideosDir, file), 'run video');
52
+ for (const { file_path } of builds) {
53
+ const found = resolveBuildFile(file_path, dirs.uploadsDir);
54
+ if (found !== null)
55
+ unlinkSafe(found, 'build');
56
+ }
57
+ }
58
+ //# sourceMappingURL=buildDeletion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildDeletion.js","sourceRoot":"","sources":["../../src/lib/buildDeletion.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,18 @@ export interface ResolvedClientAddress {
22
22
  * resolved as usual: it keys the login rate limiter and appears in the logs.
23
23
  */
24
24
  export declare function resolveClientAddress(input: ResolveClientAddressInput): ResolvedClientAddress;
25
+ /**
26
+ * A request from a listed proxy that carries no `X-Forwarded-For` is resolved by its socket — local, for a
27
+ * proxy on loopback. That is deliberate: this host's own agent, CLI and first-admin claim arrive exactly so,
28
+ * and by address they cannot be told from a proxied request (GHSA-pq37's finding 2). So it cannot be refused,
29
+ * only noticed. Returns the proxy header that gives such a request away, or `null`.
30
+ *
31
+ * Only on a header a proxy adds, because "from a listed proxy, no `X-Forwarded-For`" alone is every
32
+ * connection the host's agent makes — a warning on that would greet every correct deployment on every
33
+ * start. What this catches is the common slip: an nginx block that sets `X-Real-IP` or
34
+ * `X-Forwarded-Proto` and not `X-Forwarded-For`. A proxy that adds nothing at all cannot be seen.
35
+ */
36
+ export declare function proxiedWithoutForwardedFor(socketAddr: string, headers: http.IncomingHttpHeaders, trustedProxies: string[]): string | null;
25
37
  export declare function markTunnelIngress(req: http.IncomingMessage): void;
26
38
  export declare function isTunnelIngress(req: http.IncomingMessage): boolean;
27
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"clientAddress.d.ts","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAmB5B,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAMrE;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,qBAAqB,CAG5F;AA6BD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,IAAI,CAEjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAQ/G"}
1
+ {"version":3,"file":"clientAddress.d.ts","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAmB5B,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAMrE;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,qBAAqB,CAG5F;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,IAAI,CAAC,mBAAmB,EACjC,cAAc,EAAE,MAAM,EAAE,GACvB,MAAM,GAAG,IAAI,CAKf;AAOD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,IAAI,CAEjE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAQ/G"}
@@ -54,6 +54,28 @@ function resolveByAddress(input) {
54
54
  // 비신뢰 출발지가 보낸 XFF는 스푸핑 가능하므로 무시하고, 어느 경우든 소켓 IP로 판정한다.
55
55
  return { addr: socket, isLocal: isLoopback(socket) };
56
56
  }
57
+ /** Headers a reverse proxy adds and nothing on the relay host sends: the agent, the CLI and a browser on
58
+ * this Mac connect with none of them. */
59
+ const PROXY_ONLY_HEADERS = ['forwarded', 'x-real-ip', 'x-forwarded-proto', 'x-forwarded-host', 'via'];
60
+ /**
61
+ * A request from a listed proxy that carries no `X-Forwarded-For` is resolved by its socket — local, for a
62
+ * proxy on loopback. That is deliberate: this host's own agent, CLI and first-admin claim arrive exactly so,
63
+ * and by address they cannot be told from a proxied request (GHSA-pq37's finding 2). So it cannot be refused,
64
+ * only noticed. Returns the proxy header that gives such a request away, or `null`.
65
+ *
66
+ * Only on a header a proxy adds, because "from a listed proxy, no `X-Forwarded-For`" alone is every
67
+ * connection the host's agent makes — a warning on that would greet every correct deployment on every
68
+ * start. What this catches is the common slip: an nginx block that sets `X-Real-IP` or
69
+ * `X-Forwarded-Proto` and not `X-Forwarded-For`. A proxy that adds nothing at all cannot be seen.
70
+ */
71
+ export function proxiedWithoutForwardedFor(socketAddr, headers, trustedProxies) {
72
+ if (!trustedProxies.includes(normalize(socketAddr)))
73
+ return null;
74
+ const xff = headers['x-forwarded-for'];
75
+ if ((Array.isArray(xff) ? xff.join('') : xff ?? '').trim().length > 0)
76
+ return null;
77
+ return PROXY_ONLY_HEADERS.find((h) => headers[h] !== undefined) ?? null;
78
+ }
57
79
  // Keyed by the request object rather than the socket: an HTTPS server hands its `connection` listener the
58
80
  // raw TCP socket while `req.socket` is the TLS one, and the upgrade path passes this same object on to the
59
81
  // WebSocket `connection` handler.
@@ -1 +1 @@
1
- {"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../../src/lib/clientAddress.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,15 @@
1
1
  export declare function unlinkSafe(filePath: string, label: string): void;
2
+ /**
3
+ * Writes an uploaded file to `dest`. Resolves once it is on disk; on a failed upload or write, closes the
4
+ * writer, removes what was written and rejects.
5
+ *
6
+ * `stream.pipe(writer)` does neither: when busboy destroys a file's stream — a body that ends inside the
7
+ * part — the writer stays open and the partial file stays on disk, once per failed upload.
8
+ *
9
+ * The rejection is marked handled here, for the case where nobody awaits it: a failed part also fails the
10
+ * parser, whose `'error'` handler answers the request, and the route's `'finish'` never runs. A failed
11
+ * *write* (a full disk) is different — the parser still finishes and the route awaits a rejection, so every
12
+ * caller catches it.
13
+ */
14
+ export declare function pipeUpload(stream: NodeJS.ReadableStream, dest: string, label: string): Promise<void>;
2
15
  //# sourceMappingURL=uploads.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE"}
1
+ {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpG"}
@@ -11,4 +11,45 @@ export function unlinkSafe(filePath, label) {
11
11
  }
12
12
  }
13
13
  }
14
+ /**
15
+ * Writes an uploaded file to `dest`. Resolves once it is on disk; on a failed upload or write, closes the
16
+ * writer, removes what was written and rejects.
17
+ *
18
+ * `stream.pipe(writer)` does neither: when busboy destroys a file's stream — a body that ends inside the
19
+ * part — the writer stays open and the partial file stays on disk, once per failed upload.
20
+ *
21
+ * The rejection is marked handled here, for the case where nobody awaits it: a failed part also fails the
22
+ * parser, whose `'error'` handler answers the request, and the route's `'finish'` never runs. A failed
23
+ * *write* (a full disk) is different — the parser still finishes and the route awaits a rejection, so every
24
+ * caller catches it.
25
+ */
26
+ export function pipeUpload(stream, dest, label) {
27
+ const writer = fs.createWriteStream(dest);
28
+ const written = new Promise((resolve, reject) => {
29
+ let failed = false;
30
+ const fail = (err) => {
31
+ if (failed)
32
+ return;
33
+ failed = true;
34
+ // Keep reading the upload: a writer error unpipes it, and a part nobody reads holds the parser short
35
+ // of `'finish'`, so the route would never answer.
36
+ stream.resume();
37
+ // Remove the file once the writer has closed it: Windows refuses to delete an open file, and an error
38
+ // before the open completes would otherwise delete nothing and leave the file it then creates.
39
+ const remove = () => { unlinkSafe(dest, label); reject(err); };
40
+ if (writer.closed)
41
+ remove();
42
+ else {
43
+ writer.once('close', remove);
44
+ writer.destroy();
45
+ }
46
+ };
47
+ writer.on('finish', resolve);
48
+ writer.on('error', fail);
49
+ stream.on('error', fail);
50
+ });
51
+ written.catch(() => { });
52
+ stream.pipe(writer);
53
+ return written;
54
+ }
14
55
  //# sourceMappingURL=uploads.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/lib/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,yDAAyD;AACzD,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,KAAa;IACxD,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,8BAA8B,KAAK,EAAE,EAAG,GAAa,CAAC,OAAO,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,MAA6B,EAAE,IAAY,EAAE,KAAa;IACnF,MAAM,MAAM,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACpD,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,MAAM,IAAI,GAAG,CAAC,GAAY,EAAE,EAAE;YAC5B,IAAI,MAAM;gBAAE,OAAM;YAClB,MAAM,GAAG,IAAI,CAAA;YACb,qGAAqG;YACrG,kDAAkD;YAClD,MAAM,CAAC,MAAM,EAAE,CAAA;YACf,sGAAsG;YACtG,+FAA+F;YAC/F,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA,CAAC,CAAC,CAAA;YAC7D,IAAI,MAAM,CAAC,MAAM;gBAAE,MAAM,EAAE,CAAA;iBACtB,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAAC,MAAM,CAAC,OAAO,EAAE,CAAA;YAAC,CAAC;QACzD,CAAC,CAAA;QACD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC5B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACxB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAC1B,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACvB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACnB,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Point, WatchActionKind } from '@tapflowio/protocol';
2
+ /**
3
+ * A key as watchers see it. **A key that types a character is not named**: watchers are the whole team, and the
4
+ * keys pressed one by one are the text typed. Keep in step with flow-runner's `activityLabel` (`pressKey`), which
5
+ * applies the same rule to a flow step's name.
6
+ */
7
+ export declare function keyForWatchers(code: string): string;
8
+ /** The gesture a touch made, from where it began (if seen) to where it ended. Null when there is nothing to show. */
9
+ export declare function gestureAction(start: Point | null, end: Point | null): WatchActionKind | null;
10
+ //# sourceMappingURL=watchActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchActions.d.ts","sourceRoot":"","sources":["../../src/lib/watchActions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAUjE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED,qHAAqH;AACrH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,eAAe,GAAG,IAAI,CAM5F"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What a session's watchers are told the holder did (A2), derived from the input the relay passes on. Pure, so the
3
+ * rules are tested apart from the socket plumbing.
4
+ */
5
+ /** A touch that ends within this distance of where it began is a tap; further is a swipe. Normalised 0–1. */
6
+ const TAP_RADIUS = 0.02;
7
+ /**
8
+ * A key as watchers see it. **A key that types a character is not named**: watchers are the whole team, and the
9
+ * keys pressed one by one are the text typed. Keep in step with flow-runner's `activityLabel` (`pressKey`), which
10
+ * applies the same rule to a flow step's name.
11
+ */
12
+ export function keyForWatchers(code) {
13
+ return /^(Key[A-Z]|Digit\d|Numpad\d|Numpad(Add|Subtract|Multiply|Divide|Decimal|Comma|Equal|ParenLeft|ParenRight|Hash|Star)|Space|Minus|Equal|Bracket(Left|Right)|Backslash|Semicolon|Quote|Backquote|Comma|Period|Slash|IntlBackslash|IntlRo|IntlYen)$/.test(code)
14
+ || code.length === 1
15
+ ? 'character'
16
+ : code;
17
+ }
18
+ /** The gesture a touch made, from where it began (if seen) to where it ended. Null when there is nothing to show. */
19
+ export function gestureAction(start, end) {
20
+ if (!start)
21
+ return end ? { kind: 'tap', x: end.x, y: end.y } : null;
22
+ const to = end ?? start;
23
+ return Math.hypot(to.x - start.x, to.y - start.y) <= TAP_RADIUS
24
+ ? { kind: 'tap', x: start.x, y: start.y }
25
+ : { kind: 'swipe', from: [start.x, start.y], to: [to.x, to.y] };
26
+ }
27
+ //# sourceMappingURL=watchActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchActions.js","sourceRoot":"","sources":["../../src/lib/watchActions.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,6GAA6G;AAC7G,MAAM,UAAU,GAAG,IAAI,CAAA;AAEvB;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,iPAAiP,CAAC,IAAI,CAAC,IAAI,CAAC;WAC9P,IAAI,CAAC,MAAM,KAAK,CAAC;QACpB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,IAAI,CAAA;AACV,CAAC;AAED,qHAAqH;AACrH,MAAM,UAAU,aAAa,CAAC,KAAmB,EAAE,GAAiB;IAClE,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACnE,MAAM,EAAE,GAAG,GAAG,IAAI,KAAK,CAAA;IACvB,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU;QAC7D,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;QACzC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AACnE,CAAC"}
@@ -77,5 +77,6 @@ export declare function hashPat(token: string): string;
77
77
  export declare function requireViewAuth(req: http.IncomingMessage, res: http.ServerResponse): AuthContext | null;
78
78
  export declare function requireBuildAuth(req: http.IncomingMessage, res: http.ServerResponse): {
79
79
  userId: number;
80
+ patId?: number;
80
81
  } | null;
81
82
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAOvB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEnE;AAED,2GAA2G;AAC3G,wBAAgB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAWpD;AAED,2GAA2G;AAC3G,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAE1D;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAM3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAM3D;AAED,wFAAwF;AACxF,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,iGAAiG;IACjG,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0GAA0G;IAC1G,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,WAAW,GAAG,IAAI,CASrE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAK5F;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,WAAW,GAAG,IAAI,CAQpB;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUnF;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,EAAE,GACd,WAAW,GAAG,IAAI,CAWpB;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAShF;AAED,oEAAoE;AACpE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAyBD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,GAAG,IAAI,CAMnE;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAGrD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,WAAW,GAAG,IAAI,CAgBpB;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAc3B"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AAOvB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEnE;AAED,2GAA2G;AAC3G,wBAAgB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAWpD;AAED,2GAA2G;AAC3G,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAE1D;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAM3D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAM3D;AAED,wFAAwF;AACxF,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,iGAAiG;IACjG,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,0GAA0G;IAC1G,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,WAAW,GAAG,IAAI,CASrE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAK5F;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,WAAW,GAAG,IAAI,CAQpB;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUnF;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,EAAE,GACd,WAAW,GAAG,IAAI,CAWpB;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAShF;AAED,oEAAoE;AACpE,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAyBD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,GAAG,IAAI,CAMnE;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAGrD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,WAAW,GAAG,IAAI,CAgBpB;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAc3C"}
@@ -203,7 +203,7 @@ export function requireBuildAuth(req, res) {
203
203
  return null;
204
204
  }
205
205
  touchPat(pat.patId);
206
- return { userId: pat.userId };
206
+ return { userId: pat.userId, patId: pat.patId };
207
207
  }
208
208
  const auth = requireAuth(req, res);
209
209
  if (!auth)
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ -- 015_flow_runs.sql
2
+ -- A record of each `tapflow flow run`: the runs page lists them (in progress and history), and a build's
3
+ -- runs go when the build goes. Written by the CLI over REST with a `builds:write` token.
4
+
5
+ CREATE TABLE IF NOT EXISTS flow_runs (
6
+ -- `seq` orders and pages the list; `id` is what clients see, so a run's address does not count runs.
7
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
8
+ id TEXT NOT NULL UNIQUE,
9
+ -- No ON DELETE: a build's runs are removed with it by `deleteBuildsWithDependents`, which also unlinks
10
+ -- their screenshot files. A cascade would drop the rows and leave the files.
11
+ build_id INTEGER REFERENCES builds(id),
12
+ -- The runner's `?client=` id. The run is live while a socket with that id is open — see `holderKeys`.
13
+ holder_client TEXT NOT NULL,
14
+ -- SET NULL: removing a member keeps the team's history. Their PATs are gone, so nobody can write to it.
15
+ created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
16
+ -- Not a foreign key: revoking a token deletes its row, and the run must outlive that.
17
+ pat_id INTEGER,
18
+ is_ci INTEGER NOT NULL DEFAULT 0,
19
+ ci_provider TEXT,
20
+ ci_branch TEXT,
21
+ ci_commit TEXT,
22
+ ci_job_url TEXT,
23
+ status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running', 'passed', 'failed', 'aborted')),
24
+ -- 'client' when the CLI finished it, 'relay' when the relay closed it because the holder went away.
25
+ finished_by TEXT CHECK (finished_by IN ('client', 'relay')),
26
+ failure_kind TEXT,
27
+ error_message TEXT,
28
+ exit_code INTEGER,
29
+ flows_json TEXT NOT NULL,
30
+ flows_total INTEGER NOT NULL,
31
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
32
+ last_activity_at TEXT NOT NULL DEFAULT (datetime('now')),
33
+ finished_at TEXT,
34
+ -- Only for a run with no build; a build's runs follow the build's own lifecycle.
35
+ delete_after TEXT
36
+ );
37
+
38
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_build ON flow_runs(build_id);
39
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_ci ON flow_runs(is_ci, seq);
40
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_status ON flow_runs(status, last_activity_at);
41
+ CREATE INDEX IF NOT EXISTS idx_flow_runs_delete_after ON flow_runs(delete_after);
42
+
43
+ CREATE TABLE IF NOT EXISTS flow_run_flows (
44
+ run_seq INTEGER NOT NULL REFERENCES flow_runs(seq) ON DELETE CASCADE,
45
+ idx INTEGER NOT NULL,
46
+ name TEXT NOT NULL,
47
+ file TEXT,
48
+ device_id TEXT,
49
+ device_name TEXT,
50
+ platform TEXT,
51
+ status TEXT NOT NULL CHECK (status IN ('passed', 'failed')),
52
+ failure_kind TEXT,
53
+ failure_message TEXT,
54
+ duration_ms INTEGER NOT NULL,
55
+ steps_json TEXT NOT NULL,
56
+ screenshot_file TEXT,
57
+ screenshot_mime TEXT,
58
+ PRIMARY KEY (run_seq, idx)
59
+ );