watch-tail 0.6.1 → 0.7.1

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 (268) hide show
  1. package/README.md +115 -354
  2. package/build/client/_app/immutable/assets/0.DKleCc0-.css +2 -0
  3. package/build/client/_app/immutable/assets/0.DKleCc0-.css.br +0 -0
  4. package/build/client/_app/immutable/assets/0.DKleCc0-.css.gz +0 -0
  5. package/build/client/_app/immutable/chunks/{CJY9dzlo.js → 1mB5Ee1Q.js} +1 -1
  6. package/build/client/_app/immutable/chunks/1mB5Ee1Q.js.br +0 -0
  7. package/build/client/_app/immutable/chunks/1mB5Ee1Q.js.gz +0 -0
  8. package/build/client/_app/immutable/chunks/{0HQmZBP8.js → 3fFVdy92.js} +1 -1
  9. package/build/client/_app/immutable/chunks/3fFVdy92.js.br +0 -0
  10. package/build/client/_app/immutable/chunks/3fFVdy92.js.gz +0 -0
  11. package/build/client/_app/immutable/chunks/{CHWzTWIO.js → 8mpn3Xst.js} +1 -1
  12. package/build/client/_app/immutable/chunks/8mpn3Xst.js.br +0 -0
  13. package/build/client/_app/immutable/chunks/8mpn3Xst.js.gz +0 -0
  14. package/build/client/_app/immutable/chunks/{CIRHUa7o.js → B78Vj1az.js} +1 -1
  15. package/build/client/_app/immutable/chunks/B78Vj1az.js.br +0 -0
  16. package/build/client/_app/immutable/chunks/B78Vj1az.js.gz +0 -0
  17. package/build/client/_app/immutable/chunks/{DsjX0FWg.js → B7aS9tS2.js} +1 -1
  18. package/build/client/_app/immutable/chunks/B7aS9tS2.js.br +0 -0
  19. package/build/client/_app/immutable/chunks/B7aS9tS2.js.gz +0 -0
  20. package/build/client/_app/immutable/chunks/{Bpq3-dbO.js → BF84Orj8.js} +1 -1
  21. package/build/client/_app/immutable/chunks/BF84Orj8.js.br +0 -0
  22. package/build/client/_app/immutable/chunks/BF84Orj8.js.gz +0 -0
  23. package/build/client/_app/immutable/chunks/BIdvnjrP.js +1 -0
  24. package/build/client/_app/immutable/chunks/BIdvnjrP.js.br +1 -0
  25. package/build/client/_app/immutable/chunks/BIdvnjrP.js.gz +0 -0
  26. package/build/client/_app/immutable/chunks/{BNZjpNgL.js → BPoZrXrH.js} +1 -1
  27. package/build/client/_app/immutable/chunks/BPoZrXrH.js.br +0 -0
  28. package/build/client/_app/immutable/chunks/BPoZrXrH.js.gz +0 -0
  29. package/build/client/_app/immutable/chunks/{BPnf3PCq.js → BSy__Jrd.js} +1 -1
  30. package/build/client/_app/immutable/chunks/BSy__Jrd.js.br +0 -0
  31. package/build/client/_app/immutable/chunks/BSy__Jrd.js.gz +0 -0
  32. package/build/client/_app/immutable/chunks/{BLIhNWn-.js → BdW_yBQU.js} +1 -1
  33. package/build/client/_app/immutable/chunks/BdW_yBQU.js.br +0 -0
  34. package/build/client/_app/immutable/chunks/BdW_yBQU.js.gz +0 -0
  35. package/build/client/_app/immutable/chunks/{BMFtpXWH.js → BnRQs9nz.js} +5 -5
  36. package/build/client/_app/immutable/chunks/BnRQs9nz.js.br +0 -0
  37. package/build/client/_app/immutable/chunks/BnRQs9nz.js.gz +0 -0
  38. package/build/client/_app/immutable/chunks/{MQIJFRGs.js → C6r7NvtG.js} +1 -1
  39. package/build/client/_app/immutable/chunks/C6r7NvtG.js.br +0 -0
  40. package/build/client/_app/immutable/chunks/C6r7NvtG.js.gz +0 -0
  41. package/build/client/_app/immutable/chunks/{B7Wrulwc.js → CEw1go7g.js} +1 -1
  42. package/build/client/_app/immutable/chunks/CEw1go7g.js.br +0 -0
  43. package/build/client/_app/immutable/chunks/CEw1go7g.js.gz +0 -0
  44. package/build/client/_app/immutable/chunks/{BMAPes50.js → CFJEGo4j.js} +1 -1
  45. package/build/client/_app/immutable/chunks/CFJEGo4j.js.br +0 -0
  46. package/build/client/_app/immutable/chunks/CFJEGo4j.js.gz +0 -0
  47. package/build/client/_app/immutable/chunks/CGnVqaBL.js +1 -0
  48. package/build/client/_app/immutable/chunks/CGnVqaBL.js.br +0 -0
  49. package/build/client/_app/immutable/chunks/CGnVqaBL.js.gz +0 -0
  50. package/build/client/_app/immutable/chunks/{CknPwNsn.js → CY8zQ4KM.js} +1 -1
  51. package/build/client/_app/immutable/chunks/CY8zQ4KM.js.br +0 -0
  52. package/build/client/_app/immutable/chunks/CY8zQ4KM.js.gz +0 -0
  53. package/build/client/_app/immutable/chunks/{DGPOPiag.js → CZ3S843d.js} +1 -1
  54. package/build/client/_app/immutable/chunks/CZ3S843d.js.br +0 -0
  55. package/build/client/_app/immutable/chunks/CZ3S843d.js.gz +0 -0
  56. package/build/client/_app/immutable/chunks/{BS49-HdT.js → CgAZPeK7.js} +1 -1
  57. package/build/client/_app/immutable/chunks/CgAZPeK7.js.br +0 -0
  58. package/build/client/_app/immutable/chunks/CgAZPeK7.js.gz +0 -0
  59. package/build/client/_app/immutable/chunks/{B5Gt-01T.js → CrmB4MvE.js} +1 -1
  60. package/build/client/_app/immutable/chunks/CrmB4MvE.js.br +0 -0
  61. package/build/client/_app/immutable/chunks/CrmB4MvE.js.gz +0 -0
  62. package/build/client/_app/immutable/chunks/{HbGXDNOY.js → CtWwlW0t.js} +1 -1
  63. package/build/client/_app/immutable/chunks/CtWwlW0t.js.br +0 -0
  64. package/build/client/_app/immutable/chunks/CtWwlW0t.js.gz +0 -0
  65. package/build/client/_app/immutable/chunks/{DOY2FQbe.js → D-AkVRH7.js} +1 -1
  66. package/build/client/_app/immutable/chunks/D-AkVRH7.js.br +0 -0
  67. package/build/client/_app/immutable/chunks/D-AkVRH7.js.gz +0 -0
  68. package/build/client/_app/immutable/chunks/{DeAq2fo8.js → D0CZlpgd.js} +1 -1
  69. package/build/client/_app/immutable/chunks/D0CZlpgd.js.br +0 -0
  70. package/build/client/_app/immutable/chunks/D0CZlpgd.js.gz +0 -0
  71. package/build/client/_app/immutable/chunks/{BNe95Eqc.js → D0IZin0e.js} +1 -1
  72. package/build/client/_app/immutable/chunks/D0IZin0e.js.br +0 -0
  73. package/build/client/_app/immutable/chunks/D0IZin0e.js.gz +0 -0
  74. package/build/client/_app/immutable/chunks/{C5DTlk-U.js → DI6o1zMC.js} +1 -1
  75. package/build/client/_app/immutable/chunks/DI6o1zMC.js.br +0 -0
  76. package/build/client/_app/immutable/chunks/DI6o1zMC.js.gz +0 -0
  77. package/build/client/_app/immutable/chunks/{SPw4Pe1k.js → DbWb9_dK.js} +1 -1
  78. package/build/client/_app/immutable/chunks/DbWb9_dK.js.br +0 -0
  79. package/build/client/_app/immutable/chunks/DbWb9_dK.js.gz +0 -0
  80. package/build/client/_app/immutable/chunks/{DBvBFE2b.js → Dh3ZWuG8.js} +1 -1
  81. package/build/client/_app/immutable/chunks/Dh3ZWuG8.js.br +0 -0
  82. package/build/client/_app/immutable/chunks/Dh3ZWuG8.js.gz +0 -0
  83. package/build/client/_app/immutable/chunks/{BZ7frOsj.js → Dp3OTI-g.js} +1 -1
  84. package/build/client/_app/immutable/chunks/Dp3OTI-g.js.br +0 -0
  85. package/build/client/_app/immutable/chunks/Dp3OTI-g.js.gz +0 -0
  86. package/build/client/_app/immutable/chunks/{ByL_HxfT.js → DtdjxckD.js} +1 -1
  87. package/build/client/_app/immutable/chunks/DtdjxckD.js.br +0 -0
  88. package/build/client/_app/immutable/chunks/DtdjxckD.js.gz +0 -0
  89. package/build/client/_app/immutable/chunks/YehCS1lO.js +5 -0
  90. package/build/client/_app/immutable/chunks/YehCS1lO.js.br +0 -0
  91. package/build/client/_app/immutable/chunks/YehCS1lO.js.gz +0 -0
  92. package/build/client/_app/immutable/chunks/{BQzvXDmX.js → g-7YfdwH.js} +1 -1
  93. package/build/client/_app/immutable/chunks/g-7YfdwH.js.br +0 -0
  94. package/build/client/_app/immutable/chunks/g-7YfdwH.js.gz +0 -0
  95. package/build/client/_app/immutable/chunks/{BVyebcr0.js → zfc2KyIr.js} +1 -1
  96. package/build/client/_app/immutable/chunks/zfc2KyIr.js.br +0 -0
  97. package/build/client/_app/immutable/chunks/zfc2KyIr.js.gz +0 -0
  98. package/build/client/_app/immutable/entry/{app.B1Kx6Gr2.js → app.C-KKyvGI.js} +2 -2
  99. package/build/client/_app/immutable/entry/app.C-KKyvGI.js.br +0 -0
  100. package/build/client/_app/immutable/entry/app.C-KKyvGI.js.gz +0 -0
  101. package/build/client/_app/immutable/entry/start.obx3dQT_.js +1 -0
  102. package/build/client/_app/immutable/entry/start.obx3dQT_.js.br +1 -0
  103. package/build/client/_app/immutable/entry/start.obx3dQT_.js.gz +0 -0
  104. package/build/client/_app/immutable/nodes/{0.BN3NguWs.js → 0.2dnHMwE1.js} +1 -1
  105. package/build/client/_app/immutable/nodes/0.2dnHMwE1.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/{0.BN3NguWs.js.gz → 0.2dnHMwE1.js.gz} +0 -0
  107. package/build/client/_app/immutable/nodes/{1.CjbVqPIj.js → 1.D5nbnmDb.js} +1 -1
  108. package/build/client/_app/immutable/nodes/1.D5nbnmDb.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/1.D5nbnmDb.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/2.DAQ4mvAt.js +5 -0
  111. package/build/client/_app/immutable/nodes/2.DAQ4mvAt.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/2.DAQ4mvAt.js.gz +0 -0
  113. package/build/client/_app/version.json +1 -1
  114. package/build/client/_app/version.json.br +0 -0
  115. package/build/client/_app/version.json.gz +0 -0
  116. package/build/handler.js +4 -4
  117. package/build/index.js +4 -4
  118. package/build/server/chunks/chunks/{EventScatter.js-D3Jaw_Cw.js → EventScatter.js-Du7AJN9m.js} +50 -17
  119. package/build/server/chunks/chunks/{EventScatter.js-D3Jaw_Cw.js.map → EventScatter.js-Du7AJN9m.js.map} +1 -1
  120. package/build/server/chunks/chunks/{archive.js-C2D-5edp.js → archive.js-D2jtMmDo.js} +134 -26
  121. package/build/server/chunks/chunks/archive.js-D2jtMmDo.js.map +1 -0
  122. package/build/server/chunks/chunks/{aws.js-DkPqAybc.js → env2.js-C5BgBJDY.js} +63 -6
  123. package/build/server/chunks/chunks/env2.js-C5BgBJDY.js.map +1 -0
  124. package/build/server/chunks/chunks/identity.js-NmGXxBz3.js +22 -0
  125. package/build/server/chunks/chunks/identity.js-NmGXxBz3.js.map +1 -0
  126. package/build/server/chunks/chunks/{internal2.js-V-6GgvEA.js → internal2.js--RCssYze.js} +2 -2
  127. package/build/server/chunks/chunks/{internal2.js-V-6GgvEA.js.map → internal2.js--RCssYze.js.map} +1 -1
  128. package/build/server/chunks/chunks/{level-filter.js-B3o2hyWD.js → level-filter.js-D9MNrew3.js} +2 -2
  129. package/build/server/chunks/chunks/{level-filter.js-B3o2hyWD.js.map → level-filter.js-D9MNrew3.js.map} +1 -1
  130. package/build/server/chunks/chunks/{log-buffer.js-BI_gQOls.js → log-buffer.js-A9FA-Qv8.js} +18 -3
  131. package/build/server/chunks/chunks/log-buffer.js-A9FA-Qv8.js.map +1 -0
  132. package/build/server/chunks/chunks/{regions.js-IQPMyP5C.js → regions.js-COf7DgnH.js} +3 -3
  133. package/build/server/chunks/chunks/regions.js-COf7DgnH.js.map +1 -0
  134. package/build/server/chunks/chunks/{series-buckets.js-BjigySff.js → series-buckets.js-BmCYga3F.js} +28 -3
  135. package/build/server/chunks/chunks/series-buckets.js-BmCYga3F.js.map +1 -0
  136. package/build/server/chunks/chunks/{state.js-D3IR3OVb.js → state.js-CI2ef6Vi.js} +2 -2
  137. package/build/server/chunks/chunks/{state.js-D3IR3OVb.js.map → state.js-CI2ef6Vi.js.map} +1 -1
  138. package/build/server/chunks/entries/endpoints/api/archive/{_server.ts.js-83Ch7djd.js → _server.ts.js-C4hWyXuu.js} +17 -9
  139. package/build/server/chunks/entries/endpoints/api/archive/_server.ts.js-C4hWyXuu.js.map +1 -0
  140. package/build/server/chunks/entries/endpoints/api/health/{_server.ts.js-VctnBhIJ.js → _server.ts.js-C5tfrpmC.js} +4 -5
  141. package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-C5tfrpmC.js.map +1 -0
  142. package/build/server/chunks/entries/endpoints/api/identity/{_server.ts.js-Dt540Sio.js → _server.ts.js-PWRPScuN.js} +6 -24
  143. package/build/server/chunks/entries/endpoints/api/identity/_server.ts.js-PWRPScuN.js.map +1 -0
  144. package/build/server/chunks/entries/endpoints/api/log-groups/{_server.ts.js-drLgUdvB.js → _server.ts.js-D4y43Vwe.js} +14 -11
  145. package/build/server/chunks/entries/endpoints/api/log-groups/_server.ts.js-D4y43Vwe.js.map +1 -0
  146. package/build/server/chunks/entries/endpoints/api/regions/{_server.ts.js-CBqfN6Pg.js → _server.ts.js-9_g0ojki.js} +8 -9
  147. package/build/server/chunks/entries/endpoints/api/regions/_server.ts.js-9_g0ojki.js.map +1 -0
  148. package/build/server/chunks/entries/endpoints/api/series/{_server.ts.js-DOvBhEDU.js → _server.ts.js-DibT3Hjc.js} +34 -16
  149. package/build/server/chunks/entries/endpoints/api/series/_server.ts.js-DibT3Hjc.js.map +1 -0
  150. package/build/server/chunks/entries/endpoints/api/stream/{_server.ts.js-B9_-4ssJ.js → _server.ts.js-3ZYI-Za9.js} +15 -12
  151. package/build/server/chunks/entries/endpoints/api/stream/_server.ts.js-3ZYI-Za9.js.map +1 -0
  152. package/build/server/chunks/entries/fallbacks/{error.svelte.js-C9F075al.js → error.svelte.js-DP0OULWi.js} +3 -3
  153. package/build/server/chunks/entries/fallbacks/{error.svelte.js-C9F075al.js.map → error.svelte.js-DP0OULWi.js.map} +1 -1
  154. package/build/server/chunks/entries/pages/{_layout.svelte.js-CBQpEToy.js → _layout.svelte.js-8U7ZeKYO.js} +3 -3
  155. package/build/server/chunks/entries/pages/_layout.svelte.js-8U7ZeKYO.js.map +1 -0
  156. package/build/server/chunks/entries/pages/{_page.svelte.js-NmVMu4KB.js → _page.svelte.js-hG1agdw-.js} +82 -33
  157. package/build/server/chunks/entries/pages/_page.svelte.js-hG1agdw-.js.map +1 -0
  158. package/build/server/chunks/{handler-dtYbHuwP.js → handler-_dxqeJJj.js} +3 -3
  159. package/build/server/chunks/{handler-dtYbHuwP.js.map → handler-_dxqeJJj.js.map} +1 -1
  160. package/build/server/chunks/{index.js-C9CJvnha.js → index.js-arX1nCCw.js} +2 -2
  161. package/build/server/chunks/{index.js-C9CJvnha.js.map → index.js-arX1nCCw.js.map} +1 -1
  162. package/build/server/chunks/{manifest.js-C_VOyvDI.js → manifest.js-D3447-0_.js} +12 -12
  163. package/build/server/chunks/{manifest.js-C_VOyvDI.js.map → manifest.js-D3447-0_.js.map} +1 -1
  164. package/build/server/chunks/nodes/{0.js-CNFDDPj5.js → 0.js-XM75fTfb.js} +4 -4
  165. package/build/server/chunks/nodes/{0.js-CNFDDPj5.js.map → 0.js-XM75fTfb.js.map} +1 -1
  166. package/build/server/chunks/nodes/{1.js-bsWFfMNd.js → 1.js-CRIDfcrR.js} +3 -3
  167. package/build/server/chunks/nodes/{1.js-bsWFfMNd.js.map → 1.js-CRIDfcrR.js.map} +1 -1
  168. package/build/server/chunks/nodes/{2.js-Cq_bF6lW.js → 2.js-1qmqKlMg.js} +3 -3
  169. package/build/server/chunks/nodes/{2.js-Cq_bF6lW.js.map → 2.js-1qmqKlMg.js.map} +1 -1
  170. package/dist/cli/options.js +1 -1
  171. package/dist/lib/cli/aws.js +4 -4
  172. package/dist/lib/log-buffer.js +1 -1
  173. package/package.json +7 -6
  174. package/build/client/_app/immutable/assets/0.Dfts6BC4.css +0 -2
  175. package/build/client/_app/immutable/assets/0.Dfts6BC4.css.br +0 -0
  176. package/build/client/_app/immutable/assets/0.Dfts6BC4.css.gz +0 -0
  177. package/build/client/_app/immutable/chunks/0HQmZBP8.js.br +0 -0
  178. package/build/client/_app/immutable/chunks/0HQmZBP8.js.gz +0 -0
  179. package/build/client/_app/immutable/chunks/B5Gt-01T.js.br +0 -0
  180. package/build/client/_app/immutable/chunks/B5Gt-01T.js.gz +0 -0
  181. package/build/client/_app/immutable/chunks/B7Wrulwc.js.br +0 -0
  182. package/build/client/_app/immutable/chunks/B7Wrulwc.js.gz +0 -0
  183. package/build/client/_app/immutable/chunks/BDcZ4Wyi.js +0 -1
  184. package/build/client/_app/immutable/chunks/BDcZ4Wyi.js.br +0 -0
  185. package/build/client/_app/immutable/chunks/BDcZ4Wyi.js.gz +0 -0
  186. package/build/client/_app/immutable/chunks/BLIhNWn-.js.br +0 -0
  187. package/build/client/_app/immutable/chunks/BLIhNWn-.js.gz +0 -0
  188. package/build/client/_app/immutable/chunks/BMAPes50.js.br +0 -0
  189. package/build/client/_app/immutable/chunks/BMAPes50.js.gz +0 -0
  190. package/build/client/_app/immutable/chunks/BMFtpXWH.js.br +0 -0
  191. package/build/client/_app/immutable/chunks/BMFtpXWH.js.gz +0 -0
  192. package/build/client/_app/immutable/chunks/BNZjpNgL.js.br +0 -0
  193. package/build/client/_app/immutable/chunks/BNZjpNgL.js.gz +0 -0
  194. package/build/client/_app/immutable/chunks/BNe95Eqc.js.br +0 -0
  195. package/build/client/_app/immutable/chunks/BNe95Eqc.js.gz +0 -0
  196. package/build/client/_app/immutable/chunks/BPnf3PCq.js.br +0 -0
  197. package/build/client/_app/immutable/chunks/BPnf3PCq.js.gz +0 -0
  198. package/build/client/_app/immutable/chunks/BQzvXDmX.js.br +0 -0
  199. package/build/client/_app/immutable/chunks/BQzvXDmX.js.gz +0 -0
  200. package/build/client/_app/immutable/chunks/BS49-HdT.js.br +0 -0
  201. package/build/client/_app/immutable/chunks/BS49-HdT.js.gz +0 -0
  202. package/build/client/_app/immutable/chunks/BVyebcr0.js.br +0 -0
  203. package/build/client/_app/immutable/chunks/BVyebcr0.js.gz +0 -0
  204. package/build/client/_app/immutable/chunks/BZ7frOsj.js.br +0 -0
  205. package/build/client/_app/immutable/chunks/BZ7frOsj.js.gz +0 -0
  206. package/build/client/_app/immutable/chunks/BjxZ_neZ.js +0 -5
  207. package/build/client/_app/immutable/chunks/BjxZ_neZ.js.br +0 -0
  208. package/build/client/_app/immutable/chunks/BjxZ_neZ.js.gz +0 -0
  209. package/build/client/_app/immutable/chunks/Bpq3-dbO.js.br +0 -0
  210. package/build/client/_app/immutable/chunks/Bpq3-dbO.js.gz +0 -0
  211. package/build/client/_app/immutable/chunks/ByL_HxfT.js.br +0 -0
  212. package/build/client/_app/immutable/chunks/ByL_HxfT.js.gz +0 -0
  213. package/build/client/_app/immutable/chunks/C5DTlk-U.js.br +0 -0
  214. package/build/client/_app/immutable/chunks/C5DTlk-U.js.gz +0 -0
  215. package/build/client/_app/immutable/chunks/CHWzTWIO.js.br +0 -0
  216. package/build/client/_app/immutable/chunks/CHWzTWIO.js.gz +0 -0
  217. package/build/client/_app/immutable/chunks/CIRHUa7o.js.br +0 -0
  218. package/build/client/_app/immutable/chunks/CIRHUa7o.js.gz +0 -0
  219. package/build/client/_app/immutable/chunks/CJY9dzlo.js.br +0 -0
  220. package/build/client/_app/immutable/chunks/CJY9dzlo.js.gz +0 -0
  221. package/build/client/_app/immutable/chunks/CYBzPCyF.js +0 -1
  222. package/build/client/_app/immutable/chunks/CYBzPCyF.js.br +0 -0
  223. package/build/client/_app/immutable/chunks/CYBzPCyF.js.gz +0 -0
  224. package/build/client/_app/immutable/chunks/CknPwNsn.js.br +0 -0
  225. package/build/client/_app/immutable/chunks/CknPwNsn.js.gz +0 -0
  226. package/build/client/_app/immutable/chunks/DBvBFE2b.js.br +0 -0
  227. package/build/client/_app/immutable/chunks/DBvBFE2b.js.gz +0 -0
  228. package/build/client/_app/immutable/chunks/DGPOPiag.js.br +0 -0
  229. package/build/client/_app/immutable/chunks/DGPOPiag.js.gz +0 -0
  230. package/build/client/_app/immutable/chunks/DOY2FQbe.js.br +0 -0
  231. package/build/client/_app/immutable/chunks/DOY2FQbe.js.gz +0 -0
  232. package/build/client/_app/immutable/chunks/DeAq2fo8.js.br +0 -2
  233. package/build/client/_app/immutable/chunks/DeAq2fo8.js.gz +0 -0
  234. package/build/client/_app/immutable/chunks/DsjX0FWg.js.br +0 -0
  235. package/build/client/_app/immutable/chunks/DsjX0FWg.js.gz +0 -0
  236. package/build/client/_app/immutable/chunks/HbGXDNOY.js.br +0 -0
  237. package/build/client/_app/immutable/chunks/HbGXDNOY.js.gz +0 -0
  238. package/build/client/_app/immutable/chunks/MQIJFRGs.js.br +0 -0
  239. package/build/client/_app/immutable/chunks/MQIJFRGs.js.gz +0 -0
  240. package/build/client/_app/immutable/chunks/SPw4Pe1k.js.br +0 -0
  241. package/build/client/_app/immutable/chunks/SPw4Pe1k.js.gz +0 -0
  242. package/build/client/_app/immutable/entry/app.B1Kx6Gr2.js.br +0 -0
  243. package/build/client/_app/immutable/entry/app.B1Kx6Gr2.js.gz +0 -0
  244. package/build/client/_app/immutable/entry/start.DUspS8mW.js +0 -1
  245. package/build/client/_app/immutable/entry/start.DUspS8mW.js.br +0 -0
  246. package/build/client/_app/immutable/entry/start.DUspS8mW.js.gz +0 -0
  247. package/build/client/_app/immutable/nodes/0.BN3NguWs.js.br +0 -0
  248. package/build/client/_app/immutable/nodes/1.CjbVqPIj.js.br +0 -0
  249. package/build/client/_app/immutable/nodes/1.CjbVqPIj.js.gz +0 -0
  250. package/build/client/_app/immutable/nodes/2.B3li1f44.js +0 -4
  251. package/build/client/_app/immutable/nodes/2.B3li1f44.js.br +0 -0
  252. package/build/client/_app/immutable/nodes/2.B3li1f44.js.gz +0 -0
  253. package/build/server/chunks/chunks/archive.js-C2D-5edp.js.map +0 -1
  254. package/build/server/chunks/chunks/aws.js-DkPqAybc.js.map +0 -1
  255. package/build/server/chunks/chunks/env2.js-CcIskxOZ.js +0 -60
  256. package/build/server/chunks/chunks/env2.js-CcIskxOZ.js.map +0 -1
  257. package/build/server/chunks/chunks/log-buffer.js-BI_gQOls.js.map +0 -1
  258. package/build/server/chunks/chunks/regions.js-IQPMyP5C.js.map +0 -1
  259. package/build/server/chunks/chunks/series-buckets.js-BjigySff.js.map +0 -1
  260. package/build/server/chunks/entries/endpoints/api/archive/_server.ts.js-83Ch7djd.js.map +0 -1
  261. package/build/server/chunks/entries/endpoints/api/health/_server.ts.js-VctnBhIJ.js.map +0 -1
  262. package/build/server/chunks/entries/endpoints/api/identity/_server.ts.js-Dt540Sio.js.map +0 -1
  263. package/build/server/chunks/entries/endpoints/api/log-groups/_server.ts.js-drLgUdvB.js.map +0 -1
  264. package/build/server/chunks/entries/endpoints/api/regions/_server.ts.js-CBqfN6Pg.js.map +0 -1
  265. package/build/server/chunks/entries/endpoints/api/series/_server.ts.js-DOvBhEDU.js.map +0 -1
  266. package/build/server/chunks/entries/endpoints/api/stream/_server.ts.js-B9_-4ssJ.js.map +0 -1
  267. package/build/server/chunks/entries/pages/_layout.svelte.js-CBQpEToy.js.map +0 -1
  268. package/build/server/chunks/entries/pages/_page.svelte.js-NmVMu4KB.js.map +0 -1
