cursedbelt-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (606) hide show
  1. package/LICENSE +15 -0
  2. package/dist/server/activity/index.d.ts +36 -0
  3. package/dist/server/activity/index.js +36 -0
  4. package/dist/server/activity/migrations.d.ts +21 -0
  5. package/dist/server/activity/migrations.js +55 -0
  6. package/dist/server/activity/shareSource.d.ts +11 -0
  7. package/dist/server/activity/shareSource.js +45 -0
  8. package/dist/server/activity/store.d.ts +123 -0
  9. package/dist/server/activity/store.js +178 -0
  10. package/dist/server/app.d.ts +56 -0
  11. package/dist/server/app.js +45 -0
  12. package/dist/server/audit/index.d.ts +2 -0
  13. package/dist/server/audit/index.js +2 -0
  14. package/dist/server/audit/migrations.d.ts +2 -0
  15. package/dist/server/audit/migrations.js +79 -0
  16. package/dist/server/audit/sqliteSink.d.ts +36 -0
  17. package/dist/server/audit/sqliteSink.js +95 -0
  18. package/dist/server/audit/sqliteSink.test.d.ts +1 -0
  19. package/dist/server/audit/sqliteSink.test.js +180 -0
  20. package/dist/server/auth/cookie.d.ts +22 -0
  21. package/dist/server/auth/cookie.js +35 -0
  22. package/dist/server/auth/csrf.d.ts +42 -0
  23. package/dist/server/auth/csrf.js +36 -0
  24. package/dist/server/auth/fileTokenSigner.d.ts +10 -0
  25. package/dist/server/auth/fileTokenSigner.js +22 -0
  26. package/dist/server/auth/getOnly.d.ts +20 -0
  27. package/dist/server/auth/getOnly.js +27 -0
  28. package/dist/server/auth/index.d.ts +12 -0
  29. package/dist/server/auth/index.js +15 -0
  30. package/dist/server/auth/jwt.d.ts +18 -0
  31. package/dist/server/auth/jwt.js +56 -0
  32. package/dist/server/auth/loginThrottle.d.ts +118 -0
  33. package/dist/server/auth/loginThrottle.js +204 -0
  34. package/dist/server/auth/middleware.d.ts +14 -0
  35. package/dist/server/auth/middleware.js +47 -0
  36. package/dist/server/auth/password.d.ts +14 -0
  37. package/dist/server/auth/password.js +65 -0
  38. package/dist/server/auth/sessionStore.d.ts +19 -0
  39. package/dist/server/auth/sessionStore.js +221 -0
  40. package/dist/server/auth/totp.d.ts +34 -0
  41. package/dist/server/auth/totp.js +81 -0
  42. package/dist/server/auth/types.d.ts +133 -0
  43. package/dist/server/auth/types.js +1 -0
  44. package/dist/server/auth/vault.d.ts +27 -0
  45. package/dist/server/auth/vault.js +57 -0
  46. package/dist/server/context.d.ts +35 -0
  47. package/dist/server/context.js +1 -0
  48. package/dist/server/ctgr.d.ts +32 -0
  49. package/dist/server/ctgr.js +69 -0
  50. package/dist/server/db/kysely.d.ts +14 -0
  51. package/dist/server/db/kysely.js +16 -0
  52. package/dist/server/db/plumbingTypes.d.ts +116 -0
  53. package/dist/server/db/plumbingTypes.js +12 -0
  54. package/dist/server/dropzone/duplicates.d.ts +82 -0
  55. package/dist/server/dropzone/duplicates.js +90 -0
  56. package/dist/server/dropzone/index.d.ts +13 -0
  57. package/dist/server/dropzone/index.js +13 -0
  58. package/dist/server/dropzone/scan.d.ts +166 -0
  59. package/dist/server/dropzone/scan.js +272 -0
  60. package/dist/server/errors.d.ts +7 -0
  61. package/dist/server/errors.js +7 -0
  62. package/dist/server/guard/argon2Binding.d.ts +97 -0
  63. package/dist/server/guard/argon2Binding.js +138 -0
  64. package/dist/server/guard/index.d.ts +4 -0
  65. package/dist/server/guard/index.js +6 -0
  66. package/dist/server/guard/kdfWorker.d.ts +101 -0
  67. package/dist/server/guard/kdfWorker.js +301 -0
  68. package/dist/server/guard/kdfWorkerEntry.d.ts +1 -0
  69. package/dist/server/guard/kdfWorkerEntry.js +15 -0
  70. package/dist/server/guard/passwordVerifier.d.ts +65 -0
  71. package/dist/server/guard/passwordVerifier.js +122 -0
  72. package/dist/server/guard/revocationStore.d.ts +132 -0
  73. package/dist/server/guard/revocationStore.js +211 -0
  74. package/dist/server/guard/sessionSigner.d.ts +132 -0
  75. package/dist/server/guard/sessionSigner.js +303 -0
  76. package/dist/server/guard/verifier.d.ts +21 -0
  77. package/dist/server/guard/verifier.js +1 -0
  78. package/dist/server/incidents/channels.d.ts +161 -0
  79. package/dist/server/incidents/channels.js +357 -0
  80. package/dist/server/incidents/checks.d.ts +61 -0
  81. package/dist/server/incidents/checks.js +55 -0
  82. package/dist/server/incidents/index.d.ts +51 -0
  83. package/dist/server/incidents/index.js +51 -0
  84. package/dist/server/incidents/migrations.d.ts +20 -0
  85. package/dist/server/incidents/migrations.js +58 -0
  86. package/dist/server/incidents/notifier.d.ts +79 -0
  87. package/dist/server/incidents/notifier.js +141 -0
  88. package/dist/server/incidents/reporter.d.ts +60 -0
  89. package/dist/server/incidents/reporter.js +49 -0
  90. package/dist/server/incidents/routes.d.ts +91 -0
  91. package/dist/server/incidents/routes.js +202 -0
  92. package/dist/server/incidents/store.d.ts +75 -0
  93. package/dist/server/incidents/store.js +176 -0
  94. package/dist/server/incidents/types.d.ts +107 -0
  95. package/dist/server/incidents/types.js +32 -0
  96. package/dist/server/index.d.ts +25 -0
  97. package/dist/server/index.js +53 -0
  98. package/dist/server/jobs/fireQueue.d.ts +12 -0
  99. package/dist/server/jobs/fireQueue.js +37 -0
  100. package/dist/server/jobs/index.d.ts +6 -0
  101. package/dist/server/jobs/index.js +10 -0
  102. package/dist/server/jobs/logger.d.ts +10 -0
  103. package/dist/server/jobs/logger.js +14 -0
  104. package/dist/server/jobs/plainjobAdapter.d.ts +19 -0
  105. package/dist/server/jobs/plainjobAdapter.js +48 -0
  106. package/dist/server/jobs/polling.d.ts +17 -0
  107. package/dist/server/jobs/polling.js +79 -0
  108. package/dist/server/jobs/runner.d.ts +24 -0
  109. package/dist/server/jobs/runner.js +186 -0
  110. package/dist/server/jobs/timeout.d.ts +28 -0
  111. package/dist/server/jobs/timeout.js +47 -0
  112. package/dist/server/jobs/types.d.ts +167 -0
  113. package/dist/server/jobs/types.js +12 -0
  114. package/dist/server/master-lock/guard.d.ts +53 -0
  115. package/dist/server/master-lock/guard.js +205 -0
  116. package/dist/server/master-lock/index.d.ts +21 -0
  117. package/dist/server/master-lock/index.js +21 -0
  118. package/dist/server/master-lock/lockPage.d.ts +34 -0
  119. package/dist/server/master-lock/lockPage.js +281 -0
  120. package/dist/server/master-lock/masterLock.d.ts +294 -0
  121. package/dist/server/master-lock/masterLock.js +523 -0
  122. package/dist/server/master-lock/principals.d.ts +76 -0
  123. package/dist/server/master-lock/principals.js +157 -0
  124. package/dist/server/master-lock/seed.d.ts +47 -0
  125. package/dist/server/master-lock/seed.js +93 -0
  126. package/dist/server/master-lock/store.d.ts +19 -0
  127. package/dist/server/master-lock/store.js +20 -0
  128. package/dist/server/media-bun/image.d.ts +7 -0
  129. package/dist/server/media-bun/image.js +96 -0
  130. package/dist/server/media-bun/index.d.ts +4 -0
  131. package/dist/server/media-bun/index.js +10 -0
  132. package/dist/server/media-bun/streaming.d.ts +86 -0
  133. package/dist/server/media-bun/streaming.js +237 -0
  134. package/dist/server/media-bun/video.d.ts +35 -0
  135. package/dist/server/media-bun/video.js +181 -0
  136. package/dist/server/metrics/metricsBuffer.d.ts +39 -0
  137. package/dist/server/metrics/metricsBuffer.js +36 -0
  138. package/dist/server/metrics/normalizeRoute.d.ts +5 -0
  139. package/dist/server/metrics/normalizeRoute.js +58 -0
  140. package/dist/server/middleware/correlationId.d.ts +9 -0
  141. package/dist/server/middleware/correlationId.js +20 -0
  142. package/dist/server/middleware/corsAllowlist.d.ts +38 -0
  143. package/dist/server/middleware/corsAllowlist.js +37 -0
  144. package/dist/server/middleware/errorEnvelope.d.ts +17 -0
  145. package/dist/server/middleware/errorEnvelope.js +32 -0
  146. package/dist/server/middleware/index.d.ts +9 -0
  147. package/dist/server/middleware/index.js +10 -0
  148. package/dist/server/middleware/localOrigin.d.ts +71 -0
  149. package/dist/server/middleware/localOrigin.js +119 -0
  150. package/dist/server/middleware/rateLimit.d.ts +56 -0
  151. package/dist/server/middleware/rateLimit.js +86 -0
  152. package/dist/server/middleware/requestLogger.d.ts +29 -0
  153. package/dist/server/middleware/requestLogger.js +47 -0
  154. package/dist/server/middleware/securityHeaders.d.ts +29 -0
  155. package/dist/server/middleware/securityHeaders.js +44 -0
  156. package/dist/server/middleware/zValidator.d.ts +29 -0
  157. package/dist/server/middleware/zValidator.js +57 -0
  158. package/dist/server/migration/runner.d.ts +42 -0
  159. package/dist/server/migration/runner.js +70 -0
  160. package/dist/server/migration/types.d.ts +16 -0
  161. package/dist/server/migration/types.js +1 -0
  162. package/dist/server/net/outboundGuard.d.ts +30 -0
  163. package/dist/server/net/outboundGuard.js +199 -0
  164. package/dist/server/notifications/hub.d.ts +67 -0
  165. package/dist/server/notifications/hub.js +187 -0
  166. package/dist/server/notifications/index.d.ts +47 -0
  167. package/dist/server/notifications/index.js +46 -0
  168. package/dist/server/notifications/migrations.d.ts +13 -0
  169. package/dist/server/notifications/migrations.js +20 -0
  170. package/dist/server/notifications/routes.d.ts +58 -0
  171. package/dist/server/notifications/routes.js +113 -0
  172. package/dist/server/notifications/service.d.ts +58 -0
  173. package/dist/server/notifications/service.js +41 -0
  174. package/dist/server/paths/appDataHome.d.ts +19 -0
  175. package/dist/server/paths/appDataHome.js +68 -0
  176. package/dist/server/private-media/crypto.d.ts +37 -0
  177. package/dist/server/private-media/crypto.js +111 -0
  178. package/dist/server/private-media/index-store.d.ts +31 -0
  179. package/dist/server/private-media/index-store.js +36 -0
  180. package/dist/server/private-media/mountPrivateRoutes.d.ts +26 -0
  181. package/dist/server/private-media/mountPrivateRoutes.js +219 -0
  182. package/dist/server/private-media/pipeline.d.ts +37 -0
  183. package/dist/server/private-media/pipeline.js +97 -0
  184. package/dist/server/private-media/unlock.d.ts +52 -0
  185. package/dist/server/private-media/unlock.js +55 -0
  186. package/dist/server/resume/index.d.ts +2 -0
  187. package/dist/server/resume/index.js +2 -0
  188. package/dist/server/resume/routes.d.ts +41 -0
  189. package/dist/server/resume/routes.js +50 -0
  190. package/dist/server/resume/store.d.ts +37 -0
  191. package/dist/server/resume/store.js +38 -0
  192. package/dist/server/retention/archive.d.ts +78 -0
  193. package/dist/server/retention/archive.js +284 -0
  194. package/dist/server/retention/fleet.d.ts +50 -0
  195. package/dist/server/retention/fleet.js +66 -0
  196. package/dist/server/retention/index.d.ts +38 -0
  197. package/dist/server/retention/index.js +38 -0
  198. package/dist/server/retention/policy.d.ts +263 -0
  199. package/dist/server/retention/policy.js +264 -0
  200. package/dist/server/retention/store.d.ts +101 -0
  201. package/dist/server/retention/store.js +251 -0
  202. package/dist/server/retention/sweeper.d.ts +69 -0
  203. package/dist/server/retention/sweeper.js +289 -0
  204. package/dist/server/retention/target.d.ts +143 -0
  205. package/dist/server/retention/target.js +438 -0
  206. package/dist/server/search/index.d.ts +2 -0
  207. package/dist/server/search/index.js +6 -0
  208. package/dist/server/search/pgSearchProvider.d.ts +91 -0
  209. package/dist/server/search/pgSearchProvider.js +330 -0
  210. package/dist/server/search/pgSearchProvider.pg.test.d.ts +1 -0
  211. package/dist/server/search/pgSearchProvider.pg.test.js +338 -0
  212. package/dist/server/search/pgSearchSchema.d.ts +81 -0
  213. package/dist/server/search/pgSearchSchema.js +89 -0
  214. package/dist/server/sharing/index.d.ts +18 -0
  215. package/dist/server/sharing/index.js +16 -0
  216. package/dist/server/sharing/migrations.d.ts +6 -0
  217. package/dist/server/sharing/migrations.js +79 -0
  218. package/dist/server/sharing/router.d.ts +111 -0
  219. package/dist/server/sharing/router.js +93 -0
  220. package/dist/server/sharing/sql.d.ts +67 -0
  221. package/dist/server/sharing/sql.js +88 -0
  222. package/dist/server/sharing/store.d.ts +173 -0
  223. package/dist/server/sharing/store.js +484 -0
  224. package/dist/server/sqlite/backup.d.ts +48 -0
  225. package/dist/server/sqlite/backup.js +97 -0
  226. package/dist/server/sqlite/browse.d.ts +42 -0
  227. package/dist/server/sqlite/browse.js +84 -0
  228. package/dist/server/sqlite/export.d.ts +32 -0
  229. package/dist/server/sqlite/export.js +42 -0
  230. package/dist/server/sqlite/fts5.d.ts +106 -0
  231. package/dist/server/sqlite/fts5.js +154 -0
  232. package/dist/server/sqlite/health.d.ts +44 -0
  233. package/dist/server/sqlite/health.js +52 -0
  234. package/dist/server/sqlite/import.d.ts +36 -0
  235. package/dist/server/sqlite/import.js +108 -0
  236. package/dist/server/sqlite/index.d.ts +9 -0
  237. package/dist/server/sqlite/index.js +15 -0
  238. package/dist/server/sqlite/readonlySql.d.ts +15 -0
  239. package/dist/server/sqlite/readonlySql.js +65 -0
  240. package/dist/server/sqlite/stats.d.ts +22 -0
  241. package/dist/server/sqlite/stats.js +32 -0
  242. package/dist/server/sqlite/viewer.d.ts +17 -0
  243. package/dist/server/sqlite/viewer.js +56 -0
  244. package/dist/server/storage/binaryServerProcessing.d.ts +23 -0
  245. package/dist/server/storage/binaryServerProcessing.js +81 -0
  246. package/dist/server/storage/binaryServerStore.d.ts +3 -0
  247. package/dist/server/storage/binaryServerStore.js +95 -0
  248. package/dist/server/storage/diskStore.d.ts +2 -0
  249. package/dist/server/storage/diskStore.js +88 -0
  250. package/dist/server/storage/files/adapter.d.ts +33 -0
  251. package/dist/server/storage/files/adapter.js +203 -0
  252. package/dist/server/storage/files/catalogue.d.ts +72 -0
  253. package/dist/server/storage/files/catalogue.js +1033 -0
  254. package/dist/server/storage/files/chunkedUpload.d.ts +56 -0
  255. package/dist/server/storage/files/chunkedUpload.js +70 -0
  256. package/dist/server/storage/files/fileRoutes.d.ts +51 -0
  257. package/dist/server/storage/files/fileRoutes.js +405 -0
  258. package/dist/server/storage/files/index.d.ts +9 -0
  259. package/dist/server/storage/files/index.js +11 -0
  260. package/dist/server/storage/files/migrations.d.ts +2 -0
  261. package/dist/server/storage/files/migrations.js +163 -0
  262. package/dist/server/storage/files/mimeByExt.d.ts +1 -0
  263. package/dist/server/storage/files/mimeByExt.js +13 -0
  264. package/dist/server/storage/files/stack.d.ts +136 -0
  265. package/dist/server/storage/files/stack.js +132 -0
  266. package/dist/server/storage/files/storageOps.d.ts +54 -0
  267. package/dist/server/storage/files/storageOps.js +110 -0
  268. package/dist/server/storage/files/types.d.ts +261 -0
  269. package/dist/server/storage/files/types.js +22 -0
  270. package/dist/server/storage/imageThumbnail.d.ts +3 -0
  271. package/dist/server/storage/imageThumbnail.js +50 -0
  272. package/dist/server/storage/index.d.ts +15 -0
  273. package/dist/server/storage/index.js +27 -0
  274. package/dist/server/storage/mountMediaRoutes.d.ts +28 -0
  275. package/dist/server/storage/mountMediaRoutes.js +141 -0
  276. package/dist/server/storage/objectStoreMediaStore.d.ts +4 -0
  277. package/dist/server/storage/objectStoreMediaStore.js +57 -0
  278. package/dist/server/storage/s3ObjectStore.d.ts +63 -0
  279. package/dist/server/storage/s3ObjectStore.js +187 -0
  280. package/dist/server/storage/sources.d.ts +47 -0
  281. package/dist/server/storage/sources.js +148 -0
  282. package/dist/server/storage/streamRange.d.ts +19 -0
  283. package/dist/server/storage/streamRange.js +69 -0
  284. package/dist/server/storage/streamToken.d.ts +16 -0
  285. package/dist/server/storage/streamToken.js +54 -0
  286. package/dist/server/storage/transcodeJobs.d.ts +65 -0
  287. package/dist/server/storage/transcodeJobs.js +104 -0
  288. package/dist/server/storage/types.d.ts +193 -0
  289. package/dist/server/storage/types.js +41 -0
  290. package/dist/server/storage/videoDerivativeKeys.d.ts +127 -0
  291. package/dist/server/storage/videoDerivativeKeys.js +149 -0
  292. package/dist/server/storage/videoProcessor.d.ts +30 -0
  293. package/dist/server/storage/videoProcessor.js +148 -0
  294. package/dist/server/sync/alarm.d.ts +34 -0
  295. package/dist/server/sync/alarm.js +91 -0
  296. package/dist/server/sync/commands.d.ts +87 -0
  297. package/dist/server/sync/commands.js +241 -0
  298. package/dist/server/sync/engine.d.ts +62 -0
  299. package/dist/server/sync/engine.js +184 -0
  300. package/dist/server/sync/http.d.ts +106 -0
  301. package/dist/server/sync/http.js +243 -0
  302. package/dist/server/sync/index.d.ts +41 -0
  303. package/dist/server/sync/index.js +41 -0
  304. package/dist/server/sync/opLog.d.ts +61 -0
  305. package/dist/server/sync/opLog.js +96 -0
  306. package/dist/server/sync/planner.d.ts +31 -0
  307. package/dist/server/sync/planner.js +30 -0
  308. package/dist/server/sync/status.d.ts +63 -0
  309. package/dist/server/sync/status.js +49 -0
  310. package/dist/server/sync/timer.d.ts +52 -0
  311. package/dist/server/sync/timer.js +170 -0
  312. package/dist/server/sync/tokens.d.ts +25 -0
  313. package/dist/server/sync/tokens.js +51 -0
  314. package/dist/server/sync/types.d.ts +101 -0
  315. package/dist/server/sync/types.js +29 -0
  316. package/dist/server/ws/eventBus.d.ts +14 -0
  317. package/dist/server/ws/eventBus.js +42 -0
  318. package/dist/server/ws/hub.d.ts +20 -0
  319. package/dist/server/ws/hub.js +154 -0
  320. package/dist/server/ws/index.d.ts +5 -0
  321. package/dist/server/ws/index.js +7 -0
  322. package/dist/server/ws/presence.d.ts +11 -0
  323. package/dist/server/ws/presence.js +20 -0
  324. package/dist/server/ws/room.d.ts +17 -0
  325. package/dist/server/ws/room.js +23 -0
  326. package/dist/server/ws/types.d.ts +122 -0
  327. package/dist/server/ws/types.js +1 -0
  328. package/package.json +234 -0
  329. package/src/declaredDepsAreImported.spec.ts +87 -0
  330. package/src/leafSubpathsImportNothing.spec.ts +358 -0
  331. package/src/lockfileIsTracked.spec.ts +50 -0
  332. package/src/namedSubpathsResolve.spec.ts +122 -0
  333. package/src/noPathDeps.spec.ts +24 -0
  334. package/src/publishShape.spec.ts +89 -0
  335. package/src/server/activity/index.ts +59 -0
  336. package/src/server/activity/migrations.ts +67 -0
  337. package/src/server/activity/shareSource.ts +57 -0
  338. package/src/server/activity/store.spec.ts +255 -0
  339. package/src/server/activity/store.ts +368 -0
  340. package/src/server/app.spec.ts +243 -0
  341. package/src/server/app.ts +89 -0
  342. package/src/server/audit/index.ts +2 -0
  343. package/src/server/audit/migrations.ts +88 -0
  344. package/src/server/audit/sqliteSink.test.ts +200 -0
  345. package/src/server/audit/sqliteSink.ts +162 -0
  346. package/src/server/auth/cookie.spec.ts +46 -0
  347. package/src/server/auth/cookie.ts +42 -0
  348. package/src/server/auth/csrf.spec.ts +81 -0
  349. package/src/server/auth/csrf.ts +83 -0
  350. package/src/server/auth/fileTokenSigner.ts +40 -0
  351. package/src/server/auth/getOnly.spec.ts +53 -0
  352. package/src/server/auth/getOnly.ts +32 -0
  353. package/src/server/auth/index.ts +51 -0
  354. package/src/server/auth/jwt.spec.ts +106 -0
  355. package/src/server/auth/jwt.ts +75 -0
  356. package/src/server/auth/loginThrottle.spec.ts +213 -0
  357. package/src/server/auth/loginThrottle.ts +261 -0
  358. package/src/server/auth/middleware.spec.ts +148 -0
  359. package/src/server/auth/middleware.ts +56 -0
  360. package/src/server/auth/password.spec.ts +48 -0
  361. package/src/server/auth/password.ts +71 -0
  362. package/src/server/auth/sessionStore.spec.ts +189 -0
  363. package/src/server/auth/sessionStore.ts +261 -0
  364. package/src/server/auth/totp.spec.ts +73 -0
  365. package/src/server/auth/totp.ts +92 -0
  366. package/src/server/auth/types.ts +146 -0
  367. package/src/server/auth/vault.spec.ts +51 -0
  368. package/src/server/auth/vault.ts +71 -0
  369. package/src/server/context.ts +37 -0
  370. package/src/server/ctgr.spec.ts +138 -0
  371. package/src/server/ctgr.ts +108 -0
  372. package/src/server/db/kysely.spec.ts +62 -0
  373. package/src/server/db/kysely.ts +21 -0
  374. package/src/server/db/plumbingTypes.ts +126 -0
  375. package/src/server/dropzone/duplicates.ts +121 -0
  376. package/src/server/dropzone/index.ts +30 -0
  377. package/src/server/dropzone/scan.spec.ts +255 -0
  378. package/src/server/dropzone/scan.ts +342 -0
  379. package/src/server/errors.spec.ts +76 -0
  380. package/src/server/errors.ts +22 -0
  381. package/src/server/guard/argon2Binding.spec.ts +117 -0
  382. package/src/server/guard/argon2Binding.ts +195 -0
  383. package/src/server/guard/argon2Kat.spec.ts +250 -0
  384. package/src/server/guard/guard.spec.ts +390 -0
  385. package/src/server/guard/index.ts +6 -0
  386. package/src/server/guard/kdfWorker.spec.ts +283 -0
  387. package/src/server/guard/kdfWorker.ts +367 -0
  388. package/src/server/guard/kdfWorkerEntry.ts +16 -0
  389. package/src/server/guard/passwordVerifier.spec.ts +71 -0
  390. package/src/server/guard/passwordVerifier.ts +175 -0
  391. package/src/server/guard/revocationStore.spec.ts +135 -0
  392. package/src/server/guard/revocationStore.ts +291 -0
  393. package/src/server/guard/sessionSigner.ts +425 -0
  394. package/src/server/guard/verifier.ts +27 -0
  395. package/src/server/incidents/channels.ts +487 -0
  396. package/src/server/incidents/checks.ts +120 -0
  397. package/src/server/incidents/incidents.spec.ts +463 -0
  398. package/src/server/incidents/index.ts +96 -0
  399. package/src/server/incidents/migrations.ts +66 -0
  400. package/src/server/incidents/notifier.ts +215 -0
  401. package/src/server/incidents/reporter.ts +110 -0
  402. package/src/server/incidents/routes.ts +314 -0
  403. package/src/server/incidents/store.ts +329 -0
  404. package/src/server/incidents/types.ts +116 -0
  405. package/src/server/index.ts +248 -0
  406. package/src/server/jobs/fireQueue.spec.ts +85 -0
  407. package/src/server/jobs/fireQueue.ts +37 -0
  408. package/src/server/jobs/index.ts +26 -0
  409. package/src/server/jobs/logger.ts +16 -0
  410. package/src/server/jobs/plainjobAdapter.spec.ts +34 -0
  411. package/src/server/jobs/plainjobAdapter.ts +54 -0
  412. package/src/server/jobs/polling.spec.ts +219 -0
  413. package/src/server/jobs/polling.ts +81 -0
  414. package/src/server/jobs/runner.spec.ts +213 -0
  415. package/src/server/jobs/runner.ts +213 -0
  416. package/src/server/jobs/timeout.spec.ts +35 -0
  417. package/src/server/jobs/timeout.ts +53 -0
  418. package/src/server/jobs/types.ts +188 -0
  419. package/src/server/master-lock/guard.spec.ts +347 -0
  420. package/src/server/master-lock/guard.ts +290 -0
  421. package/src/server/master-lock/index.ts +44 -0
  422. package/src/server/master-lock/lockPage.spec.ts +88 -0
  423. package/src/server/master-lock/lockPage.ts +313 -0
  424. package/src/server/master-lock/masterLock.spec.ts +338 -0
  425. package/src/server/master-lock/masterLock.ts +627 -0
  426. package/src/server/master-lock/principals.spec.ts +378 -0
  427. package/src/server/master-lock/principals.ts +175 -0
  428. package/src/server/master-lock/seed.spec.ts +69 -0
  429. package/src/server/master-lock/seed.ts +112 -0
  430. package/src/server/master-lock/store.ts +35 -0
  431. package/src/server/media-bun/image.spec.ts +115 -0
  432. package/src/server/media-bun/image.ts +134 -0
  433. package/src/server/media-bun/index.ts +52 -0
  434. package/src/server/media-bun/streaming.spec.ts +134 -0
  435. package/src/server/media-bun/streaming.ts +347 -0
  436. package/src/server/media-bun/video.spec.ts +115 -0
  437. package/src/server/media-bun/video.ts +232 -0
  438. package/src/server/metrics/metricsBuffer.ts +92 -0
  439. package/src/server/metrics/normalizeRoute.spec.ts +51 -0
  440. package/src/server/metrics/normalizeRoute.ts +63 -0
  441. package/src/server/middleware/correlationId.ts +24 -0
  442. package/src/server/middleware/corsAllowlist.spec.ts +118 -0
  443. package/src/server/middleware/corsAllowlist.ts +69 -0
  444. package/src/server/middleware/errorEnvelope.ts +38 -0
  445. package/src/server/middleware/index.ts +19 -0
  446. package/src/server/middleware/localOrigin.spec.ts +168 -0
  447. package/src/server/middleware/localOrigin.ts +139 -0
  448. package/src/server/middleware/rateLimit.spec.ts +72 -0
  449. package/src/server/middleware/rateLimit.ts +125 -0
  450. package/src/server/middleware/requestLogger.ts +95 -0
  451. package/src/server/middleware/securityHeaders.ts +78 -0
  452. package/src/server/middleware/zValidator.spec.ts +251 -0
  453. package/src/server/middleware/zValidator.ts +114 -0
  454. package/src/server/migration/runner.spec.ts +88 -0
  455. package/src/server/migration/runner.ts +87 -0
  456. package/src/server/migration/types.ts +17 -0
  457. package/src/server/net/outboundGuard.spec.ts +90 -0
  458. package/src/server/net/outboundGuard.ts +205 -0
  459. package/src/server/notifications/hub.ts +245 -0
  460. package/src/server/notifications/index.ts +77 -0
  461. package/src/server/notifications/migrations.ts +39 -0
  462. package/src/server/notifications/routes.ts +177 -0
  463. package/src/server/notifications/service.spec.ts +305 -0
  464. package/src/server/notifications/service.ts +112 -0
  465. package/src/server/paths/appDataHome.spec.ts +87 -0
  466. package/src/server/paths/appDataHome.ts +84 -0
  467. package/src/server/private-media/blobRoute.spec.ts +165 -0
  468. package/src/server/private-media/crypto.spec.ts +81 -0
  469. package/src/server/private-media/crypto.ts +155 -0
  470. package/src/server/private-media/gatePolicy.spec.ts +98 -0
  471. package/src/server/private-media/index-store.ts +83 -0
  472. package/src/server/private-media/mountPrivateRoutes.ts +265 -0
  473. package/src/server/private-media/pipeline.spec.ts +111 -0
  474. package/src/server/private-media/pipeline.ts +170 -0
  475. package/src/server/private-media/routes.spec.ts +265 -0
  476. package/src/server/private-media/unlock.ts +112 -0
  477. package/src/server/resume/index.ts +8 -0
  478. package/src/server/resume/resume.spec.ts +118 -0
  479. package/src/server/resume/routes.ts +92 -0
  480. package/src/server/resume/store.ts +82 -0
  481. package/src/server/retention/archive.spec.ts +181 -0
  482. package/src/server/retention/archive.ts +353 -0
  483. package/src/server/retention/fleet.ts +104 -0
  484. package/src/server/retention/index.ts +101 -0
  485. package/src/server/retention/policy.spec.ts +132 -0
  486. package/src/server/retention/policy.ts +392 -0
  487. package/src/server/retention/store.spec.ts +236 -0
  488. package/src/server/retention/store.ts +338 -0
  489. package/src/server/retention/sweeper.spec.ts +321 -0
  490. package/src/server/retention/sweeper.ts +367 -0
  491. package/src/server/retention/target.spec.ts +592 -0
  492. package/src/server/retention/target.ts +613 -0
  493. package/src/server/search/index.ts +12 -0
  494. package/src/server/search/pgSearchProvider.pg.test.ts +392 -0
  495. package/src/server/search/pgSearchProvider.ts +421 -0
  496. package/src/server/search/pgSearchSchema.ts +147 -0
  497. package/src/server/sharing/index.ts +65 -0
  498. package/src/server/sharing/migrations.ts +128 -0
  499. package/src/server/sharing/router.spec.ts +167 -0
  500. package/src/server/sharing/router.ts +194 -0
  501. package/src/server/sharing/sql.ts +109 -0
  502. package/src/server/sharing/store.spec.ts +408 -0
  503. package/src/server/sharing/store.ts +737 -0
  504. package/src/server/sqlite/backup.spec.ts +114 -0
  505. package/src/server/sqlite/backup.ts +154 -0
  506. package/src/server/sqlite/browse.spec.ts +70 -0
  507. package/src/server/sqlite/browse.ts +120 -0
  508. package/src/server/sqlite/export.spec.ts +43 -0
  509. package/src/server/sqlite/export.ts +74 -0
  510. package/src/server/sqlite/fts5.spec.ts +175 -0
  511. package/src/server/sqlite/fts5.ts +255 -0
  512. package/src/server/sqlite/health.spec.ts +79 -0
  513. package/src/server/sqlite/health.ts +105 -0
  514. package/src/server/sqlite/import.spec.ts +75 -0
  515. package/src/server/sqlite/import.ts +141 -0
  516. package/src/server/sqlite/index.ts +64 -0
  517. package/src/server/sqlite/readonlySql.spec.ts +58 -0
  518. package/src/server/sqlite/readonlySql.ts +67 -0
  519. package/src/server/sqlite/stats.spec.ts +21 -0
  520. package/src/server/sqlite/stats.ts +61 -0
  521. package/src/server/sqlite/viewer.spec.ts +127 -0
  522. package/src/server/sqlite/viewer.ts +72 -0
  523. package/src/server/storage/binaryServerProcessing.integration.spec.ts +222 -0
  524. package/src/server/storage/binaryServerProcessing.spec.ts +150 -0
  525. package/src/server/storage/binaryServerProcessing.ts +127 -0
  526. package/src/server/storage/binaryServerStore.ts +102 -0
  527. package/src/server/storage/chunked.integration.spec.ts +185 -0
  528. package/src/server/storage/diskStore.ts +83 -0
  529. package/src/server/storage/files/adapter.photo.display.spec.ts +169 -0
  530. package/src/server/storage/files/adapter.photo.spec.ts +128 -0
  531. package/src/server/storage/files/adapter.spec.ts +121 -0
  532. package/src/server/storage/files/adapter.ts +255 -0
  533. package/src/server/storage/files/catalogue.media-host.spec.ts +184 -0
  534. package/src/server/storage/files/catalogue.orderings.spec.ts +157 -0
  535. package/src/server/storage/files/catalogue.private.spec.ts +106 -0
  536. package/src/server/storage/files/catalogue.recover.spec.ts +131 -0
  537. package/src/server/storage/files/catalogue.sort.spec.ts +154 -0
  538. package/src/server/storage/files/catalogue.spec.ts +133 -0
  539. package/src/server/storage/files/catalogue.trash-import.spec.ts +125 -0
  540. package/src/server/storage/files/catalogue.ts +1326 -0
  541. package/src/server/storage/files/chunkedUpload.spec.ts +111 -0
  542. package/src/server/storage/files/chunkedUpload.ts +146 -0
  543. package/src/server/storage/files/collections.spec.ts +294 -0
  544. package/src/server/storage/files/fileRoutes.replace.spec.ts +88 -0
  545. package/src/server/storage/files/fileRoutes.spec.ts +327 -0
  546. package/src/server/storage/files/fileRoutes.ts +462 -0
  547. package/src/server/storage/files/index.ts +66 -0
  548. package/src/server/storage/files/migrations.ts +187 -0
  549. package/src/server/storage/files/mimeByExt.ts +14 -0
  550. package/src/server/storage/files/stack.spec.ts +258 -0
  551. package/src/server/storage/files/stack.ts +284 -0
  552. package/src/server/storage/files/storageOps.spec.ts +126 -0
  553. package/src/server/storage/files/storageOps.ts +213 -0
  554. package/src/server/storage/files/types.ts +285 -0
  555. package/src/server/storage/imageThumbnail.spec.ts +81 -0
  556. package/src/server/storage/imageThumbnail.ts +60 -0
  557. package/src/server/storage/index.ts +122 -0
  558. package/src/server/storage/mountMediaRoutes.ts +231 -0
  559. package/src/server/storage/objectStore.spec.ts +272 -0
  560. package/src/server/storage/objectStoreMediaStore.ts +63 -0
  561. package/src/server/storage/s3ObjectStore.ts +239 -0
  562. package/src/server/storage/sources.ts +245 -0
  563. package/src/server/storage/storage.spec.ts +219 -0
  564. package/src/server/storage/streamRange.ts +92 -0
  565. package/src/server/storage/streamToken.ts +76 -0
  566. package/src/server/storage/transcode.integration.spec.ts +134 -0
  567. package/src/server/storage/transcodeJobs.spec.ts +152 -0
  568. package/src/server/storage/transcodeJobs.ts +171 -0
  569. package/src/server/storage/types.ts +230 -0
  570. package/src/server/storage/videoDerivativeKeys.spec.ts +112 -0
  571. package/src/server/storage/videoDerivativeKeys.ts +172 -0
  572. package/src/server/storage/videoProcessor.posterOnly.spec.ts +106 -0
  573. package/src/server/storage/videoProcessor.ts +229 -0
  574. package/src/server/sync/alarm.spec.ts +149 -0
  575. package/src/server/sync/alarm.ts +137 -0
  576. package/src/server/sync/commands.spec.ts +145 -0
  577. package/src/server/sync/commands.ts +361 -0
  578. package/src/server/sync/engine.spec.ts +496 -0
  579. package/src/server/sync/engine.ts +255 -0
  580. package/src/server/sync/http.ts +316 -0
  581. package/src/server/sync/httpRemote.spec.ts +158 -0
  582. package/src/server/sync/index.ts +90 -0
  583. package/src/server/sync/opLog.spec.ts +110 -0
  584. package/src/server/sync/opLog.ts +189 -0
  585. package/src/server/sync/planner.spec.ts +53 -0
  586. package/src/server/sync/planner.ts +62 -0
  587. package/src/server/sync/status.spec.ts +92 -0
  588. package/src/server/sync/status.ts +108 -0
  589. package/src/server/sync/timer.spec.ts +150 -0
  590. package/src/server/sync/timer.ts +207 -0
  591. package/src/server/sync/tokens.spec.ts +38 -0
  592. package/src/server/sync/tokens.ts +94 -0
  593. package/src/server/sync/types.ts +108 -0
  594. package/src/server/ws/eventBus.spec.ts +67 -0
  595. package/src/server/ws/eventBus.ts +46 -0
  596. package/src/server/ws/hub.integration.spec.ts +93 -0
  597. package/src/server/ws/hub.spec.ts +282 -0
  598. package/src/server/ws/hub.ts +168 -0
  599. package/src/server/ws/index.ts +20 -0
  600. package/src/server/ws/presence.spec.ts +27 -0
  601. package/src/server/ws/presence.ts +26 -0
  602. package/src/server/ws/room.spec.ts +36 -0
  603. package/src/server/ws/room.ts +29 -0
  604. package/src/server/ws/types.ts +134 -0
  605. package/src/skippedTestsAreAnswered.spec.ts +215 -0
  606. package/src/testTmpRoot.spec.ts +102 -0
