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,272 @@
1
+ /**
2
+ * The drop-folder scraper — the reusable half.
3
+ *
4
+ * Owner's ask, 2026-08-13: *"Do this to prepare a reusable strategy for multiple apps to get
5
+ * intelligent processing for binary-server. Some functionality may be reusable in multiple
6
+ * apps in different ways and can go in cb where standardized app functionality is shared. The
7
+ * specific ingestion logic that only binary-server or one app needs can go to the specific
8
+ * app."* … *"Make this tool reusable in case we need something like it on other folders
9
+ * later."*
10
+ *
11
+ * So: WALKING a drop folder, deciding a file has finished copying, sorting content from junk,
12
+ * deleting only what has been confirmed elsewhere, and leaving nothing behind — all of that is
13
+ * the same for music, family photographs, collections videos and notes documents, and all of
14
+ * it is here. What a file MEANS — which album, which artist, which collection — is the app's,
15
+ * and none of it is here.
16
+ *
17
+ * ── 🔴 Three rules that look like paranoia and are not ─────────────────────────────────
18
+ *
19
+ * 1. **A file is deleted only after the destination CONFIRMS it.** The dropzone is the one
20
+ * place the owner's copy may be the only copy: they dragged it in expecting it to be taken.
21
+ * A sweep that deletes on "the upload didn't throw" turns any catalog failure into data
22
+ * loss. The handler returns `stored`/`duplicate` and only then does the original go.
23
+ *
24
+ * 2. **A file must measure the same size twice before it is touched.** Dropping a 4 GB video
25
+ * into a folder is not atomic. Without this the sweep ingests a truncated file, reports
26
+ * success, and deletes the real one as it is still being written. notes' ingester and
27
+ * collections' both learned this the same way.
28
+ *
29
+ * 3. **One bad file never stops the sweep.** Every handler outcome is per-file, and a throw is
30
+ * caught and recorded. The owner's instruction is explicit about the duplicate case — *"This
31
+ * should not stall uploading the rest of the in progress uploads"* — and it generalizes: a
32
+ * dropzone with one unreadable file in it must still drain the other 4,000.
33
+ */
34
+ import { readdir, rm, rmdir, stat } from "node:fs/promises";
35
+ import { join, relative } from "node:path";
36
+ /** OS bookkeeping and editor scratch. Never content, in any app. */
37
+ const OS_JUNK = new Set([
38
+ ".DS_Store",
39
+ ".localized",
40
+ "Icon\r",
41
+ "Thumbs.db",
42
+ "desktop.ini",
43
+ "README.md",
44
+ ]);
45
+ const PARTIAL_SUFFIXES = [".download", ".crdownload", ".part", ".partial", ".tmp"];
46
+ /** A name that is OS noise, editor scratch, or a copy still in flight. */
47
+ export function isJunkName(name) {
48
+ if (OS_JUNK.has(name))
49
+ return true;
50
+ // A dotfile in a drop folder is the operating system's or another tool's state. The owner
51
+ // drops content, and content does not begin with a dot.
52
+ if (name.startsWith("."))
53
+ return true;
54
+ if (name.startsWith("._"))
55
+ return true; // AppleDouble resource forks
56
+ return PARTIAL_SUFFIXES.some((s) => name.toLowerCase().endsWith(s));
57
+ }
58
+ const extOf = (name) => {
59
+ const dot = name.lastIndexOf(".");
60
+ return dot > 0 ? name.slice(dot).toLowerCase() : "";
61
+ };
62
+ /**
63
+ * Every candidate file under `root`, deepest-last, with each one's sibling listing.
64
+ *
65
+ * Junk is NOT filtered out here — it is returned like anything else, because a sweep whose job
66
+ * includes *"if it's a wrong type of file delete it"* has to see it in order to delete it.
67
+ * {@link isJunkName} is exported so a handler can classify without re-deriving the list.
68
+ */
69
+ export async function scanDropzone(root, opts = {}) {
70
+ const skip = new Set(opts.skipDirs ?? []);
71
+ const out = [];
72
+ const walk = async (dir) => {
73
+ if (opts.limit !== undefined && out.length >= opts.limit)
74
+ return;
75
+ let entries;
76
+ try {
77
+ entries = await readdir(dir, { withFileTypes: true });
78
+ }
79
+ catch {
80
+ return; // vanished mid-walk — a dropzone is a moving target by nature
81
+ }
82
+ const siblings = opts.captureSiblings
83
+ ? entries.filter((e) => e.isFile()).map((e) => e.name)
84
+ : [];
85
+ for (const entry of entries) {
86
+ if (opts.limit !== undefined && out.length >= opts.limit)
87
+ return;
88
+ const full = join(dir, entry.name);
89
+ if (entry.isDirectory()) {
90
+ if (skip.has(entry.name))
91
+ continue;
92
+ await walk(full);
93
+ continue;
94
+ }
95
+ if (!entry.isFile())
96
+ continue;
97
+ try {
98
+ const info = await stat(full);
99
+ out.push({
100
+ path: full,
101
+ relativePath: relative(root, full),
102
+ name: entry.name,
103
+ ext: extOf(entry.name),
104
+ size: info.size,
105
+ mtimeMs: info.mtimeMs,
106
+ siblings,
107
+ });
108
+ }
109
+ catch {
110
+ /* gone between readdir and stat */
111
+ }
112
+ }
113
+ };
114
+ await walk(root);
115
+ return out;
116
+ }
117
+ /**
118
+ * How old an EMPTY file has to be before it is believed. See {@link isStable}.
119
+ *
120
+ * A file that has just been created and has no bytes yet is almost certainly mid-copy; the
121
+ * same file a minute later really is empty.
122
+ */
123
+ export const EMPTY_FILE_GRACE_MS = 60_000;
124
+ /**
125
+ * Has this file finished being copied in? See rule 2 in the header.
126
+ *
127
+ * 🔴 A zero-byte file needs its own answer, and getting it wrong strands the folder forever.
128
+ * The obvious test — "same size twice AND non-empty" — treats a genuinely empty file as
129
+ * permanently mid-copy: it is never handled, never deleted, and so the dropzone never empties,
130
+ * which is the one outcome the owner's brief measures success by (*"in the end there should be
131
+ * nothing left"*). Measured on a first run: three real files, all 0 bytes, reported as "still
132
+ * copying" on every sweep for as long as they sat there.
133
+ *
134
+ * Emptiness is only evidence of an unfinished copy while the file is NEW, so age decides. A
135
+ * file created a minute ago with no bytes in it is empty, not arriving.
136
+ */
137
+ export async function isStable(file, stabilityMs = 750) {
138
+ await new Promise((resolve) => setTimeout(resolve, stabilityMs));
139
+ try {
140
+ const now = await stat(file.path);
141
+ if (now.size !== file.size)
142
+ return false; // still growing
143
+ if (now.size > 0)
144
+ return true;
145
+ return Date.now() - now.mtimeMs > EMPTY_FILE_GRACE_MS;
146
+ }
147
+ catch {
148
+ return false; // taken by something else, or never really there
149
+ }
150
+ }
151
+ /**
152
+ * Remove directories left empty by a sweep, deepest first — and never the root.
153
+ *
154
+ * 🔴 `rmdir` refuses a non-empty directory, and that refusal IS the safety property. A
155
+ * recursive delete here would take a file the sweep deliberately chose not to ingest — a held
156
+ * duplicate, a failure left in place for the owner to look at — which is precisely the set of
157
+ * files that must survive.
158
+ */
159
+ export async function pruneEmptyDirs(root, dir = root) {
160
+ let removed = 0;
161
+ let entries;
162
+ try {
163
+ entries = await readdir(dir);
164
+ }
165
+ catch {
166
+ return 0;
167
+ }
168
+ for (const name of entries) {
169
+ const full = join(dir, name);
170
+ try {
171
+ if ((await stat(full)).isDirectory())
172
+ removed += await pruneEmptyDirs(root, full);
173
+ }
174
+ catch {
175
+ /* gone */
176
+ }
177
+ }
178
+ if (dir === root)
179
+ return removed;
180
+ try {
181
+ await rmdir(dir);
182
+ return removed + 1;
183
+ }
184
+ catch {
185
+ return removed; // not empty — the right outcome, and not an error
186
+ }
187
+ }
188
+ /**
189
+ * Walk a dropzone, hand every file to `handle`, and leave nothing behind that was dealt with.
190
+ *
191
+ * 🔴 The DELETION is here, and it is deliberately not the handler's job. Every app would
192
+ * otherwise reimplement rule 1, and the one that got it wrong would lose the owner's only copy
193
+ * silently. A handler says what happened; this decides what that means for the file on disk.
194
+ */
195
+ export async function sweepDropzone(root, handle, opts = {}) {
196
+ const report = {
197
+ scanned: 0,
198
+ stored: 0,
199
+ duplicate: 0,
200
+ discarded: 0,
201
+ held: 0,
202
+ failed: [],
203
+ unstable: [],
204
+ bytesRemoved: 0,
205
+ emptyDirsRemoved: 0,
206
+ remaining: 0,
207
+ };
208
+ const files = await scanDropzone(root, opts);
209
+ for (const [index, file] of files.entries()) {
210
+ report.scanned++;
211
+ opts.onProgress?.(index + 1, files.length);
212
+ if (!(await isStable(file, opts.stabilityMs))) {
213
+ report.unstable.push(file.relativePath);
214
+ continue;
215
+ }
216
+ let outcome;
217
+ try {
218
+ outcome = opts.dryRun ? { kind: "held", detail: "dry run" } : await handle(file);
219
+ }
220
+ catch (error) {
221
+ // Rule 3: a handler that throws costs one file, never the sweep.
222
+ outcome = {
223
+ kind: "failed",
224
+ detail: error instanceof Error ? error.message : String(error),
225
+ };
226
+ }
227
+ switch (outcome.kind) {
228
+ case "stored":
229
+ case "duplicate":
230
+ case "discard": {
231
+ if (outcome.kind === "stored")
232
+ report.stored++;
233
+ else if (outcome.kind === "duplicate")
234
+ report.duplicate++;
235
+ else
236
+ report.discarded++;
237
+ if (opts.dryRun)
238
+ break;
239
+ try {
240
+ await rm(file.path);
241
+ report.bytesRemoved += file.size;
242
+ }
243
+ catch (error) {
244
+ // The bytes are safe at the destination; only the tidying failed. Reporting it
245
+ // as a FAILURE would send the owner looking for a file that arrived perfectly.
246
+ report.failed.push({
247
+ relativePath: file.relativePath,
248
+ error: `filed, but the original could not be removed: ${error instanceof Error ? error.message : String(error)}`,
249
+ });
250
+ }
251
+ break;
252
+ }
253
+ case "held":
254
+ report.held++;
255
+ break;
256
+ case "failed":
257
+ report.failed.push({ relativePath: file.relativePath, error: outcome.detail });
258
+ break;
259
+ }
260
+ }
261
+ if (!opts.dryRun)
262
+ report.emptyDirsRemoved = await pruneEmptyDirs(root);
263
+ report.remaining = (await scanDropzone(root, { skipDirs: opts.skipDirs })).length;
264
+ return report;
265
+ }
266
+ /** A one-line summary — every consumer prints one, and they should read alike. */
267
+ export const describeSweep = (report) => `${report.stored} added, ${report.duplicate} already had, ${report.discarded} discarded, ` +
268
+ `${report.held} held, ${report.failed.length} failed, ${report.unstable.length} still copying` +
269
+ (report.bytesRemoved > 0
270
+ ? ` · ${(report.bytesRemoved / 1024 ** 3).toFixed(2)} GB freed from the queue`
271
+ : "") +
272
+ (report.remaining > 0 ? ` · ${report.remaining} left in the folder` : " · folder is empty");
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Server-side re-export of the canonical error primitives, which now live in the
3
+ * framework-free {@link ../shared/errors} module so cursedshell's plugin-pure layer
4
+ * can import the SAME `ApiError` + envelope without pulling any server code
5
+ * (`cursedbelt-core/errors` subpath). Server modules keep importing from `./errors`.
6
+ */
7
+ export { AppError, type AppErrorSummary, ApiError, type ApiErrorOptions, type ErrorEnvelope, isAppError, isApiError, type ToErrorEnvelopeOptions, toErrorEnvelope, type ValidationIssue, VALIDATION_ERROR_CODE, VALIDATION_STATUS, toValidationIssues, validationEnvelope, } from 'cursedbelt-core/errors';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Server-side re-export of the canonical error primitives, which now live in the
3
+ * framework-free {@link ../shared/errors} module so cursedshell's plugin-pure layer
4
+ * can import the SAME `ApiError` + envelope without pulling any server code
5
+ * (`cursedbelt-core/errors` subpath). Server modules keep importing from `./errors`.
6
+ */
7
+ export { AppError, ApiError, isAppError, isApiError, toErrorEnvelope, VALIDATION_ERROR_CODE, VALIDATION_STATUS, toValidationIssues, validationEnvelope, } from 'cursedbelt-core/errors';
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Wiring a REAL argon2id into the KDF seam (01 §3.3/§3.4, finding 1.2).
3
+ *
4
+ * cwip ships no KDF — it is zero-dependency by contract — so
5
+ * `setArgon2idDeriver` sat inert: nothing registered a binding, and every
6
+ * `unlock()` would have thrown `GUARD_KDF_UNAVAILABLE` the first time a real
7
+ * user tried it in production. `assertArgon2idReady()` converts that into a boot
8
+ * failure; this module is the other half — the adapter that makes registering a
9
+ * binding a one-liner, and the reason a host has no excuse to hand-roll one.
10
+ *
11
+ * The requirements on a binding are not negotiable, and the adapter enforces
12
+ * them rather than documenting them:
13
+ *
14
+ * * **Raw bytes out.** A binding that returns a PHC/base64 STRING is a
15
+ * `key-material-as-string` violation regardless of how strong the KDF is —
16
+ * a JS string is immutable and GC-managed, so the key lingers in
17
+ * unallocated RAM until the collector happens to overwrite it.
18
+ * * **Caller-supplied salt.** Anything that generates its own salt (e.g.
19
+ * `Bun.password`) cannot re-derive the key for an existing envelope, so it
20
+ * cannot open a secret it sealed yesterday.
21
+ * * **Synchronous.** The seam is sync on purpose and its throughput ceiling is
22
+ * documented on `Argon2idDeriver`; an async binding would hand back a
23
+ * promise AND (usually) a string.
24
+ */
25
+ import { type Argon2idDeriver } from 'cwip/guard';
26
+ /**
27
+ * The shape of a raw, synchronous argon2id binding, in the REFERENCE
28
+ * implementation's vocabulary: `algorithm` is the argon2 variant number
29
+ * (2 = argon2id) and `version` is the argon2 algorithm version as the spec
30
+ * writes it (`0x10` / `0x13`) — the same number the envelope's `kdf.ver`
31
+ * records.
32
+ *
33
+ * `@node-rs/argon2`'s `hashRawSync` is shape-compatible but NOT
34
+ * vocabulary-compatible: its `version` is a NAPI enum (`Version.V0x10 = 0`,
35
+ * `Version.V0x13 = 1`), so handing it `0x13` is an `InvalidArg` throw on every
36
+ * single derivation. {@link nodeRsArgon2idBinding} is the (tiny) translation,
37
+ * and {@link registerNodeRsArgon2id} applies it — libsodium's `crypto_pwhash`
38
+ * needs a comparable shim.
39
+ */
40
+ export interface RawArgon2idBinding {
41
+ hashRawSync(password: Uint8Array, options: {
42
+ salt: Uint8Array;
43
+ /** Memory cost in KiB. */
44
+ memoryCost: number;
45
+ /** Time cost (iterations). */
46
+ timeCost: number;
47
+ /** Parallelism (lanes). */
48
+ parallelism: number;
49
+ /** Output length in bytes. */
50
+ outputLen: number;
51
+ /** argon2 variant: 2 = argon2id. */
52
+ algorithm?: number;
53
+ /** argon2 algorithm version (0x10 | 0x13). */
54
+ version?: number;
55
+ }): Uint8Array;
56
+ }
57
+ /** argon2id's variant number in the `@node-rs/argon2` / reference-implementation vocabulary. */
58
+ export declare const ARGON2ID_ALGORITHM = 2;
59
+ /**
60
+ * Build a deriver from a raw binding, checking the two properties that make it
61
+ * usable as key material. The length check is not paranoia: a binding that
62
+ * silently truncates would weaken every secret sealed under it, and the failure
63
+ * would look like nothing at all.
64
+ */
65
+ export declare const argon2idDeriverFrom: (binding: RawArgon2idBinding) => Argon2idDeriver;
66
+ /**
67
+ * Translate a `@node-rs/argon2` module into a {@link RawArgon2idBinding}.
68
+ *
69
+ * The whole translation is the `version` field, and skipping it is not a
70
+ * cosmetic bug: node-rs validates the enum, so an unmapped `0x13` throws
71
+ * `InvalidArg` from the native layer on EVERY derivation — the first unlock, the
72
+ * first login, every password verify. That failure is invisible until a host
73
+ * actually registers this binding, which is exactly what the local host now does
74
+ * at boot.
75
+ */
76
+ export declare const nodeRsArgon2idBinding: (module: RawArgon2idBinding) => RawArgon2idBinding;
77
+ /** Register a raw binding as the process-wide deriver, then prove the seam is armed. */
78
+ export declare const registerArgon2idBinding: (binding: RawArgon2idBinding) => void;
79
+ /**
80
+ * Register `@node-rs/argon2` if the host installed it.
81
+ *
82
+ * It is an OPTIONAL peer dependency: a generated app with no GuardEngine surface
83
+ * should not carry a native module, and an app that has one must make the choice
84
+ * explicitly. The specifier is held in a variable so bundlers and `tsc` do not
85
+ * try to resolve a package that may not be there.
86
+ *
87
+ * @throws {AppError} `GUARD_KDF_BINDING_MISSING` naming the install command —
88
+ * an unhelpful `ERR_MODULE_NOT_FOUND` at boot is exactly the failure this
89
+ * module exists to prevent.
90
+ *
91
+ * The same indirection that hides the specifier from a bundler hides it from
92
+ * every static import walker, so the guard's peer map would report
93
+ * this edge as absent. The pragma is what puts it back.
94
+ *
95
+ * @peer @node-rs/argon2
96
+ */
97
+ export declare const registerNodeRsArgon2id: () => Promise<void>;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Wiring a REAL argon2id into the KDF seam (01 §3.3/§3.4, finding 1.2).
3
+ *
4
+ * cwip ships no KDF — it is zero-dependency by contract — so
5
+ * `setArgon2idDeriver` sat inert: nothing registered a binding, and every
6
+ * `unlock()` would have thrown `GUARD_KDF_UNAVAILABLE` the first time a real
7
+ * user tried it in production. `assertArgon2idReady()` converts that into a boot
8
+ * failure; this module is the other half — the adapter that makes registering a
9
+ * binding a one-liner, and the reason a host has no excuse to hand-roll one.
10
+ *
11
+ * The requirements on a binding are not negotiable, and the adapter enforces
12
+ * them rather than documenting them:
13
+ *
14
+ * * **Raw bytes out.** A binding that returns a PHC/base64 STRING is a
15
+ * `key-material-as-string` violation regardless of how strong the KDF is —
16
+ * a JS string is immutable and GC-managed, so the key lingers in
17
+ * unallocated RAM until the collector happens to overwrite it.
18
+ * * **Caller-supplied salt.** Anything that generates its own salt (e.g.
19
+ * `Bun.password`) cannot re-derive the key for an existing envelope, so it
20
+ * cannot open a secret it sealed yesterday.
21
+ * * **Synchronous.** The seam is sync on purpose and its throughput ceiling is
22
+ * documented on `Argon2idDeriver`; an async binding would hand back a
23
+ * promise AND (usually) a string.
24
+ */
25
+ import { assertArgon2idReady, CC_ARGON2ID_VERSION, setArgon2idDeriver, } from 'cwip/guard';
26
+ import { AppError } from '../errors';
27
+ /** argon2id's variant number in the `@node-rs/argon2` / reference-implementation vocabulary. */
28
+ export const ARGON2ID_ALGORITHM = 2;
29
+ /**
30
+ * Build a deriver from a raw binding, checking the two properties that make it
31
+ * usable as key material. The length check is not paranoia: a binding that
32
+ * silently truncates would weaken every secret sealed under it, and the failure
33
+ * would look like nothing at all.
34
+ */
35
+ export const argon2idDeriverFrom = (binding) => {
36
+ return (input) => {
37
+ const output = binding.hashRawSync(input.password, {
38
+ salt: input.salt,
39
+ memoryCost: input.params.m,
40
+ timeCost: input.params.t,
41
+ parallelism: input.params.p,
42
+ outputLen: input.keyLength,
43
+ algorithm: ARGON2ID_ALGORITHM,
44
+ // Honor the version the ENVELOPE was sealed with, not the binding's
45
+ // compile-time default: 0x10 and 0x13 produce different bytes for
46
+ // identical m/t/p/salt/password, which is why the envelope records it.
47
+ version: input.version ?? CC_ARGON2ID_VERSION,
48
+ });
49
+ if (typeof output === 'string')
50
+ throw new AppError('The registered argon2id binding returned a string. Key material must be raw bytes — a string cannot be zeroized (01 §3.4).', { code: 'GUARD_KDF_BINDING_INVALID', status: 500, category: 'security', isOperational: false });
51
+ if (!(output instanceof Uint8Array))
52
+ throw new AppError('The registered argon2id binding did not return a Uint8Array.', {
53
+ code: 'GUARD_KDF_BINDING_INVALID',
54
+ status: 500,
55
+ category: 'security',
56
+ isOperational: false,
57
+ });
58
+ return output;
59
+ };
60
+ };
61
+ /**
62
+ * `@node-rs/argon2`'s `Version` enum, keyed by the argon2 version number the
63
+ * ENVELOPE records. Held here rather than imported so the adapter never has to
64
+ * load the optional native module to know how to talk to it.
65
+ */
66
+ // 0x10 and 0x13 ARE the Argon2 version identifiers: the spec, the reference
67
+ // implementation and every envelope on disk write them in hex. Biome's autofix
68
+ // rewrites them as 16 and 19 — the same map and a worse one, because nobody
69
+ // reading an `$argon2id$v=19$` record would recognise the decimal.
70
+ // biome-ignore lint/complexity/useSimpleNumberKeys: see above — hex IS the spec's spelling
71
+ const NODE_RS_VERSION = { 0x10: 0, 0x13: 1 };
72
+ /**
73
+ * Translate a `@node-rs/argon2` module into a {@link RawArgon2idBinding}.
74
+ *
75
+ * The whole translation is the `version` field, and skipping it is not a
76
+ * cosmetic bug: node-rs validates the enum, so an unmapped `0x13` throws
77
+ * `InvalidArg` from the native layer on EVERY derivation — the first unlock, the
78
+ * first login, every password verify. That failure is invisible until a host
79
+ * actually registers this binding, which is exactly what the local host now does
80
+ * at boot.
81
+ */
82
+ export const nodeRsArgon2idBinding = (module) => ({
83
+ hashRawSync(password, options) {
84
+ const declared = options.version ?? CC_ARGON2ID_VERSION;
85
+ const mapped = NODE_RS_VERSION[declared];
86
+ if (mapped === undefined)
87
+ throw new AppError(`argon2 version 0x${declared.toString(16)} is not one @node-rs/argon2 implements (0x10 or 0x13). The envelope asking for it cannot be opened by this binding — reseal it, or register a binding that supports the version.`, {
88
+ code: 'GUARD_KDF_BINDING_INVALID',
89
+ status: 500,
90
+ category: 'security',
91
+ isOperational: false,
92
+ context: { version: declared },
93
+ });
94
+ return module.hashRawSync(password, { ...options, version: mapped });
95
+ },
96
+ });
97
+ /** Register a raw binding as the process-wide deriver, then prove the seam is armed. */
98
+ export const registerArgon2idBinding = (binding) => {
99
+ setArgon2idDeriver(argon2idDeriverFrom(binding));
100
+ // Fail here rather than at the first unlock: this call is the whole point.
101
+ assertArgon2idReady();
102
+ };
103
+ /**
104
+ * Register `@node-rs/argon2` if the host installed it.
105
+ *
106
+ * It is an OPTIONAL peer dependency: a generated app with no GuardEngine surface
107
+ * should not carry a native module, and an app that has one must make the choice
108
+ * explicitly. The specifier is held in a variable so bundlers and `tsc` do not
109
+ * try to resolve a package that may not be there.
110
+ *
111
+ * @throws {AppError} `GUARD_KDF_BINDING_MISSING` naming the install command —
112
+ * an unhelpful `ERR_MODULE_NOT_FOUND` at boot is exactly the failure this
113
+ * module exists to prevent.
114
+ *
115
+ * The same indirection that hides the specifier from a bundler hides it from
116
+ * every static import walker, so the guard's peer map would report
117
+ * this edge as absent. The pragma is what puts it back.
118
+ *
119
+ * @peer @node-rs/argon2
120
+ */
121
+ export const registerNodeRsArgon2id = async () => {
122
+ const specifier = '@node-rs/argon2';
123
+ let loaded;
124
+ try {
125
+ loaded = (await import(specifier));
126
+ }
127
+ catch (cause) {
128
+ throw new AppError('GuardEngine needs an argon2id binding and `@node-rs/argon2` is not installed. Run `bun add @node-rs/argon2` in the app, or call registerArgon2idBinding(...) with your own raw, synchronous binding.', { code: 'GUARD_KDF_BINDING_MISSING', status: 500, category: 'security', isOperational: false, cause });
129
+ }
130
+ if (typeof loaded.hashRawSync !== 'function')
131
+ throw new AppError('`@node-rs/argon2` is installed but exposes no `hashRawSync` — it is too old for the raw-bytes seam.', {
132
+ code: 'GUARD_KDF_BINDING_INVALID',
133
+ status: 500,
134
+ category: 'security',
135
+ isOperational: false,
136
+ });
137
+ registerArgon2idBinding(nodeRsArgon2idBinding(loaded));
138
+ };
@@ -0,0 +1,4 @@
1
+ export * from './argon2Binding';
2
+ export * from './verifier';
3
+ export * from './revocationStore';
4
+ export * from './sessionSigner';
@@ -0,0 +1,6 @@
1
+ // The GuardEngine server wiring (02 §4): the argon2id binding adapter that arms
2
+ // cwip's KDF seam, and the Ed25519 session signer that mints and revokes.
3
+ export * from './argon2Binding';
4
+ export * from './verifier';
5
+ export * from './revocationStore';
6
+ export * from './sessionSigner';
@@ -0,0 +1,101 @@
1
+ import { createInProcessPasswordVerifier, type PasswordVerifierPort } from './passwordVerifier';
2
+ /** Raised when the worker thread dies, fails to start, or is disposed mid-flight. */
3
+ export declare const GUARD_KDF_WORKER_FAILED = "GUARD_KDF_WORKER_FAILED";
4
+ /** Raised when the worker does not answer within the configured budget. */
5
+ export declare const GUARD_KDF_WORKER_TIMEOUT = "GUARD_KDF_WORKER_TIMEOUT";
6
+ /**
7
+ * Default per-request ceiling. Generous relative to a ~250 ms derivation on
8
+ * purpose: this is a liveness backstop for a wedged thread, not a latency SLO,
9
+ * and a tight budget here would turn a loaded machine into a login outage.
10
+ */
11
+ export declare const KDF_WORKER_DEFAULT_TIMEOUT_MS = 15000;
12
+ export type KdfWorkerRequest = {
13
+ id: number;
14
+ kind: 'seal';
15
+ userId: string;
16
+ password: Uint8Array;
17
+ } | {
18
+ id: number;
19
+ kind: 'verify';
20
+ userId: string;
21
+ envelopeJson: string;
22
+ password: Uint8Array;
23
+ };
24
+ export type KdfWorkerResponse = {
25
+ id: number;
26
+ ok: true;
27
+ value: string | boolean;
28
+ } | {
29
+ id: number;
30
+ ok: false;
31
+ code: string;
32
+ message: string;
33
+ };
34
+ /** The subset of a worker-thread global this module needs, in either runtime. */
35
+ interface WorkerScope {
36
+ postMessage(data: unknown): void;
37
+ onMessage(handler: (data: unknown) => void): void;
38
+ }
39
+ /**
40
+ * Run the KDF worker's message loop. A worker entry module is this call and
41
+ * nothing else (see `kdfWorkerEntry.ts`).
42
+ *
43
+ * `register` is injectable so the spec can drive the loop with a cheap fake
44
+ * binding — registering the real native argon2 in a test that only checks
45
+ * message plumbing would pay 250 ms per case to prove nothing about the
46
+ * plumbing. The DEFAULT is the real binding, because a worker that silently ran
47
+ * a fake KDF would be a catastrophe rather than a bug.
48
+ */
49
+ export declare function serveKdfWorker(options?: {
50
+ scope?: WorkerScope;
51
+ register?: () => Promise<void>;
52
+ }): Promise<void>;
53
+ /**
54
+ * The subset of both runtimes' Worker the client needs.
55
+ *
56
+ * `post` RESOLVES ONCE THE DATA HAS BEEN HANDED TO THE THREAD, and that is not a
57
+ * stylistic choice. A worker is constructed asynchronously, so early requests
58
+ * are queued; the queue holds the caller's `Uint8Array` by reference. A client
59
+ * that zeroized the password right after a fire-and-forget `post()` would blank
60
+ * the buffer the queue is still holding, and the worker would then derive a key
61
+ * from 32 zero bytes — accepting every wrong password that happened to be
62
+ * presented during startup. Awaiting the post is what makes "zeroize as early as
63
+ * possible" and "send the real bytes" compatible.
64
+ */
65
+ interface HostWorker {
66
+ post(data: unknown): Promise<void>;
67
+ onMessage(handler: (data: unknown) => void): void;
68
+ onError(handler: (error: unknown) => void): void;
69
+ terminate(): void;
70
+ }
71
+ export interface KdfWorkerOptions {
72
+ /** Module specifier / URL of an entry that calls {@link serveKdfWorker}. */
73
+ entry: string | URL;
74
+ /** Per-request ceiling. Defaults to {@link KDF_WORKER_DEFAULT_TIMEOUT_MS}. */
75
+ timeoutMs?: number;
76
+ /** Spawn override — the spec uses it to drive the protocol without a real thread. */
77
+ spawn?: (entry: string | URL) => HostWorker;
78
+ }
79
+ /**
80
+ * A {@link PasswordVerifierPort} backed by one long-lived worker thread.
81
+ *
82
+ * Hand it to `createAccountService({ passwords })` on a host that expects login
83
+ * concurrency. Local single-user hosts should NOT — they would pay a thread and
84
+ * a native module load to serialize a workload that was never contended.
85
+ */
86
+ export declare function createKdfWorkerPasswordVerifier(options: KdfWorkerOptions): PasswordVerifierPort;
87
+ /**
88
+ * The URL of the entry module {@link createKdfWorkerPasswordVerifier} spawns.
89
+ *
90
+ * Resolved relative to THIS module rather than hard-coded by the host, so an app
91
+ * never has to know where inside the package the entry lives:
92
+ *
93
+ * createKdfWorkerPasswordVerifier({ entry: kdfWorkerEntryUrl() })
94
+ *
95
+ * Under the `bun` export condition this resolves to the TypeScript source, which
96
+ * is what every first-party consumer runs (see the monorepo's zero-build-lag
97
+ * contract). A non-Bun host consuming built `dist/` names its own built entry.
98
+ */
99
+ export declare const kdfWorkerEntryUrl: () => URL;
100
+ /** Re-exported so a host wiring the guard tier needs one import. */
101
+ export { createInProcessPasswordVerifier, type PasswordVerifierPort };