libre-webui 0.21.3 → 0.22.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 (945) hide show
  1. package/README.md +308 -328
  2. package/backend/dist/cli/migrateSqliteToPostgres.d.ts +2 -0
  3. package/backend/dist/cli/migrateSqliteToPostgres.d.ts.map +1 -0
  4. package/backend/dist/cli/migrateSqliteToPostgres.js +113 -0
  5. package/backend/dist/cli/migrateSqliteToPostgres.js.map +1 -0
  6. package/backend/dist/cli/recoveryBackup.d.ts +3 -0
  7. package/backend/dist/cli/recoveryBackup.d.ts.map +1 -0
  8. package/backend/dist/cli/recoveryBackup.js +251 -0
  9. package/backend/dist/cli/recoveryBackup.js.map +1 -0
  10. package/backend/dist/cli/recoveryInventory.d.ts +2 -0
  11. package/backend/dist/cli/recoveryInventory.d.ts.map +1 -0
  12. package/backend/dist/cli/recoveryInventory.js +109 -0
  13. package/backend/dist/cli/recoveryInventory.js.map +1 -0
  14. package/backend/dist/db.d.ts +27 -0
  15. package/backend/dist/db.d.ts.map +1 -1
  16. package/backend/dist/db.js +333 -16
  17. package/backend/dist/db.js.map +1 -1
  18. package/backend/dist/env.d.ts.map +1 -1
  19. package/backend/dist/env.js +12 -2
  20. package/backend/dist/env.js.map +1 -1
  21. package/backend/dist/index.d.ts.map +1 -1
  22. package/backend/dist/index.js +235 -47
  23. package/backend/dist/index.js.map +1 -1
  24. package/backend/dist/main.d.ts +2 -0
  25. package/backend/dist/main.d.ts.map +1 -0
  26. package/backend/dist/main.js +137 -0
  27. package/backend/dist/main.js.map +1 -0
  28. package/backend/dist/middleware/auth.d.ts.map +1 -1
  29. package/backend/dist/middleware/auth.js +7 -3
  30. package/backend/dist/middleware/auth.js.map +1 -1
  31. package/backend/dist/middleware/chatCancellationAdmission.d.ts +7 -0
  32. package/backend/dist/middleware/chatCancellationAdmission.d.ts.map +1 -0
  33. package/backend/dist/middleware/chatCancellationAdmission.js +17 -0
  34. package/backend/dist/middleware/chatCancellationAdmission.js.map +1 -0
  35. package/backend/dist/middleware/coordinatedRateLimit.d.ts +18 -0
  36. package/backend/dist/middleware/coordinatedRateLimit.d.ts.map +1 -0
  37. package/backend/dist/middleware/coordinatedRateLimit.js +52 -0
  38. package/backend/dist/middleware/coordinatedRateLimit.js.map +1 -0
  39. package/backend/dist/middleware/sharedRateLimit.d.ts +26 -0
  40. package/backend/dist/middleware/sharedRateLimit.d.ts.map +1 -0
  41. package/backend/dist/middleware/sharedRateLimit.js +99 -0
  42. package/backend/dist/middleware/sharedRateLimit.js.map +1 -0
  43. package/backend/dist/models/personaModel.d.ts +1 -26
  44. package/backend/dist/models/personaModel.d.ts.map +1 -1
  45. package/backend/dist/models/personaModel.js +54 -247
  46. package/backend/dist/models/personaModel.js.map +1 -1
  47. package/backend/dist/models/userModel.d.ts +23 -66
  48. package/backend/dist/models/userModel.d.ts.map +1 -1
  49. package/backend/dist/models/userModel.js +110 -187
  50. package/backend/dist/models/userModel.js.map +1 -1
  51. package/backend/dist/persistence/chatGenerationTypes.d.ts +24 -0
  52. package/backend/dist/persistence/chatGenerationTypes.d.ts.map +1 -0
  53. package/backend/dist/persistence/chatGenerationTypes.js +7 -0
  54. package/backend/dist/persistence/chatGenerationTypes.js.map +1 -0
  55. package/backend/dist/persistence/extensionTypes.d.ts +185 -0
  56. package/backend/dist/persistence/extensionTypes.d.ts.map +1 -0
  57. package/backend/dist/persistence/extensionTypes.js +13 -0
  58. package/backend/dist/persistence/extensionTypes.js.map +1 -0
  59. package/backend/dist/persistence/identityDeletionTypes.d.ts +16 -0
  60. package/backend/dist/persistence/identityDeletionTypes.d.ts.map +1 -0
  61. package/backend/dist/persistence/identityDeletionTypes.js +7 -0
  62. package/backend/dist/persistence/identityDeletionTypes.js.map +1 -0
  63. package/backend/dist/persistence/index.d.ts +48 -0
  64. package/backend/dist/persistence/index.d.ts.map +1 -0
  65. package/backend/dist/persistence/index.js +159 -0
  66. package/backend/dist/persistence/index.js.map +1 -0
  67. package/backend/dist/persistence/postgresConfig.d.ts +32 -0
  68. package/backend/dist/persistence/postgresConfig.d.ts.map +1 -0
  69. package/backend/dist/persistence/postgresConfig.js +91 -0
  70. package/backend/dist/persistence/postgresConfig.js.map +1 -0
  71. package/backend/dist/persistence/postgresCoreMigration.d.ts +8 -0
  72. package/backend/dist/persistence/postgresCoreMigration.d.ts.map +1 -0
  73. package/backend/dist/persistence/postgresCoreMigration.js +179 -0
  74. package/backend/dist/persistence/postgresCoreMigration.js.map +1 -0
  75. package/backend/dist/persistence/postgresDatabase.d.ts +40 -0
  76. package/backend/dist/persistence/postgresDatabase.d.ts.map +1 -0
  77. package/backend/dist/persistence/postgresDatabase.js +148 -0
  78. package/backend/dist/persistence/postgresDatabase.js.map +1 -0
  79. package/backend/dist/persistence/postgresExtensionMigration.d.ts +4 -0
  80. package/backend/dist/persistence/postgresExtensionMigration.d.ts.map +1 -0
  81. package/backend/dist/persistence/postgresExtensionMigration.js +143 -0
  82. package/backend/dist/persistence/postgresExtensionMigration.js.map +1 -0
  83. package/backend/dist/persistence/postgresExtensionRepositories.d.ts +6 -0
  84. package/backend/dist/persistence/postgresExtensionRepositories.d.ts.map +1 -0
  85. package/backend/dist/persistence/postgresExtensionRepositories.js +550 -0
  86. package/backend/dist/persistence/postgresExtensionRepositories.js.map +1 -0
  87. package/backend/dist/persistence/postgresImportState.d.ts +9 -0
  88. package/backend/dist/persistence/postgresImportState.d.ts.map +1 -0
  89. package/backend/dist/persistence/postgresImportState.js +64 -0
  90. package/backend/dist/persistence/postgresImportState.js.map +1 -0
  91. package/backend/dist/persistence/postgresMigrationRegistry.d.ts +4 -0
  92. package/backend/dist/persistence/postgresMigrationRegistry.d.ts.map +1 -0
  93. package/backend/dist/persistence/postgresMigrationRegistry.js +33 -0
  94. package/backend/dist/persistence/postgresMigrationRegistry.js.map +1 -0
  95. package/backend/dist/persistence/postgresMigrationTypes.d.ts +24 -0
  96. package/backend/dist/persistence/postgresMigrationTypes.d.ts.map +1 -0
  97. package/backend/dist/persistence/postgresMigrationTypes.js +7 -0
  98. package/backend/dist/persistence/postgresMigrationTypes.js.map +1 -0
  99. package/backend/dist/persistence/postgresMigrations.d.ts +15 -0
  100. package/backend/dist/persistence/postgresMigrations.d.ts.map +1 -0
  101. package/backend/dist/persistence/postgresMigrations.js +333 -0
  102. package/backend/dist/persistence/postgresMigrations.js.map +1 -0
  103. package/backend/dist/persistence/postgresPersistence.d.ts +17 -0
  104. package/backend/dist/persistence/postgresPersistence.d.ts.map +1 -0
  105. package/backend/dist/persistence/postgresPersistence.js +332 -0
  106. package/backend/dist/persistence/postgresPersistence.js.map +1 -0
  107. package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts +4 -0
  108. package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts.map +1 -0
  109. package/backend/dist/persistence/postgresPluginDefinitionMigration.js +40 -0
  110. package/backend/dist/persistence/postgresPluginDefinitionMigration.js.map +1 -0
  111. package/backend/dist/persistence/postgresResourceRepositories.d.ts +7 -0
  112. package/backend/dist/persistence/postgresResourceRepositories.d.ts.map +1 -0
  113. package/backend/dist/persistence/postgresResourceRepositories.js +776 -0
  114. package/backend/dist/persistence/postgresResourceRepositories.js.map +1 -0
  115. package/backend/dist/persistence/postgresSchemaInspector.d.ts +14 -0
  116. package/backend/dist/persistence/postgresSchemaInspector.d.ts.map +1 -0
  117. package/backend/dist/persistence/postgresSchemaInspector.js +817 -0
  118. package/backend/dist/persistence/postgresSchemaInspector.js.map +1 -0
  119. package/backend/dist/persistence/resourceTypes.d.ts +207 -0
  120. package/backend/dist/persistence/resourceTypes.d.ts.map +1 -0
  121. package/backend/dist/persistence/resourceTypes.js +38 -0
  122. package/backend/dist/persistence/resourceTypes.js.map +1 -0
  123. package/backend/dist/persistence/sqliteExtensionRepositories.d.ts +4 -0
  124. package/backend/dist/persistence/sqliteExtensionRepositories.d.ts.map +1 -0
  125. package/backend/dist/persistence/sqliteExtensionRepositories.js +494 -0
  126. package/backend/dist/persistence/sqliteExtensionRepositories.js.map +1 -0
  127. package/backend/dist/persistence/sqliteMigrations.d.ts +93 -0
  128. package/backend/dist/persistence/sqliteMigrations.d.ts.map +1 -0
  129. package/backend/dist/persistence/sqliteMigrations.js +2232 -0
  130. package/backend/dist/persistence/sqliteMigrations.js.map +1 -0
  131. package/backend/dist/persistence/sqlitePersistence.d.ts +23 -0
  132. package/backend/dist/persistence/sqlitePersistence.d.ts.map +1 -0
  133. package/backend/dist/persistence/sqlitePersistence.js +596 -0
  134. package/backend/dist/persistence/sqlitePersistence.js.map +1 -0
  135. package/backend/dist/persistence/sqliteResourceRepositories.d.ts +4 -0
  136. package/backend/dist/persistence/sqliteResourceRepositories.d.ts.map +1 -0
  137. package/backend/dist/persistence/sqliteResourceRepositories.js +663 -0
  138. package/backend/dist/persistence/sqliteResourceRepositories.js.map +1 -0
  139. package/backend/dist/persistence/sqliteSyncExecutor.d.ts +5 -0
  140. package/backend/dist/persistence/sqliteSyncExecutor.d.ts.map +1 -0
  141. package/backend/dist/persistence/sqliteSyncExecutor.js +19 -0
  142. package/backend/dist/persistence/sqliteSyncExecutor.js.map +1 -0
  143. package/backend/dist/persistence/sqliteToPostgresMigration.d.ts +80 -0
  144. package/backend/dist/persistence/sqliteToPostgresMigration.d.ts.map +1 -0
  145. package/backend/dist/persistence/sqliteToPostgresMigration.js +1543 -0
  146. package/backend/dist/persistence/sqliteToPostgresMigration.js.map +1 -0
  147. package/backend/dist/persistence/types.d.ts +131 -0
  148. package/backend/dist/persistence/types.d.ts.map +1 -0
  149. package/backend/dist/persistence/types.js +18 -0
  150. package/backend/dist/persistence/types.js.map +1 -0
  151. package/backend/dist/persistence/voiceProfileNameLookup.d.ts +9 -0
  152. package/backend/dist/persistence/voiceProfileNameLookup.d.ts.map +1 -0
  153. package/backend/dist/persistence/voiceProfileNameLookup.js +15 -0
  154. package/backend/dist/persistence/voiceProfileNameLookup.js.map +1 -0
  155. package/backend/dist/platform/coordination/index.d.ts +7 -0
  156. package/backend/dist/platform/coordination/index.d.ts.map +1 -0
  157. package/backend/dist/platform/coordination/index.js +24 -0
  158. package/backend/dist/platform/coordination/index.js.map +1 -0
  159. package/backend/dist/platform/coordination/localCoordinator.d.ts +49 -0
  160. package/backend/dist/platform/coordination/localCoordinator.d.ts.map +1 -0
  161. package/backend/dist/platform/coordination/localCoordinator.js +380 -0
  162. package/backend/dist/platform/coordination/localCoordinator.js.map +1 -0
  163. package/backend/dist/platform/coordination/redisCoordinator.d.ts +83 -0
  164. package/backend/dist/platform/coordination/redisCoordinator.d.ts.map +1 -0
  165. package/backend/dist/platform/coordination/redisCoordinator.js +726 -0
  166. package/backend/dist/platform/coordination/redisCoordinator.js.map +1 -0
  167. package/backend/dist/platform/coordination/service.d.ts +11 -0
  168. package/backend/dist/platform/coordination/service.d.ts.map +1 -0
  169. package/backend/dist/platform/coordination/service.js +55 -0
  170. package/backend/dist/platform/coordination/service.js.map +1 -0
  171. package/backend/dist/platform/coordination/sharedAdmission.d.ts +53 -0
  172. package/backend/dist/platform/coordination/sharedAdmission.d.ts.map +1 -0
  173. package/backend/dist/platform/coordination/sharedAdmission.js +194 -0
  174. package/backend/dist/platform/coordination/sharedAdmission.js.map +1 -0
  175. package/backend/dist/platform/coordination/types.d.ts +76 -0
  176. package/backend/dist/platform/coordination/types.d.ts.map +1 -0
  177. package/backend/dist/platform/coordination/types.js +32 -0
  178. package/backend/dist/platform/coordination/types.js.map +1 -0
  179. package/backend/dist/platform/events/durableEventGateway.d.ts +54 -0
  180. package/backend/dist/platform/events/durableEventGateway.d.ts.map +1 -0
  181. package/backend/dist/platform/events/durableEventGateway.js +262 -0
  182. package/backend/dist/platform/events/durableEventGateway.js.map +1 -0
  183. package/backend/dist/platform/events/index.d.ts +3 -0
  184. package/backend/dist/platform/events/index.d.ts.map +1 -0
  185. package/backend/dist/platform/events/index.js +8 -0
  186. package/backend/dist/platform/events/index.js.map +1 -0
  187. package/backend/dist/platform/events/service.d.ts +8 -0
  188. package/backend/dist/platform/events/service.d.ts.map +1 -0
  189. package/backend/dist/platform/events/service.js +25 -0
  190. package/backend/dist/platform/events/service.js.map +1 -0
  191. package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts +3 -0
  192. package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts.map +1 -0
  193. package/backend/dist/platform/jobs/chatGenerationEnqueuer.js +55 -0
  194. package/backend/dist/platform/jobs/chatGenerationEnqueuer.js.map +1 -0
  195. package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts +3 -0
  196. package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts.map +1 -0
  197. package/backend/dist/platform/jobs/documentIngestionEnqueuer.js +38 -0
  198. package/backend/dist/platform/jobs/documentIngestionEnqueuer.js.map +1 -0
  199. package/backend/dist/platform/jobs/domainJobContracts.d.ts +30 -0
  200. package/backend/dist/platform/jobs/domainJobContracts.d.ts.map +1 -0
  201. package/backend/dist/platform/jobs/domainJobContracts.js +53 -0
  202. package/backend/dist/platform/jobs/domainJobContracts.js.map +1 -0
  203. package/backend/dist/platform/jobs/domainJobHandlers.d.ts +11 -0
  204. package/backend/dist/platform/jobs/domainJobHandlers.d.ts.map +1 -0
  205. package/backend/dist/platform/jobs/domainJobHandlers.js +612 -0
  206. package/backend/dist/platform/jobs/domainJobHandlers.js.map +1 -0
  207. package/backend/dist/platform/jobs/durableEventIdentity.d.ts +8 -0
  208. package/backend/dist/platform/jobs/durableEventIdentity.d.ts.map +1 -0
  209. package/backend/dist/platform/jobs/durableEventIdentity.js +33 -0
  210. package/backend/dist/platform/jobs/durableEventIdentity.js.map +1 -0
  211. package/backend/dist/platform/jobs/durableJobRuntime.d.ts +57 -0
  212. package/backend/dist/platform/jobs/durableJobRuntime.d.ts.map +1 -0
  213. package/backend/dist/platform/jobs/durableJobRuntime.js +131 -0
  214. package/backend/dist/platform/jobs/durableJobRuntime.js.map +1 -0
  215. package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts +28 -0
  216. package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts.map +1 -0
  217. package/backend/dist/platform/jobs/durableJobRuntimeBackend.js +62 -0
  218. package/backend/dist/platform/jobs/durableJobRuntimeBackend.js.map +1 -0
  219. package/backend/dist/platform/jobs/durableJobService.d.ts +85 -0
  220. package/backend/dist/platform/jobs/durableJobService.d.ts.map +1 -0
  221. package/backend/dist/platform/jobs/durableJobService.js +726 -0
  222. package/backend/dist/platform/jobs/durableJobService.js.map +1 -0
  223. package/backend/dist/platform/jobs/durableJobTypes.d.ts +195 -0
  224. package/backend/dist/platform/jobs/durableJobTypes.d.ts.map +1 -0
  225. package/backend/dist/platform/jobs/durableJobTypes.js +72 -0
  226. package/backend/dist/platform/jobs/durableJobTypes.js.map +1 -0
  227. package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts +87 -0
  228. package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts.map +1 -0
  229. package/backend/dist/platform/jobs/embeddedDurableJobWorker.js +429 -0
  230. package/backend/dist/platform/jobs/embeddedDurableJobWorker.js.map +1 -0
  231. package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts +3 -0
  232. package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts.map +1 -0
  233. package/backend/dist/platform/jobs/identityDeletionEnqueuer.js +36 -0
  234. package/backend/dist/platform/jobs/identityDeletionEnqueuer.js.map +1 -0
  235. package/backend/dist/platform/jobs/index.d.ts +18 -0
  236. package/backend/dist/platform/jobs/index.d.ts.map +1 -0
  237. package/backend/dist/platform/jobs/index.js +34 -0
  238. package/backend/dist/platform/jobs/index.js.map +1 -0
  239. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts +4 -0
  240. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts.map +1 -0
  241. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js +25 -0
  242. package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js.map +1 -0
  243. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts +4 -0
  244. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts.map +1 -0
  245. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js +23 -0
  246. package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js.map +1 -0
  247. package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts +11 -0
  248. package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts.map +1 -0
  249. package/backend/dist/platform/jobs/postgresDurableJobMigration.js +106 -0
  250. package/backend/dist/platform/jobs/postgresDurableJobMigration.js.map +1 -0
  251. package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts +88 -0
  252. package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts.map +1 -0
  253. package/backend/dist/platform/jobs/postgresDurableJobRepository.js +1185 -0
  254. package/backend/dist/platform/jobs/postgresDurableJobRepository.js.map +1 -0
  255. package/backend/dist/platform/jobs/postgresDurableJobService.d.ts +86 -0
  256. package/backend/dist/platform/jobs/postgresDurableJobService.d.ts.map +1 -0
  257. package/backend/dist/platform/jobs/postgresDurableJobService.js +696 -0
  258. package/backend/dist/platform/jobs/postgresDurableJobService.js.map +1 -0
  259. package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts +53 -0
  260. package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts.map +1 -0
  261. package/backend/dist/platform/jobs/postgresDurableJobWorker.js +393 -0
  262. package/backend/dist/platform/jobs/postgresDurableJobWorker.js.map +1 -0
  263. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts +3 -0
  264. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts.map +1 -0
  265. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js +43 -0
  266. package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js.map +1 -0
  267. package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts +166 -0
  268. package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts.map +1 -0
  269. package/backend/dist/platform/jobs/sqliteDurableJobRepository.js +1008 -0
  270. package/backend/dist/platform/jobs/sqliteDurableJobRepository.js.map +1 -0
  271. package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts +4 -0
  272. package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts.map +1 -0
  273. package/backend/dist/platform/jobs/videoGenerationEnqueuer.js +46 -0
  274. package/backend/dist/platform/jobs/videoGenerationEnqueuer.js.map +1 -0
  275. package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts +3 -0
  276. package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts.map +1 -0
  277. package/backend/dist/platform/jobs/workExecutionEnqueuer.js +38 -0
  278. package/backend/dist/platform/jobs/workExecutionEnqueuer.js.map +1 -0
  279. package/backend/dist/platform/ollamaRuntimeConfig.d.ts +40 -0
  280. package/backend/dist/platform/ollamaRuntimeConfig.d.ts.map +1 -0
  281. package/backend/dist/platform/ollamaRuntimeConfig.js +72 -0
  282. package/backend/dist/platform/ollamaRuntimeConfig.js.map +1 -0
  283. package/backend/dist/platform/recovery/backupArchive.d.ts +120 -0
  284. package/backend/dist/platform/recovery/backupArchive.d.ts.map +1 -0
  285. package/backend/dist/platform/recovery/backupArchive.js +842 -0
  286. package/backend/dist/platform/recovery/backupArchive.js.map +1 -0
  287. package/backend/dist/platform/recovery/index.d.ts +3 -0
  288. package/backend/dist/platform/recovery/index.d.ts.map +1 -0
  289. package/backend/dist/platform/recovery/index.js +8 -0
  290. package/backend/dist/platform/recovery/index.js.map +1 -0
  291. package/backend/dist/platform/recovery/teamBackupArchive.d.ts +98 -0
  292. package/backend/dist/platform/recovery/teamBackupArchive.d.ts.map +1 -0
  293. package/backend/dist/platform/recovery/teamBackupArchive.js +1203 -0
  294. package/backend/dist/platform/recovery/teamBackupArchive.js.map +1 -0
  295. package/backend/dist/platform/runtimeConfig.d.ts +70 -0
  296. package/backend/dist/platform/runtimeConfig.d.ts.map +1 -0
  297. package/backend/dist/platform/runtimeConfig.js +205 -0
  298. package/backend/dist/platform/runtimeConfig.js.map +1 -0
  299. package/backend/dist/platform/storage/aesGcmKeyring.d.ts +26 -0
  300. package/backend/dist/platform/storage/aesGcmKeyring.d.ts.map +1 -0
  301. package/backend/dist/platform/storage/aesGcmKeyring.js +135 -0
  302. package/backend/dist/platform/storage/aesGcmKeyring.js.map +1 -0
  303. package/backend/dist/platform/storage/blobReferenceRepository.d.ts +36 -0
  304. package/backend/dist/platform/storage/blobReferenceRepository.d.ts.map +1 -0
  305. package/backend/dist/platform/storage/blobReferenceRepository.js +117 -0
  306. package/backend/dist/platform/storage/blobReferenceRepository.js.map +1 -0
  307. package/backend/dist/platform/storage/blobStore.d.ts +111 -0
  308. package/backend/dist/platform/storage/blobStore.d.ts.map +1 -0
  309. package/backend/dist/platform/storage/blobStore.js +46 -0
  310. package/backend/dist/platform/storage/blobStore.js.map +1 -0
  311. package/backend/dist/platform/storage/documentVectorIndex.d.ts +44 -0
  312. package/backend/dist/platform/storage/documentVectorIndex.d.ts.map +1 -0
  313. package/backend/dist/platform/storage/documentVectorIndex.js +110 -0
  314. package/backend/dist/platform/storage/documentVectorIndex.js.map +1 -0
  315. package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts +82 -0
  316. package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts.map +1 -0
  317. package/backend/dist/platform/storage/durableBlobQuotaPolicy.js +583 -0
  318. package/backend/dist/platform/storage/durableBlobQuotaPolicy.js.map +1 -0
  319. package/backend/dist/platform/storage/index.d.ts +19 -0
  320. package/backend/dist/platform/storage/index.d.ts.map +1 -0
  321. package/backend/dist/platform/storage/index.js +35 -0
  322. package/backend/dist/platform/storage/index.js.map +1 -0
  323. package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts +120 -0
  324. package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts.map +1 -0
  325. package/backend/dist/platform/storage/localEncryptedBlobStore.js +1205 -0
  326. package/backend/dist/platform/storage/localEncryptedBlobStore.js.map +1 -0
  327. package/backend/dist/platform/storage/personaMemoryIndexing.d.ts +12 -0
  328. package/backend/dist/platform/storage/personaMemoryIndexing.d.ts.map +1 -0
  329. package/backend/dist/platform/storage/personaMemoryIndexing.js +25 -0
  330. package/backend/dist/platform/storage/personaMemoryIndexing.js.map +1 -0
  331. package/backend/dist/platform/storage/pgVectorStore.d.ts +37 -0
  332. package/backend/dist/platform/storage/pgVectorStore.d.ts.map +1 -0
  333. package/backend/dist/platform/storage/pgVectorStore.js +493 -0
  334. package/backend/dist/platform/storage/pgVectorStore.js.map +1 -0
  335. package/backend/dist/platform/storage/platformDomainRepositories.d.ts +244 -0
  336. package/backend/dist/platform/storage/platformDomainRepositories.d.ts.map +1 -0
  337. package/backend/dist/platform/storage/platformDomainRepositories.js +7 -0
  338. package/backend/dist/platform/storage/platformDomainRepositories.js.map +1 -0
  339. package/backend/dist/platform/storage/platformStorageRuntime.d.ts +35 -0
  340. package/backend/dist/platform/storage/platformStorageRuntime.d.ts.map +1 -0
  341. package/backend/dist/platform/storage/platformStorageRuntime.js +299 -0
  342. package/backend/dist/platform/storage/platformStorageRuntime.js.map +1 -0
  343. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts +4 -0
  344. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts.map +1 -0
  345. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js +1017 -0
  346. package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js.map +1 -0
  347. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts +4 -0
  348. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts.map +1 -0
  349. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js +40 -0
  350. package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js.map +1 -0
  351. package/backend/dist/platform/storage/resourceContentCleanup.d.ts +29 -0
  352. package/backend/dist/platform/storage/resourceContentCleanup.d.ts.map +1 -0
  353. package/backend/dist/platform/storage/resourceContentCleanup.js +100 -0
  354. package/backend/dist/platform/storage/resourceContentCleanup.js.map +1 -0
  355. package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts +14 -0
  356. package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts.map +1 -0
  357. package/backend/dist/platform/storage/resourceDeletionLifecycle.js +31 -0
  358. package/backend/dist/platform/storage/resourceDeletionLifecycle.js.map +1 -0
  359. package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts +140 -0
  360. package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts.map +1 -0
  361. package/backend/dist/platform/storage/s3EncryptedBlobStore.js +1309 -0
  362. package/backend/dist/platform/storage/s3EncryptedBlobStore.js.map +1 -0
  363. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts +71 -0
  364. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts.map +1 -0
  365. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js +766 -0
  366. package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js.map +1 -0
  367. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts +4 -0
  368. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts.map +1 -0
  369. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js +1037 -0
  370. package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js.map +1 -0
  371. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts +25 -0
  372. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts.map +1 -0
  373. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js +1292 -0
  374. package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js.map +1 -0
  375. package/backend/dist/platform/storage/storageFactory.d.ts +81 -0
  376. package/backend/dist/platform/storage/storageFactory.d.ts.map +1 -0
  377. package/backend/dist/platform/storage/storageFactory.js +518 -0
  378. package/backend/dist/platform/storage/storageFactory.js.map +1 -0
  379. package/backend/dist/platform/storage/storageSchemaContracts.d.ts +22 -0
  380. package/backend/dist/platform/storage/storageSchemaContracts.d.ts.map +1 -0
  381. package/backend/dist/platform/storage/storageSchemaContracts.js +299 -0
  382. package/backend/dist/platform/storage/storageSchemaContracts.js.map +1 -0
  383. package/backend/dist/platform/storage/vectorStore.d.ts +117 -0
  384. package/backend/dist/platform/storage/vectorStore.d.ts.map +1 -0
  385. package/backend/dist/platform/storage/vectorStore.js +40 -0
  386. package/backend/dist/platform/storage/vectorStore.js.map +1 -0
  387. package/backend/dist/platform/workPersistence/index.d.ts +9 -0
  388. package/backend/dist/platform/workPersistence/index.d.ts.map +1 -0
  389. package/backend/dist/platform/workPersistence/index.js +14 -0
  390. package/backend/dist/platform/workPersistence/index.js.map +1 -0
  391. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts +9 -0
  392. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts.map +1 -0
  393. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js +47 -0
  394. package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js.map +1 -0
  395. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts +3 -0
  396. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts.map +1 -0
  397. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js +28 -0
  398. package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js.map +1 -0
  399. package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts +3 -0
  400. package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts.map +1 -0
  401. package/backend/dist/platform/workPersistence/postgresWorkMigration.js +101 -0
  402. package/backend/dist/platform/workPersistence/postgresWorkMigration.js.map +1 -0
  403. package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts +79 -0
  404. package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts.map +1 -0
  405. package/backend/dist/platform/workPersistence/postgresWorkPersistence.js +521 -0
  406. package/backend/dist/platform/workPersistence/postgresWorkPersistence.js.map +1 -0
  407. package/backend/dist/platform/workPersistence/service.d.ts +6 -0
  408. package/backend/dist/platform/workPersistence/service.d.ts.map +1 -0
  409. package/backend/dist/platform/workPersistence/service.js +27 -0
  410. package/backend/dist/platform/workPersistence/service.js.map +1 -0
  411. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts +77 -0
  412. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts.map +1 -0
  413. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js +463 -0
  414. package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js.map +1 -0
  415. package/backend/dist/platform/workPersistence/types.d.ts +159 -0
  416. package/backend/dist/platform/workPersistence/types.d.ts.map +1 -0
  417. package/backend/dist/platform/workPersistence/types.js +13 -0
  418. package/backend/dist/platform/workPersistence/types.js.map +1 -0
  419. package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts +13 -0
  420. package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts.map +1 -0
  421. package/backend/dist/platform/workPersistence/workExecutionTypes.js +7 -0
  422. package/backend/dist/platform/workPersistence/workExecutionTypes.js.map +1 -0
  423. package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts +8 -0
  424. package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts.map +1 -0
  425. package/backend/dist/platform/workPersistence/workMessageContentCodec.js +25 -0
  426. package/backend/dist/platform/workPersistence/workMessageContentCodec.js.map +1 -0
  427. package/backend/dist/platform/workPersistence/workTextSafety.d.ts +3 -0
  428. package/backend/dist/platform/workPersistence/workTextSafety.d.ts.map +1 -0
  429. package/backend/dist/platform/workPersistence/workTextSafety.js +8 -0
  430. package/backend/dist/platform/workPersistence/workTextSafety.js.map +1 -0
  431. package/backend/dist/routes/agentCli.js +1 -1
  432. package/backend/dist/routes/agentCli.js.map +1 -1
  433. package/backend/dist/routes/artifacts.d.ts.map +1 -1
  434. package/backend/dist/routes/artifacts.js +2 -1
  435. package/backend/dist/routes/artifacts.js.map +1 -1
  436. package/backend/dist/routes/auth.d.ts.map +1 -1
  437. package/backend/dist/routes/auth.js +64 -18
  438. package/backend/dist/routes/auth.js.map +1 -1
  439. package/backend/dist/routes/chat.d.ts.map +1 -1
  440. package/backend/dist/routes/chat.js +519 -85
  441. package/backend/dist/routes/chat.js.map +1 -1
  442. package/backend/dist/routes/documents.d.ts.map +1 -1
  443. package/backend/dist/routes/documents.js +134 -28
  444. package/backend/dist/routes/documents.js.map +1 -1
  445. package/backend/dist/routes/embeddings.d.ts.map +1 -1
  446. package/backend/dist/routes/embeddings.js +2 -1
  447. package/backend/dist/routes/embeddings.js.map +1 -1
  448. package/backend/dist/routes/health.d.ts +3 -0
  449. package/backend/dist/routes/health.d.ts.map +1 -0
  450. package/backend/dist/routes/health.js +52 -0
  451. package/backend/dist/routes/health.js.map +1 -0
  452. package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
  453. package/backend/dist/routes/huggingfaceHub.js +2 -1
  454. package/backend/dist/routes/huggingfaceHub.js.map +1 -1
  455. package/backend/dist/routes/imageGen.d.ts.map +1 -1
  456. package/backend/dist/routes/imageGen.js +42 -10
  457. package/backend/dist/routes/imageGen.js.map +1 -1
  458. package/backend/dist/routes/jobs.d.ts +3 -0
  459. package/backend/dist/routes/jobs.d.ts.map +1 -0
  460. package/backend/dist/routes/jobs.js +117 -0
  461. package/backend/dist/routes/jobs.js.map +1 -0
  462. package/backend/dist/routes/libreClaw.d.ts.map +1 -1
  463. package/backend/dist/routes/libreClaw.js +10 -7
  464. package/backend/dist/routes/libreClaw.js.map +1 -1
  465. package/backend/dist/routes/media.d.ts.map +1 -1
  466. package/backend/dist/routes/media.js +523 -77
  467. package/backend/dist/routes/media.js.map +1 -1
  468. package/backend/dist/routes/notes.d.ts.map +1 -1
  469. package/backend/dist/routes/notes.js +21 -21
  470. package/backend/dist/routes/notes.js.map +1 -1
  471. package/backend/dist/routes/ollama.d.ts.map +1 -1
  472. package/backend/dist/routes/ollama.js +40 -12
  473. package/backend/dist/routes/ollama.js.map +1 -1
  474. package/backend/dist/routes/personas.d.ts.map +1 -1
  475. package/backend/dist/routes/personas.js +4 -2
  476. package/backend/dist/routes/personas.js.map +1 -1
  477. package/backend/dist/routes/plugins.d.ts.map +1 -1
  478. package/backend/dist/routes/plugins.js +79 -51
  479. package/backend/dist/routes/plugins.js.map +1 -1
  480. package/backend/dist/routes/preferences.d.ts.map +1 -1
  481. package/backend/dist/routes/preferences.js +290 -25
  482. package/backend/dist/routes/preferences.js.map +1 -1
  483. package/backend/dist/routes/search.d.ts.map +1 -1
  484. package/backend/dist/routes/search.js +23 -14
  485. package/backend/dist/routes/search.js.map +1 -1
  486. package/backend/dist/routes/stt.d.ts +9 -0
  487. package/backend/dist/routes/stt.d.ts.map +1 -0
  488. package/backend/dist/routes/stt.js +217 -0
  489. package/backend/dist/routes/stt.js.map +1 -0
  490. package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -1
  491. package/backend/dist/routes/systemDiagnostics.js +2 -1
  492. package/backend/dist/routes/systemDiagnostics.js.map +1 -1
  493. package/backend/dist/routes/tts.d.ts.map +1 -1
  494. package/backend/dist/routes/tts.js +577 -28
  495. package/backend/dist/routes/tts.js.map +1 -1
  496. package/backend/dist/routes/users.d.ts.map +1 -1
  497. package/backend/dist/routes/users.js +16 -25
  498. package/backend/dist/routes/users.js.map +1 -1
  499. package/backend/dist/routes/work.d.ts.map +1 -1
  500. package/backend/dist/routes/work.js +167 -113
  501. package/backend/dist/routes/work.js.map +1 -1
  502. package/backend/dist/services/agentAccessService.d.ts +2 -2
  503. package/backend/dist/services/agentAccessService.d.ts.map +1 -1
  504. package/backend/dist/services/agentAccessService.js +5 -14
  505. package/backend/dist/services/agentAccessService.js.map +1 -1
  506. package/backend/dist/services/agentCliService.d.ts +3 -2
  507. package/backend/dist/services/agentCliService.d.ts.map +1 -1
  508. package/backend/dist/services/agentCliService.js +44 -16
  509. package/backend/dist/services/agentCliService.js.map +1 -1
  510. package/backend/dist/services/assistantCompletionService.d.ts +2 -1
  511. package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
  512. package/backend/dist/services/assistantCompletionService.js +7 -3
  513. package/backend/dist/services/assistantCompletionService.js.map +1 -1
  514. package/backend/dist/services/authService.d.ts +7 -2
  515. package/backend/dist/services/authService.d.ts.map +1 -1
  516. package/backend/dist/services/authService.js +23 -10
  517. package/backend/dist/services/authService.js.map +1 -1
  518. package/backend/dist/services/chatGenerationService.d.ts +5 -4
  519. package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
  520. package/backend/dist/services/chatGenerationService.js +23 -17
  521. package/backend/dist/services/chatGenerationService.js.map +1 -1
  522. package/backend/dist/services/chatRequestService.d.ts +4 -3
  523. package/backend/dist/services/chatRequestService.d.ts.map +1 -1
  524. package/backend/dist/services/chatRequestService.js +3 -3
  525. package/backend/dist/services/chatRequestService.js.map +1 -1
  526. package/backend/dist/services/chatService.d.ts +66 -16
  527. package/backend/dist/services/chatService.d.ts.map +1 -1
  528. package/backend/dist/services/chatService.js +402 -111
  529. package/backend/dist/services/chatService.js.map +1 -1
  530. package/backend/dist/services/codexOAuthService.d.ts +2 -2
  531. package/backend/dist/services/codexOAuthService.d.ts.map +1 -1
  532. package/backend/dist/services/codexOAuthService.js +63 -7
  533. package/backend/dist/services/codexOAuthService.js.map +1 -1
  534. package/backend/dist/services/dataArchiveService.d.ts +88 -0
  535. package/backend/dist/services/dataArchiveService.d.ts.map +1 -0
  536. package/backend/dist/services/dataArchiveService.js +1027 -0
  537. package/backend/dist/services/dataArchiveService.js.map +1 -0
  538. package/backend/dist/services/documentService.d.ts +67 -14
  539. package/backend/dist/services/documentService.d.ts.map +1 -1
  540. package/backend/dist/services/documentService.js +938 -193
  541. package/backend/dist/services/documentService.js.map +1 -1
  542. package/backend/dist/services/durableChatCompletion.d.ts +16 -0
  543. package/backend/dist/services/durableChatCompletion.d.ts.map +1 -0
  544. package/backend/dist/services/durableChatCompletion.js +34 -0
  545. package/backend/dist/services/durableChatCompletion.js.map +1 -0
  546. package/backend/dist/services/durableChatGenerationService.d.ts +19 -0
  547. package/backend/dist/services/durableChatGenerationService.d.ts.map +1 -0
  548. package/backend/dist/services/durableChatGenerationService.js +341 -0
  549. package/backend/dist/services/durableChatGenerationService.js.map +1 -0
  550. package/backend/dist/services/embeddingService.d.ts +1 -1
  551. package/backend/dist/services/embeddingService.d.ts.map +1 -1
  552. package/backend/dist/services/embeddingService.js +16 -13
  553. package/backend/dist/services/embeddingService.js.map +1 -1
  554. package/backend/dist/services/encryptionService.d.ts +28 -1
  555. package/backend/dist/services/encryptionService.d.ts.map +1 -1
  556. package/backend/dist/services/encryptionService.js +131 -51
  557. package/backend/dist/services/encryptionService.js.map +1 -1
  558. package/backend/dist/services/followUpService.d.ts +1 -1
  559. package/backend/dist/services/followUpService.d.ts.map +1 -1
  560. package/backend/dist/services/followUpService.js +1 -1
  561. package/backend/dist/services/followUpService.js.map +1 -1
  562. package/backend/dist/services/galleryService.d.ts +38 -37
  563. package/backend/dist/services/galleryService.d.ts.map +1 -1
  564. package/backend/dist/services/galleryService.js +356 -251
  565. package/backend/dist/services/galleryService.js.map +1 -1
  566. package/backend/dist/services/healthService.d.ts +65 -0
  567. package/backend/dist/services/healthService.d.ts.map +1 -0
  568. package/backend/dist/services/healthService.js +379 -0
  569. package/backend/dist/services/healthService.js.map +1 -0
  570. package/backend/dist/services/legacyCiphertextIntegrity.d.ts +40 -0
  571. package/backend/dist/services/legacyCiphertextIntegrity.d.ts.map +1 -0
  572. package/backend/dist/services/legacyCiphertextIntegrity.js +406 -0
  573. package/backend/dist/services/legacyCiphertextIntegrity.js.map +1 -0
  574. package/backend/dist/services/mediaGenerationJobService.d.ts +27 -5
  575. package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -1
  576. package/backend/dist/services/mediaGenerationJobService.js +185 -55
  577. package/backend/dist/services/mediaGenerationJobService.js.map +1 -1
  578. package/backend/dist/services/memoryService.d.ts +7 -83
  579. package/backend/dist/services/memoryService.d.ts.map +1 -1
  580. package/backend/dist/services/memoryService.js +428 -573
  581. package/backend/dist/services/memoryService.js.map +1 -1
  582. package/backend/dist/services/memoryUtils.d.ts.map +1 -1
  583. package/backend/dist/services/memoryUtils.js +8 -1
  584. package/backend/dist/services/memoryUtils.js.map +1 -1
  585. package/backend/dist/services/modelAccessService.d.ts +3 -3
  586. package/backend/dist/services/modelAccessService.d.ts.map +1 -1
  587. package/backend/dist/services/modelAccessService.js +8 -16
  588. package/backend/dist/services/modelAccessService.js.map +1 -1
  589. package/backend/dist/services/mutationEngineService.d.ts +0 -7
  590. package/backend/dist/services/mutationEngineService.d.ts.map +1 -1
  591. package/backend/dist/services/mutationEngineService.js +7 -78
  592. package/backend/dist/services/mutationEngineService.js.map +1 -1
  593. package/backend/dist/services/ollamaService.d.ts +4 -4
  594. package/backend/dist/services/ollamaService.d.ts.map +1 -1
  595. package/backend/dist/services/ollamaService.js +62 -31
  596. package/backend/dist/services/ollamaService.js.map +1 -1
  597. package/backend/dist/services/personaService.d.ts.map +1 -1
  598. package/backend/dist/services/personaService.js +19 -54
  599. package/backend/dist/services/personaService.js.map +1 -1
  600. package/backend/dist/services/pluginActivationService.d.ts +6 -5
  601. package/backend/dist/services/pluginActivationService.d.ts.map +1 -1
  602. package/backend/dist/services/pluginActivationService.js +36 -76
  603. package/backend/dist/services/pluginActivationService.js.map +1 -1
  604. package/backend/dist/services/pluginAudioGenerationService.d.ts +11 -6
  605. package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -1
  606. package/backend/dist/services/pluginAudioGenerationService.js +74 -16
  607. package/backend/dist/services/pluginAudioGenerationService.js.map +1 -1
  608. package/backend/dist/services/pluginCacheInvalidation.d.ts +38 -0
  609. package/backend/dist/services/pluginCacheInvalidation.d.ts.map +1 -0
  610. package/backend/dist/services/pluginCacheInvalidation.js +198 -0
  611. package/backend/dist/services/pluginCacheInvalidation.js.map +1 -0
  612. package/backend/dist/services/pluginCapabilityRegistryService.d.ts +3 -3
  613. package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
  614. package/backend/dist/services/pluginCapabilityRegistryService.js +11 -7
  615. package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
  616. package/backend/dist/services/pluginCredentialsService.d.ts +9 -8
  617. package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
  618. package/backend/dist/services/pluginCredentialsService.js +48 -89
  619. package/backend/dist/services/pluginCredentialsService.js.map +1 -1
  620. package/backend/dist/services/pluginEmbeddingService.d.ts +8 -7
  621. package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
  622. package/backend/dist/services/pluginEmbeddingService.js +13 -11
  623. package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
  624. package/backend/dist/services/pluginImageGenerationService.d.ts +10 -8
  625. package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
  626. package/backend/dist/services/pluginImageGenerationService.js +119 -14
  627. package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
  628. package/backend/dist/services/pluginSTTService.d.ts +47 -0
  629. package/backend/dist/services/pluginSTTService.d.ts.map +1 -0
  630. package/backend/dist/services/pluginSTTService.js +199 -0
  631. package/backend/dist/services/pluginSTTService.js.map +1 -0
  632. package/backend/dist/services/pluginService.d.ts +94 -40
  633. package/backend/dist/services/pluginService.d.ts.map +1 -1
  634. package/backend/dist/services/pluginService.js +799 -274
  635. package/backend/dist/services/pluginService.js.map +1 -1
  636. package/backend/dist/services/pluginTTSService.d.ts +26 -8
  637. package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
  638. package/backend/dist/services/pluginTTSService.js +277 -25
  639. package/backend/dist/services/pluginTTSService.js.map +1 -1
  640. package/backend/dist/services/pluginUsageService.d.ts +4 -4
  641. package/backend/dist/services/pluginUsageService.d.ts.map +1 -1
  642. package/backend/dist/services/pluginUsageService.js +44 -93
  643. package/backend/dist/services/pluginUsageService.js.map +1 -1
  644. package/backend/dist/services/pluginVariablesService.d.ts +14 -7
  645. package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
  646. package/backend/dist/services/pluginVariablesService.js +116 -81
  647. package/backend/dist/services/pluginVariablesService.js.map +1 -1
  648. package/backend/dist/services/pluginVideoGenerationService.d.ts +19 -8
  649. package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -1
  650. package/backend/dist/services/pluginVideoGenerationService.js +116 -20
  651. package/backend/dist/services/pluginVideoGenerationService.js.map +1 -1
  652. package/backend/dist/services/preferencesService.d.ts +31 -21
  653. package/backend/dist/services/preferencesService.d.ts.map +1 -1
  654. package/backend/dist/services/preferencesService.js +104 -102
  655. package/backend/dist/services/preferencesService.js.map +1 -1
  656. package/backend/dist/services/recoveryInventoryService.d.ts +244 -0
  657. package/backend/dist/services/recoveryInventoryService.d.ts.map +1 -0
  658. package/backend/dist/services/recoveryInventoryService.js +1436 -0
  659. package/backend/dist/services/recoveryInventoryService.js.map +1 -0
  660. package/backend/dist/services/simpleGitHubOAuth.js +3 -3
  661. package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
  662. package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -1
  663. package/backend/dist/services/simpleHuggingFaceOAuth.js +3 -3
  664. package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
  665. package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -1
  666. package/backend/dist/services/systemDiagnosticsService.js +2 -2
  667. package/backend/dist/services/systemDiagnosticsService.js.map +1 -1
  668. package/backend/dist/services/systemSettingsService.d.ts +5 -0
  669. package/backend/dist/services/systemSettingsService.d.ts.map +1 -0
  670. package/backend/dist/services/systemSettingsService.js +24 -0
  671. package/backend/dist/services/systemSettingsService.js.map +1 -0
  672. package/backend/dist/services/titleGenerationService.d.ts +1 -1
  673. package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
  674. package/backend/dist/services/titleGenerationService.js +1 -1
  675. package/backend/dist/services/titleGenerationService.js.map +1 -1
  676. package/backend/dist/services/voiceProfileService.d.ts +44 -0
  677. package/backend/dist/services/voiceProfileService.d.ts.map +1 -0
  678. package/backend/dist/services/voiceProfileService.js +195 -0
  679. package/backend/dist/services/voiceProfileService.js.map +1 -0
  680. package/backend/dist/services/webSearchService.d.ts +7 -7
  681. package/backend/dist/services/webSearchService.d.ts.map +1 -1
  682. package/backend/dist/services/webSearchService.js +40 -35
  683. package/backend/dist/services/webSearchService.js.map +1 -1
  684. package/backend/dist/services/websocketTicketService.d.ts +39 -0
  685. package/backend/dist/services/websocketTicketService.d.ts.map +1 -0
  686. package/backend/dist/services/websocketTicketService.js +183 -0
  687. package/backend/dist/services/websocketTicketService.js.map +1 -0
  688. package/backend/dist/services/workAccessService.d.ts +3 -3
  689. package/backend/dist/services/workAccessService.d.ts.map +1 -1
  690. package/backend/dist/services/workAccessService.js +8 -16
  691. package/backend/dist/services/workAccessService.js.map +1 -1
  692. package/backend/dist/services/workAdminService.d.ts +3 -3
  693. package/backend/dist/services/workAdminService.d.ts.map +1 -1
  694. package/backend/dist/services/workAdminService.js +4 -4
  695. package/backend/dist/services/workAdminService.js.map +1 -1
  696. package/backend/dist/services/workAgentService.d.ts +25 -1
  697. package/backend/dist/services/workAgentService.d.ts.map +1 -1
  698. package/backend/dist/services/workAgentService.js +294 -126
  699. package/backend/dist/services/workAgentService.js.map +1 -1
  700. package/backend/dist/services/workEventService.d.ts +15 -2
  701. package/backend/dist/services/workEventService.d.ts.map +1 -1
  702. package/backend/dist/services/workEventService.js +201 -3
  703. package/backend/dist/services/workEventService.js.map +1 -1
  704. package/backend/dist/services/workKubernetesDriver.d.ts +8 -7
  705. package/backend/dist/services/workKubernetesDriver.d.ts.map +1 -1
  706. package/backend/dist/services/workKubernetesDriver.js +65 -21
  707. package/backend/dist/services/workKubernetesDriver.js.map +1 -1
  708. package/backend/dist/services/workModelProviderService.d.ts +2 -2
  709. package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
  710. package/backend/dist/services/workModelProviderService.js +38 -34
  711. package/backend/dist/services/workModelProviderService.js.map +1 -1
  712. package/backend/dist/services/workPolicyService.d.ts +7 -7
  713. package/backend/dist/services/workPolicyService.d.ts.map +1 -1
  714. package/backend/dist/services/workPolicyService.js +50 -51
  715. package/backend/dist/services/workPolicyService.js.map +1 -1
  716. package/backend/dist/services/workPreviewProxyService.d.ts +8 -8
  717. package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -1
  718. package/backend/dist/services/workPreviewProxyService.js +47 -44
  719. package/backend/dist/services/workPreviewProxyService.js.map +1 -1
  720. package/backend/dist/services/workRuntimeDriver.d.ts +21 -18
  721. package/backend/dist/services/workRuntimeDriver.d.ts.map +1 -1
  722. package/backend/dist/services/workRuntimeDriver.js +69 -20
  723. package/backend/dist/services/workRuntimeDriver.js.map +1 -1
  724. package/backend/dist/services/workRuntimeService.d.ts +18 -13
  725. package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
  726. package/backend/dist/services/workRuntimeService.js +438 -194
  727. package/backend/dist/services/workRuntimeService.js.map +1 -1
  728. package/backend/dist/services/workRuntimeShared.d.ts +2 -0
  729. package/backend/dist/services/workRuntimeShared.d.ts.map +1 -1
  730. package/backend/dist/services/workRuntimeShared.js.map +1 -1
  731. package/backend/dist/services/workTaskService.d.ts +42 -36
  732. package/backend/dist/services/workTaskService.d.ts.map +1 -1
  733. package/backend/dist/services/workTaskService.js +445 -350
  734. package/backend/dist/services/workTaskService.js.map +1 -1
  735. package/backend/dist/services/workTerminalService.d.ts +1 -1
  736. package/backend/dist/services/workTerminalService.d.ts.map +1 -1
  737. package/backend/dist/services/workTerminalService.js +33 -6
  738. package/backend/dist/services/workTerminalService.js.map +1 -1
  739. package/backend/dist/storage.d.ts +72 -40
  740. package/backend/dist/storage.d.ts.map +1 -1
  741. package/backend/dist/storage.js +312 -660
  742. package/backend/dist/storage.js.map +1 -1
  743. package/backend/dist/types/index.d.ts +28 -0
  744. package/backend/dist/types/index.d.ts.map +1 -1
  745. package/backend/dist/types/index.js.map +1 -1
  746. package/backend/dist/types/work.d.ts +7 -2
  747. package/backend/dist/types/work.d.ts.map +1 -1
  748. package/backend/dist/utils/chatCancellation.d.ts +48 -0
  749. package/backend/dist/utils/chatCancellation.d.ts.map +1 -0
  750. package/backend/dist/utils/chatCancellation.js +152 -0
  751. package/backend/dist/utils/chatCancellation.js.map +1 -0
  752. package/backend/dist/utils/chatDocumentContext.d.ts +1 -1
  753. package/backend/dist/utils/chatDocumentContext.d.ts.map +1 -1
  754. package/backend/dist/utils/chatDocumentContext.js +11 -5
  755. package/backend/dist/utils/chatDocumentContext.js.map +1 -1
  756. package/backend/dist/utils/chatStreamCoalescer.d.ts +15 -0
  757. package/backend/dist/utils/chatStreamCoalescer.d.ts.map +1 -0
  758. package/backend/dist/utils/chatStreamCoalescer.js +59 -0
  759. package/backend/dist/utils/chatStreamCoalescer.js.map +1 -0
  760. package/backend/dist/utils/dataDirectory.d.ts +49 -0
  761. package/backend/dist/utils/dataDirectory.d.ts.map +1 -0
  762. package/backend/dist/utils/dataDirectory.js +291 -0
  763. package/backend/dist/utils/dataDirectory.js.map +1 -0
  764. package/backend/dist/utils/generationUtils.d.ts.map +1 -1
  765. package/backend/dist/utils/generationUtils.js +18 -6
  766. package/backend/dist/utils/generationUtils.js.map +1 -1
  767. package/backend/dist/utils/jwt.d.ts.map +1 -1
  768. package/backend/dist/utils/jwt.js +2 -3
  769. package/backend/dist/utils/jwt.js.map +1 -1
  770. package/backend/dist/utils/ollamaModelDefaults.d.ts.map +1 -1
  771. package/backend/dist/utils/ollamaModelDefaults.js +2 -7
  772. package/backend/dist/utils/ollamaModelDefaults.js.map +1 -1
  773. package/backend/dist/utils/ollamaStreaming.d.ts +2 -1
  774. package/backend/dist/utils/ollamaStreaming.d.ts.map +1 -1
  775. package/backend/dist/utils/ollamaStreaming.js +49 -11
  776. package/backend/dist/utils/ollamaStreaming.js.map +1 -1
  777. package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -1
  778. package/backend/dist/utils/pluginConnectionVariables.js +11 -3
  779. package/backend/dist/utils/pluginConnectionVariables.js.map +1 -1
  780. package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -1
  781. package/backend/dist/utils/pluginDefinitionTrust.js +4 -3
  782. package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -1
  783. package/backend/dist/utils/pluginStreaming.d.ts +2 -1
  784. package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
  785. package/backend/dist/utils/pluginStreaming.js +5 -1
  786. package/backend/dist/utils/pluginStreaming.js.map +1 -1
  787. package/backend/dist/utils/pluginUpload.d.ts +1 -0
  788. package/backend/dist/utils/pluginUpload.d.ts.map +1 -1
  789. package/backend/dist/utils/pluginUpload.js +9 -2
  790. package/backend/dist/utils/pluginUpload.js.map +1 -1
  791. package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
  792. package/backend/dist/utils/pluginValidation.js +29 -1
  793. package/backend/dist/utils/pluginValidation.js.map +1 -1
  794. package/backend/dist/utils/sttAudioUpload.d.ts +24 -0
  795. package/backend/dist/utils/sttAudioUpload.d.ts.map +1 -0
  796. package/backend/dist/utils/sttAudioUpload.js +500 -0
  797. package/backend/dist/utils/sttAudioUpload.js.map +1 -0
  798. package/backend/dist/utils/ttsVoiceCloneUpload.d.ts +34 -0
  799. package/backend/dist/utils/ttsVoiceCloneUpload.d.ts.map +1 -0
  800. package/backend/dist/utils/ttsVoiceCloneUpload.js +224 -0
  801. package/backend/dist/utils/ttsVoiceCloneUpload.js.map +1 -0
  802. package/backend/dist/utils/websocketMessages.d.ts +2 -1
  803. package/backend/dist/utils/websocketMessages.d.ts.map +1 -1
  804. package/backend/dist/utils/websocketMessages.js +16 -2
  805. package/backend/dist/utils/websocketMessages.js.map +1 -1
  806. package/backend/dist/websocketServer.d.ts +4 -1
  807. package/backend/dist/websocketServer.d.ts.map +1 -1
  808. package/backend/dist/websocketServer.js +290 -44
  809. package/backend/dist/websocketServer.js.map +1 -1
  810. package/backend/dist/workTerminalServer.d.ts +9 -0
  811. package/backend/dist/workTerminalServer.d.ts.map +1 -1
  812. package/backend/dist/workTerminalServer.js +221 -52
  813. package/backend/dist/workTerminalServer.js.map +1 -1
  814. package/backend/dist/worker.d.ts +2 -0
  815. package/backend/dist/worker.d.ts.map +1 -0
  816. package/backend/dist/worker.js +250 -0
  817. package/backend/dist/worker.js.map +1 -0
  818. package/backend/package.json +19 -9
  819. package/bin/cli.js +126 -99
  820. package/bin/runtime-paths.js +108 -0
  821. package/frontend/dist/artifact-runtime/.build-fingerprint +1 -1
  822. package/frontend/dist/artifact-runtime/framer-motion.js +5 -5
  823. package/frontend/dist/artifact-runtime/lucide-react.js +1 -1
  824. package/frontend/dist/assets/index-CUhEG7E2.js +33 -0
  825. package/frontend/dist/assets/index-kxtZQLV6.css +1 -0
  826. package/frontend/dist/assets/{markdown-math-ClQbWekD.css → markdown-math-ClTedVi7.css} +1 -1
  827. package/frontend/dist/index.html +18 -18
  828. package/frontend/dist/js/{ArtifactContainer-Dy2Q0iIL.js → ArtifactContainer-BTEDhBnv.js} +1 -1
  829. package/frontend/dist/js/{ArtifactDemoPage-K79dWshB.js → ArtifactDemoPage-B0gN3YTl.js} +1 -1
  830. package/frontend/dist/js/{ArtifactSandboxFrame-DhqLNUtY.js → ArtifactSandboxFrame-CLBXQkZs.js} +3 -3
  831. package/frontend/dist/js/{ArtifactSlideOutPanel-Cl8JG7bz.js → ArtifactSlideOutPanel-CfqHPFdE.js} +1 -1
  832. package/frontend/dist/js/{Button-CTXHujOd.js → Button-BV44cTnj.js} +1 -1
  833. package/frontend/dist/js/ChatPage-DIkAXZWA.js +23 -0
  834. package/frontend/dist/js/{FirstTimeSetup-kHhRzGJ8.js → FirstTimeSetup-B8phXGNA.js} +1 -1
  835. package/frontend/dist/js/GalleryPage-W4uI043I.js +1 -0
  836. package/frontend/dist/js/{HomePage-C1L8WAXL.js → HomePage-DlxehbyO.js} +1 -1
  837. package/frontend/dist/js/{LibreClawPage-Dyua8IUu.js → LibreClawPage-CgD0_G_F.js} +1 -1
  838. package/frontend/dist/js/{ModelManagerModals-CuMRGUd-.js → ModelManagerModals-D7jIT3v1.js} +1 -1
  839. package/frontend/dist/js/{ModelSelector-CqHc-Ln4.js → ModelSelector-BYxJU1UV.js} +1 -1
  840. package/frontend/dist/js/ModelsPage-C4XdCKP5.js +2 -0
  841. package/frontend/dist/js/NotesPage-CDECOl4V.js +1 -0
  842. package/frontend/dist/js/{OptimizedSyntaxHighlighter-CWYUn9Oe.js → OptimizedSyntaxHighlighter-XwqZEoTf.js} +1 -1
  843. package/frontend/dist/js/{PersonasPage-D_6WBCH5.js → PersonasPage-CjSLPrgS.js} +2 -2
  844. package/frontend/dist/js/PluginUsagePage-DJOXJuH4.js +1 -0
  845. package/frontend/dist/js/RichMessageContent-Debeh6bi.js +3 -0
  846. package/frontend/dist/js/SettingsModal-cUqAeYUP.js +1 -0
  847. package/frontend/dist/js/{SettingsToggle-DLHlCDBl.js → SettingsToggle-WTa0rgvY.js} +1 -1
  848. package/frontend/dist/js/{SystemPage-BMWEet9e.js → SystemPage-DxPw0GS7.js} +1 -1
  849. package/frontend/dist/js/UserManagementPage-CEdYFe_Z.js +1 -0
  850. package/frontend/dist/js/WorkPage-DDVeuG_9.js +6 -0
  851. package/frontend/dist/js/api-IzobHGND.js +14 -0
  852. package/frontend/dist/js/appStore-DKwC2vgn.js +2 -0
  853. package/frontend/dist/js/ar-xTSvTq05.js +2 -0
  854. package/frontend/dist/js/authStore-OaTuapL7.js +4 -0
  855. package/frontend/dist/js/{babel-CmENXdZw.js → babel-D24oDI9y.js} +1 -1
  856. package/frontend/dist/js/bn-iYAsohEA.js +2 -0
  857. package/frontend/dist/js/chatStore-DXGUVLXD.js +3 -0
  858. package/frontend/dist/js/{config-DkV1ka7I.js → config-DPEEuTAe.js} +1 -1
  859. package/frontend/dist/js/cs-YBHN88Hb.js +2 -0
  860. package/frontend/dist/js/da-D7qlLy_k.js +2 -0
  861. package/frontend/dist/js/de-DV671k2c.js +2 -0
  862. package/frontend/dist/js/es-kyBgzNq-.js +2 -0
  863. package/frontend/dist/js/{estree-D5KP-qbw.js → estree-ChwJsD2w.js} +1 -1
  864. package/frontend/dist/js/fr-Cw1vut7I.js +2 -0
  865. package/frontend/dist/js/hi-DWEFC024.js +2 -0
  866. package/frontend/dist/js/{html-Cm9c2akd.js → html-DFrVjciF.js} +1 -1
  867. package/frontend/dist/js/id-DlMHjjy0.js +2 -0
  868. package/frontend/dist/js/is-B9E_a7dG.js +2 -0
  869. package/frontend/dist/js/it-DawmVbLC.js +2 -0
  870. package/frontend/dist/js/ja-DmVvwY3W.js +2 -0
  871. package/frontend/dist/js/ko-DzOPpkVs.js +2 -0
  872. package/frontend/dist/js/{markdown-B2u7CnKN.js → markdown-FLLx7b67.js} +1 -1
  873. package/frontend/dist/js/markdown-core-BmPPZiuD.js +31 -0
  874. package/frontend/dist/js/{markdown-math-B7FlYsmr.js → markdown-math-mH7AZ_mb.js} +6 -6
  875. package/frontend/dist/js/{messageCodeStyles-DalG2j6U.js → messageCodeStyles-CBkkZY4n.js} +1 -1
  876. package/frontend/dist/js/ms-DpsaOPht.js +2 -0
  877. package/frontend/dist/js/nl-B1d8W22n.js +2 -0
  878. package/frontend/dist/js/pl-nCncRVgt.js +2 -0
  879. package/frontend/dist/js/{postcss-B5WIGhAY.js → postcss-Bx9CTcIc.js} +1 -1
  880. package/frontend/dist/js/pt-DHw8fGuu.js +2 -0
  881. package/frontend/dist/js/{react-vendor-DPNXrO-8.js → react-vendor-C5yShNlM.js} +1 -1
  882. package/frontend/dist/js/{router-vendor-Ca9zqOqT.js → router-vendor-CbPDks39.js} +1 -1
  883. package/frontend/dist/js/ru-Derl_YP_.js +2 -0
  884. package/frontend/dist/js/{standalone-Dwm1daef.js → standalone-i8-5bg5p.js} +1 -1
  885. package/frontend/dist/js/sv-pJAfBVo0.js +2 -0
  886. package/frontend/dist/js/{syntax-highlight-Ca9bHsaz.js → syntax-highlight-3EEX6CGL.js} +3 -3
  887. package/frontend/dist/js/th-C_7fIGnk.js +2 -0
  888. package/frontend/dist/js/tr-CPqsJvaP.js +2 -0
  889. package/frontend/dist/js/{typescript-CwieSptM.js → typescript-CQ3x-Uni.js} +1 -1
  890. package/frontend/dist/js/{ui-BnDZpjfc.js → ui-BHhR3Vok.js} +2 -2
  891. package/frontend/dist/js/ui-vendor-D3Ahl1x5.js +177 -0
  892. package/frontend/dist/js/uk-3o8P_kFi.js +2 -0
  893. package/frontend/dist/js/{useTranslation-CXY69qNk.js → useTranslation-C3ei3mJq.js} +1 -1
  894. package/frontend/dist/js/{utils-BM0_0iFj.js → utils-CuC1beTY.js} +1 -1
  895. package/frontend/dist/js/{utils-vendor-1zob7nK9.js → utils-vendor-BBa8OxtB.js} +1 -1
  896. package/frontend/dist/js/vi-Dv6N7OVD.js +2 -0
  897. package/frontend/dist/js/{workApi-BOS7crs9.js → workApi-Czu69yWS.js} +2 -2
  898. package/frontend/dist/js/{yaml-QD4znPfZ.js → yaml-DioTxVLA.js} +1 -1
  899. package/frontend/dist/js/zh-qg5iqtPi.js +2 -0
  900. package/package.json +16 -5
  901. package/plugins/huggingface.json +12 -3
  902. package/plugins/llama-cpp.json +18 -6
  903. package/plugins/longcat-audiodit.json +114 -0
  904. package/plugins/openai.json +18 -0
  905. package/frontend/dist/assets/index-BBpNbfKW.js +0 -16
  906. package/frontend/dist/assets/index-BLATyFmD.css +0 -1
  907. package/frontend/dist/js/ChatPage-BBayfMLS.js +0 -16
  908. package/frontend/dist/js/GalleryPage-By8VI39Q.js +0 -1
  909. package/frontend/dist/js/ModelsPage-ODeXhDDk.js +0 -2
  910. package/frontend/dist/js/NotesPage-CApzDjOq.js +0 -1
  911. package/frontend/dist/js/PluginUsagePage-kutS6SOd.js +0 -1
  912. package/frontend/dist/js/RichMessageContent-g6WT75Te.js +0 -3
  913. package/frontend/dist/js/SettingsModal-B7z51BCx.js +0 -1
  914. package/frontend/dist/js/UserManagementPage-D08lM51c.js +0 -1
  915. package/frontend/dist/js/WorkPage-DdVLefsK.js +0 -6
  916. package/frontend/dist/js/api-CLEmGcEh.js +0 -14
  917. package/frontend/dist/js/appStore-CGdhvp9P.js +0 -2
  918. package/frontend/dist/js/ar-BTmB2WVm.js +0 -2
  919. package/frontend/dist/js/authStore-Dh3beEOq.js +0 -4
  920. package/frontend/dist/js/bn-CQnH7YVT.js +0 -2
  921. package/frontend/dist/js/chatStore-CDeYWL_q.js +0 -3
  922. package/frontend/dist/js/cs-oTTZkQXr.js +0 -2
  923. package/frontend/dist/js/da-Br0gB6J6.js +0 -2
  924. package/frontend/dist/js/de-DE2iztTF.js +0 -2
  925. package/frontend/dist/js/es-DgthfVtl.js +0 -2
  926. package/frontend/dist/js/fr-BjxjFwPh.js +0 -2
  927. package/frontend/dist/js/hi-D1q7E-9N.js +0 -2
  928. package/frontend/dist/js/id-CDJZqLTF.js +0 -2
  929. package/frontend/dist/js/is-BU7Um_Tq.js +0 -2
  930. package/frontend/dist/js/it-CdAxr8P_.js +0 -2
  931. package/frontend/dist/js/ja-BLbQwz9u.js +0 -2
  932. package/frontend/dist/js/ko-CY5lpkAe.js +0 -2
  933. package/frontend/dist/js/markdown-core-DHnR5Hw8.js +0 -16
  934. package/frontend/dist/js/ms-tQ8AYXEQ.js +0 -2
  935. package/frontend/dist/js/nl-CRNi2oWT.js +0 -2
  936. package/frontend/dist/js/pl-CWtFRS_W.js +0 -2
  937. package/frontend/dist/js/pt-C7SPoLF8.js +0 -2
  938. package/frontend/dist/js/ru-Dz4AX8xc.js +0 -2
  939. package/frontend/dist/js/sv-ETy5-boa.js +0 -2
  940. package/frontend/dist/js/th-DpuMqvxU.js +0 -2
  941. package/frontend/dist/js/tr-C-1AYAqg.js +0 -2
  942. package/frontend/dist/js/ui-vendor-xUzKqAXI.js +0 -177
  943. package/frontend/dist/js/uk-CyS680gr.js +0 -2
  944. package/frontend/dist/js/vi-BG8HuiTz.js +0 -2
  945. package/frontend/dist/js/zh-NCs2mkHj.js +0 -2
