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,91 @@
1
+ /**
2
+ * `createPgSearchProvider` — the SAAS profile's ranked-retrieval tier (04 §3,
3
+ * audit gap L11 and frontier item 4(c)).
4
+ *
5
+ * Before this file, the saas profile had **no search tier at all**. `bootEngineApp`
6
+ * derived its `SearchProvider` from the local SQLite handles it does not open
7
+ * when a host injects storage, so under saas `search` was `undefined`, the
8
+ * `reindex` job fell through to the loud "needs a wired SearchProvider"
9
+ * placeholder, and `KnowledgeService.search` took its `LIKE` fallback for every
10
+ * tenant on the platform. 04 §1's gate text — "a leased `reindex` executing
11
+ * through the pg-dialect repo" — was unachievable, and the `genAppSaasSmoke`
12
+ * job leg asserted that the placeholder failed, as designed. This is the far
13
+ * side that makes both of those real.
14
+ *
15
+ * ## What is shared with the local provider, and what is not
16
+ *
17
+ * **The vector tier is shared, exactly.** Chunking, the little-endian embedding
18
+ * codec, the revision guard, the comparability predicates, the cosine rank and
19
+ * the reciprocal-rank fusion all come from `cwip`'s `searchVectorTier` — one
20
+ * implementation, driven here through a Postgres executor and there through a
21
+ * SQLite one. A second copy of ranking math is the worst kind of duplication:
22
+ * both copies keep returning plausible results after they diverge.
23
+ *
24
+ * **The keyword tier is NOT shared, and cannot be.** SQLite's is an FTS5
25
+ * external-content virtual table maintained by triggers; this one is a
26
+ * `tsvector` generated column with a GIN index. `domains/search.ts` already
27
+ * refuses to compile its chain for Postgres and says why. What IS held identical
28
+ * is the OBSERVABLE contract: the same 4× title weighting (`PG_RANK_WEIGHTS`
29
+ * against `bm25(search_fts, 4.0, 1.0)`), the same "higher score is better" sign,
30
+ * the same tenancy-as-a-predicate law, and the same behavior on a user typing
31
+ * punctuation into a search box. Two profiles that ranked one corpus differently
32
+ * would make "search ranks wrong in production" unreproducible on a laptop.
33
+ *
34
+ * ## Two things Postgres makes better, and one it makes worse
35
+ *
36
+ * **Better: a search box is not a query language, and here it is not a hazard
37
+ * either.** The SQLite provider catches an FTS5 syntax error and retries the
38
+ * whole input as a quoted phrase literal. `websearch_to_tsquery` cannot raise a
39
+ * syntax error on any input — quotes, `-`, `OR`, an unbalanced paren are all
40
+ * defined — so the retry has nothing to catch and does not exist. That is a real
41
+ * difference in the failure surface, not a stylistic one.
42
+ *
43
+ * **Better: the shadow cannot drift.** `tsv` is `GENERATED ALWAYS AS … STORED`,
44
+ * so no code path writes it — see `pgSearchSchema.ts`.
45
+ *
46
+ * **Worse: the connection accounting.** Every operation checks a connection out
47
+ * of the ONE pool, opens a transaction, scopes it to the tenant and returns it.
48
+ * The vector tier's chunk writes go through a per-statement scoped executor, so
49
+ * writing an eight-chunk document is eight checkouts rather than one. That is
50
+ * deliberate: the alternative is holding a pooled connection and an open
51
+ * transaction across eight embedding round-trips, which is how a search backlog
52
+ * takes an entire deployment's Postgres down. The chunk write is already
53
+ * dominated by inference latency; the checkout is noise beside it.
54
+ *
55
+ * ## The ceiling, again stated rather than hidden
56
+ *
57
+ * The vector rank is an exact cosine scan over a bounded candidate set, not an
58
+ * ANN index — no `pgvector`, no extension a customer's managed Postgres may
59
+ * refuse to install. `cwip`'s `searchVectorTier` header carries the numbers and
60
+ * the upgrade path; truncation is REPORTED through `onVectorTruncated` rather
61
+ * than swallowed, because a search tier that quietly degrades as a customer
62
+ * succeeds is worse than one that says so.
63
+ */
64
+ import { type RebuildableSearchProvider } from 'cwip/search-provider';
65
+ import type { ChunkOptions } from 'cwip/search';
66
+ import { type SaasPool } from 'cwip/storage';
67
+ export interface PgSearchProviderOptions {
68
+ /** The deployment's ONE pool. Injected — this module opens no socket (law #8). */
69
+ pool: SaasPool;
70
+ defaultLimit?: number;
71
+ maxLimit?: number;
72
+ /**
73
+ * The embedder backing the vector tier. Absent ⇒ the provider has no `embed`
74
+ * method at all and `search_chunks` stays honestly empty — the same capability
75
+ * signal the local provider gives, so a caller's `provider.embed?.(…)` test
76
+ * means the same thing on both profiles.
77
+ */
78
+ embed?(text: string, tenantId: string): Promise<Float32Array>;
79
+ /** Which model `embed` speaks for. Recorded per chunk; a query predicate. */
80
+ embedModel?: string;
81
+ chunkOptions?: ChunkOptions;
82
+ vectorCandidateLimit?: number;
83
+ onVectorTruncated?(detail: {
84
+ tenantId: string;
85
+ corpora: readonly string[];
86
+ scanned: number;
87
+ }): void;
88
+ /** Where a vector-tier failure goes. The keyword tier is the floor. */
89
+ onVectorError?(error: unknown, phase: 'index' | 'query'): void;
90
+ }
91
+ export declare function createPgSearchProvider(options: PgSearchProviderOptions): RebuildableSearchProvider;
@@ -0,0 +1,330 @@
1
+ /**
2
+ * `createPgSearchProvider` — the SAAS profile's ranked-retrieval tier (04 §3,
3
+ * audit gap L11 and frontier item 4(c)).
4
+ *
5
+ * Before this file, the saas profile had **no search tier at all**. `bootEngineApp`
6
+ * derived its `SearchProvider` from the local SQLite handles it does not open
7
+ * when a host injects storage, so under saas `search` was `undefined`, the
8
+ * `reindex` job fell through to the loud "needs a wired SearchProvider"
9
+ * placeholder, and `KnowledgeService.search` took its `LIKE` fallback for every
10
+ * tenant on the platform. 04 §1's gate text — "a leased `reindex` executing
11
+ * through the pg-dialect repo" — was unachievable, and the `genAppSaasSmoke`
12
+ * job leg asserted that the placeholder failed, as designed. This is the far
13
+ * side that makes both of those real.
14
+ *
15
+ * ## What is shared with the local provider, and what is not
16
+ *
17
+ * **The vector tier is shared, exactly.** Chunking, the little-endian embedding
18
+ * codec, the revision guard, the comparability predicates, the cosine rank and
19
+ * the reciprocal-rank fusion all come from `cwip`'s `searchVectorTier` — one
20
+ * implementation, driven here through a Postgres executor and there through a
21
+ * SQLite one. A second copy of ranking math is the worst kind of duplication:
22
+ * both copies keep returning plausible results after they diverge.
23
+ *
24
+ * **The keyword tier is NOT shared, and cannot be.** SQLite's is an FTS5
25
+ * external-content virtual table maintained by triggers; this one is a
26
+ * `tsvector` generated column with a GIN index. `domains/search.ts` already
27
+ * refuses to compile its chain for Postgres and says why. What IS held identical
28
+ * is the OBSERVABLE contract: the same 4× title weighting (`PG_RANK_WEIGHTS`
29
+ * against `bm25(search_fts, 4.0, 1.0)`), the same "higher score is better" sign,
30
+ * the same tenancy-as-a-predicate law, and the same behavior on a user typing
31
+ * punctuation into a search box. Two profiles that ranked one corpus differently
32
+ * would make "search ranks wrong in production" unreproducible on a laptop.
33
+ *
34
+ * ## Two things Postgres makes better, and one it makes worse
35
+ *
36
+ * **Better: a search box is not a query language, and here it is not a hazard
37
+ * either.** The SQLite provider catches an FTS5 syntax error and retries the
38
+ * whole input as a quoted phrase literal. `websearch_to_tsquery` cannot raise a
39
+ * syntax error on any input — quotes, `-`, `OR`, an unbalanced paren are all
40
+ * defined — so the retry has nothing to catch and does not exist. That is a real
41
+ * difference in the failure surface, not a stylistic one.
42
+ *
43
+ * **Better: the shadow cannot drift.** `tsv` is `GENERATED ALWAYS AS … STORED`,
44
+ * so no code path writes it — see `pgSearchSchema.ts`.
45
+ *
46
+ * **Worse: the connection accounting.** Every operation checks a connection out
47
+ * of the ONE pool, opens a transaction, scopes it to the tenant and returns it.
48
+ * The vector tier's chunk writes go through a per-statement scoped executor, so
49
+ * writing an eight-chunk document is eight checkouts rather than one. That is
50
+ * deliberate: the alternative is holding a pooled connection and an open
51
+ * transaction across eight embedding round-trips, which is how a search backlog
52
+ * takes an entire deployment's Postgres down. The chunk write is already
53
+ * dominated by inference latency; the checkout is noise beside it.
54
+ *
55
+ * ## The ceiling, again stated rather than hidden
56
+ *
57
+ * The vector rank is an exact cosine scan over a bounded candidate set, not an
58
+ * ANN index — no `pgvector`, no extension a customer's managed Postgres may
59
+ * refuse to install. `cwip`'s `searchVectorTier` header carries the numbers and
60
+ * the upgrade path; truncation is REPORTED through `onVectorTruncated` rather
61
+ * than swallowed, because a search tier that quietly degrades as a customer
62
+ * succeeds is worse than one that says so.
63
+ */
64
+ import { assertNonEmpty, clampLimit, clampPositive, countChunks, docKey, fuseSearchTiers, rankChunksByVector, UNKNOWN_EMBED_MODEL, writeDocChunks, } from 'cwip/search-provider';
65
+ import { createPostgresControlExecutor, saasSetTenantSql, } from 'cwip/storage';
66
+ import { AppError } from '../errors';
67
+ import { PG_RANK_WEIGHTS } from './pgSearchSchema';
68
+ const DEFAULT_LIMIT = 20;
69
+ const MAX_LIMIT = 200;
70
+ /** Mirrors the SQLite provider's fusion depth — see its `FUSION_DEPTH`. */
71
+ const FUSION_DEPTH = 4;
72
+ /** `ts_headline` window, in words. Comparable to the SQLite side's 14-token snippet. */
73
+ const SNIPPET_WORDS = 18;
74
+ export function createPgSearchProvider(options) {
75
+ const { pool } = options;
76
+ const defaultLimit = clampPositive(options.defaultLimit, DEFAULT_LIMIT);
77
+ const maxLimit = clampPositive(options.maxLimit, MAX_LIMIT);
78
+ const embedModel = options.embedModel ?? UNKNOWN_EMBED_MODEL;
79
+ /**
80
+ * Run `fn` on a connection scoped to `tenantId` for the duration of ONE
81
+ * transaction.
82
+ *
83
+ * The `BEGIN` is not decoration around a single statement: `set_config(…, true)`
84
+ * is transaction-local, and outside a transaction it would apply to the
85
+ * session and ride the connection back into the pool with another tenant's
86
+ * scope still set. That is the exact leak RLS exists to prevent, so the
87
+ * transaction is what makes the scoping safe rather than what makes it atomic.
88
+ */
89
+ const scoped = async (tenantId, fn) => {
90
+ assertNonEmpty(tenantId, 'tenantId');
91
+ return await pool.withConnection(async (connection) => {
92
+ await connection.execute('BEGIN');
93
+ try {
94
+ const setTenant = saasSetTenantSql(tenantId);
95
+ await connection.execute(setTenant.sql, setTenant.params);
96
+ const result = await fn(createPostgresControlExecutor(connection));
97
+ await connection.execute('COMMIT');
98
+ return result;
99
+ }
100
+ catch (error) {
101
+ // Best-effort: a connection already broken by the failure cannot roll
102
+ // back, and masking the original error with the rollback's would hide
103
+ // the thing worth reading.
104
+ await connection.execute('ROLLBACK').catch(() => undefined);
105
+ throw error;
106
+ }
107
+ });
108
+ };
109
+ /**
110
+ * An executor whose every statement is its own scoped transaction.
111
+ *
112
+ * This is what the vector tier runs on, and the shape is the point: the tier
113
+ * interleaves database writes with embedding round-trips, so a single
114
+ * long-lived transaction across it would pin a pooled connection for the
115
+ * duration of somebody else's inference queue. Each statement being separately
116
+ * atomic is also exactly what the tier's revision guard assumes — the guard is
117
+ * a `WHERE EXISTS` evaluated at write time, never a read-then-act.
118
+ */
119
+ const perStatementExecutor = (tenantId) => ({
120
+ dialect: 'postgres',
121
+ all: (statement) => scoped(tenantId, (exec) => exec.all(statement)),
122
+ get: (statement) => scoped(tenantId, (exec) => exec.get(statement)),
123
+ write: (statement) => scoped(tenantId, (exec) => exec.write(statement)),
124
+ });
125
+ const keywordQuery = (query, tenantId, corpora, limit) => {
126
+ const where = ['d.tenant_id = ?', "d.tsv @@ websearch_to_tsquery('simple', ?)"];
127
+ const params = [query, query, tenantId, query];
128
+ if (corpora.length > 0) {
129
+ where.push(`d.corpus IN (${corpora.map(() => '?').join(', ')})`);
130
+ params.push(...corpora);
131
+ }
132
+ params.push(limit);
133
+ return {
134
+ // `ts_headline` gets the same empty start/stop markers the SQLite
135
+ // `snippet()` call uses, so a client rendering a hit does not have to know
136
+ // which profile produced it.
137
+ sql: `SELECT d.source_id AS id,
138
+ d.corpus AS corpus,
139
+ d.tenant_id AS tenant_id,
140
+ d.title AS title,
141
+ ts_headline('simple', d.body, websearch_to_tsquery('simple', ?),
142
+ 'MaxWords=${SNIPPET_WORDS}, MinWords=1, ShortWord=1, HighlightAll=false, MaxFragments=1, StartSel="", StopSel=""') AS snippet,
143
+ ts_rank('${PG_RANK_WEIGHTS}'::float4[], d.tsv, websearch_to_tsquery('simple', ?)) AS rank
144
+ FROM search_docs d
145
+ WHERE ${where.join(' AND ')}
146
+ ORDER BY rank DESC, d.id DESC
147
+ LIMIT ?`,
148
+ params,
149
+ };
150
+ };
151
+ return {
152
+ async now() {
153
+ // The INDEX's clock, in the index's own format — the same law the SQLite
154
+ // provider states. Comparing a JS `Date` against a value the database
155
+ // wrote is a format coupling nobody remembers is there.
156
+ const row = await pool.withConnection(async (connection) => createPostgresControlExecutor(connection).get({ sql: 'SELECT {{now}} AS now' }));
157
+ if (row === null)
158
+ throw new AppError('The search index clock returned no row.', {
159
+ code: 'SEARCH_CLOCK_UNAVAILABLE',
160
+ status: 500,
161
+ });
162
+ return row.now;
163
+ },
164
+ ...(options.embed ? { embed: options.embed } : {}),
165
+ async index(doc) {
166
+ assertNonEmpty(doc.corpus, 'corpus');
167
+ assertNonEmpty(doc.id, 'id');
168
+ assertNonEmpty(doc.tenantId, 'tenantId');
169
+ // The document lands first and alone — the keyword tier is the floor, and
170
+ // an embedding round-trip is not something to hold a write lock across.
171
+ const identity = await scoped(doc.tenantId, async (executor) => {
172
+ const row = await executor.get({
173
+ sql: `INSERT INTO search_docs (corpus, source_id, tenant_id, user_id, title, body, rev, indexed_at)
174
+ VALUES (?, ?, ?, ?, ?, ?, 0, {{now}})
175
+ ON CONFLICT (corpus, source_id, tenant_id) DO UPDATE SET
176
+ user_id = excluded.user_id,
177
+ title = excluded.title,
178
+ body = excluded.body,
179
+ rev = search_docs.rev + 1,
180
+ indexed_at = excluded.indexed_at
181
+ RETURNING id, rev`,
182
+ params: [doc.corpus, doc.id, doc.tenantId, null, doc.title, doc.body],
183
+ });
184
+ if (row === null)
185
+ throw new AppError('The search index upsert returned no row, so the document id is unknown.', {
186
+ code: 'SEARCH_UPSERT_EMPTY',
187
+ status: 500,
188
+ context: { corpus: doc.corpus, id: doc.id },
189
+ });
190
+ return row;
191
+ });
192
+ if (!options.embed)
193
+ return;
194
+ const embed = options.embed;
195
+ try {
196
+ await writeDocChunks(perStatementExecutor(doc.tenantId), {
197
+ // A pg `bigint` arrives as a string; it is an opaque key here either way.
198
+ docId: String(identity.id),
199
+ rev: Number(identity.rev),
200
+ text: doc.title ? `${doc.title}\n\n${doc.body}` : doc.body,
201
+ tenantId: doc.tenantId,
202
+ embed: (text, tenantId) => embed(text, tenantId),
203
+ model: embedModel,
204
+ ...(options.chunkOptions ? { chunkOptions: options.chunkOptions } : {}),
205
+ });
206
+ }
207
+ catch (error) {
208
+ // Degrade, do not fail — see the SQLite provider's identical rule. The
209
+ // document IS indexed; failing here would make an embedder outage look
210
+ // like a write failure to the CDC tap, which retries.
211
+ options.onVectorError?.(error, 'index');
212
+ }
213
+ },
214
+ async remove(corpus, id, tenantId) {
215
+ // ONE transaction for both tables: an interrupted removal that dropped the
216
+ // document but kept its chunks would leave the vector tier ranking a
217
+ // document that no longer exists. (The FK cascade would handle it, but the
218
+ // explicit delete keeps the two profiles' behavior identical rather than
219
+ // resting on a schema detail one of them does not have.)
220
+ await scoped(tenantId, async (executor) => {
221
+ await executor.write({
222
+ sql: `DELETE FROM search_chunks WHERE doc_id IN (
223
+ SELECT id FROM search_docs WHERE corpus = ? AND source_id = ? AND tenant_id = ?)`,
224
+ params: [corpus, id, tenantId],
225
+ });
226
+ await executor.write({
227
+ sql: 'DELETE FROM search_docs WHERE corpus = ? AND source_id = ? AND tenant_id = ?',
228
+ params: [corpus, id, tenantId],
229
+ });
230
+ });
231
+ },
232
+ async query(q, opts) {
233
+ assertNonEmpty(opts.tenantId, 'tenantId');
234
+ const trimmed = q.trim();
235
+ if (trimmed.length === 0)
236
+ return [];
237
+ const corpora = opts.corpus ? [...opts.corpus] : [];
238
+ const limit = clampLimit(opts.limit, defaultLimit, maxLimit);
239
+ const tierLimit = options.embed ? Math.min(maxLimit, limit * FUSION_DEPTH) : limit;
240
+ const rows = await scoped(opts.tenantId, (executor) => executor.all(keywordQuery(trimmed, opts.tenantId, corpora, tierLimit)));
241
+ const keywordHits = rows.map((row) => ({
242
+ id: row.id,
243
+ corpus: row.corpus,
244
+ tenantId: row.tenant_id,
245
+ // `ts_rank` is already higher-is-better, which is the interface's
246
+ // contract — so unlike BM25 there is no sign to flip. Said explicitly
247
+ // because "flip it, the other one does" is the mistake available here.
248
+ score: Number(row.rank),
249
+ title: row.title,
250
+ snippet: row.snippet ?? '',
251
+ }));
252
+ if (!options.embed)
253
+ return keywordHits.slice(0, limit);
254
+ let vector;
255
+ try {
256
+ vector = await rankChunksByVector(perStatementExecutor(opts.tenantId), {
257
+ tenantId: opts.tenantId,
258
+ corpora,
259
+ queryVector: await options.embed(trimmed, opts.tenantId),
260
+ model: embedModel,
261
+ limit: tierLimit,
262
+ ...(options.vectorCandidateLimit !== undefined
263
+ ? { candidateLimit: options.vectorCandidateLimit }
264
+ : {}),
265
+ });
266
+ }
267
+ catch (error) {
268
+ options.onVectorError?.(error, 'query');
269
+ return keywordHits.slice(0, limit);
270
+ }
271
+ if (vector.truncated)
272
+ options.onVectorTruncated?.({ tenantId: opts.tenantId, corpora, scanned: vector.scanned });
273
+ return await fuseSearchTiers({
274
+ keyword: keywordHits,
275
+ vector: vector.chunks,
276
+ limit,
277
+ tenantId: opts.tenantId,
278
+ hydrate: async (keys) => {
279
+ // ONE statement for every missing title. A per-document lookup here is
280
+ // an N+1 on the hot path, and each of those N is a pool checkout.
281
+ const placeholders = keys.map(() => '(?, ?)').join(', ');
282
+ const params = keys.flatMap((key) => [key.corpus, key.docId]);
283
+ const found = await scoped(opts.tenantId, (executor) => executor.all({
284
+ sql: `SELECT corpus, source_id, title FROM search_docs
285
+ WHERE tenant_id = ? AND (corpus, source_id) IN (${placeholders})`,
286
+ params: [opts.tenantId, ...params],
287
+ }));
288
+ return new Map(found.map((row) => [docKey(row.corpus, row.source_id), { title: row.title }]));
289
+ },
290
+ });
291
+ },
292
+ async sweepStale(corpus, tenantId, epoch) {
293
+ assertNonEmpty(corpus, 'corpus');
294
+ assertNonEmpty(tenantId, 'tenantId');
295
+ assertNonEmpty(epoch, 'epoch');
296
+ return await scoped(tenantId, async (executor) => {
297
+ // Counted with its own statement rather than read off the DELETE's row
298
+ // count, so the number the reindex job logs is documents and not
299
+ // documents-plus-cascaded-chunks. The SQLite provider counts separately
300
+ // for the same reason (its FTS triggers inflate `changes`).
301
+ const stale = await executor.get({
302
+ sql: 'SELECT COUNT(*) AS n FROM search_docs WHERE corpus = ? AND tenant_id = ? AND indexed_at < ?',
303
+ params: [corpus, tenantId, epoch],
304
+ });
305
+ await executor.write({
306
+ sql: `DELETE FROM search_chunks WHERE doc_id IN (
307
+ SELECT id FROM search_docs WHERE corpus = ? AND tenant_id = ? AND indexed_at < ?)`,
308
+ params: [corpus, tenantId, epoch],
309
+ });
310
+ await executor.write({
311
+ sql: 'DELETE FROM search_docs WHERE corpus = ? AND tenant_id = ? AND indexed_at < ?',
312
+ params: [corpus, tenantId, epoch],
313
+ });
314
+ return Number(stale?.n ?? 0);
315
+ });
316
+ },
317
+ async count(corpus, tenantId) {
318
+ return await scoped(tenantId, async (executor) => {
319
+ const row = await executor.get({
320
+ sql: 'SELECT COUNT(*) AS n FROM search_docs WHERE corpus = ? AND tenant_id = ?',
321
+ params: [corpus, tenantId],
322
+ });
323
+ return Number(row?.n ?? 0);
324
+ });
325
+ },
326
+ async countChunks(corpus, tenantId) {
327
+ return await scoped(tenantId, (executor) => countChunks(executor, corpus, tenantId));
328
+ },
329
+ };
330
+ }
@@ -0,0 +1 @@
1
+ export {};