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,263 @@
1
+ /**
2
+ * The fleet's retention VOCABULARY — one place that decides how long
3
+ * regenerable, diagnostic data lives, and what may never be governed this way.
4
+ *
5
+ * ── Why this exists ─────────────────────────────────────────────────────────
6
+ * Before this module, every app that bounded a growing table did it by hand and
7
+ * decided the number privately: `watchdog_runs` keeps the newest N on insert,
8
+ * `ai_check_runs` keeps N per check, the proposal ledger caps at 200,
9
+ * orch's own `eventRetention` was a whole bespoke sweeper with its own timer, and `deploy-engine/backupRetention.ts` a second one with different
10
+ * rules. Meanwhile the things nobody had written a rule for grew without limit:
11
+ * orch's own state directory reached **1.0 GB** — 74 MB of attempt transcripts and a
12
+ * single 70 MB peer-link `dedupe.json` holding 118 entries — with no policy, no
13
+ * backup, and nothing that could report it.
14
+ *
15
+ * The owner's ask (2026-08-01) was for ONE standard: a default that keeps
16
+ * diagnostic data no more than two weeks, per-resource overrides, a UI to see
17
+ * and change them, and no per-app copies of the logic.
18
+ *
19
+ * ── The rule that makes this safe: retention is OPT-IN, by CATEGORY ─────────
20
+ * A resource can only be swept if it declares a `RetentionCategory`, and the
21
+ * categories below describe exactly one kind of data: **a record that exists so
22
+ * a human can find out what happened, and whose loss costs nothing but
23
+ * hindsight.** There is deliberately no category that could describe a note, a
24
+ * saved setting, a password, a save state, a shelf row or a vault entry — so
25
+ * "should this table have a policy?" is answered by whether an honest category
26
+ * exists for it, not by an agent's judgment in the moment.
27
+ *
28
+ * Long-term data is therefore protected by ABSENCE, not by a denylist a future
29
+ * table would have to be remembered into. Two further gates back it up:
30
+ * `scripts/retentionPolicies.test.ts` pins the exact (app, resource) set that
31
+ * sweeps anywhere in this repo — adding one is an edit to a reviewed list, never
32
+ * a side effect — and `floorItems` below means even a mis-set policy cannot
33
+ * empty a resource.
34
+ *
35
+ * ── The missing middle, added 2026-08-25: ARCHIVE-then-trim ─────────────────
36
+ * Until now a resource was either governed (swept, gone forever) or undeclared
37
+ * (kept forever on a 6.7 GB prod root). Neither describes an append-only history
38
+ * whose recent window is load-bearing and whose tail is worth keeping but not
39
+ * worth keeping THERE. `archived-history` is that third answer: the instance
40
+ * keeps a bounded window and everything older is written to a verified,
41
+ * append-only archive BEFORE a single row is deleted.
42
+ *
43
+ * That is why it is the one category allowed a default longer than the owner's
44
+ * two-week standard, and the exemption is narrow by construction rather than by
45
+ * convention: `archivesBeforeDelete` is a property of the CATEGORY, the
46
+ * plain-delete targets in `target.ts` REFUSE a declaration that carries it, and
47
+ * the archiving target refuses to delete a row it cannot prove it has archived.
48
+ * A category that could be swept by a target that only deletes would be a
49
+ * longer retention with no archive at the end of it — strictly worse than having
50
+ * no category at all.
51
+ *
52
+ * ── Anything that grows without bound and is NOT sweepable is a design bug ──
53
+ * The other half of the standard. If a resource grows forever and no category
54
+ * fits it, the answer is not a longer retention — it is that the thing should
55
+ * not be accumulating (peer-link's dedupe file was storing 600 KB command
56
+ * RESULTS to answer a replay question that needs only an id).
57
+ */
58
+ /**
59
+ * The closed set of things a retention policy may govern.
60
+ *
61
+ * Each entry's `defaultDays` is the fleet default for that shape. The owner's
62
+ * standard is two weeks; a DELETING category is shorter only where the data is
63
+ * cheaper than that to lose, and none is longer — a deleting category that
64
+ * wanted a longer default would be describing data that belongs to the user,
65
+ * which is the exact case this vocabulary refuses to express.
66
+ *
67
+ * `archivesBeforeDelete` is the single, narrow exemption: the rows leave the
68
+ * instance but not existence, so the number is a WINDOW rather than a lifetime
69
+ * and may honestly be longer. `policy.spec.ts` pins both halves of that rule.
70
+ */
71
+ export declare const RETENTION_CATEGORIES: {
72
+ readonly "audit-log": {
73
+ readonly label: "Audit log";
74
+ readonly defaultDays: 14;
75
+ readonly summary: "Who did what, kept so an incident can be reconstructed. Read only after a problem.";
76
+ };
77
+ readonly "event-log": {
78
+ readonly label: "Event log";
79
+ readonly defaultDays: 14;
80
+ readonly summary: "State transitions and activity trails. The narrative of a run, not the run's result.";
81
+ };
82
+ readonly "run-log": {
83
+ readonly label: "Run log";
84
+ readonly defaultDays: 14;
85
+ readonly summary: "One row per execution of a job, check or sweep — its outcome ledger.";
86
+ };
87
+ readonly transcript: {
88
+ readonly label: "Transcript";
89
+ readonly defaultDays: 14;
90
+ readonly summary: "Verbatim worker/tool output. Large, read once during triage, never again.";
91
+ };
92
+ readonly metric: {
93
+ readonly label: "Metric";
94
+ readonly defaultDays: 14;
95
+ readonly summary: "Sampled counters and telemetry. Interesting in aggregate and recent, not per-row.";
96
+ };
97
+ readonly cache: {
98
+ readonly label: "Cache";
99
+ readonly defaultDays: 7;
100
+ readonly summary: "Recomputable from its source. Shorter by default because losing it costs a refetch.";
101
+ };
102
+ readonly "replica-mirror": {
103
+ readonly label: "Replica mirror";
104
+ readonly defaultDays: 7;
105
+ readonly summary: "A copy of state that another instance owns authoritatively. Never the only copy.";
106
+ };
107
+ readonly "queue-result": {
108
+ readonly label: "Queue result";
109
+ readonly defaultDays: 3;
110
+ readonly summary: "Completed command/job rows and their payloads, kept only long enough to answer a retry or a replay.";
111
+ };
112
+ readonly "scratch-artifact": {
113
+ readonly label: "Scratch artifact";
114
+ readonly defaultDays: 14;
115
+ readonly summary: "Generated files kept for inspection — renders, dumps, exports. Reproducible by rerunning.";
116
+ };
117
+ readonly "archived-history": {
118
+ readonly label: "Archived history";
119
+ readonly defaultDays: 30;
120
+ readonly archivesBeforeDelete: true;
121
+ readonly summary: "Append-only history whose recent window is load-bearing and whose tail is not. The instance keeps the window; everything older is written to a verified archive first and only then deleted, so the number is where the history LIVES, never how long it exists.";
122
+ };
123
+ };
124
+ export type RetentionCategory = keyof typeof RETENTION_CATEGORIES;
125
+ export declare const RETENTION_CATEGORY_KEYS: RetentionCategory[];
126
+ /**
127
+ * Does this category promise the rows survive the sweep somewhere else?
128
+ *
129
+ * The one question that decides which TARGET may govern a resource, so it is
130
+ * asked as a function rather than by reading a property at four call sites — a
131
+ * plain-delete target checks it to refuse, the archiving target checks it to
132
+ * insist, and `policy.spec.ts` checks it to allow the longer default.
133
+ */
134
+ export declare function categoryArchivesBeforeDelete(category: RetentionCategory): boolean;
135
+ /** The categories whose rows are archived rather than destroyed. */
136
+ export declare const ARCHIVING_RETENTION_CATEGORIES: ("audit-log" | "event-log" | "run-log" | "transcript" | "metric" | "cache" | "replica-mirror" | "queue-result" | "scratch-artifact" | "archived-history")[];
137
+ /**
138
+ * The owner's standard (2026-08-01): diagnostic data lives two weeks unless
139
+ * something says otherwise. Exported because the UI states it as the house rule
140
+ * rather than repeating a literal, and because a category's default is only ever
141
+ * allowed to be this or shorter (pinned by `policy.test.ts`).
142
+ */
143
+ export declare const FLEET_DEFAULT_RETENTION_DAYS = 14;
144
+ /** Bounds an override is clamped into unless a declaration narrows them. */
145
+ export declare const RETENTION_MIN_DAYS = 1;
146
+ export declare const RETENTION_MAX_DAYS = 365;
147
+ /** What a resource is counted in — decides the UI's noun and the target's `measure`. */
148
+ export type RetentionUnit = "rows" | "files";
149
+ /**
150
+ * One governable resource, declared by the app that owns it.
151
+ *
152
+ * `id` is stable and app-scoped (`events`, `attempt-transcripts`), because it is
153
+ * the override key — renaming one silently orphans the owner's setting, which is
154
+ * why `retentionPolicies.test.ts` pins the ids too.
155
+ */
156
+ export interface RetentionDeclaration {
157
+ /** App key, matching the fleet registry's app-tracking rows (`orch`, `notes`, …). */
158
+ app: string;
159
+ /** Stable, app-scoped id. The override key is `<app>:<id>`. */
160
+ id: string;
161
+ /** Human label for the UI. */
162
+ label: string;
163
+ category: RetentionCategory;
164
+ unit: RetentionUnit;
165
+ /** Where it physically lives, for the UI: `orch.sqlite · events`, `logs/attempts/*.jsonl`. */
166
+ location: string;
167
+ /** One sentence: what is lost when this ages out. The UI shows it beside the control. */
168
+ consequence: string;
169
+ /** Defaults to the category's `defaultDays`. */
170
+ defaultDays?: number;
171
+ /**
172
+ * Absolute item-count backstop, liveness ignored, applied after the age
173
+ * sweep. `0` disables it. This is the bound that must hold when the age sweep
174
+ * cannot — a runaway loop writing rows against one live task is the realistic
175
+ * way that happens. A bound that politely declines to bind is not a bound.
176
+ */
177
+ defaultMaxItems?: number;
178
+ /**
179
+ * Byte budget for the resource, applied like `defaultMaxItems` but measured in
180
+ * size — the right bound when items vary by orders of magnitude, which is why
181
+ * `orch`'s worker transcripts use it (one deep run can be 5 MB, one trivial
182
+ * attempt 4 KB, so a count cap bounds nothing useful). `0` disables it.
183
+ * Honored by targets that can measure bytes; a sqlite-table target ignores it.
184
+ */
185
+ defaultMaxBytes?: number;
186
+ /**
187
+ * Never delete the newest N, at any age, for any reason — the rule that makes
188
+ * an unattended sweep safe (learned in `deploy-engine/backupRetention.ts`: a
189
+ * naive age rule deletes every artifact of an app that stopped being
190
+ * deployed). A resource with a floor converges to the floor and stays there.
191
+ */
192
+ floorItems?: number;
193
+ /** Narrowed bounds for this resource's override. */
194
+ minDays?: number;
195
+ maxDays?: number;
196
+ }
197
+ /** The owner's per-resource change, made in the station UI. */
198
+ export interface RetentionOverride {
199
+ days?: number;
200
+ maxItems?: number;
201
+ maxBytes?: number;
202
+ /** `false` suspends the sweep and keeps everything — deliberate, and shown as such. */
203
+ enabled?: boolean;
204
+ note?: string;
205
+ updatedAt?: number;
206
+ updatedBy?: string;
207
+ }
208
+ export type RetentionFieldSource = "default" | "override";
209
+ /**
210
+ * The fleet's canonical `RetentionPolicy` — an alias for the resolved,
211
+ * in-effect policy a sweep runs with. Named here (DEDUP-8(c)) so exactly one
212
+ * module owns the word: the billing/audit WINDOWS carry `RetentionWindows` and
213
+ * backup pruning carries `BackupRetentionPolicy`, both deliberately distinct.
214
+ */
215
+ export type RetentionPolicy = EffectiveRetentionPolicy;
216
+ /** What a sweep actually runs with, plus where each number came from. */
217
+ export interface EffectiveRetentionPolicy {
218
+ key: string;
219
+ app: string;
220
+ id: string;
221
+ enabled: boolean;
222
+ /** Age cutoff in days. `0` means the age sweep is off (the cap may still apply). */
223
+ days: number;
224
+ maxItems: number;
225
+ maxBytes: number;
226
+ floorItems: number;
227
+ minDays: number;
228
+ maxDays: number;
229
+ sources: {
230
+ days: RetentionFieldSource;
231
+ maxItems: RetentionFieldSource;
232
+ maxBytes: RetentionFieldSource;
233
+ enabled: RetentionFieldSource;
234
+ };
235
+ /** Set when an override asked for something out of bounds and was clamped. */
236
+ clamped?: {
237
+ field: "days" | "maxItems" | "maxBytes";
238
+ requested: number;
239
+ applied: number;
240
+ };
241
+ }
242
+ /** The override key. One function so the UI, the store and the sweeper agree. */
243
+ export declare function retentionKey(app: string, id: string): string;
244
+ /**
245
+ * Reject a malformed declaration at construction rather than at sweep time — a
246
+ * resource whose id cannot be an override key is a control the owner would
247
+ * change with no effect.
248
+ */
249
+ export declare function assertRetentionDeclaration(declaration: RetentionDeclaration): void;
250
+ /**
251
+ * Merge a declaration with the owner's override into the numbers a sweep runs
252
+ * with. Pure, so both the sweeper and the UI's "what would this delete?" preview
253
+ * resolve identically — a preview computed by different code than the sweep is a
254
+ * preview that can lie.
255
+ *
256
+ * `days: 0` is preserved rather than clamped up to `minDays`: it is the explicit
257
+ * "keep forever" the UI offers, and clamping it would silently re-arm a sweep the
258
+ * owner turned off.
259
+ */
260
+ export declare function resolveRetentionPolicy(declaration: RetentionDeclaration, override?: RetentionOverride | null): EffectiveRetentionPolicy;
261
+ export declare const DAY_MS = 86400000;
262
+ /** The age cutoff a sweep compares against, or `null` when the age sweep is off. */
263
+ export declare function cutoffFor(policy: EffectiveRetentionPolicy, now: number): number | null;
@@ -0,0 +1,264 @@
1
+ /**
2
+ * The fleet's retention VOCABULARY — one place that decides how long
3
+ * regenerable, diagnostic data lives, and what may never be governed this way.
4
+ *
5
+ * ── Why this exists ─────────────────────────────────────────────────────────
6
+ * Before this module, every app that bounded a growing table did it by hand and
7
+ * decided the number privately: `watchdog_runs` keeps the newest N on insert,
8
+ * `ai_check_runs` keeps N per check, the proposal ledger caps at 200,
9
+ * orch's own `eventRetention` was a whole bespoke sweeper with its own timer, and `deploy-engine/backupRetention.ts` a second one with different
10
+ * rules. Meanwhile the things nobody had written a rule for grew without limit:
11
+ * orch's own state directory reached **1.0 GB** — 74 MB of attempt transcripts and a
12
+ * single 70 MB peer-link `dedupe.json` holding 118 entries — with no policy, no
13
+ * backup, and nothing that could report it.
14
+ *
15
+ * The owner's ask (2026-08-01) was for ONE standard: a default that keeps
16
+ * diagnostic data no more than two weeks, per-resource overrides, a UI to see
17
+ * and change them, and no per-app copies of the logic.
18
+ *
19
+ * ── The rule that makes this safe: retention is OPT-IN, by CATEGORY ─────────
20
+ * A resource can only be swept if it declares a `RetentionCategory`, and the
21
+ * categories below describe exactly one kind of data: **a record that exists so
22
+ * a human can find out what happened, and whose loss costs nothing but
23
+ * hindsight.** There is deliberately no category that could describe a note, a
24
+ * saved setting, a password, a save state, a shelf row or a vault entry — so
25
+ * "should this table have a policy?" is answered by whether an honest category
26
+ * exists for it, not by an agent's judgment in the moment.
27
+ *
28
+ * Long-term data is therefore protected by ABSENCE, not by a denylist a future
29
+ * table would have to be remembered into. Two further gates back it up:
30
+ * `scripts/retentionPolicies.test.ts` pins the exact (app, resource) set that
31
+ * sweeps anywhere in this repo — adding one is an edit to a reviewed list, never
32
+ * a side effect — and `floorItems` below means even a mis-set policy cannot
33
+ * empty a resource.
34
+ *
35
+ * ── The missing middle, added 2026-08-25: ARCHIVE-then-trim ─────────────────
36
+ * Until now a resource was either governed (swept, gone forever) or undeclared
37
+ * (kept forever on a 6.7 GB prod root). Neither describes an append-only history
38
+ * whose recent window is load-bearing and whose tail is worth keeping but not
39
+ * worth keeping THERE. `archived-history` is that third answer: the instance
40
+ * keeps a bounded window and everything older is written to a verified,
41
+ * append-only archive BEFORE a single row is deleted.
42
+ *
43
+ * That is why it is the one category allowed a default longer than the owner's
44
+ * two-week standard, and the exemption is narrow by construction rather than by
45
+ * convention: `archivesBeforeDelete` is a property of the CATEGORY, the
46
+ * plain-delete targets in `target.ts` REFUSE a declaration that carries it, and
47
+ * the archiving target refuses to delete a row it cannot prove it has archived.
48
+ * A category that could be swept by a target that only deletes would be a
49
+ * longer retention with no archive at the end of it — strictly worse than having
50
+ * no category at all.
51
+ *
52
+ * ── Anything that grows without bound and is NOT sweepable is a design bug ──
53
+ * The other half of the standard. If a resource grows forever and no category
54
+ * fits it, the answer is not a longer retention — it is that the thing should
55
+ * not be accumulating (peer-link's dedupe file was storing 600 KB command
56
+ * RESULTS to answer a replay question that needs only an id).
57
+ */
58
+ /**
59
+ * The closed set of things a retention policy may govern.
60
+ *
61
+ * Each entry's `defaultDays` is the fleet default for that shape. The owner's
62
+ * standard is two weeks; a DELETING category is shorter only where the data is
63
+ * cheaper than that to lose, and none is longer — a deleting category that
64
+ * wanted a longer default would be describing data that belongs to the user,
65
+ * which is the exact case this vocabulary refuses to express.
66
+ *
67
+ * `archivesBeforeDelete` is the single, narrow exemption: the rows leave the
68
+ * instance but not existence, so the number is a WINDOW rather than a lifetime
69
+ * and may honestly be longer. `policy.spec.ts` pins both halves of that rule.
70
+ */
71
+ export const RETENTION_CATEGORIES = {
72
+ "audit-log": {
73
+ label: "Audit log",
74
+ defaultDays: 14,
75
+ summary: "Who did what, kept so an incident can be reconstructed. Read only after a problem.",
76
+ },
77
+ "event-log": {
78
+ label: "Event log",
79
+ defaultDays: 14,
80
+ summary: "State transitions and activity trails. The narrative of a run, not the run's result.",
81
+ },
82
+ "run-log": {
83
+ label: "Run log",
84
+ defaultDays: 14,
85
+ summary: "One row per execution of a job, check or sweep — its outcome ledger.",
86
+ },
87
+ transcript: {
88
+ label: "Transcript",
89
+ defaultDays: 14,
90
+ summary: "Verbatim worker/tool output. Large, read once during triage, never again.",
91
+ },
92
+ metric: {
93
+ label: "Metric",
94
+ defaultDays: 14,
95
+ summary: "Sampled counters and telemetry. Interesting in aggregate and recent, not per-row.",
96
+ },
97
+ cache: {
98
+ label: "Cache",
99
+ defaultDays: 7,
100
+ summary: "Recomputable from its source. Shorter by default because losing it costs a refetch.",
101
+ },
102
+ "replica-mirror": {
103
+ label: "Replica mirror",
104
+ defaultDays: 7,
105
+ summary: "A copy of state that another instance owns authoritatively. Never the only copy.",
106
+ },
107
+ "queue-result": {
108
+ label: "Queue result",
109
+ defaultDays: 3,
110
+ summary: "Completed command/job rows and their payloads, kept only long enough to answer a retry or a replay.",
111
+ },
112
+ "scratch-artifact": {
113
+ label: "Scratch artifact",
114
+ defaultDays: 14,
115
+ summary: "Generated files kept for inspection — renders, dumps, exports. Reproducible by rerunning.",
116
+ },
117
+ "archived-history": {
118
+ label: "Archived history",
119
+ defaultDays: 30,
120
+ archivesBeforeDelete: true,
121
+ summary: "Append-only history whose recent window is load-bearing and whose tail is not. The instance keeps the window; everything older is written to a verified archive first and only then deleted, so the number is where the history LIVES, never how long it exists.",
122
+ },
123
+ };
124
+ export const RETENTION_CATEGORY_KEYS = Object.keys(RETENTION_CATEGORIES);
125
+ /**
126
+ * Does this category promise the rows survive the sweep somewhere else?
127
+ *
128
+ * The one question that decides which TARGET may govern a resource, so it is
129
+ * asked as a function rather than by reading a property at four call sites — a
130
+ * plain-delete target checks it to refuse, the archiving target checks it to
131
+ * insist, and `policy.spec.ts` checks it to allow the longer default.
132
+ */
133
+ export function categoryArchivesBeforeDelete(category) {
134
+ // An UNKNOWN category answers `false` rather than throwing. It is asked at
135
+ // target construction, which runs before `assertRetentionDeclaration` gets to
136
+ // say "unknown category (the closed set is …)" — and a TypeError about an
137
+ // undefined property would replace that message with one that names nothing.
138
+ const entry = RETENTION_CATEGORIES[category];
139
+ return entry?.archivesBeforeDelete === true;
140
+ }
141
+ /** The categories whose rows are archived rather than destroyed. */
142
+ export const ARCHIVING_RETENTION_CATEGORIES = RETENTION_CATEGORY_KEYS.filter(categoryArchivesBeforeDelete);
143
+ /**
144
+ * The owner's standard (2026-08-01): diagnostic data lives two weeks unless
145
+ * something says otherwise. Exported because the UI states it as the house rule
146
+ * rather than repeating a literal, and because a category's default is only ever
147
+ * allowed to be this or shorter (pinned by `policy.test.ts`).
148
+ */
149
+ export const FLEET_DEFAULT_RETENTION_DAYS = 14;
150
+ /** Bounds an override is clamped into unless a declaration narrows them. */
151
+ export const RETENTION_MIN_DAYS = 1;
152
+ export const RETENTION_MAX_DAYS = 365;
153
+ /** The override key. One function so the UI, the store and the sweeper agree. */
154
+ export function retentionKey(app, id) {
155
+ return `${app}:${id}`;
156
+ }
157
+ const ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
158
+ /**
159
+ * Reject a malformed declaration at construction rather than at sweep time — a
160
+ * resource whose id cannot be an override key is a control the owner would
161
+ * change with no effect.
162
+ */
163
+ export function assertRetentionDeclaration(declaration) {
164
+ const { app, id } = declaration;
165
+ if (!ID_PATTERN.test(app))
166
+ throw new Error(`retention: app key "${app}" must be lower-kebab`);
167
+ if (!ID_PATTERN.test(id))
168
+ throw new Error(`retention: resource id "${id}" must be lower-kebab`);
169
+ if (!(declaration.category in RETENTION_CATEGORIES)) {
170
+ throw new Error(`retention: "${retentionKey(app, id)}" declares unknown category "${declaration.category}". ` +
171
+ `Retention is opt-in by category (${RETENTION_CATEGORY_KEYS.join(", ")}); data that fits ` +
172
+ "none of them must not be swept.");
173
+ }
174
+ if (!declaration.consequence.trim()) {
175
+ throw new Error(`retention: "${retentionKey(app, id)}" must say what is lost when it ages out — the owner ` +
176
+ "reads that sentence before changing the number.");
177
+ }
178
+ for (const [field, value] of [
179
+ ["defaultDays", declaration.defaultDays],
180
+ ["defaultMaxItems", declaration.defaultMaxItems],
181
+ ["defaultMaxBytes", declaration.defaultMaxBytes],
182
+ ["floorItems", declaration.floorItems],
183
+ ]) {
184
+ if (value !== undefined && (!Number.isFinite(value) || value < 0)) {
185
+ throw new Error(`retention: "${retentionKey(app, id)}" ${field} must be a non-negative number`);
186
+ }
187
+ }
188
+ }
189
+ const clamp = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
190
+ /**
191
+ * Merge a declaration with the owner's override into the numbers a sweep runs
192
+ * with. Pure, so both the sweeper and the UI's "what would this delete?" preview
193
+ * resolve identically — a preview computed by different code than the sweep is a
194
+ * preview that can lie.
195
+ *
196
+ * `days: 0` is preserved rather than clamped up to `minDays`: it is the explicit
197
+ * "keep forever" the UI offers, and clamping it would silently re-arm a sweep the
198
+ * owner turned off.
199
+ */
200
+ export function resolveRetentionPolicy(declaration, override) {
201
+ assertRetentionDeclaration(declaration);
202
+ const category = RETENTION_CATEGORIES[declaration.category];
203
+ const minDays = declaration.minDays ?? RETENTION_MIN_DAYS;
204
+ const maxDays = declaration.maxDays ?? RETENTION_MAX_DAYS;
205
+ const defaultDays = declaration.defaultDays ?? category.defaultDays;
206
+ let days = defaultDays;
207
+ let daysSource = "default";
208
+ let clamped;
209
+ if (typeof override?.days === "number" && Number.isFinite(override.days)) {
210
+ const requested = Math.round(override.days);
211
+ const applied = requested === 0 ? 0 : clamp(requested, minDays, maxDays);
212
+ if (applied !== requested)
213
+ clamped = { field: "days", requested, applied };
214
+ days = applied;
215
+ daysSource = "override";
216
+ }
217
+ let maxItems = declaration.defaultMaxItems ?? 0;
218
+ let maxItemsSource = "default";
219
+ if (typeof override?.maxItems === "number" && Number.isFinite(override.maxItems)) {
220
+ const requested = Math.round(override.maxItems);
221
+ const applied = Math.max(0, requested);
222
+ if (applied !== requested)
223
+ clamped = { field: "maxItems", requested, applied };
224
+ maxItems = applied;
225
+ maxItemsSource = "override";
226
+ }
227
+ let maxBytes = declaration.defaultMaxBytes ?? 0;
228
+ let maxBytesSource = "default";
229
+ if (typeof override?.maxBytes === "number" && Number.isFinite(override.maxBytes)) {
230
+ const requested = Math.round(override.maxBytes);
231
+ const applied = Math.max(0, requested);
232
+ if (applied !== requested)
233
+ clamped = { field: "maxBytes", requested, applied };
234
+ maxBytes = applied;
235
+ maxBytesSource = "override";
236
+ }
237
+ const enabled = override?.enabled ?? true;
238
+ return {
239
+ key: retentionKey(declaration.app, declaration.id),
240
+ app: declaration.app,
241
+ id: declaration.id,
242
+ enabled,
243
+ days,
244
+ maxItems,
245
+ maxBytes,
246
+ floorItems: declaration.floorItems ?? 0,
247
+ minDays,
248
+ maxDays,
249
+ sources: {
250
+ days: daysSource,
251
+ maxItems: maxItemsSource,
252
+ maxBytes: maxBytesSource,
253
+ enabled: override?.enabled === undefined ? "default" : "override",
254
+ },
255
+ ...(clamped ? { clamped } : {}),
256
+ };
257
+ }
258
+ export const DAY_MS = 86_400_000;
259
+ /** The age cutoff a sweep compares against, or `null` when the age sweep is off. */
260
+ export function cutoffFor(policy, now) {
261
+ if (!policy.enabled || policy.days <= 0)
262
+ return null;
263
+ return now - policy.days * DAY_MS;
264
+ }
@@ -0,0 +1,101 @@
1
+ import type { RetentionDeclaration, RetentionOverride } from "./policy";
2
+ /** What one sweep of one resource did. Published so the UI can show it. */
3
+ export interface RetentionSweepReport {
4
+ at: number;
5
+ /** Items removed because they aged past the cutoff. */
6
+ aged: number;
7
+ /** Items removed by the item-count backstop, liveness ignored. */
8
+ overflow: number;
9
+ /**
10
+ * Items the sweep deliberately left alone because they are still live — a
11
+ * running worker's transcript, an unsettled task's trail. Reported so a
12
+ * resource that stays large has an explanation rather than looking like a
13
+ * broken sweep.
14
+ */
15
+ protectedItems?: number;
16
+ bytesFreed?: number;
17
+ /**
18
+ * Items written to the archive before they were deleted — the `archived-history`
19
+ * category's receipt. Reported so the station can show "moved" rather than
20
+ * "removed": for an archiving resource those two words are the whole difference,
21
+ * and a UI that said the second would be describing data loss that did not happen.
22
+ */
23
+ archived?: number;
24
+ /** Bytes those archived items occupy in the archive. */
25
+ archivedBytes?: number;
26
+ /**
27
+ * Why this sweep deliberately removed nothing, when it otherwise would have.
28
+ * An archiving resource whose archive is not being collected REFUSES to trim,
29
+ * and a resource that quietly stops working is indistinguishable from one with
30
+ * nothing to do — so the reason is carried out to the UI rather than logged and
31
+ * lost.
32
+ */
33
+ blocked?: string;
34
+ error?: string;
35
+ }
36
+ /** A live measurement of a resource, taken at sweep time. */
37
+ export interface RetentionMeasurement {
38
+ items: number;
39
+ bytes?: number;
40
+ /** Timestamp of the oldest item, when the target can report it cheaply. */
41
+ oldestAt?: number;
42
+ }
43
+ /** One resource as published by its owning app. */
44
+ export interface PublishedResource {
45
+ declaration: RetentionDeclaration;
46
+ measurement?: RetentionMeasurement;
47
+ lastSweep?: RetentionSweepReport;
48
+ }
49
+ /** One app's publication file. */
50
+ export interface RetentionPublication {
51
+ app: string;
52
+ version: 1;
53
+ publishedAt: number;
54
+ /** The instance that published — `local`, `prod`, `dev`; purely informational. */
55
+ instance?: string;
56
+ /** True when the process that published it has sweeping disabled entirely. */
57
+ sweepDisabled?: boolean;
58
+ resources: PublishedResource[];
59
+ }
60
+ export interface RetentionOverridesFile {
61
+ version: 1;
62
+ updatedAt: number;
63
+ /** Keyed by `<app>:<id>` — `retentionKey()`. */
64
+ overrides: Record<string, RetentionOverride>;
65
+ }
66
+ /**
67
+ * Resolve the retention home. See the module note for the ordering rationale.
68
+ * Cached per process — it is consulted on every sweep and cannot change under a
69
+ * running app.
70
+ */
71
+ export declare function resolveRetentionHome(env?: Record<string, string | undefined>): string;
72
+ /** Test seam — point the home somewhere else for this process. */
73
+ export declare function setRetentionHomeForTests(home: string | null): void;
74
+ /**
75
+ * Publish one app's resources. Best-effort by contract: a retention publication
76
+ * that cannot be written is a missing row in a dashboard, and must never take
77
+ * down the app that owns the data.
78
+ */
79
+ export declare function publishRetention(publication: Omit<RetentionPublication, "version" | "publishedAt">, options?: {
80
+ home?: string;
81
+ log?: (line: string) => void;
82
+ }): boolean;
83
+ /** Every app's publication, newest-published first. */
84
+ export declare function readRetentionRegistry(home?: string): RetentionPublication[];
85
+ export declare function readRetentionOverrides(home?: string): RetentionOverridesFile;
86
+ /**
87
+ * Apply one override. Read-modify-write, so an unrelated resource's setting is
88
+ * never lost to a concurrent edit of this one; the station is the only writer,
89
+ * which is what keeps that honest.
90
+ *
91
+ * A patch field set to `undefined` is left alone; set to `null` it is CLEARED,
92
+ * which is how the UI's "reset to default" works — deleting the key is the only
93
+ * way to make the declaration's default authoritative again, since a stored
94
+ * value that merely equals the default would freeze the resource at today's
95
+ * number if the default ever moves.
96
+ */
97
+ export declare function writeRetentionOverride(app: string, id: string, patch: Partial<Record<"days" | "maxItems" | "maxBytes" | "enabled" | "note", unknown>> | null, options?: {
98
+ home?: string;
99
+ updatedBy?: string;
100
+ now?: number;
101
+ }): RetentionOverridesFile;