@@ -0,0 +1,329 @@
1
+ /**
2
+ * The incident store, and the reconcile step that is the whole dedupe promise.
3
+ *
4
+ * ── The one rule ────────────────────────────────────────────────────────────
5
+ * `reconcile()` is the ONLY way an incident changes state, and it is what
6
+ * decides whether anything is notified. A detector hands it the complete set of
7
+ * conditions that are true RIGHT NOW; the store diffs that against what it
8
+ * already holds. Three things can come out of the diff — opened, escalated,
9
+ * resolved — and everything else is a counter bump that notifies nobody.
10
+ * Because the diff is set-shaped rather than event-shaped, a poller running
11
+ * every five minutes for a week produces exactly two messages about one broken
12
+ * thing: one when it broke, one when it was fixed.
13
+ *
14
+ * 🔴 The subtle half is the RESOLVE, and it is where a naive version of this
15
+ * lies to its owner. A detector that throws, times out, or is not registered on
16
+ * this host reports nothing — and "reported nothing" must never be read as
17
+ * "everything it watches is fixed", or a crashed detector cheerfully announces
18
+ * that an outage is over. Two things prevent that: `reconcile` only ever
19
+ * resolves fingerprints belonging to the check it was called for AND inside the
20
+ * namespaces that check declares it is authoritative for, and `runIncidentSweep`
21
+ * (`checks.ts`) does not call `reconcile` at all for a check that threw.
22
+ *
23
+ * ── Where the file lives ────────────────────────────────────────────────────
24
+ * Whatever `Database` the caller opens. The console keeps it in an incidents
25
+ * database of its own under the host's app-data root, deliberately NOT in the
26
+ * metrics database: metrics are capped, regenerable telemetry that trims on write, and
27
+ * an incident is a governed record whose whole value is that it survives — most
28
+ * of all across the restart a deploy of the console itself performs.
29
+ */
30
+ import type { Database } from "bun:sqlite";
31
+ import { runMigrations } from "../migration/runner";
32
+ import { INCIDENT_MIGRATIONS, INCIDENTS_TABLE } from "./migrations";
33
+ import {
34
+ fingerprint,
35
+ type Incident,
36
+ type IncidentFact,
37
+ type IncidentReport,
38
+ type IncidentTransitions,
39
+ } from "./types";
40
+
41
+ interface Row {
42
+ fingerprint: string;
43
+ source: string;
44
+ kind: string;
45
+ subject: string;
46
+ severity: string;
47
+ state: string;
48
+ title: string;
49
+ what_broke: string;
50
+ what_it_blocks: string;
51
+ what_to_do: string;
52
+ facts_json: string | null;
53
+ first_seen: number;
54
+ last_seen: number;
55
+ seen_count: number;
56
+ episodes: number;
57
+ acknowledged_at: number | null;
58
+ resolved_at: number | null;
59
+ notified_at: number | null;
60
+ notify_result: string | null;
61
+ resolved_notified_at: number | null;
62
+ }
63
+
64
+ const toIncident = (r: Row): Incident => ({
65
+ fingerprint: r.fingerprint,
66
+ source: r.source,
67
+ kind: r.kind,
68
+ subject: r.subject,
69
+ severity: r.severity === "blocking" ? "blocking" : "warning",
70
+ state: r.state === "open" ? "open" : r.state === "acknowledged" ? "acknowledged" : "resolved",
71
+ title: r.title,
72
+ whatBroke: r.what_broke,
73
+ whatItBlocks: r.what_it_blocks,
74
+ whatToDo: r.what_to_do,
75
+ facts: r.facts_json ? (JSON.parse(r.facts_json) as Record<string, IncidentFact>) : undefined,
76
+ firstSeen: r.first_seen,
77
+ lastSeen: r.last_seen,
78
+ seenCount: r.seen_count,
79
+ episodes: r.episodes,
80
+ acknowledgedAt: r.acknowledged_at,
81
+ resolvedAt: r.resolved_at,
82
+ notifiedAt: r.notified_at,
83
+ notifyResult: r.notify_result,
84
+ resolvedNotifiedAt: r.resolved_notified_at,
85
+ });
86
+
87
+ /**
88
+ * The privacy gate, enforced rather than reviewed. `facts` is for numbers —
89
+ * bytes free, items failed, commits behind — and a string slipping in there is
90
+ * how a file name reaches an SMS. See the header of `types.ts`.
91
+ *
92
+ * It throws rather than sanitising, because a detector author meets the failure
93
+ * in their own test run, which is the only moment the mistake is cheap.
94
+ */
95
+ export function assertNoContent(report: IncidentReport): void {
96
+ for (const [key, value] of Object.entries(report.facts ?? {})) {
97
+ if (typeof value === "number" || typeof value === "boolean" || value === null) continue;
98
+ throw new Error(
99
+ `incident ${fingerprint(report)}: fact "${key}" is a ${typeof value}. ` +
100
+ "facts take numbers, booleans and null only — a string here is how private " +
101
+ "content reaches a text message. Put the words in whatBroke / whatItBlocks / " +
102
+ "whatToDo, which a detector's author writes and reviews.",
103
+ );
104
+ }
105
+ }
106
+
107
+ export interface ReconcileOptions {
108
+ /**
109
+ * The `source:kind:` prefixes this check is authoritative for on this run.
110
+ * Resolving is confined to them, so one detector can never resolve another's
111
+ * incidents — and a check that RAN and found nothing can still clear its own,
112
+ * which a report list alone cannot express (an empty array is
113
+ * indistinguishable from "did not run"). `runIncidentSweep` derives these
114
+ * from the check's declared `kinds`; omitted, they fall back to whatever the
115
+ * reports mention, which is the safe direction to be wrong in.
116
+ */
117
+ namespaces?: string[];
118
+ now?: number;
119
+ }
120
+
121
+ export interface IncidentStore {
122
+ readonly db: Database;
123
+ /** Newest activity first. `state: "active"` means open + acknowledged. */
124
+ list: (opts?: { state?: Incident["state"] | "active"; limit?: number }) => Incident[];
125
+ get: (fp: string) => Incident | null;
126
+ /** The dedupe engine. See the module header. */
127
+ reconcile: (
128
+ checkKey: string,
129
+ reports: IncidentReport[],
130
+ opts?: ReconcileOptions,
131
+ ) => IncidentTransitions;
132
+ /** Record that the OPEN notification for these fingerprints went out. */
133
+ markNotified: (fps: string[], result: string, now?: number) => void;
134
+ /** Record that the RESOLVED notification went out. */
135
+ markResolvedNotified: (fps: string[], now?: number) => void;
136
+ /** The owner has seen it: stop counting it as needing attention, keep it listed. */
137
+ acknowledge: (fp: string, now?: number) => boolean;
138
+ }
139
+
140
+ /**
141
+ * Open the store over an existing database. The caller owns the `Database` (and
142
+ * its lifetime) — this primitive owns one table in it.
143
+ */
144
+ export function createIncidentStore(db: Database): IncidentStore {
145
+ runMigrations(db, INCIDENT_MIGRATIONS);
146
+
147
+ const selectOne = db.prepare(`SELECT * FROM ${INCIDENTS_TABLE} WHERE fingerprint = ?`);
148
+ const insert = db.prepare(`INSERT INTO ${INCIDENTS_TABLE} (
149
+ fingerprint, source, check_key, kind, subject, severity, state, title,
150
+ what_broke, what_it_blocks, what_to_do, facts_json,
151
+ first_seen, last_seen, seen_count, episodes
152
+ ) VALUES (?, ?, ?, ?, ?, ?, 'open', ?, ?, ?, ?, ?, ?, ?, 1, 1)`);
153
+ /** A NEW episode of a fingerprint that had resolved. Counters restart; `episodes` does not. */
154
+ const reopen = db.prepare(`UPDATE ${INCIDENTS_TABLE} SET
155
+ state = 'open', severity = ?, title = ?, what_broke = ?, what_it_blocks = ?,
156
+ what_to_do = ?, facts_json = ?, first_seen = ?, last_seen = ?, seen_count = 1,
157
+ episodes = episodes + 1, acknowledged_at = NULL, resolved_at = NULL,
158
+ notified_at = NULL, notify_result = NULL, resolved_notified_at = NULL
159
+ WHERE fingerprint = ?`);
160
+ /**
161
+ * Observed again. The words and the facts are REFRESHED — the numbers move,
162
+ * and "17 GB free" must not stay frozen at whatever it was on Tuesday — but
163
+ * nothing about the lifecycle moves, so no transition is emitted and nothing
164
+ * is sent. This statement is the dedupe, in one place.
165
+ */
166
+ const touch = db.prepare(`UPDATE ${INCIDENTS_TABLE} SET
167
+ last_seen = ?, seen_count = seen_count + 1, title = ?, what_broke = ?,
168
+ what_it_blocks = ?, what_to_do = ?, facts_json = ?, severity = ?
169
+ WHERE fingerprint = ?`);
170
+ const resolveStmt = db.prepare(
171
+ `UPDATE ${INCIDENTS_TABLE} SET state = 'resolved', resolved_at = ? WHERE fingerprint = ?`,
172
+ );
173
+
174
+ const store: IncidentStore = {
175
+ db,
176
+
177
+ list(opts = {}) {
178
+ const limit = opts.limit ?? 200;
179
+ if (opts.state === "active") {
180
+ return (
181
+ db
182
+ .prepare(
183
+ `SELECT * FROM ${INCIDENTS_TABLE} WHERE state IN ('open','acknowledged')
184
+ ORDER BY last_seen DESC LIMIT ?`,
185
+ )
186
+ .all(limit) as Row[]
187
+ ).map(toIncident);
188
+ }
189
+ if (opts.state) {
190
+ return (
191
+ db
192
+ .prepare(
193
+ `SELECT * FROM ${INCIDENTS_TABLE} WHERE state = ? ORDER BY last_seen DESC LIMIT ?`,
194
+ )
195
+ .all(opts.state, limit) as Row[]
196
+ ).map(toIncident);
197
+ }
198
+ return (
199
+ db
200
+ .prepare(`SELECT * FROM ${INCIDENTS_TABLE} ORDER BY last_seen DESC LIMIT ?`)
201
+ .all(limit) as Row[]
202
+ ).map(toIncident);
203
+ },
204
+
205
+ get(fp) {
206
+ const row = selectOne.get(fp) as Row | null;
207
+ return row ? toIncident(row) : null;
208
+ },
209
+
210
+ reconcile(checkKey, reports, opts = {}) {
211
+ const now = opts.now ?? Date.now();
212
+ const out: IncidentTransitions = { opened: [], escalated: [], resolved: [], unchanged: [] };
213
+ const seen = new Set<string>();
214
+
215
+ for (const report of reports) {
216
+ assertNoContent(report);
217
+ const fp = fingerprint(report);
218
+ seen.add(fp);
219
+ const facts = report.facts ? JSON.stringify(report.facts) : null;
220
+ const existing = selectOne.get(fp) as Row | null;
221
+
222
+ if (!existing) {
223
+ insert.run(
224
+ fp,
225
+ report.source,
226
+ checkKey,
227
+ report.kind,
228
+ report.subject,
229
+ report.severity,
230
+ report.title,
231
+ report.whatBroke,
232
+ report.whatItBlocks,
233
+ report.whatToDo,
234
+ facts,
235
+ now,
236
+ now,
237
+ );
238
+ const opened = store.get(fp);
239
+ if (opened) out.opened.push(opened);
240
+ continue;
241
+ }
242
+
243
+ if (existing.state === "resolved") {
244
+ reopen.run(
245
+ report.severity,
246
+ report.title,
247
+ report.whatBroke,
248
+ report.whatItBlocks,
249
+ report.whatToDo,
250
+ facts,
251
+ now,
252
+ now,
253
+ fp,
254
+ );
255
+ const reopened = store.get(fp);
256
+ if (reopened) out.opened.push(reopened);
257
+ continue;
258
+ }
259
+
260
+ // Still open, or acknowledged. The one thing left that can be worth a
261
+ // message is a WARNING that has become BLOCKING, because that changes
262
+ // which channels the incident is entitled to. Everything else is noise.
263
+ const escalating = existing.severity !== "blocking" && report.severity === "blocking";
264
+ touch.run(
265
+ now,
266
+ report.title,
267
+ report.whatBroke,
268
+ report.whatItBlocks,
269
+ report.whatToDo,
270
+ facts,
271
+ report.severity,
272
+ fp,
273
+ );
274
+ const current = store.get(fp);
275
+ if (!current) continue;
276
+ if (escalating) out.escalated.push(current);
277
+ else out.unchanged.push(current);
278
+ }
279
+
280
+ const prefixes = opts.namespaces ?? [
281
+ ...new Set(reports.map((r) => `${r.source}:${r.kind}:`)),
282
+ ];
283
+ const candidates = db
284
+ .prepare(
285
+ `SELECT * FROM ${INCIDENTS_TABLE} WHERE check_key = ? AND state IN ('open','acknowledged')`,
286
+ )
287
+ .all(checkKey) as Row[];
288
+ for (const row of candidates) {
289
+ if (seen.has(row.fingerprint)) continue;
290
+ // Outside the namespaces this run is authoritative for — leave it alone.
291
+ // With no namespaces at all (a check that declared none and reported
292
+ // none) nothing resolves, which is the correct reading of "I have no
293
+ // idea" rather than "everything is fine".
294
+ if (!prefixes.some((p) => row.fingerprint.startsWith(p))) continue;
295
+ resolveStmt.run(now, row.fingerprint);
296
+ const resolved = store.get(row.fingerprint);
297
+ if (resolved) out.resolved.push(resolved);
298
+ }
299
+
300
+ return out;
301
+ },
302
+
303
+ markNotified(fps, result, now = Date.now()) {
304
+ const stmt = db.prepare(
305
+ `UPDATE ${INCIDENTS_TABLE} SET notified_at = ?, notify_result = ? WHERE fingerprint = ?`,
306
+ );
307
+ for (const fp of fps) stmt.run(now, result, fp);
308
+ },
309
+
310
+ markResolvedNotified(fps, now = Date.now()) {
311
+ const stmt = db.prepare(
312
+ `UPDATE ${INCIDENTS_TABLE} SET resolved_notified_at = ? WHERE fingerprint = ?`,
313
+ );
314
+ for (const fp of fps) stmt.run(now, fp);
315
+ },
316
+
317
+ acknowledge(fp, now = Date.now()) {
318
+ const row = selectOne.get(fp) as Row | null;
319
+ if (!row || row.state !== "open") return false;
320
+ db.prepare(
321
+ `UPDATE ${INCIDENTS_TABLE} SET state = 'acknowledged', acknowledged_at = ?
322
+ WHERE fingerprint = ?`,
323
+ ).run(now, fp);
324
+ return true;
325
+ },
326
+ };
327
+
328
+ return store;
329
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * The incident contract — what a detector reports, and what the store keeps.
3
+ *
4
+ * ── Why an INCIDENT and not an event (2026-08-13, the owner) ────────────────
5
+ * "auto notifying me once per incident (it needs to avoid sending me the same
6
+ * problem over and over in duplicated notifications if it's polling for
7
+ * problems)". A poller that re-sends every five minutes is the failure mode
8
+ * that gets the whole feature muted, which puts him back where he started but
9
+ * with more noise. So the unit of this module is a *condition that is true for
10
+ * a while*, identified by a stable {@link fingerprint}, with a lifecycle —
11
+ * and a notification is attached to a TRANSITION of that lifecycle, never to
12
+ * an observation. Observing the same broken thing for the ninth hour running
13
+ * bumps a counter and sends nothing.
14
+ *
15
+ * ── 🔴 An incident carries WHAT failed, never the content ───────────────────
16
+ * These messages go to a phone and to an inbox, and several apps on this fleet
17
+ * are private (notes) or zero-knowledge by construction (vault). A file name,
18
+ * a note title or a vault key in an SMS is a leak by a different door. So the
19
+ * shape below has no free-form payload: `subject` is a stable IDENTIFIER (an
20
+ * app key, a launchd label, a queue name), the three human fields are written
21
+ * by the detector's own author, and {@link IncidentReport.facts} takes NUMBERS
22
+ * and enum-ish strings only. `assertNoContent` in `store.ts` enforces the last
23
+ * one at write time rather than trusting a reviewer.
24
+ */
25
+
26
+ /** How loud an incident is. There are only two, on purpose — see `notifier.ts`. */
27
+ export type IncidentSeverity =
28
+ /** The owner's own examples: "can't deploy, can't ingest files". Email AND text. */
29
+ | "blocking"
30
+ /** Worth knowing, in-app only. A warning that texts him is a warning that mutes the channel. */
31
+ | "warning";
32
+
33
+ /** Where an incident is in its life. */
34
+ export type IncidentState =
35
+ /** Still true, not yet dealt with. */
36
+ | "open"
37
+ /** Still true; the owner has seen it and does not want to be told again. */
38
+ | "acknowledged"
39
+ /** No longer reported by its detector. */
40
+ | "resolved";
41
+
42
+ /** A fact attached to an incident. Numbers and enum-ish strings only — see the header. */
43
+ export type IncidentFact = number | boolean | null;
44
+
45
+ /**
46
+ * One condition, as a detector reports it. The detector does NOT decide whether
47
+ * this is new, whether to notify, or what the current state is — that is the
48
+ * store's job, and keeping it there is the whole dedupe guarantee.
49
+ */
50
+ export interface IncidentReport {
51
+ /** Which app or service noticed it: `binary-server`, `station`, `orch`. */
52
+ source: string;
53
+ /** The detector that produced it, e.g. `disk-below-reserve`. Stable across runs. */
54
+ kind: string;
55
+ /**
56
+ * WHAT the condition is about, as a stable identifier — an app key, a launchd
57
+ * label, a queue name. Never a file name, a title, or anything a person typed.
58
+ */
59
+ subject: string;
60
+ severity: IncidentSeverity;
61
+ /** One line, for a notification subject and a table row. Names the app. */
62
+ title: string;
63
+ /** ELI5: what actually broke. Assume he does not know what your daemon is. */
64
+ whatBroke: string;
65
+ /** ELI5: what it stops him doing. This is the sentence that earns the text message. */
66
+ whatItBlocks: string;
67
+ /** ELI5: what to do about it. A runnable command carries its own `cd` (fleet rule). */
68
+ whatToDo: string;
69
+ /** Numbers only — bytes free, items failed, commits behind. See the header. */
70
+ facts?: Record<string, IncidentFact>;
71
+ }
72
+
73
+ /** A stored incident: a report, plus everything the store knows about its life. */
74
+ export interface Incident extends IncidentReport {
75
+ fingerprint: string;
76
+ state: IncidentState;
77
+ /** Epoch ms of the first observation of this episode. */
78
+ firstSeen: number;
79
+ /** Epoch ms of the most recent observation. */
80
+ lastSeen: number;
81
+ /** How many sweeps have observed it in this episode. */
82
+ seenCount: number;
83
+ /** How many times this fingerprint has opened, ever. A flapper is visible. */
84
+ episodes: number;
85
+ acknowledgedAt: number | null;
86
+ resolvedAt: number | null;
87
+ /** When the OPEN notification went out, and what happened to each channel. */
88
+ notifiedAt: number | null;
89
+ notifyResult: string | null;
90
+ /** When the RESOLVED notification went out. */
91
+ resolvedNotifiedAt: number | null;
92
+ }
93
+
94
+ /**
95
+ * What one sweep changed. Only these three lists produce notifications — an
96
+ * incident merely observed again appears in none of them.
97
+ */
98
+ export interface IncidentTransitions {
99
+ /** Newly true, or true again after a resolve. Notify. */
100
+ opened: Incident[];
101
+ /** Was a warning, is now blocking. Notify — the channel set changed. */
102
+ escalated: Incident[];
103
+ /** No longer reported. Notify once, so "is it fixed?" is answered without asking. */
104
+ resolved: Incident[];
105
+ /** Observed again while already open. **Never notified.** Here so a test can see it. */
106
+ unchanged: Incident[];
107
+ }
108
+
109
+ /**
110
+ * A stable identity for a condition. Deliberately NOT a hash of the message:
111
+ * an author who improves the wording of `whatToDo` must not thereby re-alert
112
+ * the owner about a problem he already knows about.
113
+ */
114
+ export function fingerprint(report: Pick<IncidentReport, "source" | "kind" | "subject">): string {
115
+ return `${report.source}:${report.kind}:${report.subject}`;
116
+ }
@@ -0,0 +1,248 @@
1
+ // cursedbelt server toolkit — native Hono on Bun.serve. Consumed by ca + ru.
2
+ //
3
+ // HTTP app + middleware + the canonical error envelope + a versioned SQLite
4
+ // migration runner + Kysely-typed access for the plumbing tables. Business routes,
5
+ // auth model, sharing, jobs, and `data JSON` tables stay in the apps; cursedbelt
6
+ // owns the plumbing.
7
+
8
+ // ── ctgr (isomorphic codec re-exports + the Hono GET-tunnel transport) ───────
9
+ export {
10
+ ChunkStore,
11
+ type ChunkStoreOpts,
12
+ CTGR_WIRE_VERSION,
13
+ type CtgrDecoded,
14
+ type CtgrMethod,
15
+ decodeRequest,
16
+ type EncodedRequest,
17
+ type EncodeOpts,
18
+ encodeRequest,
19
+ type UploadedFile,
20
+ } from 'cursedbelt-core/ctgr';
21
+ // ── HTTP app ────────────────────────────────────────────────────────────────
22
+ export { type CreateAppOpts, createApp, type ServeBunOpts, serveBun } from './app';
23
+ // ── Auth toolkit (task 26): jose JWT, cookies, CSRF, getOnly, session store, ──
24
+ // login throttle, argon2id passwords, TOTP, vault crypto, the composed middleware.
25
+ export {
26
+ type AppJwtPayload,
27
+ AUTH_COOKIE_NAME,
28
+ type AuthEnv,
29
+ type AuthUser,
30
+ type AuthVariables,
31
+ type CreateSessionInput,
32
+ CSRF_COOKIE_NAME,
33
+ CSRF_HEADER_NAME,
34
+ type CsrfOptions,
35
+ clearAuthCookie,
36
+ createAuthMiddleware,
37
+ createCsrfMiddleware,
38
+ clientKeyOf,
39
+ clientKeyOfContext,
40
+ createLoginThrottle,
41
+ createSessionStore,
42
+ createRs256FileTokenSigner,
43
+ DEFAULT_TOTP_ISSUER,
44
+ decryptVaultItem,
45
+ deriveVaultKey,
46
+ encryptVaultItem,
47
+ generateRecoveryCodes,
48
+ generateTotpSecret,
49
+ getOnlyEnforcement,
50
+ getTotpUri,
51
+ hashPassword,
52
+ isGetOnlyViolation,
53
+ type LoginThrottle,
54
+ type LoginThrottleOptions,
55
+ type ThrottleVerdict,
56
+ needsRehash,
57
+ type Rs256FileTokenSignerOptions,
58
+ type Session,
59
+ type SessionStore,
60
+ type SessionStoreOptions,
61
+ signToken,
62
+ type TokenPurpose,
63
+ verifyPassword,
64
+ verifyPurposeToken,
65
+ verifyRecoveryCode,
66
+ verifyToken,
67
+ verifyTotpCode,
68
+ } from './auth';
69
+ export type { CursedbeltEnv, CursedbeltVariables } from './context';
70
+ export { buildRoutes, CTGR_ROUTE_PATTERN, getCtgrDecoded, unGETify } from './ctgr';
71
+ // ── Kysely-typed plumbing tables ────────────────────────────────────────────
72
+ export { createKysely, type PlumbingDb } from './db/kysely';
73
+ export type {
74
+ AppConfigRow,
75
+ AuthSessionRow,
76
+ EmailFailureRow,
77
+ EventLogRow,
78
+ JobRunRow,
79
+ JobStateRow,
80
+ MigrationRow,
81
+ PlumbingSchema,
82
+ RequestMetricRow,
83
+ SystemSampleRow,
84
+ } from './db/plumbingTypes';
85
+ // ── Errors ──────────────────────────────────────────────────────────────────
86
+ export {
87
+ ApiError,
88
+ type ApiErrorOptions,
89
+ type ErrorEnvelope,
90
+ isApiError,
91
+ toErrorEnvelope,
92
+ toValidationIssues,
93
+ VALIDATION_ERROR_CODE,
94
+ type ValidationIssue,
95
+ validationEnvelope,
96
+ } from './errors';
97
+ // ── Jobs & scheduler (task 29): plainjob-backed cron runner + restart-aware ───
98
+ // pollers + the due-row fire queue. App job *definitions* stay business.
99
+ export {
100
+ type CreateJobRunnerOptions,
101
+ createFireQueue,
102
+ createJobRunner,
103
+ createPollingJob,
104
+ DEFAULT_FIRE_INTERVAL_MS,
105
+ DEFAULT_JOB_TIMEOUT_MS,
106
+ defaultJobLogger,
107
+ type FireQueue,
108
+ type FireQueueOpts,
109
+ type JobContext,
110
+ type JobDef,
111
+ type JobLogger,
112
+ type JobRunner,
113
+ type JobRunRecord,
114
+ JobTimeoutError,
115
+ type PollingJob,
116
+ type PollingJobOpts,
117
+ } from './jobs';
118
+ // ── Media adapter (task 19): image rendering via sharp (lazy/optional peer) + ──
119
+ // video trim / probe / thumbnail via native ffmpeg. Also at the dedicated
120
+ // media-bun entry below; sharp is imported lazily inside renderImage,
121
+ // so importing this barrel never loads the native binary.
122
+ export {
123
+ buildProbeArgs,
124
+ buildThumbnailArgs,
125
+ buildTrimArgs,
126
+ extractThumbnail,
127
+ ffmpegTimeToSeconds,
128
+ isFfmpegAvailable,
129
+ isFfprobeAvailable,
130
+ type ProbeResult,
131
+ parseFfmpegProgress,
132
+ parseFfprobe,
133
+ probeMedia,
134
+ renderImage,
135
+ trimVideo,
136
+ type VideoCodecPlan,
137
+ videoCodecPlan,
138
+ } from './media-bun';
139
+ // ── Metrics ───────────────────────────────────────────────────────────────────
140
+ export {
141
+ createMetricsBuffer,
142
+ type MetricRow,
143
+ type MetricsBuffer,
144
+ type MetricsBufferOptions,
145
+ } from './metrics/metricsBuffer';
146
+ export { normalizeRoute } from './metrics/normalizeRoute';
147
+ // ── Middleware ────────────────────────────────────────────────────────────────
148
+ export { correlationId } from './middleware/correlationId';
149
+ export { type CorsOpts, corsAllowlist, corsOptsFromEnv } from './middleware/corsAllowlist';
150
+ export { errorEnvelope } from './middleware/errorEnvelope';
151
+ export { crossOriginRefusal } from './middleware/localOrigin';
152
+ export { clientIp, createRateLimiter, type RateLimitOpts } from './middleware/rateLimit';
153
+ export { type RequestLoggerOpts, requestLogger } from './middleware/requestLogger';
154
+ export {
155
+ type CspDirectives,
156
+ type SecurityHeadersOpts,
157
+ securityHeaders,
158
+ } from './middleware/securityHeaders';
159
+ // ── zod validation toolkit ────────────────────────────────────────────────────
160
+ // (the `validationEnvelope`/`toValidationIssues`/`ValidationIssue` builders now
161
+ // live with the canonical envelope in `./errors`, re-exported above.)
162
+ export { type ZValidatorTarget, zValidator } from './middleware/zValidator';
163
+ // ── Migration runner ──────────────────────────────────────────────────────────
164
+ export { addColumnIfMissing, applyRecommendedPragmas, columnExists, runMigrations } from './migration/runner';
165
+ export type { Migration } from './migration/types';
166
+ // ── Audit log: the SQLite-backed AuditSink cursedshell's service dispatch ─────
167
+ // writes to (see `cwip/audit` for the storage-agnostic contract + the
168
+ // zero-config in-memory default).
169
+ export {
170
+ AUDIT_LOG_MIGRATIONS,
171
+ auditStateAt,
172
+ auditStateAtVersion,
173
+ auditStep,
174
+ createSqliteAuditSink,
175
+ } from './audit';
176
+ // ── SQLite toolkit extras (task 30): FTS5 ranked search + DDL generator, the ───
177
+ // read-only DB viewer middleware, the VACUUM-INTO backup service, DB health probes.
178
+ export {
179
+ applyFtsSchema,
180
+ type BackupInfo,
181
+ buildFtsSchema,
182
+ clampLimit,
183
+ clampOffset,
184
+ collectSqliteStats,
185
+ createFts5Search,
186
+ createSqliteBackupService,
187
+ createSqliteHealthChecks,
188
+ createSqliteViewerMiddleware,
189
+ type DbStats,
190
+ exportSqliteSnapshot,
191
+ exportSqliteTable,
192
+ type Fts5Search,
193
+ type FtsHighlightOpts,
194
+ type FtsResult,
195
+ type FtsSearchOpts,
196
+ type FtsSnippetOpts,
197
+ type FtsTableSpec,
198
+ type ImportMode,
199
+ type ImportResult,
200
+ importRowsIntoSqliteTable,
201
+ isKnownTable,
202
+ isReadOnlySql,
203
+ listSqliteTables,
204
+ NotReadOnlyError,
205
+ quoteIdent,
206
+ type RestoreResult,
207
+ readSqliteTable,
208
+ restoreSqliteSnapshot,
209
+ runReadonlySqlite,
210
+ type SnapshotExport,
211
+ type SqliteBackupOpts,
212
+ type SqliteBackupS3Opts,
213
+ type SqliteBackupService,
214
+ type SqliteHealthCheck,
215
+ type SqliteHealthOpts,
216
+ type SqliteHealthResult,
217
+ type SqliteHealthStatus,
218
+ type SqliteTableInfo,
219
+ type SqliteTablePage,
220
+ sanitizeFtsQuery,
221
+ snapshotSqlite,
222
+ type TableExport,
223
+ type TableExportFormat,
224
+ type TableStat,
225
+ UnknownTableError,
226
+ } from './sqlite';
227
+ // ── WebSocket hub (task 28): Bun-native upgrade, channel registry, heartbeat, ──
228
+ // presence-as-a-view, room helpers, and the push-only event-bus subset (ru).
229
+ export {
230
+ computePresence,
231
+ createEventBus,
232
+ createWsHub,
233
+ type EventBus,
234
+ type EventBusData,
235
+ joinRoom,
236
+ leaveRoom,
237
+ type PresenceEntry,
238
+ type PresenceState,
239
+ ROOM_META_KEY,
240
+ roomOf,
241
+ type WsChannel,
242
+ type WsClient,
243
+ type WsData,
244
+ type WsHandshake,
245
+ type WsHub,
246
+ type WsHubOpts,
247
+ type WsMessage,
248
+ } from './ws';