@@ -0,0 +1,1309 @@
1
+ /*
2
+ * Libre WebUI
3
+ * Copyright (C) 2025 Kroonen AI, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at:
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import crypto from 'node:crypto';
18
+ import { Readable } from 'node:stream';
19
+ import { DeleteObjectCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, S3Client, } from '@aws-sdk/client-s3';
20
+ import { Upload } from '@aws-sdk/lib-storage';
21
+ import { parseAesGcmEnvelope, StorageEncryptionError, } from './aesGcmKeyring.js';
22
+ import { BlobNotFoundError, BlobStoreError, NoopBlobQuotaPolicy, } from './blobStore.js';
23
+ const FORMAT_VERSION = 1;
24
+ const AUTH_TAG_BYTES = 16;
25
+ const BODY_NONCE_BYTES = 8;
26
+ const METADATA_IV_BYTES = 12;
27
+ const DEFAULT_CHUNK_BYTES = 1024 * 1024;
28
+ const DEFAULT_MAX_OBJECT_BYTES = 512 * 1024 * 1024;
29
+ const MIN_CHUNK_BYTES = 64 * 1024;
30
+ const MAX_CHUNK_BYTES = 8 * 1024 * 1024;
31
+ const MAX_METADATA_BYTES = 64 * 1024;
32
+ const MAX_RECORDS_PER_RECONCILIATION = 10000;
33
+ const MAX_OBJECT_VERSIONS_PER_PURGE = 10000;
34
+ const OBJECT_VERSION_PAGE_SIZE = 1000;
35
+ const REQUIRED_EMPTY_VERSION_LISTS = 2;
36
+ const OBJECT_LIFECYCLE_LOCK_NAMESPACE = 'libre-s3-blob-lifecycle-v1';
37
+ const BLOB_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
38
+ const PURPOSE_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,63}$/;
39
+ const METADATA_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
40
+ const PREFIX_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$/;
41
+ const blobError = (code, message, cause) => new BlobStoreError(code, message, cause);
42
+ const throwIfAborted = (signal) => {
43
+ if (signal?.aborted) {
44
+ throw blobError('aborted', 'Blob operation was aborted', signal.reason);
45
+ }
46
+ };
47
+ const hasClientOwnership = (executor) => 'withClient' in executor &&
48
+ typeof executor.withClient === 'function';
49
+ const isPinnedClient = (executor) => 'release' in executor &&
50
+ typeof executor.release === 'function';
51
+ const encodeReconciliationCursor = (cursor) => Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url');
52
+ const decodeReconciliationCursor = (value) => {
53
+ if (!value)
54
+ return undefined;
55
+ try {
56
+ const parsed = JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));
57
+ if (parsed.version !== 1 ||
58
+ typeof parsed.afterKey !== 'string' ||
59
+ parsed.afterKey.length === 0 ||
60
+ Buffer.byteLength(parsed.afterKey, 'utf8') > 1024) {
61
+ throw new Error('invalid cursor');
62
+ }
63
+ return { version: 1, afterKey: parsed.afterKey };
64
+ }
65
+ catch {
66
+ throw blobError('invalid-input', 'Invalid S3 reconciliation cursor');
67
+ }
68
+ };
69
+ const validateString = (value, field, maximumBytes) => {
70
+ if (typeof value !== 'string' ||
71
+ value.length === 0 ||
72
+ Buffer.byteLength(value, 'utf8') > maximumBytes ||
73
+ [...value].some(character => {
74
+ const codePoint = character.codePointAt(0) ?? 0;
75
+ return codePoint <= 31 || codePoint === 127;
76
+ })) {
77
+ throw blobError('invalid-input', `Invalid blob ${field}`);
78
+ }
79
+ };
80
+ const validateBlobId = (id) => {
81
+ if (!BLOB_ID_PATTERN.test(id))
82
+ throw new BlobNotFoundError();
83
+ };
84
+ const normalizeMetadata = (metadata) => {
85
+ const entries = Object.entries(metadata ?? {});
86
+ if (entries.length > 32) {
87
+ throw blobError('invalid-input', 'Blob metadata has too many fields');
88
+ }
89
+ const normalized = {};
90
+ for (const [key, value] of entries.sort(([left], [right]) => left.localeCompare(right))) {
91
+ if (!METADATA_KEY_PATTERN.test(key)) {
92
+ throw blobError('invalid-input', `Invalid blob metadata key: ${key}`);
93
+ }
94
+ if (typeof value !== 'string' ||
95
+ Buffer.byteLength(value, 'utf8') > 4096 ||
96
+ value.includes('\u0000')) {
97
+ throw blobError('invalid-input', `Invalid blob metadata value: ${key}`);
98
+ }
99
+ normalized[key] = value;
100
+ }
101
+ return Object.freeze(normalized);
102
+ };
103
+ const validatePutRequest = (request, maxObjectBytes) => {
104
+ validateString(request.ownerUserId, 'owner', 256);
105
+ if (!PURPOSE_PATTERN.test(request.purpose)) {
106
+ throw blobError('invalid-input', 'Invalid blob purpose');
107
+ }
108
+ validateString(request.contentType, 'content type', 255);
109
+ if (request.originalFilename !== undefined) {
110
+ validateString(request.originalFilename, 'filename', 255);
111
+ }
112
+ if (request.expectedSize !== undefined &&
113
+ (!Number.isSafeInteger(request.expectedSize) ||
114
+ request.expectedSize < 0 ||
115
+ request.expectedSize > maxObjectBytes)) {
116
+ throw blobError('invalid-input', 'Invalid expected blob size');
117
+ }
118
+ return normalizeMetadata(request.metadata);
119
+ };
120
+ const keyAad = (id) => Buffer.from(JSON.stringify(['libre-s3-blob-key', FORMAT_VERSION, id]), 'utf8');
121
+ const metadataAad = (id, objectKey) => Buffer.from(JSON.stringify(['libre-s3-blob-metadata', FORMAT_VERSION, id, objectKey]), 'utf8');
122
+ const chunkAad = (metadata, chunkIndex, plaintextBytes) => Buffer.from(JSON.stringify([
123
+ 'libre-blob-chunk',
124
+ FORMAT_VERSION,
125
+ metadata.id,
126
+ metadata.ownerUserId,
127
+ metadata.purpose,
128
+ chunkIndex,
129
+ plaintextBytes,
130
+ ]), 'utf8');
131
+ const createChunkIv = (nonce, index) => {
132
+ if (nonce.length !== BODY_NONCE_BYTES || index < 0 || index > 0xffffffff) {
133
+ throw blobError('corrupt', 'Invalid encrypted blob chunk nonce');
134
+ }
135
+ const iv = Buffer.allocUnsafe(12);
136
+ nonce.copy(iv, 0);
137
+ iv.writeUInt32BE(index, BODY_NONCE_BYTES);
138
+ return iv;
139
+ };
140
+ const fixedChunks = async function* (source, chunkBytes, signal) {
141
+ let carry = Buffer.alloc(0);
142
+ for await (const value of source) {
143
+ throwIfAborted(signal);
144
+ let input = Buffer.isBuffer(value)
145
+ ? value
146
+ : Buffer.from(value.buffer, value.byteOffset, value.byteLength);
147
+ if (carry.length > 0) {
148
+ const needed = chunkBytes - carry.length;
149
+ if (input.length < needed) {
150
+ carry = Buffer.concat([carry, input], carry.length + input.length);
151
+ continue;
152
+ }
153
+ yield Buffer.concat([carry, input.subarray(0, needed)], chunkBytes);
154
+ carry = Buffer.alloc(0);
155
+ input = input.subarray(needed);
156
+ }
157
+ while (input.length >= chunkBytes) {
158
+ yield input.subarray(0, chunkBytes);
159
+ input = input.subarray(chunkBytes);
160
+ }
161
+ if (input.length > 0)
162
+ carry = Buffer.from(input);
163
+ }
164
+ throwIfAborted(signal);
165
+ if (carry.length > 0)
166
+ yield carry;
167
+ };
168
+ const safeInteger = (value, description) => {
169
+ const parsed = typeof value === 'number' ? value : Number(value);
170
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
171
+ throw blobError('corrupt', `Invalid S3 blob ${description}`);
172
+ }
173
+ return parsed;
174
+ };
175
+ const isNotFound = (error) => {
176
+ if (!error || typeof error !== 'object')
177
+ return false;
178
+ const candidate = error;
179
+ return (candidate.name === 'NoSuchKey' ||
180
+ candidate.name === 'NotFound' ||
181
+ candidate.Code === 'NoSuchKey' ||
182
+ candidate.$metadata?.httpStatusCode === 404);
183
+ };
184
+ const publicDescriptor = (metadata) => ({
185
+ id: metadata.id,
186
+ ownerUserId: metadata.ownerUserId,
187
+ purpose: metadata.purpose,
188
+ contentType: metadata.contentType,
189
+ ...(metadata.originalFilename
190
+ ? { originalFilename: metadata.originalFilename }
191
+ : {}),
192
+ metadata: Object.freeze({ ...metadata.metadata }),
193
+ size: metadata.size,
194
+ sha256: metadata.sha256,
195
+ createdAt: metadata.createdAt,
196
+ encryptionKeyId: metadata.encryptionKeyId,
197
+ formatVersion: metadata.formatVersion,
198
+ });
199
+ const isStoredMetadata = (value) => {
200
+ if (!value || typeof value !== 'object' || Array.isArray(value))
201
+ return false;
202
+ const item = value;
203
+ return (typeof item.id === 'string' &&
204
+ BLOB_ID_PATTERN.test(item.id) &&
205
+ typeof item.ownerUserId === 'string' &&
206
+ item.ownerUserId.length > 0 &&
207
+ typeof item.purpose === 'string' &&
208
+ PURPOSE_PATTERN.test(item.purpose) &&
209
+ typeof item.contentType === 'string' &&
210
+ typeof item.objectKey === 'string' &&
211
+ typeof item.size === 'number' &&
212
+ Number.isSafeInteger(item.size) &&
213
+ item.size >= 0 &&
214
+ typeof item.sha256 === 'string' &&
215
+ /^[0-9a-f]{64}$/.test(item.sha256) &&
216
+ typeof item.ciphertextSha256 === 'string' &&
217
+ /^[0-9a-f]{64}$/.test(item.ciphertextSha256) &&
218
+ typeof item.encryptedBytes === 'number' &&
219
+ Number.isSafeInteger(item.encryptedBytes) &&
220
+ item.encryptedBytes >= 0 &&
221
+ typeof item.chunkBytes === 'number' &&
222
+ Number.isSafeInteger(item.chunkBytes) &&
223
+ item.chunkBytes >= MIN_CHUNK_BYTES &&
224
+ item.chunkBytes <= MAX_CHUNK_BYTES &&
225
+ typeof item.chunkCount === 'number' &&
226
+ Number.isSafeInteger(item.chunkCount) &&
227
+ item.chunkCount >= 0 &&
228
+ typeof item.bodyNonce === 'string' &&
229
+ typeof item.createdAt === 'string' &&
230
+ Number.isFinite(Date.parse(item.createdAt)) &&
231
+ typeof item.encryptionKeyId === 'string' &&
232
+ item.formatVersion === FORMAT_VERSION &&
233
+ Boolean(item.metadata) &&
234
+ typeof item.metadata === 'object' &&
235
+ !Array.isArray(item.metadata));
236
+ };
237
+ const asyncIterableBody = (body) => {
238
+ if (!body ||
239
+ typeof body !== 'object' ||
240
+ !(Symbol.asyncIterator in body) ||
241
+ typeof body[Symbol.asyncIterator] !==
242
+ 'function') {
243
+ throw blobError('unavailable', 'S3 returned a non-streaming object body');
244
+ }
245
+ return body;
246
+ };
247
+ class AsyncByteReader {
248
+ constructor(source) {
249
+ this.carry = Buffer.alloc(0);
250
+ this.ended = false;
251
+ this.iterator = source[Symbol.asyncIterator]();
252
+ }
253
+ async readExactly(length) {
254
+ while (this.carry.length < length && !this.ended) {
255
+ const next = await this.iterator.next();
256
+ if (next.done) {
257
+ this.ended = true;
258
+ break;
259
+ }
260
+ const chunk = Buffer.from(next.value.buffer, next.value.byteOffset, next.value.byteLength);
261
+ if (chunk.length > 0) {
262
+ this.carry = Buffer.concat([this.carry, chunk], this.carry.length + chunk.length);
263
+ }
264
+ }
265
+ if (this.carry.length < length) {
266
+ throw blobError('corrupt', 'Encrypted S3 blob is truncated');
267
+ }
268
+ const output = this.carry.subarray(0, length);
269
+ this.carry = Buffer.from(this.carry.subarray(length));
270
+ return output;
271
+ }
272
+ async assertEnd() {
273
+ if (this.carry.length > 0) {
274
+ throw blobError('corrupt', 'Encrypted S3 blob has trailing bytes');
275
+ }
276
+ if (!this.ended) {
277
+ const next = await this.iterator.next();
278
+ if (!next.done && next.value.byteLength > 0) {
279
+ throw blobError('corrupt', 'Encrypted S3 blob has trailing bytes');
280
+ }
281
+ this.ended = Boolean(next.done);
282
+ }
283
+ }
284
+ async close() {
285
+ await this.iterator.return?.();
286
+ }
287
+ }
288
+ export const resolveS3BlobConfiguration = (env = process.env) => {
289
+ const bucket = env.S3_BUCKET?.trim();
290
+ const region = env.S3_REGION?.trim();
291
+ if (!bucket || bucket.length > 255) {
292
+ throw blobError('invalid-input', 'S3_BUCKET is required and must be at most 255 characters');
293
+ }
294
+ if (!region || !/^[A-Za-z0-9][A-Za-z0-9-]{0,62}$/.test(region)) {
295
+ throw blobError('invalid-input', 'S3_REGION is required and invalid');
296
+ }
297
+ const keyPrefix = (env.S3_BLOB_PREFIX?.trim() || 'libre/blobs').replace(/\/+$/, '');
298
+ if (!PREFIX_PATTERN.test(keyPrefix) || keyPrefix.includes('..')) {
299
+ throw blobError('invalid-input', 'S3_BLOB_PREFIX is invalid');
300
+ }
301
+ let endpoint;
302
+ if (env.S3_ENDPOINT?.trim()) {
303
+ let parsed;
304
+ try {
305
+ parsed = new URL(env.S3_ENDPOINT.trim());
306
+ }
307
+ catch {
308
+ throw blobError('invalid-input', 'S3_ENDPOINT must be an absolute URL');
309
+ }
310
+ if ((parsed.protocol !== 'http:' && parsed.protocol !== 'https:') ||
311
+ parsed.username ||
312
+ parsed.password ||
313
+ parsed.search ||
314
+ parsed.hash) {
315
+ throw blobError('invalid-input', 'S3_ENDPOINT must be an HTTP(S) URL without credentials, query, or fragment');
316
+ }
317
+ endpoint = parsed.toString();
318
+ }
319
+ const accessKeyId = env.S3_ACCESS_KEY_ID?.trim();
320
+ const secretAccessKey = env.S3_SECRET_ACCESS_KEY?.trim();
321
+ if (Boolean(accessKeyId) !== Boolean(secretAccessKey)) {
322
+ throw blobError('invalid-input', 'S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY must be configured together');
323
+ }
324
+ if (env.S3_SESSION_TOKEN?.trim() && !accessKeyId) {
325
+ throw blobError('invalid-input', 'S3_SESSION_TOKEN requires explicit S3 access credentials');
326
+ }
327
+ const rawPathStyle = env.S3_FORCE_PATH_STYLE?.trim().toLowerCase();
328
+ if (rawPathStyle && rawPathStyle !== 'true' && rawPathStyle !== 'false') {
329
+ throw blobError('invalid-input', 'S3_FORCE_PATH_STYLE must be true or false');
330
+ }
331
+ return {
332
+ bucket,
333
+ keyPrefix,
334
+ clientConfig: {
335
+ region,
336
+ ...(endpoint ? { endpoint } : {}),
337
+ forcePathStyle: rawPathStyle === 'true',
338
+ ...(accessKeyId && secretAccessKey
339
+ ? {
340
+ credentials: {
341
+ accessKeyId,
342
+ secretAccessKey,
343
+ ...(env.S3_SESSION_TOKEN?.trim()
344
+ ? { sessionToken: env.S3_SESSION_TOKEN.trim() }
345
+ : {}),
346
+ },
347
+ }
348
+ : {}),
349
+ },
350
+ };
351
+ };
352
+ /**
353
+ * Private S3-compatible blob storage with application-owned envelope
354
+ * encryption. S3 receives opaque keys and ciphertext only. Metadata is
355
+ * authenticated and encrypted in PostgreSQL; no provider URL is persisted.
356
+ */
357
+ export class S3EncryptedBlobStore {
358
+ constructor(options) {
359
+ /** Prevent this process's just-published objects from racing reconciliation. */
360
+ this.activeObjectKeys = new Set();
361
+ validateString(options.bucket, 'S3 bucket', 255);
362
+ const keyPrefix = (options.keyPrefix ?? 'libre/blobs').replace(/\/+$/, '');
363
+ if (!PREFIX_PATTERN.test(keyPrefix) || keyPrefix.includes('..')) {
364
+ throw blobError('invalid-input', 'Invalid S3 blob key prefix');
365
+ }
366
+ const chunkBytes = options.chunkBytes ?? DEFAULT_CHUNK_BYTES;
367
+ if (!Number.isSafeInteger(chunkBytes) ||
368
+ chunkBytes < MIN_CHUNK_BYTES ||
369
+ chunkBytes > MAX_CHUNK_BYTES) {
370
+ throw blobError('invalid-input', 'Blob chunk size must be between 64 KiB and 8 MiB');
371
+ }
372
+ const maxObjectBytes = options.maxObjectBytes ?? DEFAULT_MAX_OBJECT_BYTES;
373
+ if (!Number.isSafeInteger(maxObjectBytes) || maxObjectBytes <= 0) {
374
+ throw blobError('invalid-input', 'Invalid maximum S3 blob size');
375
+ }
376
+ const partBytes = options.multipartPartBytes ?? 8 * 1024 * 1024;
377
+ if (!Number.isSafeInteger(partBytes) || partBytes < 5 * 1024 * 1024) {
378
+ throw blobError('invalid-input', 'S3 multipart part size must be at least 5 MiB');
379
+ }
380
+ const concurrency = options.multipartConcurrency ?? 2;
381
+ if (!Number.isSafeInteger(concurrency) ||
382
+ concurrency < 1 ||
383
+ concurrency > 8) {
384
+ throw blobError('invalid-input', 'S3 multipart concurrency must be between 1 and 8');
385
+ }
386
+ this.database = options.database;
387
+ this.client = options.client;
388
+ this.bucket = options.bucket;
389
+ this.keyPrefix = keyPrefix;
390
+ this.keyring = options.keyring;
391
+ this.quotaPolicy = options.quotaPolicy ?? new NoopBlobQuotaPolicy();
392
+ this.chunkBytes = chunkBytes;
393
+ this.maxObjectBytes = maxObjectBytes;
394
+ this.multipartPartBytes = partBytes;
395
+ this.multipartConcurrency = concurrency;
396
+ this.now = options.now ?? (() => new Date());
397
+ }
398
+ objectKey(id) {
399
+ validateBlobId(id);
400
+ return `${this.keyPrefix}/v1/${id.slice(0, 2)}/${id.slice(2, 4)}/${id}.blob`;
401
+ }
402
+ /**
403
+ * Serialize every mutation of one deterministic object key across replicas.
404
+ * Random-ID writes do not normally contend, but using the same lock there
405
+ * also fences cleanup of a failed write from a concurrent import/retry.
406
+ */
407
+ async withObjectLifecycleLock(objectKey, operation, ownerUserId) {
408
+ const withPinnedClient = async (client) => {
409
+ const lockNames = [
410
+ `${OBJECT_LIFECYCLE_LOCK_NAMESPACE}:object:${objectKey}`,
411
+ ...(ownerUserId
412
+ ? [`${OBJECT_LIFECYCLE_LOCK_NAMESPACE}:owner:${ownerUserId}`]
413
+ : []),
414
+ ].sort();
415
+ const acquired = [];
416
+ let result;
417
+ let primaryError;
418
+ try {
419
+ for (const lockName of lockNames) {
420
+ await client.query('SELECT pg_advisory_lock(hashtextextended($1, 0))', [lockName]);
421
+ acquired.push(lockName);
422
+ }
423
+ result = await operation(client);
424
+ }
425
+ catch (error) {
426
+ primaryError = error;
427
+ }
428
+ for (const lockName of acquired.reverse()) {
429
+ try {
430
+ const unlocked = await client.query('SELECT pg_advisory_unlock(hashtextextended($1, 0)) AS released', [lockName]);
431
+ if (unlocked.rows[0]?.released !== true) {
432
+ throw new Error('S3 blob lifecycle lock was not held');
433
+ }
434
+ }
435
+ catch (unlockError) {
436
+ if (!primaryError)
437
+ primaryError = unlockError;
438
+ }
439
+ }
440
+ if (primaryError)
441
+ throw primaryError;
442
+ return result;
443
+ };
444
+ if (hasClientOwnership(this.database)) {
445
+ return this.database.withClient(withPinnedClient);
446
+ }
447
+ if (isPinnedClient(this.database)) {
448
+ return withPinnedClient(this.database);
449
+ }
450
+ throw blobError('unavailable', 'S3 blob lifecycle requires a PostgreSQL database or pinned client');
451
+ }
452
+ async listExactObjectVersions(objectKey, signal) {
453
+ let keyMarker;
454
+ let versionIdMarker;
455
+ const versions = [];
456
+ let inspectedEntries = 0;
457
+ for (;;) {
458
+ throwIfAborted(signal);
459
+ let page;
460
+ try {
461
+ page = await this.client.send(new ListObjectVersionsCommand({
462
+ Bucket: this.bucket,
463
+ Prefix: objectKey,
464
+ MaxKeys: OBJECT_VERSION_PAGE_SIZE,
465
+ ...(keyMarker ? { KeyMarker: keyMarker } : {}),
466
+ ...(versionIdMarker ? { VersionIdMarker: versionIdMarker } : {}),
467
+ }), { abortSignal: signal });
468
+ }
469
+ catch (error) {
470
+ if (signal?.aborted)
471
+ throwIfAborted(signal);
472
+ throw blobError('unavailable', 'Unable to enumerate S3 blob object versions', error);
473
+ }
474
+ const pageItems = [
475
+ ...(page.Versions ?? []),
476
+ ...(page.DeleteMarkers ?? []),
477
+ ];
478
+ for (const item of pageItems) {
479
+ inspectedEntries += 1;
480
+ if (inspectedEntries > MAX_OBJECT_VERSIONS_PER_PURGE) {
481
+ throw blobError('verification-limit', 'S3 exact-key version scan exceeded its safety bound');
482
+ }
483
+ if (item.Key !== objectKey)
484
+ continue;
485
+ versions.push({
486
+ key: objectKey,
487
+ ...(item.VersionId ? { versionId: item.VersionId } : {}),
488
+ ...(item.LastModified ? { lastModified: item.LastModified } : {}),
489
+ });
490
+ }
491
+ // S3 orders versions by key. Once the exact prefix has advanced to a
492
+ // longer/nonmatching key, no exact-key version can appear later.
493
+ if (pageItems.some(item => item.Key && item.Key !== objectKey)) {
494
+ return versions;
495
+ }
496
+ if (!page.IsTruncated)
497
+ return versions;
498
+ if (!page.NextKeyMarker) {
499
+ throw blobError('unavailable', 'S3 version listing omitted its continuation key');
500
+ }
501
+ keyMarker = page.NextKeyMarker;
502
+ versionIdMarker = page.NextVersionIdMarker;
503
+ }
504
+ }
505
+ /**
506
+ * Remove every immutable version and delete marker for one exact managed
507
+ * key. Two consecutive empty listings make an eventually-consistent result
508
+ * explicit; the per-key PostgreSQL advisory lock prevents a cooperating
509
+ * put/import from publishing a replacement inside that verification window.
510
+ */
511
+ async purgeExactObjectVersions(objectKey, signal) {
512
+ let emptyPasses = 0;
513
+ let deleted = 0;
514
+ while (emptyPasses < REQUIRED_EMPTY_VERSION_LISTS) {
515
+ const versions = await this.listExactObjectVersions(objectKey, signal);
516
+ if (versions.length === 0) {
517
+ emptyPasses += 1;
518
+ continue;
519
+ }
520
+ emptyPasses = 0;
521
+ for (const version of versions) {
522
+ throwIfAborted(signal);
523
+ deleted += 1;
524
+ if (deleted > MAX_OBJECT_VERSIONS_PER_PURGE) {
525
+ throw blobError('verification-limit', 'S3 blob object has too many retained versions to purge safely');
526
+ }
527
+ try {
528
+ await this.client.send(new DeleteObjectCommand({
529
+ Bucket: this.bucket,
530
+ Key: version.key,
531
+ ...(version.versionId ? { VersionId: version.versionId } : {}),
532
+ }), { abortSignal: signal });
533
+ }
534
+ catch (error) {
535
+ if (signal?.aborted)
536
+ throwIfAborted(signal);
537
+ throw blobError('unavailable', 'Unable to purge an S3 blob object version', error);
538
+ }
539
+ }
540
+ }
541
+ }
542
+ /**
543
+ * Only keys emitted by objectKey() belong to this lifecycle. Unknown keys
544
+ * beneath a shared operator prefix are never treated as Libre garbage.
545
+ */
546
+ managedObjectId(objectKey) {
547
+ const prefix = `${this.keyPrefix}/v1/`;
548
+ if (!objectKey.startsWith(prefix))
549
+ return undefined;
550
+ const relative = objectKey.slice(prefix.length);
551
+ const match = /^([0-9a-f]{2})\/([0-9a-f]{2})\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.blob$/.exec(relative);
552
+ const id = match?.[3];
553
+ return id && match[1] === id.slice(0, 2) && match[2] === id.slice(2, 4)
554
+ ? id
555
+ : undefined;
556
+ }
557
+ async row(id, ownerUserId, includeDeleting = false, executor = this.database) {
558
+ validateBlobId(id);
559
+ validateString(ownerUserId, 'owner', 256);
560
+ const result = await executor.query(`SELECT id, owner_user_id, purpose, object_key, encrypted_bytes,
561
+ plaintext_bytes, plaintext_sha256, ciphertext_sha256,
562
+ wrapped_data_key, metadata_iv, metadata_tag,
563
+ encrypted_metadata, state, created_at, updated_at
564
+ FROM platform_blob_objects
565
+ WHERE id = $1 AND owner_user_id = $2
566
+ ${includeDeleting ? '' : "AND state = 'ready'"}`, [id, ownerUserId]);
567
+ return result.rows[0];
568
+ }
569
+ decryptMetadata(row) {
570
+ let dataKey;
571
+ try {
572
+ const rawEnvelope = typeof row.wrapped_data_key === 'string'
573
+ ? JSON.parse(row.wrapped_data_key)
574
+ : row.wrapped_data_key;
575
+ const envelope = parseAesGcmEnvelope(rawEnvelope);
576
+ dataKey = this.keyring.decrypt(envelope, keyAad(row.id));
577
+ if (dataKey.length !== 32) {
578
+ throw blobError('corrupt', 'Invalid S3 blob data key');
579
+ }
580
+ if (!Buffer.isBuffer(row.metadata_iv) ||
581
+ row.metadata_iv.length !== METADATA_IV_BYTES ||
582
+ !Buffer.isBuffer(row.metadata_tag) ||
583
+ row.metadata_tag.length !== AUTH_TAG_BYTES ||
584
+ !Buffer.isBuffer(row.encrypted_metadata) ||
585
+ row.encrypted_metadata.length === 0 ||
586
+ row.encrypted_metadata.length > MAX_METADATA_BYTES) {
587
+ throw blobError('corrupt', 'Invalid encrypted S3 blob metadata');
588
+ }
589
+ const decipher = crypto.createDecipheriv('aes-256-gcm', dataKey, row.metadata_iv, { authTagLength: AUTH_TAG_BYTES });
590
+ decipher.setAAD(metadataAad(row.id, row.object_key));
591
+ decipher.setAuthTag(row.metadata_tag);
592
+ const plaintext = Buffer.concat([
593
+ decipher.update(row.encrypted_metadata),
594
+ decipher.final(),
595
+ ]);
596
+ let value;
597
+ try {
598
+ value = JSON.parse(plaintext.toString('utf8'));
599
+ }
600
+ finally {
601
+ plaintext.fill(0);
602
+ }
603
+ if (!isStoredMetadata(value)) {
604
+ throw blobError('corrupt', 'Invalid encrypted S3 blob descriptor');
605
+ }
606
+ const encryptedBytes = safeInteger(row.encrypted_bytes, 'encrypted byte count');
607
+ const plaintextBytes = safeInteger(row.plaintext_bytes, 'plaintext byte count');
608
+ const bodyNonce = Buffer.from(value.bodyNonce, 'base64');
609
+ if (value.id !== row.id ||
610
+ value.ownerUserId !== row.owner_user_id ||
611
+ value.purpose !== row.purpose ||
612
+ value.objectKey !== row.object_key ||
613
+ value.size !== plaintextBytes ||
614
+ value.encryptedBytes !== encryptedBytes ||
615
+ value.sha256 !== row.plaintext_sha256 ||
616
+ value.ciphertextSha256 !== row.ciphertext_sha256 ||
617
+ value.encryptionKeyId !== envelope.keyId ||
618
+ value.chunkCount !== Math.ceil(value.size / value.chunkBytes) ||
619
+ value.encryptedBytes !==
620
+ value.size + value.chunkCount * AUTH_TAG_BYTES ||
621
+ bodyNonce.length !== BODY_NONCE_BYTES ||
622
+ bodyNonce.toString('base64') !== value.bodyNonce) {
623
+ throw blobError('corrupt', 'S3 blob metadata does not match its row');
624
+ }
625
+ return { metadata: value, dataKey };
626
+ }
627
+ catch (error) {
628
+ dataKey?.fill(0);
629
+ if (error instanceof BlobStoreError)
630
+ throw error;
631
+ if (error instanceof StorageEncryptionError) {
632
+ throw blobError('corrupt', 'S3 blob metadata authentication failed', error);
633
+ }
634
+ throw blobError('corrupt', 'Unable to decrypt S3 blob metadata', error);
635
+ }
636
+ }
637
+ async assertPhysicalObject(metadata, signal) {
638
+ try {
639
+ const head = await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: metadata.objectKey }), { abortSignal: signal });
640
+ if (head.ContentLength !== metadata.encryptedBytes ||
641
+ head.Metadata?.['libre-format'] !== String(FORMAT_VERSION)) {
642
+ throw blobError('corrupt', 'S3 blob object metadata is inconsistent');
643
+ }
644
+ }
645
+ catch (error) {
646
+ if (error instanceof BlobStoreError)
647
+ throw error;
648
+ if (isNotFound(error)) {
649
+ throw blobError('corrupt', 'S3 blob object is missing', error);
650
+ }
651
+ if (signal?.aborted)
652
+ throwIfAborted(signal);
653
+ throw blobError('unavailable', 'Unable to inspect S3 blob object', error);
654
+ }
655
+ }
656
+ /**
657
+ * Resolve a commit acknowledgement loss from authoritative SQL while the
658
+ * per-object lifecycle lock is still held. A complete metadata/quota commit
659
+ * is authenticated against the just-uploaded object and returned as
660
+ * success. Only a provably absent outcome permits physical purge; any
661
+ * partial/mismatched state is preserved for fail-closed reconciliation.
662
+ */
663
+ async resolvePutCommitOutcome(executor, expected, signal) {
664
+ const metadataResult = await executor.query(`SELECT id, owner_user_id, purpose, object_key, encrypted_bytes,
665
+ plaintext_bytes, plaintext_sha256, ciphertext_sha256,
666
+ wrapped_data_key, metadata_iv, metadata_tag, encrypted_metadata,
667
+ state, created_at, updated_at
668
+ FROM platform_blob_objects
669
+ WHERE id = $1 OR object_key = $2
670
+ ORDER BY id`, [expected.id, expected.objectKey]);
671
+ const quotaResult = await executor.query(`SELECT blob_id, owner_user_id, purpose, stored_bytes
672
+ FROM platform_blob_quota_objects
673
+ WHERE blob_id = $1`, [expected.id]);
674
+ if (metadataResult.rowCount === 0 && quotaResult.rowCount === 0) {
675
+ return 'absent';
676
+ }
677
+ if (metadataResult.rowCount !== 1 || quotaResult.rowCount !== 1) {
678
+ throw blobError('corrupt', 'S3 blob commit outcome is inconsistent; uploaded evidence was preserved');
679
+ }
680
+ const row = metadataResult.rows[0];
681
+ const quota = quotaResult.rows[0];
682
+ const opened = this.decryptMetadata(row);
683
+ try {
684
+ const actual = opened.metadata;
685
+ if (row.state !== 'ready' ||
686
+ quota.blob_id !== expected.id ||
687
+ quota.owner_user_id !== expected.ownerUserId ||
688
+ quota.purpose !== expected.purpose ||
689
+ safeInteger(quota.stored_bytes, 'quota stored byte count') !==
690
+ expected.size ||
691
+ actual.id !== expected.id ||
692
+ actual.ownerUserId !== expected.ownerUserId ||
693
+ actual.purpose !== expected.purpose ||
694
+ actual.contentType !== expected.contentType ||
695
+ actual.originalFilename !== expected.originalFilename ||
696
+ JSON.stringify(actual.metadata) !== JSON.stringify(expected.metadata) ||
697
+ actual.objectKey !== expected.objectKey ||
698
+ actual.size !== expected.size ||
699
+ actual.sha256 !== expected.sha256 ||
700
+ actual.ciphertextSha256 !== expected.ciphertextSha256 ||
701
+ actual.encryptedBytes !== expected.encryptedBytes ||
702
+ actual.chunkBytes !== expected.chunkBytes ||
703
+ actual.chunkCount !== expected.chunkCount ||
704
+ actual.bodyNonce !== expected.bodyNonce ||
705
+ actual.createdAt !== expected.createdAt ||
706
+ actual.encryptionKeyId !== expected.encryptionKeyId) {
707
+ throw blobError('corrupt', 'S3 blob commit outcome does not match the attempted upload; uploaded evidence was preserved');
708
+ }
709
+ await this.assertPhysicalObject(actual, signal);
710
+ return { descriptor: publicDescriptor(actual) };
711
+ }
712
+ finally {
713
+ opened.dataKey.fill(0);
714
+ }
715
+ }
716
+ async put(request) {
717
+ return this.putInternal(request);
718
+ }
719
+ /**
720
+ * Storage-migration seam. A deterministic ID makes a crash after S3 upload
721
+ * but before the import ledger commit recoverable without duplicating data.
722
+ */
723
+ async putWithId(request, id, createdAt) {
724
+ validateBlobId(id);
725
+ if (createdAt !== undefined && !Number.isFinite(Date.parse(createdAt))) {
726
+ throw blobError('invalid-input', 'Invalid migrated blob creation time');
727
+ }
728
+ return this.putInternal(request, id, createdAt);
729
+ }
730
+ async putInternal(request, requestedId, requestedCreatedAt) {
731
+ throwIfAborted(request.signal);
732
+ const normalizedMetadata = validatePutRequest(request, this.maxObjectBytes);
733
+ const id = requestedId ?? crypto.randomUUID();
734
+ const objectKey = this.objectKey(id);
735
+ return this.withObjectLifecycleLock(objectKey, async (executor) => {
736
+ const existing = await executor.query('SELECT 1 FROM platform_blob_objects WHERE object_key = $1', [objectKey]);
737
+ if (existing.rowCount !== 0) {
738
+ throw blobError('invalid-input', 'S3 blob ID already exists');
739
+ }
740
+ const reservation = await this.quotaPolicy.reserve({
741
+ ownerUserId: request.ownerUserId,
742
+ purpose: request.purpose,
743
+ ...(request.expectedSize !== undefined
744
+ ? { expectedSize: request.expectedSize }
745
+ : {}),
746
+ });
747
+ return this.putLocked(request, id, objectKey, requestedCreatedAt, normalizedMetadata, reservation);
748
+ }, request.ownerUserId);
749
+ }
750
+ async putLocked(request, id, objectKey, requestedCreatedAt, normalizedMetadata, reservation) {
751
+ this.activeObjectKeys.add(objectKey);
752
+ const dataKey = crypto.randomBytes(32);
753
+ const bodyNonce = crypto.randomBytes(BODY_NONCE_BYTES);
754
+ const plaintextDigest = crypto.createHash('sha256');
755
+ const ciphertextDigest = crypto.createHash('sha256');
756
+ let size = 0;
757
+ let chunkCount = 0;
758
+ let encryptedBytes = 0;
759
+ let uploaded = false;
760
+ let metadataCommitted = false;
761
+ let storedMetadata;
762
+ const encryptedBody = (async function* (store) {
763
+ for await (const chunk of fixedChunks(request.source, store.chunkBytes, request.signal)) {
764
+ const nextSize = size + chunk.length;
765
+ if (nextSize > store.maxObjectBytes) {
766
+ throw blobError('quota-exceeded', 'Blob exceeds the maximum object size');
767
+ }
768
+ await reservation.consume(chunk.length);
769
+ const cipher = crypto.createCipheriv('aes-256-gcm', dataKey, createChunkIv(bodyNonce, chunkCount));
770
+ cipher.setAAD(chunkAad({ id, ownerUserId: request.ownerUserId, purpose: request.purpose }, chunkCount, chunk.length));
771
+ const ciphertext = Buffer.concat([
772
+ cipher.update(chunk),
773
+ cipher.final(),
774
+ ]);
775
+ const tag = cipher.getAuthTag();
776
+ plaintextDigest.update(chunk);
777
+ ciphertextDigest.update(ciphertext);
778
+ ciphertextDigest.update(tag);
779
+ size = nextSize;
780
+ chunkCount += 1;
781
+ encryptedBytes += ciphertext.length + tag.length;
782
+ yield ciphertext;
783
+ yield tag;
784
+ }
785
+ })(this);
786
+ const upload = new Upload({
787
+ client: this.client,
788
+ params: {
789
+ Bucket: this.bucket,
790
+ Key: objectKey,
791
+ Body: Readable.from(encryptedBody, { objectMode: false }),
792
+ ContentType: 'application/octet-stream',
793
+ Metadata: { 'libre-format': String(FORMAT_VERSION) },
794
+ },
795
+ partSize: this.multipartPartBytes,
796
+ queueSize: this.multipartConcurrency,
797
+ leavePartsOnError: false,
798
+ });
799
+ const abortUpload = () => {
800
+ void upload.abort();
801
+ };
802
+ request.signal?.addEventListener('abort', abortUpload, { once: true });
803
+ try {
804
+ await upload.done();
805
+ uploaded = true;
806
+ throwIfAborted(request.signal);
807
+ if (request.expectedSize !== undefined && request.expectedSize !== size) {
808
+ throw blobError('invalid-input', `Expected ${request.expectedSize} blob bytes but received ${size}`);
809
+ }
810
+ const wrappedDataKey = this.keyring.encrypt(dataKey, keyAad(id));
811
+ const createdAt = requestedCreatedAt
812
+ ? new Date(requestedCreatedAt)
813
+ : this.now();
814
+ const metadata = {
815
+ id,
816
+ ownerUserId: request.ownerUserId,
817
+ purpose: request.purpose,
818
+ contentType: request.contentType,
819
+ ...(request.originalFilename
820
+ ? { originalFilename: request.originalFilename }
821
+ : {}),
822
+ metadata: normalizedMetadata,
823
+ size,
824
+ sha256: plaintextDigest.digest('hex'),
825
+ createdAt: createdAt.toISOString(),
826
+ encryptionKeyId: wrappedDataKey.keyId,
827
+ formatVersion: FORMAT_VERSION,
828
+ objectKey,
829
+ chunkBytes: this.chunkBytes,
830
+ chunkCount,
831
+ bodyNonce: bodyNonce.toString('base64'),
832
+ encryptedBytes,
833
+ ciphertextSha256: ciphertextDigest.digest('hex'),
834
+ };
835
+ storedMetadata = metadata;
836
+ const metadataPlaintext = Buffer.from(JSON.stringify(metadata), 'utf8');
837
+ if (metadataPlaintext.length > MAX_METADATA_BYTES) {
838
+ throw blobError('invalid-input', 'Blob metadata is too large');
839
+ }
840
+ const metadataIv = crypto.randomBytes(METADATA_IV_BYTES);
841
+ const cipher = crypto.createCipheriv('aes-256-gcm', dataKey, metadataIv);
842
+ cipher.setAAD(metadataAad(id, objectKey));
843
+ const encryptedMetadata = Buffer.concat([
844
+ cipher.update(metadataPlaintext),
845
+ cipher.final(),
846
+ ]);
847
+ metadataPlaintext.fill(0);
848
+ const now = createdAt.getTime();
849
+ const descriptor = publicDescriptor(metadata);
850
+ const insertMetadata = async (executor) => {
851
+ await executor.query(`INSERT INTO platform_blob_objects (
852
+ id, owner_user_id, purpose, object_key, encrypted_bytes,
853
+ plaintext_bytes, plaintext_sha256, ciphertext_sha256,
854
+ wrapped_data_key, metadata_iv, metadata_tag, encrypted_metadata,
855
+ state, created_at, updated_at
856
+ ) VALUES (
857
+ $1, $2, $3, $4, $5, $6, $7, $8, $9::jsonb, $10, $11, $12,
858
+ 'ready', $13, $13
859
+ )`, [
860
+ id,
861
+ request.ownerUserId,
862
+ request.purpose,
863
+ objectKey,
864
+ encryptedBytes,
865
+ size,
866
+ metadata.sha256,
867
+ metadata.ciphertextSha256,
868
+ JSON.stringify(wrappedDataKey),
869
+ metadataIv,
870
+ cipher.getAuthTag(),
871
+ encryptedMetadata,
872
+ now,
873
+ ]);
874
+ };
875
+ const transactionalReservation = reservation;
876
+ if (transactionalReservation.commitWithMetadata) {
877
+ await transactionalReservation.commitWithMetadata(descriptor, executor => insertMetadata(executor));
878
+ }
879
+ else {
880
+ await insertMetadata(this.database);
881
+ await reservation.commit(descriptor);
882
+ }
883
+ metadataCommitted = true;
884
+ return descriptor;
885
+ }
886
+ catch (error) {
887
+ if (uploaded && !metadataCommitted) {
888
+ let outcome;
889
+ try {
890
+ if (!storedMetadata) {
891
+ await this.purgeExactObjectVersions(objectKey);
892
+ }
893
+ else {
894
+ outcome = await this.resolvePutCommitOutcome(this.database, storedMetadata, request.signal);
895
+ if (outcome !== 'absent') {
896
+ metadataCommitted = true;
897
+ return outcome.descriptor;
898
+ }
899
+ await this.purgeExactObjectVersions(objectKey, request.signal);
900
+ }
901
+ }
902
+ catch (resolutionError) {
903
+ if (resolutionError instanceof BlobStoreError)
904
+ throw resolutionError;
905
+ throw blobError('unavailable', 'Unable to resolve the S3 blob commit outcome; uploaded evidence was preserved', resolutionError);
906
+ }
907
+ }
908
+ if (error instanceof BlobStoreError)
909
+ throw error;
910
+ if (request.signal?.aborted)
911
+ throwIfAborted(request.signal);
912
+ throw blobError('unavailable', 'Unable to store encrypted S3 blob', error);
913
+ }
914
+ finally {
915
+ request.signal?.removeEventListener('abort', abortUpload);
916
+ this.activeObjectKeys.delete(objectKey);
917
+ dataKey.fill(0);
918
+ if (!metadataCommitted)
919
+ await reservation.release();
920
+ }
921
+ }
922
+ async stat(id, ownerUserId) {
923
+ const row = await this.row(id, ownerUserId);
924
+ if (!row)
925
+ throw new BlobNotFoundError();
926
+ const opened = this.decryptMetadata(row);
927
+ try {
928
+ await this.assertPhysicalObject(opened.metadata);
929
+ return publicDescriptor(opened.metadata);
930
+ }
931
+ finally {
932
+ opened.dataKey.fill(0);
933
+ }
934
+ }
935
+ async health() {
936
+ try {
937
+ await this.client.send(new HeadBucketCommand({ Bucket: this.bucket }));
938
+ return true;
939
+ }
940
+ catch {
941
+ return false;
942
+ }
943
+ }
944
+ async close() {
945
+ this.client.destroy();
946
+ }
947
+ normalizeRange(metadata, request) {
948
+ if (!request.range)
949
+ return null;
950
+ if (metadata.size === 0) {
951
+ throw blobError('invalid-range', 'Empty blobs do not support ranges');
952
+ }
953
+ const requestedEnd = request.range.end ?? metadata.size - 1;
954
+ if (!Number.isSafeInteger(request.range.start) ||
955
+ !Number.isSafeInteger(requestedEnd) ||
956
+ request.range.start < 0 ||
957
+ request.range.start >= metadata.size ||
958
+ requestedEnd < request.range.start) {
959
+ throw blobError('invalid-range', 'Invalid blob byte range');
960
+ }
961
+ const end = Math.min(requestedEnd, metadata.size - 1);
962
+ return {
963
+ start: request.range.start,
964
+ end,
965
+ total: metadata.size,
966
+ length: end - request.range.start + 1,
967
+ };
968
+ }
969
+ async open(request) {
970
+ throwIfAborted(request.signal);
971
+ const row = await this.row(request.id, request.ownerUserId);
972
+ if (!row)
973
+ throw new BlobNotFoundError();
974
+ const opened = this.decryptMetadata(row);
975
+ const { metadata, dataKey } = opened;
976
+ let range;
977
+ try {
978
+ range = this.normalizeRange(metadata, request);
979
+ }
980
+ catch (error) {
981
+ dataKey.fill(0);
982
+ throw error;
983
+ }
984
+ const start = range?.start ?? 0;
985
+ const end = range?.end ?? metadata.size - 1;
986
+ const firstChunk = metadata.size === 0 ? 0 : Math.floor(start / metadata.chunkBytes);
987
+ const finalChunk = metadata.size === 0 ? -1 : Math.floor(end / metadata.chunkBytes);
988
+ const encryptedStart = firstChunk * (metadata.chunkBytes + AUTH_TAG_BYTES);
989
+ const finalPlaintextBytes = finalChunk < 0
990
+ ? 0
991
+ : Math.min(metadata.chunkBytes, metadata.size - finalChunk * metadata.chunkBytes);
992
+ const encryptedEnd = finalChunk < 0
993
+ ? -1
994
+ : finalChunk * (metadata.chunkBytes + AUTH_TAG_BYTES) +
995
+ finalPlaintextBytes +
996
+ AUTH_TAG_BYTES -
997
+ 1;
998
+ const fullRead = range === null;
999
+ let response;
1000
+ try {
1001
+ response = await this.client.send(new GetObjectCommand({
1002
+ Bucket: this.bucket,
1003
+ Key: metadata.objectKey,
1004
+ ...(metadata.size > 0 && !fullRead
1005
+ ? { Range: `bytes=${encryptedStart}-${encryptedEnd}` }
1006
+ : {}),
1007
+ }), { abortSignal: request.signal });
1008
+ }
1009
+ catch (error) {
1010
+ dataKey.fill(0);
1011
+ if (isNotFound(error)) {
1012
+ throw blobError('corrupt', 'S3 blob object is missing', error);
1013
+ }
1014
+ if (request.signal?.aborted)
1015
+ throwIfAborted(request.signal);
1016
+ throw blobError('unavailable', 'Unable to open S3 blob object', error);
1017
+ }
1018
+ const rawBody = response.Body;
1019
+ let source;
1020
+ try {
1021
+ source = asyncIterableBody(rawBody);
1022
+ }
1023
+ catch (error) {
1024
+ dataKey.fill(0);
1025
+ throw error;
1026
+ }
1027
+ const reader = new AsyncByteReader(source);
1028
+ const bodyNonce = Buffer.from(metadata.bodyNonce, 'base64');
1029
+ let disposed = false;
1030
+ const dispose = async () => {
1031
+ if (disposed)
1032
+ return;
1033
+ disposed = true;
1034
+ dataKey.fill(0);
1035
+ await reader.close().catch(() => undefined);
1036
+ const destroy = rawBody
1037
+ ?.destroy;
1038
+ destroy?.call(rawBody);
1039
+ };
1040
+ const iterator = (async function* () {
1041
+ const plaintextDigest = fullRead ? crypto.createHash('sha256') : null;
1042
+ const ciphertextDigest = fullRead ? crypto.createHash('sha256') : null;
1043
+ try {
1044
+ for (let index = firstChunk; index <= finalChunk; index += 1) {
1045
+ throwIfAborted(request.signal);
1046
+ const chunkStart = index * metadata.chunkBytes;
1047
+ const plaintextBytes = Math.min(metadata.chunkBytes, metadata.size - chunkStart);
1048
+ const encrypted = await reader.readExactly(plaintextBytes + AUTH_TAG_BYTES);
1049
+ ciphertextDigest?.update(encrypted);
1050
+ let plaintext;
1051
+ try {
1052
+ const decipher = crypto.createDecipheriv('aes-256-gcm', dataKey, createChunkIv(bodyNonce, index), { authTagLength: AUTH_TAG_BYTES });
1053
+ decipher.setAAD(chunkAad(metadata, index, plaintextBytes));
1054
+ decipher.setAuthTag(encrypted.subarray(plaintextBytes));
1055
+ plaintext = Buffer.concat([
1056
+ decipher.update(encrypted.subarray(0, plaintextBytes)),
1057
+ decipher.final(),
1058
+ ]);
1059
+ }
1060
+ catch (error) {
1061
+ throw blobError('corrupt', 'Encrypted S3 blob chunk authentication failed', error);
1062
+ }
1063
+ plaintextDigest?.update(plaintext);
1064
+ const sliceStart = Math.max(start - chunkStart, 0);
1065
+ const sliceEnd = Math.min(end - chunkStart + 1, plaintext.length);
1066
+ if (sliceEnd > sliceStart)
1067
+ yield plaintext.subarray(sliceStart, sliceEnd);
1068
+ }
1069
+ await reader.assertEnd();
1070
+ if (fullRead &&
1071
+ (plaintextDigest?.digest('hex') !== metadata.sha256 ||
1072
+ ciphertextDigest?.digest('hex') !== metadata.ciphertextSha256)) {
1073
+ throw blobError('corrupt', 'Encrypted S3 blob checksum mismatch');
1074
+ }
1075
+ }
1076
+ finally {
1077
+ await dispose();
1078
+ }
1079
+ })();
1080
+ const body = Readable.from(iterator, { objectMode: false });
1081
+ body.once('close', () => {
1082
+ void dispose();
1083
+ });
1084
+ return { descriptor: publicDescriptor(metadata), range, body };
1085
+ }
1086
+ /** Offline migration rollback seam for an upload that never gained SQL. */
1087
+ async purgeUntrackedObject(id, signal) {
1088
+ throwIfAborted(signal);
1089
+ const objectKey = this.objectKey(id);
1090
+ await this.withObjectLifecycleLock(objectKey, async (executor) => {
1091
+ const tracked = await executor.query('SELECT 1 FROM platform_blob_objects WHERE object_key = $1', [objectKey]);
1092
+ if (tracked.rowCount !== 0) {
1093
+ throw blobError('invalid-input', 'Refusing to purge a tracked S3 blob object');
1094
+ }
1095
+ await this.purgeExactObjectVersions(objectKey, signal);
1096
+ });
1097
+ }
1098
+ async delete(request) {
1099
+ throwIfAborted(request.signal);
1100
+ const objectKey = this.objectKey(request.id);
1101
+ return this.withObjectLifecycleLock(objectKey, async (executor) => {
1102
+ const anyOwner = await executor.query('SELECT owner_user_id FROM platform_blob_objects WHERE id = $1', [request.id]);
1103
+ if (anyOwner.rows[0] &&
1104
+ anyOwner.rows[0].owner_user_id !== request.ownerUserId) {
1105
+ return false;
1106
+ }
1107
+ const row = await this.row(request.id, request.ownerUserId, true, executor);
1108
+ if (!row) {
1109
+ await this.purgeExactObjectVersions(objectKey, request.signal);
1110
+ if ('releaseStored' in this.quotaPolicy) {
1111
+ await this.quotaPolicy.releaseStored({
1112
+ id: request.id,
1113
+ ownerUserId: request.ownerUserId,
1114
+ });
1115
+ }
1116
+ return false;
1117
+ }
1118
+ await executor.query(`UPDATE platform_blob_objects
1119
+ SET state = 'deleting', updated_at = $3
1120
+ WHERE id = $1 AND owner_user_id = $2`, [request.id, request.ownerUserId, this.now().getTime()]);
1121
+ try {
1122
+ await this.purgeExactObjectVersions(row.object_key, request.signal);
1123
+ await this.finalizeDeletingRow(row);
1124
+ return true;
1125
+ }
1126
+ catch (error) {
1127
+ if (request.signal?.aborted)
1128
+ throwIfAborted(request.signal);
1129
+ if (error instanceof BlobStoreError)
1130
+ throw error;
1131
+ throw blobError('unavailable', 'Unable to delete S3 blob object', error);
1132
+ }
1133
+ }, request.ownerUserId);
1134
+ }
1135
+ async finalizeDeletingRow(row) {
1136
+ let removed = 0;
1137
+ const deleteMetadata = async (executor) => {
1138
+ const deleted = await executor.query(`DELETE FROM platform_blob_objects
1139
+ WHERE id = $1 AND owner_user_id = $2 AND state = 'deleting'`, [row.id, row.owner_user_id]);
1140
+ removed = deleted.rowCount ?? 0;
1141
+ };
1142
+ const transactionalQuota = this.quotaPolicy;
1143
+ if (transactionalQuota.releaseStoredWithMetadata) {
1144
+ await transactionalQuota.releaseStoredWithMetadata({ id: row.id, ownerUserId: row.owner_user_id }, executor => deleteMetadata(executor));
1145
+ }
1146
+ else {
1147
+ await deleteMetadata(this.database);
1148
+ if ('releaseStored' in this.quotaPolicy) {
1149
+ await this.quotaPolicy.releaseStored({ id: row.id, ownerUserId: row.owner_user_id });
1150
+ }
1151
+ }
1152
+ return removed;
1153
+ }
1154
+ async resumeDeletes(limit, signal) {
1155
+ const rows = await this.database.query(`SELECT id, owner_user_id, object_key
1156
+ FROM platform_blob_objects
1157
+ WHERE state = 'deleting'
1158
+ ORDER BY updated_at, id
1159
+ LIMIT $1`, [limit]);
1160
+ let resumed = 0;
1161
+ for (const row of rows.rows) {
1162
+ throwIfAborted(signal);
1163
+ resumed += await this.withObjectLifecycleLock(row.object_key, async (executor) => {
1164
+ const current = await this.row(row.id, row.owner_user_id, true, executor);
1165
+ if (!current || current.state !== 'deleting')
1166
+ return 0;
1167
+ await this.purgeExactObjectVersions(current.object_key, signal);
1168
+ return this.finalizeDeletingRow(current);
1169
+ }, row.owner_user_id);
1170
+ }
1171
+ return resumed;
1172
+ }
1173
+ async reconcileOrphans(options) {
1174
+ if (!Number.isFinite(options.olderThan.getTime())) {
1175
+ throw blobError('invalid-input', 'Invalid S3 blob orphan cutoff');
1176
+ }
1177
+ const maxObjects = options.maxObjects ?? MAX_RECORDS_PER_RECONCILIATION;
1178
+ if (!Number.isSafeInteger(maxObjects) || maxObjects <= 0) {
1179
+ throw blobError('invalid-input', 'Invalid S3 reconciliation object limit');
1180
+ }
1181
+ if (options.continuationToken !== undefined &&
1182
+ (typeof options.continuationToken !== 'string' ||
1183
+ options.continuationToken.length === 0 ||
1184
+ Buffer.byteLength(options.continuationToken, 'utf8') > 8192)) {
1185
+ throw blobError('invalid-input', 'Invalid S3 reconciliation cursor');
1186
+ }
1187
+ const resumedDeletes = await this.resumeDeletes(maxObjects, options.signal);
1188
+ let afterKey = decodeReconciliationCursor(options.continuationToken)?.afterKey;
1189
+ if (afterKey && !afterKey.startsWith(`${this.keyPrefix}/v1/`)) {
1190
+ throw blobError('invalid-input', 'Invalid S3 reconciliation cursor');
1191
+ }
1192
+ let deletedOrphans = 0;
1193
+ let inspectedObjects = 0;
1194
+ let complete = false;
1195
+ while (inspectedObjects < maxObjects) {
1196
+ throwIfAborted(options.signal);
1197
+ const remaining = maxObjects - inspectedObjects;
1198
+ const page = await this.client.send(new ListObjectVersionsCommand({
1199
+ Bucket: this.bucket,
1200
+ Prefix: `${this.keyPrefix}/v1/`,
1201
+ MaxKeys: Math.min(1000, remaining),
1202
+ ...(afterKey ? { KeyMarker: afterKey } : {}),
1203
+ }), { abortSignal: options.signal });
1204
+ const keys = [
1205
+ ...(page.Versions ?? []).map(item => item.Key),
1206
+ ...(page.DeleteMarkers ?? []).map(item => item.Key),
1207
+ ]
1208
+ .filter((key) => Boolean(key))
1209
+ .filter((key, index, values) => values.indexOf(key) === index)
1210
+ .sort();
1211
+ if (keys.length === 0) {
1212
+ complete = true;
1213
+ afterKey = undefined;
1214
+ break;
1215
+ }
1216
+ for (const objectKey of keys) {
1217
+ throwIfAborted(options.signal);
1218
+ inspectedObjects += 1;
1219
+ afterKey = objectKey;
1220
+ if (!this.managedObjectId(objectKey))
1221
+ continue;
1222
+ if (this.activeObjectKeys.has(objectKey))
1223
+ continue;
1224
+ deletedOrphans += await this.withObjectLifecycleLock(objectKey, async (executor) => {
1225
+ const reference = await executor.query('SELECT id FROM platform_blob_objects WHERE object_key = $1', [objectKey]);
1226
+ if (reference.rows.length > 0)
1227
+ return 0;
1228
+ const versions = await this.listExactObjectVersions(objectKey, options.signal);
1229
+ if (versions.length === 0 ||
1230
+ versions.some(version => !version.lastModified ||
1231
+ version.lastModified.getTime() >= options.olderThan.getTime())) {
1232
+ return 0;
1233
+ }
1234
+ await this.purgeExactObjectVersions(objectKey, options.signal);
1235
+ return 1;
1236
+ });
1237
+ if (inspectedObjects >= maxObjects)
1238
+ break;
1239
+ }
1240
+ }
1241
+ return {
1242
+ deletedOrphans,
1243
+ resumedDeletes,
1244
+ inspectedObjects,
1245
+ complete,
1246
+ ...(!complete && afterKey
1247
+ ? {
1248
+ continuationToken: encodeReconciliationCursor({
1249
+ version: 1,
1250
+ afterKey,
1251
+ }),
1252
+ }
1253
+ : {}),
1254
+ };
1255
+ }
1256
+ async verifyIntegrity(options = {}) {
1257
+ const maxObjects = options.maxObjects ?? 250000;
1258
+ const maxEncryptedBytes = options.maxEncryptedBytes ?? 64 * 1024 * 1024 * 1024;
1259
+ const maxPlaintextBytes = options.maxPlaintextBytes ?? 64 * 1024 * 1024 * 1024;
1260
+ for (const [value, name] of [
1261
+ [maxObjects, 'object'],
1262
+ [maxEncryptedBytes, 'encrypted-byte'],
1263
+ [maxPlaintextBytes, 'plaintext-byte'],
1264
+ ]) {
1265
+ if (!Number.isSafeInteger(value) || value <= 0) {
1266
+ throw blobError('invalid-input', `Invalid S3 integrity ${name} limit`);
1267
+ }
1268
+ }
1269
+ const aggregate = await this.database.query(`SELECT COUNT(*) AS objects,
1270
+ COALESCE(SUM(encrypted_bytes), 0) AS encrypted_bytes,
1271
+ COALESCE(SUM(plaintext_bytes), 0) AS plaintext_bytes
1272
+ FROM platform_blob_objects
1273
+ WHERE state = 'ready'`);
1274
+ const objects = safeInteger(aggregate.rows[0]?.objects ?? 0, 'object count');
1275
+ const encryptedBytes = safeInteger(aggregate.rows[0]?.encrypted_bytes ?? 0, 'encrypted byte total');
1276
+ const plaintextBytes = safeInteger(aggregate.rows[0]?.plaintext_bytes ?? 0, 'plaintext byte total');
1277
+ if (objects > maxObjects ||
1278
+ encryptedBytes > maxEncryptedBytes ||
1279
+ plaintextBytes > maxPlaintextBytes) {
1280
+ throw blobError('verification-limit', 'S3 blob storage exceeds bounded integrity verification limits');
1281
+ }
1282
+ const rows = await this.database.query(`SELECT id, owner_user_id
1283
+ FROM platform_blob_objects
1284
+ WHERE state = 'ready'
1285
+ ORDER BY id`);
1286
+ for (const row of rows.rows) {
1287
+ throwIfAborted(options.signal);
1288
+ const opened = await this.open({
1289
+ id: row.id,
1290
+ ownerUserId: row.owner_user_id,
1291
+ signal: options.signal,
1292
+ });
1293
+ for await (const _chunk of opened.body) {
1294
+ // Authentication and both checksums are verified by a complete read.
1295
+ }
1296
+ }
1297
+ return { objects, encryptedBytes, plaintextBytes };
1298
+ }
1299
+ }
1300
+ export const createS3EncryptedBlobStore = (options) => {
1301
+ const configuration = resolveS3BlobConfiguration(options.env ?? process.env);
1302
+ return new S3EncryptedBlobStore({
1303
+ ...options,
1304
+ client: new S3Client(configuration.clientConfig),
1305
+ bucket: configuration.bucket,
1306
+ keyPrefix: configuration.keyPrefix,
1307
+ });
1308
+ };
1309
+ //# sourceMappingURL=s3EncryptedBlobStore.js.map