package/README.md CHANGED
@@ -2,100 +2,111 @@
2
2
 
3
3
  # watch-tail
4
4
 
5
- **Your CloudWatch logs, in a real window, in one command.**
5
+ **CloudWatch logs. One command. A clearer picture.**
6
6
 
7
- `npx watch-tail` starts a local UI, lists the log groups in your AWS account, and streams whichever one
8
- you pick - live, or across any historic window. No config file, no credentials to paste, no browser
9
- tab fighting the AWS console.
7
+ Tail live logs, investigate an incident across services, and keep what you find in a local archive.
8
+ Uses your existing AWS credentials. Runs on your machine.
10
9
 
11
10
  [![npm version](https://img.shields.io/npm/v/watch-tail?color=blue)](https://www.npmjs.com/package/watch-tail)
12
- [![CI](https://github.com/antstanley/watch-stream/actions/workflows/ci.yml/badge.svg)](https://github.com/antstanley/watch-stream/actions/workflows/ci.yml)
11
+ [![CI](https://github.com/antstanley/watch-tail/actions/workflows/ci.yml/badge.svg)](https://github.com/antstanley/watch-tail/actions/workflows/ci.yml)
13
12
  [![license](https://img.shields.io/npm/l/watch-tail)](./LICENSE)
14
13
  [![node](https://img.shields.io/node/v/watch-tail)](package.json)
15
14
 
16
- <img src="./docs/screenshot.png" alt="watch-tail streaming CloudWatch Logs" width="900">
15
+ <img src="https://raw.githubusercontent.com/antstanley/watch-tail/v0.7.1/docs/watch-tail-overview.png" alt="watch-tail: historic logs from multiple groups, with severity chart and request grouping" width="1200">
17
16
 
18
17
  </div>
19
18
 
19
+ ## Start here
20
+
20
21
  ```bash
21
- npx watch-tail # uses your ambient AWS credentials
22
- npx watch-tail --profile my-profile --region af-south-1 # or a specific profile and region
23
- npx watch-tail --floci # or a local emulator, no AWS account
22
+ npx watch-tail # use your existing AWS credentials
23
+ npx watch-tail --profile my-profile --region af-south-1 # choose a profile and region
24
+ npx watch-tail --floci # use a local emulator
24
25
  ```
25
26
 
26
- ## Why watch-tail?
27
-
28
- Because the two things you have today are the AWS console and `aws logs tail`, and both make you
29
- work for every line.
30
-
31
- - **The console is a form-filling exercise.** Region dropdown, log-group dropdown, sometimes a stream
32
- dropdown, then a text-only event viewer that forgets where you were. `watch-tail` opens on your
33
- region, lists every group with its size, and starts streaming the moment you click one.
34
- - **`aws logs tail` is a wall of text.** `watch-tail` gives you pause with buffering, client-side
35
- filtering, clear, auto-scroll, a 5 000-line ring buffer, and a stream-name column that is truncated
36
- with the full value on hover - so a 95-character Lambda stream name cannot push your message off
37
- screen.
38
- - **Logs arrive as payloads, not prose.** JSON entries are pretty-printed with syntax colouring by
39
- default, and one toggle shows the raw line when you need the wire format. With that toggle off,
40
- **click a line that carries JSON** and just that payload opens beneath it - indented, coloured, and
41
- without losing the raw line - and clicking again closes it.
42
- - **"What happened an hour ago?" is the normal question.** Flip to **Historic** and scan 15 min, 1 h,
43
- 3 h, 12 h, 24 h, 5 days - or pick a custom `from`/`to` window. The scan finishes on its own and the
44
- window lives in the URL, so `…&mode=historic&range=24h` is a shareable view of an incident.
45
- - **Your credentials never move.** No keys to paste into a SaaS, no CLI to install into your CI, no
46
- vendor account: it uses the ambient AWS profile you already use, needs only two read-only IAM
47
- actions, and binds to loopback. Throwaway keys are used for a local emulator and only there.
48
- - **It is one command and it goes away.** `npx watch-tail`, Ctrl+C. Nothing is deployed, nothing is
49
- sent anywhere, and there is no agent, sidecar or daemon to clean up.
50
- - **You keep what you have seen.** Logs you stream are appended to a local DuckDB file, so the incident
51
- you looked at last week is still there - no re-scanning AWS, no 14-day cliff, no credentials needed
52
- to read it back. Switch the source to **Local archive** in the UI and the same window controls work
53
- against that file.
54
-
55
- Use it when you are debugging a Lambda, chasing an API Gateway 5xx, watching a worker drain a queue,
56
- or handing a teammate a link that shows exactly the window you are staring at.
27
+ Requires **Node.js 22+**. Prefer a global install? `npm install -g watch-tail` gives you both
28
+ `watch-tail` and the shorter `wt`. Press **Ctrl+C** to stop, including during a live stream or login prompt.
57
29
 
58
30
  ## What you get
59
31
 
60
- - **Region-first UI** - pick a region, see its log groups (with stored size), click one to stream.
61
- - **Live and historic** - follow new events over SSE, or scan a fixed window up to the 14 days
62
- CloudWatch Logs keeps.
63
- - **A log window built for real logs** - horizontal scrolling or wrapping, JSON pretty-printing with
64
- click-to-open payloads, drag-resizable stream-name column and group-list pane, level colouring,
65
- pause/clear/auto-scroll.
66
- - **Shareable views** - region, group, mode and window all live in the URL.
67
- - **Local emulation friendly** - `--floci` points at [floci](https://floci.io) on port 4566 for
68
- development without an AWS account.
69
- - **History that outlives the window** - everything you stream is archived to a local
70
- [DuckDB](https://duckdb.org) file, so you can come back to it later - after the 14-day CloudWatch
71
- limit, with no AWS credentials at all - and query it with plain SQL.
72
- - **See the shape of an incident before you read it.** A scatter chart above the log view plots events
73
- over time, coloured by level, so a spike is visible in one glance. Drag across it to zoom into that
74
- moment - the log view follows the brush, and a click clears it.
75
- - **Follow more than one group at once.** Tick extra groups in the sidebar and the chart and the log
76
- view cover all of them, with a group column and a merged stream; the selection lives in the URL.
77
- - **One request, one row.** Lines that share a request id are grouped - in the log view and in the
78
- chart - and coloured by the most critical line in the request, so you read requests instead of the
79
- twenty lines each one wrote. Toggle it off to see every line.
80
- - **Severity you can filter on.** Every archived line is tagged `error`, `warn`, `info` or `debug`,
81
- and the viewer has chips to narrow to one level. A level the log itself declares
82
- (`{"level":"error"}`) is trusted; otherwise it is read from the line, and a line that carries no
83
- level at all stays unclassified instead of being called `info`.
84
-
85
- ## Install
32
+ - **Live tail and historic scans.** Follow new events or select a preset (15 minutes to 5 days) or
33
+ custom window. Pause with buffering, filter text, clear the view, and toggle auto-scroll.
34
+ - **Several groups, one view.** Select groups in the sidebar to merge their logs and chart. A group
35
+ column keeps each line's source visible.
36
+ - **Requests, not just lines.** **By request** groups matching request IDs into one expandable row,
37
+ showing line count, elapsed span, and highest severity. Lines without an ID stay visible.
38
+ - **Spot the spike.** In Historic mode, the chart shows request counts over time, coloured by severity.
39
+ Drag to zoom into an incident; severity chips filter both chart and logs. Switch off **By request**
40
+ to count individual events. Collapse the chart when you want the space back.
41
+ - **Readable payloads.** Syntax-coloured JSON, expandable payloads, wrapping, horizontal scrolling,
42
+ and resizable sidebar and stream-name columns. The viewer keeps a 5,000-line buffer.
43
+ - **Offline history.** Streamed events are saved to a local DuckDB archive. Browse them later without
44
+ AWS credentials, or query them with SQL.
45
+ - **Reopen the same view.** Region, groups, source, mode, and time window live in the URL. A teammate
46
+ needs their own AWS access or a copy of the archive; the link does not include logs or credentials.
47
+
48
+ ## Follow a request
49
+
50
+ Grouping is on by default. Click a request row to expand its lines; use **By request** to return to
51
+ individual events. IDs are detected from `requestId`, `request_id`, `awsRequestId`, `x-request-id`,
52
+ and Lambda's `RequestId:` lines. Each request takes the severity of its most critical line.
53
+
54
+ <img src="https://raw.githubusercontent.com/antstanley/watch-tail/v0.7.1/docs/watch-tail-requests.png" alt="watch-tail: an expanded checkout request showing its JSON payloads and Lambda log lines" width="1200">
55
+
56
+ In **Historic**, drag across the chart to narrow the window. Click to clear the brush, or use
57
+ **Reset zoom** to restore the preset. CloudWatch charts reflect the events loaded into the viewer;
58
+ archive charts query the whole selected window.
59
+
60
+ Switch the chart from **Count** to **Duration (ms)** to see one point per request: X is its first
61
+ observed event timestamp; Y is `(last timestamp + last event duration) − first timestamp` in
62
+ milliseconds. The last event's JSON `duration` (or `durationMs`) is used when present; otherwise it
63
+ adds zero. Hover for the request ID and duration. Severity filters and chart zoom work in both modes.
64
+ Only events with request IDs contribute; incomplete windows can show partial durations.
65
+
66
+ ## Keep your history
67
+
68
+ Choose **Local archive** to browse events already captured on this machine, even offline or with an
69
+ expired SSO session. Only events received while streaming are archived; it does not back up your
70
+ whole AWS account.
86
71
 
87
72
  ```bash
88
- npx watch-tail # no install
89
- pnpm add -g watch-tail # or install once; `wt` is installed as a shorthand
73
+ watch-tail --db ./logs.duckdb # choose an archive file
74
+ watch-tail --no-archive # disable archiving
90
75
  ```
91
76
 
92
- Installed globally, the command is available as both `watch-tail` and the shorter `wt`:
77
+ <img src="https://raw.githubusercontent.com/antstanley/watch-tail/v0.7.1/docs/watch-tail-archive.png" alt="watch-tail: local archive replay with stored event counts and a severity chart" width="1200">
93
78
 
94
- ```bash
95
- wt --profile my-profile --region af-south-1
79
+ Each AWS account and region gets its own `<account-id>/<region>/archive.duckdb` beneath:
80
+
81
+ | Platform | Directory |
82
+ | -------- | ---------------------------------------------- |
83
+ | macOS | `~/Library/Application Support/watch-tail/` |
84
+ | Linux | `${XDG_DATA_HOME:-~/.local/share}/watch-tail/` |
85
+ | Windows | `%LOCALAPPDATA%\watch-tail\` |
86
+
87
+ Account IDs come from AWS STS, so two profiles for the same account share its regional archive.
88
+ Changing regions switches files automatically. Emulator endpoints have a separate namespace.
89
+ Account mappings are cached locally for offline reads; a new CloudWatch stream verifies its account
90
+ before archiving. If verification fails, logs still stream but are not archived.
91
+
92
+ Existing `archive.duckdb` files stay untouched. Open a legacy archive with `--db /path/to/archive.duckdb`.
93
+ `--db` deliberately overrides automatic account/region separation: use it to inspect an existing file
94
+ or manage a file yourself. For offline access on another machine, copy the regional database and
95
+ open it with `--db`.
96
+
97
+ DuckDB is optional: if its native driver cannot load, the viewer runs without archiving. One process
98
+ can own an archive file at a time; use separate `--db` paths for concurrent instances. To inspect it
99
+ with a DuckDB client, stop the app first:
100
+
101
+ ```sql
102
+ SELECT log_group, level, count(*) AS events
103
+ FROM log_events
104
+ GROUP BY log_group, level
105
+ ORDER BY events DESC;
96
106
  ```
97
107
 
98
- Requires Node 22 or newer (developed and tested on Node 24).
108
+ CloudWatch scans in this app are limited to the last 14 days; actual AWS retention depends on the
109
+ log group's settings. The local archive can retain events beyond that window.
99
110
 
100
111
  ## CLI
101
112
 
@@ -112,47 +123,30 @@ watch-tail [options]
112
123
  --print Print the environment that would be used, then exit
113
124
  --list List the AWS profiles found on disk, then exit
114
125
  --verbose Log the server's own output
115
- --db <path> Database file for local history (default: app data dir)
126
+ --db <path> Explicit archive file (default: per account and region)
116
127
  --no-archive Do not keep a local history archive
117
128
  -h, --help Show this help
118
129
  -v, --version Show the version
119
130
  ```
120
131
 
121
- The CLI keeps the terminal while it runs: `Ctrl+C` stops the server and exits - whether it is idle,
122
- whether it is waiting at one of its questions (the login offer, the profile picker, where cancelling is a
123
- stop rather than a "no"), and whether a browser is streaming from it. An open live tail never ends on its
124
- own, so the app ends its own streams when it is asked to stop instead of letting them hold the shutdown
125
- open.
126
-
127
- Shell completions come from [`@bomb.sh/tab`](https://bomb.sh): flags, `--region` values from the
128
- CloudWatch Logs region list, and `--profile` values from your own `~/.aws/config`. zsh, bash, fish and
129
- powershell are supported.
132
+ Shell completions support zsh, bash, fish, and PowerShell, including your AWS profile names and
133
+ available regions:
130
134
 
131
135
  ```bash
132
- source <(watch-tail complete zsh) # this shell, now
133
- watch-tail complete zsh > ~/.watch-tail-completion.zsh # or install it permanently
134
- echo 'source ~/.watch-tail-completion.zsh' >> ~/.zshrc
136
+ source <(watch-tail complete zsh)
135
137
  ```
136
138
 
137
- The generated script re-invokes `watch-tail complete -- <words>`, so completions keep working after
138
- you upgrade. Install the [`@bomb.sh/tab`](https://www.npmjs.com/package/@bomb.sh/tab) CLI globally if
139
- you also want completions for a locally installed copy through your package manager
140
- (`pnpm watch-tail <TAB>`).
141
-
142
- `--profile` sets `AWS_PROFILE` for the server process only. Nothing is written to disk, and any local
143
- emulator settings are neutralized for that run, so a stray `.env.local` cannot redirect a real AWS run.
144
-
145
139
  ## AWS access
146
140
 
147
- Credentials are **ambient**: resolved by the AWS SDK provider chain - SSO, shared config, environment
148
- variables or an instance role.
141
+ Uses the AWS SDK credential chain: SSO, shared config, environment variables, or an instance role.
142
+ The server binds to loopback by default. No vendor account or deployed agent is needed.
149
143
 
150
144
  ```bash
151
145
  aws sso login --profile my-profile
152
- watch-tail --profile my-profile
146
+ wt --profile my-profile
153
147
  ```
154
148
 
155
- Two read-only actions are enough; the app never writes logs:
149
+ The app reads logs using these IAM actions:
156
150
 
157
151
  ```json
158
152
  {
@@ -167,273 +161,40 @@ Two read-only actions are enough; the app never writes logs:
167
161
  }
168
162
  ```
169
163
 
170
- Scope `Resource` down with a log-group ARN pattern if you only need a subset.
171
-
172
- ### When credentials are missing
173
-
174
- On startup the CLI asks the running app for one log group. If AWS refuses because of credentials, it
175
- works out which login command fixes it - from how your profile is configured, not from guesswork -
176
- and offers to run it:
177
-
178
- ```text
179
- warning: AWS credentials are not usable: ... The SSO session token associated with
180
- profile=my-profile was not found or is invalid.
181
- ? Sign in to the SSO session for my-profile. Run `aws sso login --profile my-profile` now? › yes
182
- running aws sso login --profile my-profile
183
- signed in - credentials work now
184
- ```
185
-
186
- If you did not name a profile and you have more than one, it asks which one first. The answer decides
187
- both the login and the profile the app runs with, so a chosen profile is applied by restarting the
188
- server with it (and with that profile's own region). **A profile that already works is never sent to a
189
- login prompt**: the CLI asks `sts:GetCallerIdentity` about the chosen profile first, and only offers a
190
- login when that profile really has nothing usable.
191
-
192
- ```text
193
- ? Which AWS profile should watch-tail use? (type to search, then Enter)
194
- using profile beyond-mzansi
195
- restarting with profile beyond-mzansi
196
- profile beyond-mzansi already works (AWSReservedSSO_AWSAdministratorAccess) - using it
197
- ```
198
-
199
- ```text
200
- ? Which AWS profile should watch-tail use? (type to search, then Enter)
201
- using profile beyond-mzansi
202
- ? Sign in to the SSO session for beyond-mzansi. Run `aws sso login --profile beyond-mzansi` now? › yes
203
- restarting with profile beyond-mzansi
204
- signed in as beyond-mzansi - credentials work now
205
- ```
206
-
207
- | Your profile | What it runs |
208
- | -------------------------------------- | ------------------------------------------------------------------------------------------ |
209
- | `sso_session` / `sso_start_url` | `aws sso login --profile <name>` |
210
- | `login_session` (console sign-in) | `aws login --profile <name>` |
211
- | nothing configured yet | `aws login` (which creates the session) |
212
- | static keys, or a `credential_process` | no login is offered - those are fixed with `aws configure` or where the process is defined |
213
-
214
- The login runs with your terminal attached, so the browser flow works. `--remote` is added when there
215
- is no browser (SSH, headless). Decline, or run non-interactively, and the CLI prints the exact command
216
- instead and keeps the app up - log in elsewhere, then press Refresh. Emulator runs (`--endpoint`,
217
- `--floci`) skip the check, because those use throwaway credentials by design.
218
-
219
- **The region is optional.** Precedence is `--region`, then `AWS_REGION`/`AWS_DEFAULT_REGION`, then the
220
- profile's own region, then `[default]` in `~/.aws/config`. Nothing resolvable produces a clear
221
- `missing-region` message instead of a silent guess. Log groups, retention and events are per region,
222
- so a group in `eu-west-1` will not appear under `us-east-2`.
223
-
224
- ### Local emulator
225
-
226
- ```bash
227
- curl -fsSL https://floci.io/install.sh | sh
228
- floci start
229
- npx watch-tail --floci # throwaway credentials are supplied automatically
230
- ```
231
-
232
- `--floci` is the only thing that points the CLI at an emulator. If an `.env.local` next to the app
233
- sets `AWS_ENDPOINT_URL` - as this repository's `pnpm floci:up` writes for the dev server - the CLI
234
- ignores it, says so, and runs against real AWS; your own exported variables always win over that file.
164
+ If credentials fail, the CLI can help you choose a profile and offer `aws sso login` or `aws login`
165
+ as appropriate. Working profiles are checked before offering login. In a non-interactive session it
166
+ prints the command to run instead.
235
167
 
236
- ## Local history
168
+ Region precedence: `--region`, `AWS_REGION` / `AWS_DEFAULT_REGION`, the chosen profile, then the
169
+ default profile. Use `--floci` or `--endpoint` to select an emulator explicitly; emulator settings
170
+ from the checkout's `.env.local` do not silently redirect a normal CLI run.
237
171
 
238
- While a stream is open, every event that arrives is appended to a local DuckDB file. Nothing else
239
- changes: the live tail, the historic scan and the UI work exactly as before. What the archive adds is
240
- a **second source** you can read later.
172
+ ## Local development
241
173
 
242
- In the UI, a **Local archive** toggle appears next to the mode controls whenever the archive is
243
- available. Choosing it:
244
-
245
- - lists the log groups the archive holds for the current region, with how many events are stored
246
- locally,
247
- - replays a window from the file instead of calling CloudWatch - instant, and **no credentials
248
- needed**, so it works with an expired SSO session, offline, or on a machine that never had AWS
249
- access,
250
- - keeps the same range controls (`15m` … `5d`, or a custom `from`/`to`), and puts the source in the URL
251
- so `…&source=archive&range=24h` is a shareable view of the archive.
252
-
253
- ```bash
254
- watch-tail # archive on, file in your app data directory
255
- watch-tail --db ./logs.duckdb # keep the archive next to the project instead
256
- watch-tail --no-archive # do not archive anything
257
- ```
258
-
259
- The default file is `archive.duckdb` inside your platform's data directory:
260
-
261
- | Platform | Path |
262
- | -------- | ------------------------------------------------------------ |
263
- | macOS | `~/Library/Application Support/watch-tail/archive.duckdb` |
264
- | Linux | `${XDG_DATA_HOME:-~/.local/share}/watch-tail/archive.duckdb` |
265
- | Windows | `%LOCALAPPDATA%\watch-tail\archive.duckdb` |
266
-
267
- `WATCH_STREAM_ARCHIVE=off` turns the archive off for the server, and `WATCH_STREAM_ARCHIVE_DB` sets the
268
- file, for people who drive the server directly.
269
-
270
- Because it is a DuckDB database, you can point any DuckDB client at the same file - with the app
271
- stopped, since DuckDB allows one writer:
272
-
273
- ```bash
274
- duckdb ~/Library/Application\ Support/watch-tail/archive.duckdb
275
- ```
276
-
277
- ```sql
278
- SELECT log_group, count(*) AS events, max(timestamp_ms) AS newest
279
- FROM log_events
280
- GROUP BY log_group
281
- ORDER BY events DESC;
282
-
283
- SELECT to_timestamp(timestamp_ms / 1000) AS at, message
284
- FROM log_events
285
- WHERE log_group = '/aws/lambda/checkout' AND message ILIKE '%timeout%'
286
- ORDER BY timestamp_ms;
287
-
288
- -- how many errors per group, ignoring levels that were never detected
289
- SELECT log_group, level, count(*) AS events
290
- FROM log_events
291
- WHERE level = 'error'
292
- GROUP BY log_group, level
293
- ORDER BY events DESC;
294
- ```
295
-
296
- Three things worth knowing:
297
-
298
- - **DuckDB is an optional dependency.** It is a native module (roughly 114 MB installed, prebuilt for
299
- every supported platform - no compiler needed). If it cannot be installed or loaded, `watch-tail`
300
- runs exactly as it did before, without history, and says so in the startup banner. To skip it
301
- deliberately: `npm install -g watch-tail --no-optional`.
302
- - **One process owns the file.** DuckDB takes an exclusive lock, so a second `watch-tail` on the same
303
- archive runs without history while the first is up; `--db` is the way to keep two instances
304
- separate.
305
- - Levels are detected, not received: CloudWatch Logs does not report a severity, so `error`/`warn`/
306
- `info`/`debug` come from the line itself, and `NULL` means nothing could be read from it.
307
- - **The archive is as wide as what you watched.** Events are recorded as they stream, so history covers
308
- the windows you have actually visited. It is also local, unencrypted and outside your AWS account -
309
- treat the file like the logs themselves.
310
-
311
- ## Requests, not lines
312
-
313
- Log lines that belong to the same request are one thing, not twenty. watch-tail reads a request id out
314
- of each line - a declared `requestId` (also `request_id`, `awsRequestId`, an `x-request-id`) or the
315
- `RequestId: ...` that a Lambda prints - and groups the lines that share it:
316
-
317
- - **The log view** collapses each request into a single row: its request id, how many lines it wrote,
318
- how long it took, and the level of its **most critical line**, so a request with one error among
319
- twenty info lines reads as an error. Click the row to open it and see every line, indented, in order.
320
- - **The chart** counts **one mark per request**, placed at the request's first line and coloured by
321
- that same most critical level, so a spike of failing requests is a spike of marks rather than a spike
322
- of log volume.
323
- - **By request** in the log view's toolbar turns it off, and the view goes back to one row per line
324
- (and the chart back to one mark per line). Your choice is remembered.
325
-
326
- Grouping is on by default. Lines with no request id are never grouped: each keeps its own row and its
327
- own mark, so nothing is hidden by a request id the log did not have. A request whose lines span more
328
- than one bucket is counted once, where it started, which is why the chart's total can be lower than
329
- the number of lines.
330
-
331
- ## The chart
332
-
333
- In **Historic** mode (and for the local archive) a scatter chart sits above the log view: X is time, Y
334
- is the number of requests in a bucket, and each level is its own colour. Drag across it to brush a
335
- range - the log view, the window chip and the URL all follow, so a brush is a shareable view of the
336
- spike you just found. Click the chart to clear the brush, or press **Reset zoom** to go back to the
337
- preset window. The level chips filter the chart and the log view together.
338
-
339
- A drag only counts as a zoom when it is a real drag: a click, or a pointer that slips a couple of
340
- pixels, clears the brush instead of zooming into a sliver of a window, and the view is re-scoped when
341
- you release rather than while you drag - so the stream is not restarted mid-gesture.
342
-
343
- With several groups selected, the counts cover all of them and the chart's legend splits the totals by
344
- level. The level chips filter requests by their most critical level, which is the level the marks are
345
- drawn in, so the legend and the filter never disagree. The archive answers the chart with one SQL query over the whole window; a CloudWatch view has no
346
- aggregate API, so there the chart counts the events already in the view.
347
-
348
- The panel has a header you can click to collapse it, and it remembers that choice: collapsed, it is
349
- just one line of totals and per-level counts, and the space goes back to the log view.
350
-
351
- The chart is drawn with [layerchart](https://www.layerchart.com), which is **loaded on demand**: the
352
- charting code is fetched in the browser only once the panel is open, so it never delays the log view's
353
- first paint. Measured on the production build, an open panel pulls about 235 KiB of chart code after
354
- the page has started, and a collapsed one pulls none at all.
355
-
356
- ## Development
174
+ With [floci](https://floci.io) installed:
357
175
 
358
176
  ```bash
359
177
  pnpm install
360
- pnpm dev # SvelteKit dev server on http://localhost:5173
361
- # (its history archive lives in .watch-tail/)
362
- pnpm seed # fixtures in the local emulator (--watch for live traffic)
363
- pnpm dev:aws --profile my-profile # dev server against a real profile
364
- pnpm build # adapter-node build + the CLI in dist/
365
- pnpm start # run the built CLI
178
+ pnpm floci:up # start the emulator and write its dev environment
179
+ pnpm seed # demo logs; use pnpm seed:watch for live traffic
180
+ pnpm dev # http://localhost:5173
366
181
  ```
367
182
 
368
- | Command | What it does |
369
- | --------------------------- | ----------------------------------------------------------- |
370
- | `pnpm check` | `svelte-check` types |
371
- | `pnpm test:unit` | vitest unit, component and integration projects |
372
- | `pnpm test:e2e` | floci integration suite (`WATCH_STREAM_E2E=1`) |
373
- | `pnpm test:cli` | the built CLI serves and stops cleanly (`WATCH_TAIL_E2E=1`) |
374
- | `pnpm test:ui` | Playwright smoke check of the UI against a running app |
375
- | `pnpm lint` / `pnpm format` | oxlint / oxfmt |
376
- | `pnpm knip` | unused files, exports and dependencies |
377
- | `pnpm verify` | all of the above plus the build |
378
- | `pnpm publish:check` | publint plus the exact tarball contents |
379
-
380
- ## Releasing
381
-
382
- Releases use [changesets](https://github.com/changesets/changesets): a changeset is a small file
383
- that records _what changed and how much it matters_, reviewed with the code. Pending changesets are
384
- folded into one "Release: version packages" PR; merging it bumps the version and writes
385
- `CHANGELOG.md`; the release workflow then stages that version to npm and tags the commit.
183
+ Use `pnpm dev:aws --profile my-profile` to develop against AWS instead.
386
184
 
387
- ```bash
388
- pnpm changeset # describe the change; the Version PR does the rest
389
- pnpm changeset status # preview the next version
390
- ```
391
-
392
- Publishing is **staged**, not direct: the tarball lands in npm's staging area and a human approves it
393
- before it goes live, so no npm token exists in the repository - authentication is GitHub OIDC trusted
394
- publishing, scoped to the publish job. See [RELEASING.md](./RELEASING.md) for the concept, the
395
- one-time setup and the approval flow.
396
-
397
- ## Architecture
398
-
399
- ```
400
- Browser (SvelteKit client)
401
- | GET /api/log-groups group list for a region
402
- | GET /api/stream SSE: ready, log, ping, error, end
403
- v
404
- SvelteKit server routes (Node)
405
- | @aws-sdk/client-cloudwatch-logs DescribeLogGroups + FilterLogEvents polling
406
- v
407
- CloudWatch Logs API -- ambient AWS credentials
408
- or floci on http://localhost:4566
409
-
410
- Everything streamed is also appended to a local archive,
411
- which the UI can read back without AWS:
412
-
413
- SvelteKit server ---- @duckdb/node-api ----> archive.duckdb (DuckDB file)
414
- ^
415
- Browser -- GET /api/stream?source=archive -+
416
- ```
185
+ | Command | Purpose |
186
+ | --------------------------- | ------------------------------------------------------------- |
187
+ | `pnpm verify` | Types, lint, formatting, tests, unused-code checks, and build |
188
+ | `pnpm test:e2e` | Emulator integration tests (requires floci) |
189
+ | `pnpm test:cli` | Built CLI startup and shutdown checks |
190
+ | `pnpm test:ui` | Browser smoke checks against the running app |
191
+ | `pnpm build` / `pnpm start` | Build and run the production CLI |
192
+ | `pnpm publish:check` | Validate package metadata and tarball contents |
417
193
 
418
- The CLI (`src/cli/`) boots the packaged adapter-node server, waits for `/api/health` and opens a
419
- browser. Full details, including the HTTP and SSE contract, are in [ARCHITECTURE.md](./ARCHITECTURE.md).
420
-
421
- ## Notes and limits
422
-
423
- - CloudWatch Logs has no push API for reading, so the app polls `FilterLogEvents` (1 s by default,
424
- 250 ms - 15 s configurable). Expect roughly a second of latency and one API call per second per open
425
- stream.
426
- - `FilterLogEvents` only returns events from the last 14 days.
427
- - The local server has no authentication: it binds to loopback and inherits your AWS permissions.
428
- Binding elsewhere prints a warning - only do it on a trusted network.
429
- - floci omits `logStreamName` in `FilterLogEvents`, so the stream column stays empty locally; real AWS
430
- fills it.
431
- - The archive is written from the same process that serves the UI, so it only grows while something is
432
- streaming. A window you never opened is not in it, and events dropped by the 10 000-event cap of a
433
- historic scan are not archived either.
434
- - Archived events are de-duplicated by CloudWatch event id (or by a hash of timestamp, stream and
435
- message when an emulator omits ids), so re-scanning the same window does not duplicate rows.
194
+ See [ARCHITECTURE.md](./ARCHITECTURE.md) for internals,
195
+ [CHANGELOG.md](./CHANGELOG.md) for release history, and [RELEASING.md](./RELEASING.md) for the
196
+ Changesets and npm staged-publishing workflow.
436
197
 
437
198
  ## License
438
199
 
439
- MIT - see [LICENSE](./LICENSE).
200
+ [MIT](./LICENSE)
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-amber-950:oklch(27.9% .077 45.635);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-900:oklch(37.8% .077 168.94);--color-emerald-950:oklch(26.2% .051 172.552);--color-teal-300:oklch(85.5% .138 181.071);--color-teal-400:oklch(77.7% .152 181.912);--color-teal-700:oklch(51.1% .096 186.391);--color-teal-900:oklch(38.6% .063 188.416);--color-teal-950:oklch(27.7% .046 192.524);--color-sky-200:oklch(90.1% .058 230.902);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-sky-700:oklch(50% .134 242.749);--color-sky-800:oklch(44.3% .11 240.79);--color-sky-900:oklch(39.1% .09 240.876);--color-sky-950:oklch(29.3% .066 243.157);--color-violet-300:oklch(81.1% .111 293.571);--color-violet-900:oklch(38% .189 293.745);--color-violet-950:oklch(28.3% .141 291.089);--color-fuchsia-300:oklch(83.3% .145 321.434);--color-neutral-100:oklch(97% 0 none);--color-neutral-200:oklch(92.2% 0 none);--color-neutral-300:oklch(87% 0 none);--color-neutral-400:oklch(70.8% 0 none);--color-neutral-500:oklch(55.6% 0 none);--color-neutral-600:oklch(43.9% 0 none);--color-neutral-700:oklch(37.1% 0 none);--color-neutral-800:oklch(26.9% 0 none);--color-neutral-900:oklch(20.5% 0 none);--color-neutral-950:oklch(14.5% 0 none);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wider:.05em;--radius-md:.375rem;--radius-lg:.5rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-y-0{inset-block:0}.isolate{isolation:isolate}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.ml-1{margin-left:var(--spacing)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.h-2{height:calc(var(--spacing) * 2)}.h-5{height:calc(var(--spacing) * 5)}.h-dvh{height:100dvh}.min-h-0{min-height:0}.min-h-\[30rem\]{min-height:30rem}.min-h-full{min-height:100%}.w-2{width:calc(var(--spacing) * 2)}.w-40{width:calc(var(--spacing) * 40)}.w-\[7\.5rem\]{width:7.5rem}.w-\[9rem\]{width:9rem}.w-full{width:100%}.w-max{width:max-content}.max-w-\[22rem\]{max-width:22rem}.min-w-0{min-width:0}.min-w-full{min-width:100%}.flex-1{flex:1}.flex-none{flex:none}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.animate-pulse{animation:var(--animate-pulse)}.cursor-col-resize{cursor:col-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-y-1{row-gap:var(--spacing)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-amber-700{border-color:var(--color-amber-700)}.border-amber-800{border-color:var(--color-amber-800)}.border-amber-900{border-color:var(--color-amber-900)}.border-emerald-900{border-color:var(--color-emerald-900)}.border-neutral-700{border-color:var(--color-neutral-700)}.border-neutral-800{border-color:var(--color-neutral-800)}.border-neutral-900{border-color:var(--color-neutral-900)}.border-red-800{border-color:var(--color-red-800)}.border-red-900{border-color:var(--color-red-900)}.border-sky-700{border-color:var(--color-sky-700)}.border-sky-800{border-color:var(--color-sky-800)}.border-sky-900{border-color:var(--color-sky-900)}.border-teal-700{border-color:var(--color-teal-700)}.border-teal-900{border-color:var(--color-teal-900)}.border-transparent{border-color:#0000}.border-violet-900{border-color:var(--color-violet-900)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-950\/40{background-color:#46190166}@supports (color:color-mix(in lab, red, red)){.bg-amber-950\/40{background-color:color-mix(in oklab, var(--color-amber-950) 40%, transparent)}}.bg-amber-950\/50{background-color:#46190180}@supports (color:color-mix(in lab, red, red)){.bg-amber-950\/50{background-color:color-mix(in oklab, var(--color-amber-950) 50%, transparent)}}.bg-amber-950\/70{background-color:#461901b3}@supports (color:color-mix(in lab, red, red)){.bg-amber-950\/70{background-color:color-mix(in oklab, var(--color-amber-950) 70%, transparent)}}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-950\/70{background-color:#002c22b3}@supports (color:color-mix(in lab, red, red)){.bg-emerald-950\/70{background-color:color-mix(in oklab, var(--color-emerald-950) 70%, transparent)}}.bg-neutral-500{background-color:var(--color-neutral-500)}.bg-neutral-800{background-color:var(--color-neutral-800)}.bg-neutral-800\/60{background-color:#26262699}@supports (color:color-mix(in lab, red, red)){.bg-neutral-800\/60{background-color:color-mix(in oklab, var(--color-neutral-800) 60%, transparent)}}.bg-neutral-800\/80{background-color:#262626cc}@supports (color:color-mix(in lab, red, red)){.bg-neutral-800\/80{background-color:color-mix(in oklab, var(--color-neutral-800) 80%, transparent)}}.bg-neutral-900{background-color:var(--color-neutral-900)}.bg-neutral-900\/40{background-color:#17171766}@supports (color:color-mix(in lab, red, red)){.bg-neutral-900\/40{background-color:color-mix(in oklab, var(--color-neutral-900) 40%, transparent)}}.bg-neutral-900\/60{background-color:#17171799}@supports (color:color-mix(in lab, red, red)){.bg-neutral-900\/60{background-color:color-mix(in oklab, var(--color-neutral-900) 60%, transparent)}}.bg-neutral-900\/70{background-color:#171717b3}@supports (color:color-mix(in lab, red, red)){.bg-neutral-900\/70{background-color:color-mix(in oklab, var(--color-neutral-900) 70%, transparent)}}.bg-neutral-950{background-color:var(--color-neutral-950)}.bg-neutral-950\/60{background-color:#0a0a0a99}@supports (color:color-mix(in lab, red, red)){.bg-neutral-950\/60{background-color:color-mix(in oklab, var(--color-neutral-950) 60%, transparent)}}.bg-neutral-950\/90{background-color:#0a0a0ae6}@supports (color:color-mix(in lab, red, red)){.bg-neutral-950\/90{background-color:color-mix(in oklab, var(--color-neutral-950) 90%, transparent)}}.bg-red-400{background-color:var(--color-red-400)}.bg-red-950\/50{background-color:#46080980}@supports (color:color-mix(in lab, red, red)){.bg-red-950\/50{background-color:color-mix(in oklab, var(--color-red-950) 50%, transparent)}}.bg-red-950\/70{background-color:#460809b3}@supports (color:color-mix(in lab, red, red)){.bg-red-950\/70{background-color:color-mix(in oklab, var(--color-red-950) 70%, transparent)}}.bg-sky-400{background-color:var(--color-sky-400)}.bg-sky-950{background-color:var(--color-sky-950)}.bg-sky-950\/50{background-color:#052f4a80}@supports (color:color-mix(in lab, red, red)){.bg-sky-950\/50{background-color:color-mix(in oklab, var(--color-sky-950) 50%, transparent)}}.bg-sky-950\/60{background-color:#052f4a99}@supports (color:color-mix(in lab, red, red)){.bg-sky-950\/60{background-color:color-mix(in oklab, var(--color-sky-950) 60%, transparent)}}.bg-sky-950\/70{background-color:#052f4ab3}@supports (color:color-mix(in lab, red, red)){.bg-sky-950\/70{background-color:color-mix(in oklab, var(--color-sky-950) 70%, transparent)}}.bg-teal-950\/50{background-color:#022f2e80}@supports (color:color-mix(in lab, red, red)){.bg-teal-950\/50{background-color:color-mix(in oklab, var(--color-teal-950) 50%, transparent)}}.bg-teal-950\/60{background-color:#022f2e99}@supports (color:color-mix(in lab, red, red)){.bg-teal-950\/60{background-color:color-mix(in oklab, var(--color-teal-950) 60%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-950\/60{background-color:#2f0d6899}@supports (color:color-mix(in lab, red, red)){.bg-violet-950\/60{background-color:color-mix(in oklab, var(--color-violet-950) 60%, transparent)}}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.pr-1{padding-right:var(--spacing)}.pl-8{padding-left:calc(var(--spacing) * 8)}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.625rem\]{font-size:.625rem}.text-\[0\.6875rem\]{font-size:.6875rem}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-200{color:var(--color-amber-200)}.text-amber-300{color:var(--color-amber-300)}.text-amber-300\/80{color:#ffd236cc}@supports (color:color-mix(in lab, red, red)){.text-amber-300\/80{color:color-mix(in oklab, var(--color-amber-300) 80%, transparent)}}.text-amber-400\/80{color:#fcbb00cc}@supports (color:color-mix(in lab, red, red)){.text-amber-400\/80{color:color-mix(in oklab, var(--color-amber-400) 80%, transparent)}}.text-emerald-300{color:var(--color-emerald-300)}.text-emerald-400\/80{color:#00d294cc}@supports (color:color-mix(in lab, red, red)){.text-emerald-400\/80{color:color-mix(in oklab, var(--color-emerald-400) 80%, transparent)}}.text-fuchsia-300{color:var(--color-fuchsia-300)}.text-neutral-100{color:var(--color-neutral-100)}.text-neutral-200{color:var(--color-neutral-200)}.text-neutral-300{color:var(--color-neutral-300)}.text-neutral-400{color:var(--color-neutral-400)}.text-neutral-500{color:var(--color-neutral-500)}.text-neutral-600{color:var(--color-neutral-600)}.text-red-300{color:var(--color-red-300)}.text-red-400{color:var(--color-red-400)}.text-sky-200{color:var(--color-sky-200)}.text-sky-300{color:var(--color-sky-300)}.text-sky-400{color:var(--color-sky-400)}.text-sky-400\/80{color:#00bcfecc}@supports (color:color-mix(in lab, red, red)){.text-sky-400\/80{color:color-mix(in oklab, var(--color-sky-400) 80%, transparent)}}.text-teal-300{color:var(--color-teal-300)}.text-teal-300\/80{color:#46ecd5cc}@supports (color:color-mix(in lab, red, red)){.text-teal-300\/80{color:color-mix(in oklab, var(--color-teal-300) 80%, transparent)}}.text-teal-400\/80{color:#00d3bdcc}@supports (color:color-mix(in lab, red, red)){.text-teal-400\/80{color:color-mix(in oklab, var(--color-teal-400) 80%, transparent)}}.text-violet-300{color:var(--color-violet-300)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.accent-sky-500{accent-color:var(--color-sky-500)}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.selection\:bg-sky-900\/60 ::selection{background-color:#024a7099}@supports (color:color-mix(in lab, red, red)){.selection\:bg-sky-900\/60 ::selection{background-color:color-mix(in oklab, var(--color-sky-900) 60%, transparent)}}.selection\:bg-sky-900\/60::selection{background-color:#024a7099}@supports (color:color-mix(in lab, red, red)){.selection\:bg-sky-900\/60::selection{background-color:color-mix(in oklab, var(--color-sky-900) 60%, transparent)}}.placeholder\:text-neutral-600::placeholder{color:var(--color-neutral-600)}@media (hover:hover){.hover\:border-neutral-700:hover{border-color:var(--color-neutral-700)}.hover\:border-neutral-800:hover{border-color:var(--color-neutral-800)}.hover\:border-sky-600:hover{border-color:var(--color-sky-600)}.hover\:bg-neutral-900\/60:hover{background-color:#17171799}@supports (color:color-mix(in lab, red, red)){.hover\:bg-neutral-900\/60:hover{background-color:color-mix(in oklab, var(--color-neutral-900) 60%, transparent)}}.hover\:bg-sky-500\/30:hover{background-color:#00a5ef4d}@supports (color:color-mix(in lab, red, red)){.hover\:bg-sky-500\/30:hover{background-color:color-mix(in oklab, var(--color-sky-500) 30%, transparent)}}.hover\:text-neutral-100:hover{color:var(--color-neutral-100)}.hover\:text-neutral-200:hover{color:var(--color-neutral-200)}}.focus\:border-sky-600:focus{border-color:var(--color-sky-600)}.focus\:bg-sky-500\/50:focus{background-color:#00a5ef80}@supports (color:color-mix(in lab, red, red)){.focus\:bg-sky-500\/50:focus{background-color:color-mix(in oklab, var(--color-sky-500) 50%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\:inline{display:inline}.sm\:px-4{padding-inline:calc(var(--spacing) * 4)}}@media (width>=64rem){.lg\:block{display:block}.lg\:w-2{width:calc(var(--spacing) * 2)}.lg\:shrink-0{flex-shrink:0}.lg\:flex-row{flex-direction:row}}@media (width>=80rem){.xl\:inline{display:inline}}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}