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
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `cursedbelt-server/activity` — the fleet's ONE append-only activity/audit
3
+ * stream: who did what, to which record, when, and how it went.
4
+ *
5
+ * The vocabulary is `cursedbelt-core/activity` (pure), this is the storage + query
6
+ * half, and the console's **Event Logs** tab is the fleet-wide reader — it asks
7
+ * every live deployment through `satellite-kit/metrics`' bearer-gated
8
+ * `?view=events`, so an app is on the board by writing events, with no
9
+ * admin-side wiring at all.
10
+ *
11
+ * ── Retention ───────────────────────────────────────────────────────────────
12
+ * This package never deletes an event. An app whose stream is high-volume opts
13
+ * into the fleet standard (`docs/retention.md` in `cursed-satellites`) by
14
+ * declaring the table, which puts the number under the owner's control in the
15
+ * station rather than in a constant here:
16
+ *
17
+ * ```ts
18
+ * createSqliteTableTarget({
19
+ * db, table: ACTIVITY_EVENTS_TABLE, timeColumn: "at", timeFormat: "iso",
20
+ * declaration: { app: "notes", id: "activity", label: "Activity log",
21
+ * category: "event-log", unit: "rows", location: "notes.sqlite · activity_events",
22
+ * consequence: "Who did what, for hindsight. Losing it costs no data." },
23
+ * })
24
+ * ```
25
+ *
26
+ * An app whose stream is a handful of rows a month — an audit of destructive
27
+ * actions, say — is right to declare NOTHING and say so: the standard is opt-in
28
+ * by category, and an audit trail of production deletions is precisely the data
29
+ * a 14-day cutoff must not reach.
30
+ */
31
+ export { ACTIVITY_EVENTS_TABLE, ACTIVITY_MIGRATIONS } from "./migrations";
32
+ export { shareEventsSource, type ShareEventsSourceOptions } from "./shareSource";
33
+ export { createActivityLog } from "./store";
34
+ export type { ActivityFacet, ActivityFacets, ActivityLog, ActivityLogOptions, ActivityPage, ActivityQuery, ActivitySource, } from "./store";
35
+ export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "cursedbelt-core/activity/model";
36
+ export type { ActivityEvent, ActivityEventInput, ActivityOutcome, ActivityResource, } from "cursedbelt-core/activity/model";
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `cursedbelt-server/activity` — the fleet's ONE append-only activity/audit
3
+ * stream: who did what, to which record, when, and how it went.
4
+ *
5
+ * The vocabulary is `cursedbelt-core/activity` (pure), this is the storage + query
6
+ * half, and the console's **Event Logs** tab is the fleet-wide reader — it asks
7
+ * every live deployment through `satellite-kit/metrics`' bearer-gated
8
+ * `?view=events`, so an app is on the board by writing events, with no
9
+ * admin-side wiring at all.
10
+ *
11
+ * ── Retention ───────────────────────────────────────────────────────────────
12
+ * This package never deletes an event. An app whose stream is high-volume opts
13
+ * into the fleet standard (`docs/retention.md` in `cursed-satellites`) by
14
+ * declaring the table, which puts the number under the owner's control in the
15
+ * station rather than in a constant here:
16
+ *
17
+ * ```ts
18
+ * createSqliteTableTarget({
19
+ * db, table: ACTIVITY_EVENTS_TABLE, timeColumn: "at", timeFormat: "iso",
20
+ * declaration: { app: "notes", id: "activity", label: "Activity log",
21
+ * category: "event-log", unit: "rows", location: "notes.sqlite · activity_events",
22
+ * consequence: "Who did what, for hindsight. Losing it costs no data." },
23
+ * })
24
+ * ```
25
+ *
26
+ * An app whose stream is a handful of rows a month — an audit of destructive
27
+ * actions, say — is right to declare NOTHING and say so: the standard is opt-in
28
+ * by category, and an audit trail of production deletions is precisely the data
29
+ * a 14-day cutoff must not reach.
30
+ */
31
+ export { ACTIVITY_EVENTS_TABLE, ACTIVITY_MIGRATIONS } from "./migrations";
32
+ export { shareEventsSource } from "./shareSource";
33
+ export { createActivityLog } from "./store";
34
+ // Re-exported so a server consumer needs ONE import for the whole contract; the
35
+ // pure entry (`cursedbelt-core/activity`) stays available for a browser or a spec.
36
+ export { ACTIVITY_OUTCOMES, activityFromShareEvent, activitySubject, describeActivityEvent, describeActivityResource, isActivityAction, isActivityOutcome, } from "cursedbelt-core/activity/model";
@@ -0,0 +1,21 @@
1
+ import type { Migration } from "../migration/types";
2
+ /** The one table this primitive owns. Exported so an app can declare a retention
3
+ * target over it (see this module's `index.ts` for the recipe). */
4
+ export declare const ACTIVITY_EVENTS_TABLE = "activity_events";
5
+ /**
6
+ * ONE append-only table per app, not a shadow table per business table.
7
+ *
8
+ * The stream's whole value is being readable as one list — "everything that
9
+ * happened in `notes` yesterday", "everything `curt@…` did", "everything that
10
+ * touched person `3f2`" — and a per-table history cannot answer any of those
11
+ * without a UNION nobody maintains. `(kind, resource_id)` plays the role a
12
+ * shadow table would, and is a business key the app already has rather than a
13
+ * migration in `cursedbelt`.
14
+ *
15
+ * 🔴 **Append only.** There is no update and no delete verb anywhere in this
16
+ * package. The one sanctioned deleter is the fleet retention standard
17
+ * (`satellite-kit/retention`), which an app opts into by declaring this table as
18
+ * an `event-log`/`audit-log` resource — a control the owner can see and change,
19
+ * rather than a cutoff buried in a store.
20
+ */
21
+ export declare const ACTIVITY_MIGRATIONS: readonly Migration[];
@@ -0,0 +1,55 @@
1
+ /** The one table this primitive owns. Exported so an app can declare a retention
2
+ * target over it (see this module's `index.ts` for the recipe). */
3
+ export const ACTIVITY_EVENTS_TABLE = "activity_events";
4
+ /**
5
+ * ONE append-only table per app, not a shadow table per business table.
6
+ *
7
+ * The stream's whole value is being readable as one list — "everything that
8
+ * happened in `notes` yesterday", "everything `curt@…` did", "everything that
9
+ * touched person `3f2`" — and a per-table history cannot answer any of those
10
+ * without a UNION nobody maintains. `(kind, resource_id)` plays the role a
11
+ * shadow table would, and is a business key the app already has rather than a
12
+ * migration in `cursedbelt`.
13
+ *
14
+ * 🔴 **Append only.** There is no update and no delete verb anywhere in this
15
+ * package. The one sanctioned deleter is the fleet retention standard
16
+ * (`satellite-kit/retention`), which an app opts into by declaring this table as
17
+ * an `event-log`/`audit-log` resource — a control the owner can see and change,
18
+ * rather than a cutoff buried in a store.
19
+ */
20
+ export const ACTIVITY_MIGRATIONS = [
21
+ {
22
+ name: "0001_activity_events",
23
+ up(db) {
24
+ db.run(`
25
+ CREATE TABLE IF NOT EXISTS ${ACTIVITY_EVENTS_TABLE} (
26
+ event_id INTEGER PRIMARY KEY AUTOINCREMENT,
27
+ at TEXT NOT NULL,
28
+ app TEXT NOT NULL,
29
+ actor TEXT NOT NULL,
30
+ action TEXT NOT NULL,
31
+ kind TEXT,
32
+ resource_id TEXT,
33
+ outcome TEXT NOT NULL DEFAULT 'ok'
34
+ CHECK (outcome IN ('ok', 'denied', 'error')),
35
+ note TEXT NOT NULL DEFAULT '',
36
+ data TEXT
37
+ )
38
+ `);
39
+ // The stream itself, newest first — the read every screen starts from.
40
+ db.run(`CREATE INDEX IF NOT EXISTS idx_activity_events_at
41
+ ON ${ACTIVITY_EVENTS_TABLE} (at DESC, event_id DESC)`);
42
+ // "Everything this person did" — the offboarding and the who-broke-it
43
+ // question, and the one a fleet-wide search runs first.
44
+ db.run(`CREATE INDEX IF NOT EXISTS idx_activity_events_actor
45
+ ON ${ACTIVITY_EVENTS_TABLE} (actor, event_id DESC)`);
46
+ // "Everything that ever happened to this record."
47
+ db.run(`CREATE INDEX IF NOT EXISTS idx_activity_events_resource
48
+ ON ${ACTIVITY_EVENTS_TABLE} (kind, resource_id, event_id DESC)`);
49
+ // "Everything backups ever did" — an action-prefix filter is a range
50
+ // scan on this index, which is why the vocabulary is dotted.
51
+ db.run(`CREATE INDEX IF NOT EXISTS idx_activity_events_action
52
+ ON ${ACTIVITY_EVENTS_TABLE} (action, event_id DESC)`);
53
+ },
54
+ },
55
+ ];
@@ -0,0 +1,11 @@
1
+ import type { ActivitySource } from "./store";
2
+ export interface ShareEventsSourceOptions {
3
+ /** The satellite this log speaks for — the same value passed to
4
+ * `createActivityLog`, used where a group event names no resource. */
5
+ app: string;
6
+ /** Overridden only by a test hosting the table under another name. */
7
+ table?: string;
8
+ /** The contributor name, which prefixes every id it produces. */
9
+ name?: string;
10
+ }
11
+ export declare function shareEventsSource(options: ShareEventsSourceOptions): ActivitySource;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The sharing primitive, as a contributor to the activity stream.
3
+ *
4
+ * 🔴 This is the whole point of `sources`: `cursedbelt-server/sharing` already
5
+ * keeps an audit trail nothing ever deletes, in `share_events`, and it is
6
+ * guaranteed to be complete (no grant can be made without a row — see that
7
+ * store's property 1). So the activity stream READS it where it lives rather
8
+ * than asking an app to mirror it. One row, one truth, no drift, and nothing to
9
+ * reconcile if a mirror write is ever missed.
10
+ *
11
+ * ```ts
12
+ * const activity = createActivityLog({
13
+ * db, app: "family", sources: [shareEventsSource({ app: "family" })],
14
+ * });
15
+ * ```
16
+ *
17
+ * The mapping is field-for-field the one `activityFromShareEvent` performs in
18
+ * the vocabulary, and `store.spec.ts` asserts the two agree — a SQL projection
19
+ * and a TypeScript function are two implementations of one shape, so the suite
20
+ * pins them together rather than trusting that they were written on the same
21
+ * afternoon.
22
+ *
23
+ * `share_events.app` is NULL for a GROUP lifecycle event (creating a group is
24
+ * about no single resource), so the app is coalesced to the log's own name: a
25
+ * fleet-wide board merges on that column and an unlabeled row would be
26
+ * unattributable.
27
+ */
28
+ import { SHARE_EVENTS_TABLE } from "../sharing/migrations";
29
+ export function shareEventsSource(options) {
30
+ const table = options.table ?? SHARE_EVENTS_TABLE;
31
+ const name = options.name ?? "share";
32
+ return {
33
+ name,
34
+ requiresTable: table,
35
+ // Column contract: source, seq, at, app, actor, action, kind, resource_id,
36
+ // outcome, note, data — in this order. See `ActivitySource`.
37
+ sql: `SELECT '${name}' AS source, event_id AS seq, at, COALESCE(app, ?) AS app, actor,
38
+ 'share.' || action AS action, kind, resource_id,
39
+ 'ok' AS outcome, note,
40
+ json_object('subjectType', subject_type, 'subjectId', subject_id,
41
+ 'level', level, 'previousLevel', previous_level) AS data
42
+ FROM ${table}`,
43
+ params: [options.app],
44
+ };
45
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * The activity store: one append-only table, plus any number of read-only
3
+ * SOURCES projected into the same shape, queried as one stream.
4
+ *
5
+ * ── How an app uses it ──────────────────────────────────────────────────────
6
+ * ```ts
7
+ * const activity = createActivityLog({
8
+ * db,
9
+ * app: "family",
10
+ * // The sharing primitive already audits itself. Read those rows where they
11
+ * // are instead of copying them — see `shareEventsSource`.
12
+ * sources: [shareEventsSource()],
13
+ * });
14
+ *
15
+ * activity.record({ actor: viewer.email, action: "person.delete",
16
+ * resource: { kind: "person", id }, note: "duplicate" });
17
+ *
18
+ * activity.query({ since, actor, action: "share.", limit: 100 });
19
+ * ```
20
+ *
21
+ * ── 🔴 Four properties this file exists to guarantee ────────────────────────
22
+ * 1. **Append only.** No update verb, no delete verb, no `TRUNCATE`. Ageing
23
+ * rows out is the fleet retention standard's job, through a declaration the
24
+ * owner can see (`satellite-kit/retention`) — never a silent cutoff here.
25
+ * 2. **A source is READ, never copied.** `share_events` stays the canonical
26
+ * sharing trail; this store selects from it. Two tables holding the same
27
+ * audit rows is two tables that will one day disagree, and the one people
28
+ * would trust is whichever the screen happened to read.
29
+ * 3. **A missing source table is an empty source, not a 500.** An app may
30
+ * register `shareEventsSource()` before it has ever created a grant, and a
31
+ * dashboard must not die on the app that has done nothing yet. (The same
32
+ * lesson `orch`'s `plainjob_jobs` retention target learned at boot.)
33
+ * 4. **`action` is validated at the write.** An action vocabulary that drifts
34
+ * cannot be filtered, and filtering is the whole point of the column.
35
+ */
36
+ import type { Database, SQLQueryBindings } from "bun:sqlite";
37
+ import { type ActivityEvent, type ActivityEventInput, type ActivityOutcome } from "cursedbelt-core/activity/model";
38
+ /**
39
+ * A read-only stream contributor: a SELECT projecting some other table into the
40
+ * union's eleven columns, in this order and with these names —
41
+ *
42
+ * `source, seq, at, app, actor, action, kind, resource_id, outcome, note, data`
43
+ *
44
+ * `seq` is that table's own row id: it breaks ties within one `at`, and it is
45
+ * what makes the event id (`"<source>:<seq>"`) stable and unique across sources.
46
+ */
47
+ export interface ActivitySource {
48
+ /** Short, stable, unique within the log — it prefixes every id it produces. */
49
+ name: string;
50
+ /** The projection. See the column contract above. */
51
+ sql: string;
52
+ /** Bound in order, before any filter parameter. */
53
+ params?: readonly SQLQueryBindings[];
54
+ /**
55
+ * A table this projection needs. When it does not exist the source is skipped
56
+ * for that call rather than throwing — see property 3 in the header.
57
+ */
58
+ requiresTable?: string;
59
+ }
60
+ /** Everything the stream can be narrowed by. Every field is optional; the empty
61
+ * query is "the newest `limit` events". */
62
+ export interface ActivityQuery {
63
+ /** ISO-8601, inclusive. */
64
+ since?: string;
65
+ /** ISO-8601, inclusive. */
66
+ until?: string;
67
+ /** Case-insensitive exact match on the account. */
68
+ actor?: string;
69
+ /** Exact, or a PREFIX when it ends in a dot: `"share."` matches `share.grant`. */
70
+ action?: string;
71
+ kind?: string;
72
+ resourceId?: string;
73
+ outcome?: ActivityOutcome;
74
+ /** Restrict to one contributor (`"log"`, `"share"`). */
75
+ source?: string;
76
+ /** Substring, over actor + action + note + resource id. */
77
+ q?: string;
78
+ /** Default 100, hard cap 1000. */
79
+ limit?: number;
80
+ }
81
+ export interface ActivityPage {
82
+ events: ActivityEvent[];
83
+ /** The limit actually applied, after defaulting and capping. */
84
+ limit: number;
85
+ /** There is at least one more row older than the last one returned. */
86
+ truncated: boolean;
87
+ }
88
+ /** One dimension of "what is in this result", for the filter UI. */
89
+ export interface ActivityFacet {
90
+ value: string;
91
+ count: number;
92
+ }
93
+ export interface ActivityFacets {
94
+ actions: ActivityFacet[];
95
+ actors: ActivityFacet[];
96
+ kinds: ActivityFacet[];
97
+ }
98
+ export interface ActivityLogOptions {
99
+ db: Database;
100
+ /** The satellite this log speaks for. Fixed at construction, so a caller
101
+ * cannot write an event under another app's name. */
102
+ app: string;
103
+ /** Read-only contributors merged into the stream. */
104
+ sources?: readonly ActivitySource[];
105
+ /** Injectable clock, ISO-8601. */
106
+ now?: () => string;
107
+ }
108
+ export interface ActivityLog {
109
+ /** The app this log speaks for. */
110
+ readonly app: string;
111
+ /** Append one event. Returns it as it will be read back. */
112
+ record(input: ActivityEventInput): ActivityEvent;
113
+ /** Newest first, bounded. */
114
+ query(query?: ActivityQuery): ActivityPage;
115
+ /** How many events match — the unbounded count behind a bounded page. */
116
+ count(query?: ActivityQuery): number;
117
+ /** What is in the result, per dimension, for a filter UI. */
118
+ facets(query?: ActivityQuery, limit?: number): ActivityFacets;
119
+ /** Which contributors are live right now (a source whose table is missing is
120
+ * absent, which is what the read surface reports). */
121
+ sources(): string[];
122
+ }
123
+ export declare function createActivityLog(options: ActivityLogOptions): ActivityLog;
@@ -0,0 +1,178 @@
1
+ import { isActivityAction, isActivityOutcome, } from "cursedbelt-core/activity/model";
2
+ import { runMigrations } from "../migration/runner";
3
+ import { ACTIVITY_EVENTS_TABLE, ACTIVITY_MIGRATIONS } from "./migrations";
4
+ const DEFAULT_LIMIT = 100;
5
+ const MAX_LIMIT = 1000;
6
+ const MAX_FACET = 25;
7
+ /** `%` and `_` are wildcards and `\` is the escape — a note containing any of
8
+ * them must still search literally. */
9
+ const likeContains = (value) => `%${value.replace(/[\\%_]/g, (ch) => `\\${ch}`)}%`;
10
+ const toEvent = (row) => ({
11
+ id: `${row.source}:${row.seq}`,
12
+ source: row.source,
13
+ at: row.at,
14
+ app: row.app,
15
+ actor: row.actor,
16
+ action: row.action,
17
+ resource: row.kind === null || row.resource_id === null
18
+ ? null
19
+ : { app: row.app, kind: row.kind, id: row.resource_id },
20
+ outcome: isActivityOutcome(row.outcome) ? row.outcome : "ok",
21
+ note: row.note ?? "",
22
+ data: parseData(row.data),
23
+ });
24
+ /** A row whose `data` is unreadable must not take the page down with it — the
25
+ * event still says who did what, which is the part that matters. */
26
+ function parseData(raw) {
27
+ if (!raw)
28
+ return null;
29
+ try {
30
+ const parsed = JSON.parse(raw);
31
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
32
+ ? parsed
33
+ : { value: parsed };
34
+ }
35
+ catch {
36
+ return { unparsed: raw };
37
+ }
38
+ }
39
+ export function createActivityLog(options) {
40
+ const { db, app } = options;
41
+ const now = options.now ?? (() => new Date().toISOString());
42
+ const registered = options.sources ?? [];
43
+ runMigrations(db, ACTIVITY_MIGRATIONS);
44
+ const insert = db.query(`INSERT INTO ${ACTIVITY_EVENTS_TABLE}
45
+ (at, app, actor, action, kind, resource_id, outcome, note, data)
46
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`);
47
+ const tableExists = (name) => !!db
48
+ .query("SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = ?")
49
+ .get(name);
50
+ /** The contributors that can actually answer right now. */
51
+ const liveSources = () => registered.filter((source) => !source.requiresTable || tableExists(source.requiresTable));
52
+ const OWN_SELECT = `SELECT 'log' AS source, event_id AS seq, at, app, actor, action,
53
+ kind, resource_id, outcome, note, data
54
+ FROM ${ACTIVITY_EVENTS_TABLE}`;
55
+ /** The union, plus the WHERE the caller asked for, plus their parameters in
56
+ * bind order (sources first — they are inside the FROM). */
57
+ const stream = (query) => {
58
+ const params = [];
59
+ const selects = [OWN_SELECT];
60
+ for (const source of liveSources()) {
61
+ if (query.source && query.source !== source.name)
62
+ continue;
63
+ selects.push(source.sql);
64
+ params.push(...(source.params ?? []));
65
+ }
66
+ const where = [];
67
+ if (query.source) {
68
+ where.push("source = ?");
69
+ params.push(query.source);
70
+ }
71
+ if (query.since) {
72
+ where.push("at >= ?");
73
+ params.push(query.since);
74
+ }
75
+ if (query.until) {
76
+ where.push("at <= ?");
77
+ params.push(query.until);
78
+ }
79
+ if (query.actor) {
80
+ where.push("LOWER(actor) = LOWER(?)");
81
+ params.push(query.actor);
82
+ }
83
+ if (query.action) {
84
+ if (query.action.endsWith(".")) {
85
+ where.push("action LIKE ? ESCAPE '\\'");
86
+ params.push(`${query.action.replace(/[\\%_]/g, (ch) => `\\${ch}`)}%`);
87
+ }
88
+ else {
89
+ where.push("action = ?");
90
+ params.push(query.action);
91
+ }
92
+ }
93
+ if (query.kind) {
94
+ where.push("kind = ?");
95
+ params.push(query.kind);
96
+ }
97
+ if (query.resourceId) {
98
+ where.push("resource_id = ?");
99
+ params.push(query.resourceId);
100
+ }
101
+ if (query.outcome) {
102
+ where.push("outcome = ?");
103
+ params.push(query.outcome);
104
+ }
105
+ if (query.q) {
106
+ where.push("(actor LIKE ? ESCAPE '\\' OR action LIKE ? ESCAPE '\\' OR note LIKE ? ESCAPE '\\' OR IFNULL(resource_id, '') LIKE ? ESCAPE '\\')");
107
+ const like = likeContains(query.q);
108
+ params.push(like, like, like, like);
109
+ }
110
+ // `query.source` naming a contributor that is not live leaves only the own
111
+ // select, filtered to a source it cannot be — an empty result, which is the
112
+ // honest answer rather than every row.
113
+ const sql = `SELECT * FROM (${selects.join("\n UNION ALL\n")}) AS stream${where.length ? ` WHERE ${where.join(" AND ")}` : ""}`;
114
+ return { sql, params };
115
+ };
116
+ return {
117
+ app,
118
+ record(input) {
119
+ if (!isActivityAction(input.action)) {
120
+ throw new Error(`activity: "${input.action}" is not an action — use lowercase subject.verb, e.g. "backup.delete"`);
121
+ }
122
+ const actor = input.actor?.trim();
123
+ if (!actor) {
124
+ // An event that cannot say who is a log line, not an audit trail.
125
+ throw new Error(`activity: ${input.action} has no actor`);
126
+ }
127
+ const at = input.at ?? now();
128
+ const outcome = input.outcome ?? "ok";
129
+ const data = input.data ? JSON.stringify(input.data) : null;
130
+ const info = insert.run(at, app, actor, input.action, input.resource?.kind ?? null, input.resource?.id ?? null, outcome, input.note ?? "", data);
131
+ return {
132
+ id: `log:${Number(info.lastInsertRowid)}`,
133
+ source: "log",
134
+ at,
135
+ app,
136
+ actor,
137
+ action: input.action,
138
+ resource: input.resource ? { app, ...input.resource } : null,
139
+ outcome,
140
+ note: input.note ?? "",
141
+ data: input.data ?? null,
142
+ };
143
+ },
144
+ query(query = {}) {
145
+ const limit = Math.min(MAX_LIMIT, Math.max(1, Math.floor(query.limit ?? DEFAULT_LIMIT)));
146
+ const { sql, params } = stream(query);
147
+ // One row past the limit, so "there is more" is a fact rather than a
148
+ // guess made from `rows.length === limit`.
149
+ const rows = db
150
+ .query(`${sql} ORDER BY at DESC, seq DESC LIMIT ?`)
151
+ .all(...params, limit + 1);
152
+ const truncated = rows.length > limit;
153
+ return { events: rows.slice(0, limit).map(toEvent), limit, truncated };
154
+ },
155
+ count(query = {}) {
156
+ const { sql, params } = stream(query);
157
+ const row = db.query(`SELECT COUNT(*) AS n FROM (${sql})`).get(...params);
158
+ return row?.n ?? 0;
159
+ },
160
+ facets(query = {}, limit = MAX_FACET) {
161
+ const { sql, params } = stream(query);
162
+ const capped = Math.min(MAX_FACET, Math.max(1, Math.floor(limit)));
163
+ const dimension = (column) => db
164
+ .query(`SELECT ${column} AS value, COUNT(*) AS count FROM (${sql})
165
+ WHERE ${column} IS NOT NULL AND ${column} <> ''
166
+ GROUP BY ${column} ORDER BY count DESC, value ASC LIMIT ?`)
167
+ .all(...params, capped).map((row) => ({ value: row.value, count: row.count }));
168
+ return {
169
+ actions: dimension("action"),
170
+ actors: dimension("actor"),
171
+ kinds: dimension("kind"),
172
+ };
173
+ },
174
+ sources() {
175
+ return ["log", ...liveSources().map((source) => source.name)];
176
+ },
177
+ };
178
+ }
@@ -0,0 +1,56 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ import type { Server, TLSOptions, WebSocketHandler } from 'bun';
3
+ import { Hono } from 'hono';
4
+ import type { CursedbeltEnv } from './context';
5
+ import { type CorsOpts } from './middleware/corsAllowlist';
6
+ import { type RateLimitOpts } from './middleware/rateLimit';
7
+ import { type SecurityHeadersOpts } from './middleware/securityHeaders';
8
+ export interface CreateAppOpts {
9
+ /** When provided, the request logger writes metrics/events to this DB. */
10
+ db?: Database;
11
+ /**
12
+ * CORS for a split deploy (SPA origin ≠ API origin). Pass `{ siteDomain }` /
13
+ * `{ origins }` (see {@link CorsOpts}) or `corsOptsFromEnv()` to read the
14
+ * conventional `CORS_SITE_DOMAIN` / `CORS_ORIGINS` env vars. Omit for a
15
+ * same-origin deploy. Mounted FIRST so every response — preflight, rate-limit
16
+ * 429, error envelope — carries the CORS headers a browser needs to read it.
17
+ */
18
+ cors?: CorsOpts;
19
+ /** Security-header options, or `false` to skip the security-headers middleware. */
20
+ security?: SecurityHeadersOpts | false;
21
+ /** Mount a global rate limiter. (Per-route limiters: use `createRateLimiter` directly.) */
22
+ rateLimit?: RateLimitOpts;
23
+ /**
24
+ * How many trusted reverse proxies sit in front of this app, for the client-IP
25
+ * rate-limit key. Default `0` — `x-forwarded-for` is caller-controlled, so
26
+ * believing it by default let anyone mint a fresh rate-limit bucket per
27
+ * request. Set to the real hop count you operate (nginx in front ⇒ `1`).
28
+ */
29
+ trustedProxyHops?: number;
30
+ /** Mount the default `GET /health` liveness route. Default: true. */
31
+ health?: boolean;
32
+ }
33
+ /**
34
+ * Build the configured cursedbelt Hono app: correlation id → (optional) CORS →
35
+ * security headers →
36
+ * (optional) rate limit → (optional) request logger, a default `/health`, and the
37
+ * canonical error-envelope `onError`. The caller mounts feature routers on the
38
+ * returned app (`app.route('/api/v1', notesRouter)`).
39
+ */
40
+ export declare function createApp(opts?: CreateAppOpts): Hono<CursedbeltEnv>;
41
+ export interface ServeBunOpts<T = unknown> {
42
+ /** Listen port. Default: 3000. */
43
+ port?: number;
44
+ /** Bind hostname (e.g. `'127.0.0.1'`). Default: Bun's default (all interfaces). */
45
+ hostname?: string;
46
+ /** WebSocket handler from the WS hub (task 28). Only set when the app upgrades. */
47
+ websocket?: WebSocketHandler<T>;
48
+ /** TLS options for HTTPS. */
49
+ tls?: TLSOptions;
50
+ }
51
+ /**
52
+ * Serve a Hono app on `Bun.serve` (`fetch: app.fetch`, zero adapter). Pass
53
+ * `websocket` only when the app actually calls `server.upgrade()` (task 28) — Bun
54
+ * rejects a `websocket` handler that is never used.
55
+ */
56
+ export declare function serveBun<T = unknown>(app: Hono<CursedbeltEnv>, opts?: ServeBunOpts<T>): Server<T>;
@@ -0,0 +1,45 @@
1
+ import { Hono } from 'hono';
2
+ import { correlationId } from './middleware/correlationId';
3
+ import { corsAllowlist } from './middleware/corsAllowlist';
4
+ import { errorEnvelope } from './middleware/errorEnvelope';
5
+ import { createRateLimiter } from './middleware/rateLimit';
6
+ import { requestLogger } from './middleware/requestLogger';
7
+ import { securityHeaders } from './middleware/securityHeaders';
8
+ /**
9
+ * Build the configured cursedbelt Hono app: correlation id → (optional) CORS →
10
+ * security headers →
11
+ * (optional) rate limit → (optional) request logger, a default `/health`, and the
12
+ * canonical error-envelope `onError`. The caller mounts feature routers on the
13
+ * returned app (`app.route('/api/v1', notesRouter)`).
14
+ */
15
+ export function createApp(opts = {}) {
16
+ const app = new Hono();
17
+ app.use('*', correlationId());
18
+ if (opts.cors)
19
+ app.use('*', corsAllowlist(opts.cors));
20
+ if (opts.security !== false)
21
+ app.use('*', securityHeaders(opts.security ?? {}));
22
+ if (opts.rateLimit) {
23
+ app.use('*', createRateLimiter({ trustedProxyHops: opts.trustedProxyHops ?? 0, ...opts.rateLimit }));
24
+ }
25
+ if (opts.db)
26
+ app.use('*', requestLogger(opts.db));
27
+ if (opts.health !== false)
28
+ app.get('/health', (c) => c.json({ status: 'ok' }));
29
+ app.onError(errorEnvelope);
30
+ return app;
31
+ }
32
+ /**
33
+ * Serve a Hono app on `Bun.serve` (`fetch: app.fetch`, zero adapter). Pass
34
+ * `websocket` only when the app actually calls `server.upgrade()` (task 28) — Bun
35
+ * rejects a `websocket` handler that is never used.
36
+ */
37
+ export function serveBun(app, opts = {}) {
38
+ const port = opts.port ?? 3000;
39
+ const { hostname, tls, websocket } = opts;
40
+ // Two concrete call shapes (not a spread) so Bun.serve picks the right overload.
41
+ if (websocket) {
42
+ return Bun.serve({ port, hostname, fetch: app.fetch, tls, websocket });
43
+ }
44
+ return Bun.serve({ port, hostname, fetch: app.fetch, tls });
45
+ }
@@ -0,0 +1,2 @@
1
+ export { AUDIT_LOG_MIGRATIONS } from './migrations';
2
+ export { auditStateAt, auditStateAtVersion, auditStep, createSqliteAuditSink } from './sqliteSink';
@@ -0,0 +1,2 @@
1
+ export { AUDIT_LOG_MIGRATIONS } from './migrations';
2
+ export { auditStateAt, auditStateAtVersion, auditStep, createSqliteAuditSink } from './sqliteSink';
@@ -0,0 +1,2 @@
1
+ import type { Migration } from '../migration/types';
2
+ export declare const AUDIT_LOG_MIGRATIONS: readonly Migration[];