libre-webui 0.21.3 → 0.22.1

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 +617 -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 +83 -0
  376. package/backend/dist/platform/storage/storageFactory.d.ts.map +1 -0
  377. package/backend/dist/platform/storage/storageFactory.js +530 -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 +126 -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 +833 -275
  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 +14 -4
  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-Jtx9Amhz.js +16 -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-fZegtmva.js} +1 -1
  829. package/frontend/dist/js/{ArtifactDemoPage-K79dWshB.js → ArtifactDemoPage-BDBXYv9l.js} +1 -1
  830. package/frontend/dist/js/{ArtifactSandboxFrame-DhqLNUtY.js → ArtifactSandboxFrame-BN16NtKe.js} +3 -3
  831. package/frontend/dist/js/{ArtifactSlideOutPanel-Cl8JG7bz.js → ArtifactSlideOutPanel-x1fS85Ww.js} +1 -1
  832. package/frontend/dist/js/{Button-CTXHujOd.js → Button-BV44cTnj.js} +1 -1
  833. package/frontend/dist/js/ChatPage-C_pXh7WN.js +23 -0
  834. package/frontend/dist/js/{FirstTimeSetup-kHhRzGJ8.js → FirstTimeSetup-oRrlZnBm.js} +1 -1
  835. package/frontend/dist/js/GalleryPage-CV_vbE7X.js +1 -0
  836. package/frontend/dist/js/{HomePage-C1L8WAXL.js → HomePage-P-e7Huco.js} +1 -1
  837. package/frontend/dist/js/{LibreClawPage-Dyua8IUu.js → LibreClawPage-Cee06SUM.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-DXucbvrz.js} +1 -1
  840. package/frontend/dist/js/ModelsPage-C3_fZpMM.js +2 -0
  841. package/frontend/dist/js/NotesPage-rEIPWGIb.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-BXtepFuD.js} +2 -2
  844. package/frontend/dist/js/PluginUsagePage-hhu8cxsu.js +1 -0
  845. package/frontend/dist/js/RichMessageContent-DkiEvdSg.js +3 -0
  846. package/frontend/dist/js/SettingsModal-BNxCtJ51.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-BvvKFuoG.js} +1 -1
  849. package/frontend/dist/js/UserManagementPage-BccyR7si.js +1 -0
  850. package/frontend/dist/js/WorkPage-BgxrvY3I.js +6 -0
  851. package/frontend/dist/js/api-BvPDxsUQ.js +14 -0
  852. package/frontend/dist/js/appStore-DRSSjaHn.js +2 -0
  853. package/frontend/dist/js/ar-xTSvTq05.js +2 -0
  854. package/frontend/dist/js/authStore-BVykIRec.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-UPp5TV_t.js +3 -0
  858. package/frontend/dist/js/{config-DkV1ka7I.js → config-BTlPm-cZ.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-CfYahF_d.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-BJsDX1UZ.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-GLyuUNig.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-BHddEFP1.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-Dh56V0YW.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-DRy7A9w4.js} +1 -1
  890. package/frontend/dist/js/{ui-BnDZpjfc.js → ui-CuY4IifA.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-DHuYNHLf.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,1205 @@
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 fs from 'node:fs';
19
+ import { lstat, mkdir, open, opendir, readdir, rename, stat, unlink, } from 'node:fs/promises';
20
+ import path from 'node:path';
21
+ import { Readable } from 'node:stream';
22
+ import { parseAesGcmEnvelope, StorageEncryptionError, } from './aesGcmKeyring.js';
23
+ import { BlobNotFoundError, BlobStoreError, NoopBlobQuotaPolicy, } from './blobStore.js';
24
+ const FILE_MAGIC = Buffer.from('LWBLB001', 'ascii');
25
+ const FILE_FORMAT_VERSION = 1;
26
+ const METADATA_IV_BYTES = 12;
27
+ const AUTH_TAG_BYTES = 16;
28
+ const BODY_NONCE_BYTES = 8;
29
+ const PREFIX_BYTES = FILE_MAGIC.length + 1 + 4 + 4 + METADATA_IV_BYTES + AUTH_TAG_BYTES;
30
+ const MAX_KEY_ENVELOPE_BYTES = 8 * 1024;
31
+ const MAX_METADATA_BYTES = 64 * 1024;
32
+ const DEFAULT_CHUNK_BYTES = 1024 * 1024;
33
+ const DEFAULT_MAX_OBJECT_BYTES = 512 * 1024 * 1024;
34
+ const DEFAULT_MAX_INTEGRITY_OBJECTS = 250000;
35
+ const DEFAULT_MAX_INTEGRITY_ENCRYPTED_BYTES = 64 * 1024 * 1024 * 1024;
36
+ const DEFAULT_MAX_INTEGRITY_PLAINTEXT_BYTES = 64 * 1024 * 1024 * 1024;
37
+ const MIN_CHUNK_BYTES = 64 * 1024;
38
+ const MAX_CHUNK_BYTES = 8 * 1024 * 1024;
39
+ const BLOB_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
40
+ const PURPOSE_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,63}$/;
41
+ const METADATA_KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
42
+ /** Zero key material before any asynchronous close can fail or be delayed. */
43
+ const disposeOpenedBlob = async (opened) => {
44
+ opened.dataKey.fill(0);
45
+ await opened.handle.close();
46
+ };
47
+ const storageError = (code, message, cause) => new BlobStoreError(code, message, cause);
48
+ const throwIfAborted = (signal) => {
49
+ if (signal?.aborted) {
50
+ throw storageError('aborted', 'Blob operation was aborted', signal.reason);
51
+ }
52
+ };
53
+ const validateBoundedString = (value, field, maximumLength) => {
54
+ if (!value ||
55
+ value.length > maximumLength ||
56
+ [...value].some(character => {
57
+ const codePoint = character.codePointAt(0) ?? 0;
58
+ return codePoint <= 31 || codePoint === 127;
59
+ })) {
60
+ throw storageError('invalid-input', `Invalid blob ${field}`);
61
+ }
62
+ };
63
+ const validateBlobId = (id) => {
64
+ if (!BLOB_ID_PATTERN.test(id)) {
65
+ throw new BlobNotFoundError();
66
+ }
67
+ };
68
+ const validateIntegrityLimit = (value, description) => {
69
+ if (!Number.isSafeInteger(value) || value <= 0) {
70
+ throw storageError('invalid-input', `Invalid ${description}`);
71
+ }
72
+ };
73
+ const ownerMatches = (expected, actual) => {
74
+ const expectedHash = crypto.createHash('sha256').update(expected).digest();
75
+ const actualHash = crypto.createHash('sha256').update(actual).digest();
76
+ return crypto.timingSafeEqual(expectedHash, actualHash);
77
+ };
78
+ const metadataAad = (blobId) => Buffer.from(JSON.stringify(['libre-blob-metadata', 1, blobId]), 'utf8');
79
+ const keyAad = (blobId) => Buffer.from(JSON.stringify(['libre-blob-key', 1, blobId]), 'utf8');
80
+ const chunkAad = (metadata, chunkIndex, plaintextBytes) => Buffer.from(JSON.stringify([
81
+ 'libre-blob-chunk',
82
+ 1,
83
+ metadata.id,
84
+ metadata.ownerUserId,
85
+ metadata.purpose,
86
+ chunkIndex,
87
+ plaintextBytes,
88
+ ]), 'utf8');
89
+ const createChunkIv = (baseNonce, chunkIndex) => {
90
+ if (baseNonce.length !== BODY_NONCE_BYTES) {
91
+ throw storageError('corrupt', 'Invalid encrypted blob nonce');
92
+ }
93
+ if (chunkIndex < 0 || chunkIndex > 0xffffffff) {
94
+ throw storageError('corrupt', 'Encrypted blob has too many chunks');
95
+ }
96
+ const iv = Buffer.allocUnsafe(12);
97
+ baseNonce.copy(iv, 0);
98
+ iv.writeUInt32BE(chunkIndex, BODY_NONCE_BYTES);
99
+ return iv;
100
+ };
101
+ const writeAll = async (handle, data) => {
102
+ let offset = 0;
103
+ while (offset < data.length) {
104
+ const { bytesWritten } = await handle.write(data, offset, data.length - offset);
105
+ if (bytesWritten <= 0) {
106
+ throw storageError('unavailable', 'Unable to write encrypted blob');
107
+ }
108
+ offset += bytesWritten;
109
+ }
110
+ };
111
+ const readExactly = async (handle, length, position) => {
112
+ const buffer = Buffer.allocUnsafe(length);
113
+ let offset = 0;
114
+ while (offset < length) {
115
+ const { bytesRead } = await handle.read(buffer, offset, length - offset, position + offset);
116
+ if (bytesRead <= 0) {
117
+ throw storageError('corrupt', 'Encrypted blob is truncated');
118
+ }
119
+ offset += bytesRead;
120
+ }
121
+ return buffer;
122
+ };
123
+ const fixedChunks = async function* (source, chunkBytes, signal) {
124
+ let carry = Buffer.alloc(0);
125
+ for await (const value of source) {
126
+ throwIfAborted(signal);
127
+ let input = Buffer.isBuffer(value)
128
+ ? value
129
+ : Buffer.from(value.buffer, value.byteOffset, value.byteLength);
130
+ if (carry.length > 0) {
131
+ const required = chunkBytes - carry.length;
132
+ if (input.length < required) {
133
+ carry = Buffer.concat([carry, input], carry.length + input.length);
134
+ continue;
135
+ }
136
+ yield Buffer.concat([carry, input.subarray(0, required)], chunkBytes);
137
+ carry = Buffer.alloc(0);
138
+ input = input.subarray(required);
139
+ }
140
+ while (input.length >= chunkBytes) {
141
+ yield input.subarray(0, chunkBytes);
142
+ input = input.subarray(chunkBytes);
143
+ }
144
+ if (input.length > 0)
145
+ carry = Buffer.from(input);
146
+ }
147
+ throwIfAborted(signal);
148
+ if (carry.length > 0)
149
+ yield carry;
150
+ };
151
+ const parseJson = (value, description) => {
152
+ try {
153
+ return JSON.parse(value.toString('utf8'));
154
+ }
155
+ catch (error) {
156
+ throw storageError('corrupt', `Invalid encrypted blob ${description}`, error);
157
+ }
158
+ };
159
+ const normalizeMetadata = (metadata) => {
160
+ const entries = Object.entries(metadata ?? {});
161
+ if (entries.length > 32) {
162
+ throw storageError('invalid-input', 'Blob metadata has too many fields');
163
+ }
164
+ const normalized = {};
165
+ for (const [key, value] of entries.sort(([left], [right]) => left.localeCompare(right))) {
166
+ if (!METADATA_KEY_PATTERN.test(key)) {
167
+ throw storageError('invalid-input', `Invalid blob metadata key: ${key}`);
168
+ }
169
+ if (typeof value !== 'string' ||
170
+ Buffer.byteLength(value, 'utf8') > 4096 ||
171
+ value.includes('\u0000')) {
172
+ throw storageError('invalid-input', `Invalid blob metadata value: ${key}`);
173
+ }
174
+ normalized[key] = value;
175
+ }
176
+ return Object.freeze(normalized);
177
+ };
178
+ const validateRequest = (request, maxObjectBytes) => {
179
+ validateBoundedString(request.ownerUserId, 'owner', 256);
180
+ if (!PURPOSE_PATTERN.test(request.purpose)) {
181
+ throw storageError('invalid-input', 'Invalid blob purpose');
182
+ }
183
+ validateBoundedString(request.contentType, 'content type', 255);
184
+ if (request.originalFilename !== undefined) {
185
+ validateBoundedString(request.originalFilename, 'filename', 255);
186
+ }
187
+ if (request.expectedSize !== undefined &&
188
+ (!Number.isSafeInteger(request.expectedSize) ||
189
+ request.expectedSize < 0 ||
190
+ request.expectedSize > maxObjectBytes)) {
191
+ throw storageError('invalid-input', 'Invalid expected blob size');
192
+ }
193
+ return normalizeMetadata(request.metadata);
194
+ };
195
+ const isStoredBlobMetadata = (value) => {
196
+ if (!value || typeof value !== 'object' || Array.isArray(value))
197
+ return false;
198
+ const candidate = value;
199
+ return (typeof candidate.id === 'string' &&
200
+ BLOB_ID_PATTERN.test(candidate.id) &&
201
+ typeof candidate.ownerUserId === 'string' &&
202
+ candidate.ownerUserId.length > 0 &&
203
+ typeof candidate.purpose === 'string' &&
204
+ PURPOSE_PATTERN.test(candidate.purpose) &&
205
+ typeof candidate.contentType === 'string' &&
206
+ typeof candidate.size === 'number' &&
207
+ Number.isSafeInteger(candidate.size) &&
208
+ candidate.size >= 0 &&
209
+ typeof candidate.sha256 === 'string' &&
210
+ /^[a-f0-9]{64}$/.test(candidate.sha256) &&
211
+ typeof candidate.createdAt === 'string' &&
212
+ Number.isFinite(Date.parse(candidate.createdAt)) &&
213
+ typeof candidate.encryptionKeyId === 'string' &&
214
+ /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(candidate.encryptionKeyId) &&
215
+ candidate.formatVersion === FILE_FORMAT_VERSION &&
216
+ typeof candidate.chunkBytes === 'number' &&
217
+ Number.isSafeInteger(candidate.chunkBytes) &&
218
+ candidate.chunkBytes > 0 &&
219
+ typeof candidate.chunkCount === 'number' &&
220
+ Number.isSafeInteger(candidate.chunkCount) &&
221
+ candidate.chunkCount >= 0 &&
222
+ typeof candidate.bodyNonce === 'string' &&
223
+ Boolean(candidate.metadata) &&
224
+ typeof candidate.metadata === 'object' &&
225
+ !Array.isArray(candidate.metadata));
226
+ };
227
+ const publicDescriptor = (metadata) => ({
228
+ id: metadata.id,
229
+ ownerUserId: metadata.ownerUserId,
230
+ purpose: metadata.purpose,
231
+ contentType: metadata.contentType,
232
+ ...(metadata.originalFilename
233
+ ? { originalFilename: metadata.originalFilename }
234
+ : {}),
235
+ metadata: Object.freeze({ ...metadata.metadata }),
236
+ size: metadata.size,
237
+ sha256: metadata.sha256,
238
+ createdAt: metadata.createdAt,
239
+ encryptionKeyId: metadata.encryptionKeyId,
240
+ formatVersion: metadata.formatVersion,
241
+ });
242
+ /**
243
+ * Immutable local blob backend with chunked authenticated encryption.
244
+ *
245
+ * Each blob receives a random data key. The configured keyring wraps that key;
246
+ * metadata is encrypted, and every body chunk is bound to blob ID, owner,
247
+ * purpose, chunk index, and plaintext length through AES-GCM AAD.
248
+ */
249
+ export class LocalEncryptedBlobStore {
250
+ constructor(options) {
251
+ this.initialized = null;
252
+ if (!path.isAbsolute(options.rootDirectory)) {
253
+ throw storageError('invalid-input', 'Local blob root directory must be absolute');
254
+ }
255
+ const chunkBytes = options.chunkBytes ?? DEFAULT_CHUNK_BYTES;
256
+ if (!Number.isSafeInteger(chunkBytes) ||
257
+ chunkBytes < MIN_CHUNK_BYTES ||
258
+ chunkBytes > MAX_CHUNK_BYTES) {
259
+ throw storageError('invalid-input', 'Blob chunk size must be between 64 KiB and 8 MiB');
260
+ }
261
+ const maxObjectBytes = options.maxObjectBytes ?? DEFAULT_MAX_OBJECT_BYTES;
262
+ if (!Number.isSafeInteger(maxObjectBytes) || maxObjectBytes <= 0) {
263
+ throw storageError('invalid-input', 'Invalid maximum blob size');
264
+ }
265
+ this.rootDirectory = path.resolve(options.rootDirectory);
266
+ this.objectsDirectory = path.join(this.rootDirectory, 'objects');
267
+ this.stagingDirectory = path.join(this.rootDirectory, 'staging');
268
+ this.keyring = options.keyring;
269
+ this.quotaPolicy = options.quotaPolicy ?? new NoopBlobQuotaPolicy();
270
+ this.chunkBytes = chunkBytes;
271
+ this.maxObjectBytes = maxObjectBytes;
272
+ this.now = options.now ?? (() => new Date());
273
+ this.readOnly = options.readOnly === true;
274
+ }
275
+ async initialize() {
276
+ if (!this.initialized) {
277
+ this.initialized = (async () => {
278
+ if (this.readOnly) {
279
+ await this.assertPrivateDirectory(this.rootDirectory, false);
280
+ await this.assertPrivateDirectory(this.objectsDirectory, false);
281
+ return;
282
+ }
283
+ const rootCreated = await mkdir(this.rootDirectory, {
284
+ recursive: true,
285
+ mode: 0o700,
286
+ });
287
+ await this.assertPrivateDirectory(this.rootDirectory);
288
+ const objectsCreated = await mkdir(this.objectsDirectory, {
289
+ recursive: true,
290
+ mode: 0o700,
291
+ });
292
+ await this.assertPrivateDirectory(this.objectsDirectory);
293
+ const stagingCreated = await mkdir(this.stagingDirectory, {
294
+ recursive: true,
295
+ mode: 0o700,
296
+ });
297
+ await this.assertPrivateDirectory(this.stagingDirectory);
298
+ if (objectsCreated || stagingCreated) {
299
+ await this.syncDirectory(this.rootDirectory);
300
+ }
301
+ if (rootCreated) {
302
+ await this.syncDirectory(path.dirname(this.rootDirectory));
303
+ }
304
+ })().catch(error => {
305
+ this.initialized = null;
306
+ throw storageError('unavailable', 'Unable to initialize local blob storage', error);
307
+ });
308
+ }
309
+ await this.initialized;
310
+ }
311
+ async assertPrivateDirectory(directory, repairPermissions = true) {
312
+ const directoryStat = await lstat(directory);
313
+ if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
314
+ throw storageError('unavailable', `Local blob path is not a physical directory: ${directory}`);
315
+ }
316
+ if (repairPermissions) {
317
+ await fs.promises.chmod(directory, 0o700);
318
+ }
319
+ else if (process.platform !== 'win32' &&
320
+ (directoryStat.mode & 0o077) !== 0) {
321
+ throw storageError('unavailable', `Local blob path is not private: ${directory}`);
322
+ }
323
+ }
324
+ objectPath(id) {
325
+ validateBlobId(id);
326
+ return path.join(this.objectsDirectory, id.slice(0, 2), id.slice(2, 4), `${id}.blob`);
327
+ }
328
+ async ensureObjectDirectory(id) {
329
+ validateBlobId(id);
330
+ let current = this.objectsDirectory;
331
+ for (const shard of [id.slice(0, 2), id.slice(2, 4)]) {
332
+ current = path.join(current, shard);
333
+ let created = false;
334
+ try {
335
+ await mkdir(current, { mode: 0o700 });
336
+ created = true;
337
+ }
338
+ catch (error) {
339
+ if (error.code !== 'EEXIST')
340
+ throw error;
341
+ }
342
+ // Validate every component separately. Recursive mkdir would follow an
343
+ // attacker-controlled intermediate symlink before the final check.
344
+ await this.assertPrivateDirectory(current);
345
+ if (created) {
346
+ // A file fsync cannot make a newly-created shard name durable in its
347
+ // parent directory. Persist each level before publishing into it.
348
+ await this.syncDirectory(path.dirname(current));
349
+ }
350
+ }
351
+ return current;
352
+ }
353
+ async syncDirectory(directory) {
354
+ let handle;
355
+ try {
356
+ handle = await open(directory, fs.constants.O_RDONLY);
357
+ await handle.sync();
358
+ }
359
+ catch (error) {
360
+ if (process.platform !== 'win32')
361
+ throw error;
362
+ }
363
+ finally {
364
+ await handle?.close();
365
+ }
366
+ }
367
+ async unlinkIfExists(filePath) {
368
+ try {
369
+ await unlink(filePath);
370
+ return true;
371
+ }
372
+ catch (error) {
373
+ if (error.code === 'ENOENT')
374
+ return false;
375
+ throw error;
376
+ }
377
+ }
378
+ async unlinkDurably(filePath) {
379
+ const removed = await this.unlinkIfExists(filePath);
380
+ if (removed)
381
+ await this.syncDirectory(path.dirname(filePath));
382
+ return removed;
383
+ }
384
+ async cleanupStagingFiles(filePaths) {
385
+ let removed = false;
386
+ for (const filePath of filePaths) {
387
+ try {
388
+ removed = (await this.unlinkIfExists(filePath)) || removed;
389
+ }
390
+ catch {
391
+ // Stale private staging files are recoverable through cleanupOrphans.
392
+ }
393
+ }
394
+ if (removed) {
395
+ await this.syncDirectory(this.stagingDirectory).catch(() => undefined);
396
+ }
397
+ }
398
+ async put(request) {
399
+ await this.initialize();
400
+ throwIfAborted(request.signal);
401
+ const normalizedMetadata = validateRequest(request, this.maxObjectBytes);
402
+ const reservation = await this.quotaPolicy.reserve({
403
+ ownerUserId: request.ownerUserId,
404
+ purpose: request.purpose,
405
+ ...(request.expectedSize !== undefined
406
+ ? { expectedSize: request.expectedSize }
407
+ : {}),
408
+ });
409
+ const id = crypto.randomUUID();
410
+ const suffix = crypto.randomBytes(12).toString('hex');
411
+ const bodyTemporaryPath = path.join(this.stagingDirectory, `${id}.${suffix}.body.tmp`);
412
+ const objectTemporaryPath = path.join(this.stagingDirectory, `${id}.${suffix}.object.tmp`);
413
+ const destinationPath = this.objectPath(id);
414
+ let destinationVisible = false;
415
+ let quotaCommitted = false;
416
+ let dataKey;
417
+ try {
418
+ dataKey = crypto.randomBytes(32);
419
+ const bodyNonce = crypto.randomBytes(BODY_NONCE_BYTES);
420
+ const digest = crypto.createHash('sha256');
421
+ let size = 0;
422
+ let chunkCount = 0;
423
+ const bodyHandle = await open(bodyTemporaryPath, fs.constants.O_CREAT |
424
+ fs.constants.O_EXCL |
425
+ fs.constants.O_WRONLY |
426
+ fs.constants.O_NOFOLLOW, 0o600);
427
+ try {
428
+ for await (const chunk of fixedChunks(request.source, this.chunkBytes, request.signal)) {
429
+ const nextSize = size + chunk.length;
430
+ if (nextSize > this.maxObjectBytes) {
431
+ throw storageError('quota-exceeded', 'Blob exceeds the maximum object size');
432
+ }
433
+ await reservation.consume(chunk.length);
434
+ throwIfAborted(request.signal);
435
+ const cipher = crypto.createCipheriv('aes-256-gcm', dataKey, createChunkIv(bodyNonce, chunkCount));
436
+ cipher.setAAD(chunkAad({
437
+ id,
438
+ ownerUserId: request.ownerUserId,
439
+ purpose: request.purpose,
440
+ }, chunkCount, chunk.length));
441
+ const ciphertext = Buffer.concat([
442
+ cipher.update(chunk),
443
+ cipher.final(),
444
+ ]);
445
+ await writeAll(bodyHandle, ciphertext);
446
+ await writeAll(bodyHandle, cipher.getAuthTag());
447
+ digest.update(chunk);
448
+ size = nextSize;
449
+ chunkCount += 1;
450
+ }
451
+ await bodyHandle.sync();
452
+ }
453
+ finally {
454
+ await bodyHandle.close();
455
+ }
456
+ if (request.expectedSize !== undefined && request.expectedSize !== size) {
457
+ throw storageError('invalid-input', `Expected ${request.expectedSize} blob bytes but received ${size}`);
458
+ }
459
+ const wrappedDataKey = this.keyring.encrypt(dataKey, keyAad(id));
460
+ const metadata = {
461
+ id,
462
+ ownerUserId: request.ownerUserId,
463
+ purpose: request.purpose,
464
+ contentType: request.contentType,
465
+ ...(request.originalFilename
466
+ ? { originalFilename: request.originalFilename }
467
+ : {}),
468
+ metadata: normalizedMetadata,
469
+ size,
470
+ sha256: digest.digest('hex'),
471
+ createdAt: this.now().toISOString(),
472
+ encryptionKeyId: wrappedDataKey.keyId,
473
+ formatVersion: FILE_FORMAT_VERSION,
474
+ chunkBytes: this.chunkBytes,
475
+ chunkCount,
476
+ bodyNonce: bodyNonce.toString('base64'),
477
+ };
478
+ const metadataPlaintext = Buffer.from(JSON.stringify(metadata), 'utf8');
479
+ if (metadataPlaintext.length > MAX_METADATA_BYTES) {
480
+ throw storageError('invalid-input', 'Blob metadata is too large');
481
+ }
482
+ const metadataIv = crypto.randomBytes(METADATA_IV_BYTES);
483
+ const metadataCipher = crypto.createCipheriv('aes-256-gcm', dataKey, metadataIv);
484
+ metadataCipher.setAAD(metadataAad(id));
485
+ const encryptedMetadata = Buffer.concat([
486
+ metadataCipher.update(metadataPlaintext),
487
+ metadataCipher.final(),
488
+ ]);
489
+ const keyEnvelope = Buffer.from(JSON.stringify(wrappedDataKey), 'utf8');
490
+ if (keyEnvelope.length > MAX_KEY_ENVELOPE_BYTES) {
491
+ throw storageError('invalid-input', 'Blob key envelope is too large');
492
+ }
493
+ const prefix = Buffer.allocUnsafe(PREFIX_BYTES);
494
+ FILE_MAGIC.copy(prefix, 0);
495
+ prefix.writeUInt8(FILE_FORMAT_VERSION, FILE_MAGIC.length);
496
+ prefix.writeUInt32BE(keyEnvelope.length, FILE_MAGIC.length + 1);
497
+ prefix.writeUInt32BE(encryptedMetadata.length, FILE_MAGIC.length + 1 + 4);
498
+ metadataIv.copy(prefix, FILE_MAGIC.length + 1 + 4 + 4);
499
+ metadataCipher
500
+ .getAuthTag()
501
+ .copy(prefix, FILE_MAGIC.length + 1 + 4 + 4 + METADATA_IV_BYTES);
502
+ const objectHandle = await open(objectTemporaryPath, fs.constants.O_CREAT |
503
+ fs.constants.O_EXCL |
504
+ fs.constants.O_WRONLY |
505
+ fs.constants.O_NOFOLLOW, 0o600);
506
+ try {
507
+ await writeAll(objectHandle, prefix);
508
+ await writeAll(objectHandle, keyEnvelope);
509
+ await writeAll(objectHandle, encryptedMetadata);
510
+ const bodyStream = fs.createReadStream(bodyTemporaryPath);
511
+ for await (const chunk of bodyStream) {
512
+ throwIfAborted(request.signal);
513
+ await writeAll(objectHandle, chunk);
514
+ }
515
+ await objectHandle.sync();
516
+ }
517
+ finally {
518
+ await objectHandle.close();
519
+ }
520
+ const destinationDirectory = await this.ensureObjectDirectory(id);
521
+ throwIfAborted(request.signal);
522
+ await rename(objectTemporaryPath, destinationPath);
523
+ destinationVisible = true;
524
+ // rename(2) crosses from staging into a shard. Both directory entries
525
+ // must be synced: the destination fsync persists visibility, while the
526
+ // source fsync persists removal of the staging name.
527
+ await this.syncDirectory(destinationDirectory);
528
+ await this.syncDirectory(this.stagingDirectory);
529
+ // The encrypted body staging file is no longer needed. Remove and sync it
530
+ // before committing quota so a successful put has no undurable cleanup.
531
+ await this.unlinkDurably(bodyTemporaryPath);
532
+ const descriptor = publicDescriptor(metadata);
533
+ await reservation.commit(descriptor);
534
+ quotaCommitted = true;
535
+ return descriptor;
536
+ }
537
+ catch (error) {
538
+ if (destinationVisible) {
539
+ await this.unlinkDurably(destinationPath).catch(() => undefined);
540
+ }
541
+ if (error instanceof BlobStoreError)
542
+ throw error;
543
+ if (error instanceof StorageEncryptionError) {
544
+ throw storageError('corrupt', error.message, error);
545
+ }
546
+ throw storageError('unavailable', 'Unable to store encrypted blob', error);
547
+ }
548
+ finally {
549
+ dataKey?.fill(0);
550
+ await this.cleanupStagingFiles([bodyTemporaryPath, objectTemporaryPath]);
551
+ if (!quotaCommitted)
552
+ await reservation.release();
553
+ }
554
+ }
555
+ async openInternal(id, ownerUserId, options = {}) {
556
+ if (!options.skipInitialization)
557
+ await this.initialize();
558
+ validateBlobId(id);
559
+ let handle;
560
+ let dataKey;
561
+ try {
562
+ handle = await open(this.objectPath(id), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
563
+ }
564
+ catch (error) {
565
+ if (error.code === 'ENOENT') {
566
+ throw new BlobNotFoundError();
567
+ }
568
+ throw storageError('unavailable', 'Unable to open encrypted blob', error);
569
+ }
570
+ try {
571
+ const prefix = await readExactly(handle, PREFIX_BYTES, 0);
572
+ if (!prefix.subarray(0, FILE_MAGIC.length).equals(FILE_MAGIC)) {
573
+ throw storageError('corrupt', 'Invalid encrypted blob format');
574
+ }
575
+ const version = prefix.readUInt8(FILE_MAGIC.length);
576
+ if (version !== FILE_FORMAT_VERSION) {
577
+ throw storageError('corrupt', `Unsupported encrypted blob format version: ${version}`);
578
+ }
579
+ const envelopeBytes = prefix.readUInt32BE(FILE_MAGIC.length + 1);
580
+ const metadataBytes = prefix.readUInt32BE(FILE_MAGIC.length + 1 + 4);
581
+ if (envelopeBytes <= 0 ||
582
+ envelopeBytes > MAX_KEY_ENVELOPE_BYTES ||
583
+ metadataBytes <= 0 ||
584
+ metadataBytes > MAX_METADATA_BYTES) {
585
+ throw storageError('corrupt', 'Invalid encrypted blob header lengths');
586
+ }
587
+ const metadataIvStart = FILE_MAGIC.length + 1 + 4 + 4;
588
+ const metadataIv = prefix.subarray(metadataIvStart, metadataIvStart + METADATA_IV_BYTES);
589
+ const metadataTag = prefix.subarray(metadataIvStart + METADATA_IV_BYTES, PREFIX_BYTES);
590
+ const envelopeBuffer = await readExactly(handle, envelopeBytes, PREFIX_BYTES);
591
+ const envelope = parseAesGcmEnvelope(parseJson(envelopeBuffer, 'key envelope'));
592
+ dataKey = this.keyring.decrypt(envelope, keyAad(id));
593
+ if (dataKey.length !== 32) {
594
+ throw storageError('corrupt', 'Invalid encrypted blob data key');
595
+ }
596
+ const encryptedMetadata = await readExactly(handle, metadataBytes, PREFIX_BYTES + envelopeBytes);
597
+ let metadataPlaintext;
598
+ try {
599
+ const decipher = crypto.createDecipheriv('aes-256-gcm', dataKey, metadataIv, { authTagLength: AUTH_TAG_BYTES });
600
+ decipher.setAAD(metadataAad(id));
601
+ decipher.setAuthTag(metadataTag);
602
+ metadataPlaintext = Buffer.concat([
603
+ decipher.update(encryptedMetadata),
604
+ decipher.final(),
605
+ ]);
606
+ }
607
+ catch (error) {
608
+ throw storageError('corrupt', 'Encrypted blob metadata authentication failed', error);
609
+ }
610
+ const metadataValue = parseJson(metadataPlaintext, 'metadata');
611
+ if (!isStoredBlobMetadata(metadataValue) || metadataValue.id !== id) {
612
+ throw storageError('corrupt', 'Invalid encrypted blob metadata');
613
+ }
614
+ if (metadataValue.encryptionKeyId !== envelope.keyId ||
615
+ metadataValue.chunkBytes < MIN_CHUNK_BYTES ||
616
+ metadataValue.chunkBytes > MAX_CHUNK_BYTES) {
617
+ throw storageError('corrupt', 'Invalid encrypted blob metadata');
618
+ }
619
+ if (metadataValue.chunkCount !==
620
+ Math.ceil(metadataValue.size / metadataValue.chunkBytes) ||
621
+ metadataValue.chunkCount > 4294967296) {
622
+ throw storageError('corrupt', 'Invalid encrypted blob chunk count');
623
+ }
624
+ const bodyNonce = Buffer.from(metadataValue.bodyNonce, 'base64');
625
+ if (bodyNonce.length !== BODY_NONCE_BYTES ||
626
+ bodyNonce.toString('base64') !== metadataValue.bodyNonce) {
627
+ throw storageError('corrupt', 'Invalid encrypted blob body nonce');
628
+ }
629
+ if (ownerUserId !== undefined &&
630
+ !ownerMatches(ownerUserId, metadataValue.ownerUserId)) {
631
+ throw new BlobNotFoundError();
632
+ }
633
+ const bodyOffset = PREFIX_BYTES + envelopeBytes + metadataBytes;
634
+ const fileStat = await handle.stat();
635
+ const expectedFileBytes = bodyOffset +
636
+ metadataValue.size +
637
+ metadataValue.chunkCount * AUTH_TAG_BYTES;
638
+ if (!Number.isSafeInteger(expectedFileBytes) ||
639
+ !fileStat.isFile() ||
640
+ fileStat.size !== expectedFileBytes ||
641
+ (options.expectedStat !== undefined &&
642
+ (fileStat.dev !== options.expectedStat.dev ||
643
+ fileStat.ino !== options.expectedStat.ino ||
644
+ fileStat.size !== options.expectedStat.size))) {
645
+ throw storageError('corrupt', 'Invalid encrypted blob file size');
646
+ }
647
+ return { handle, metadata: metadataValue, dataKey, bodyOffset };
648
+ }
649
+ catch (error) {
650
+ dataKey?.fill(0);
651
+ await handle.close();
652
+ if (error instanceof BlobStoreError ||
653
+ error instanceof BlobNotFoundError) {
654
+ throw error;
655
+ }
656
+ if (error instanceof StorageEncryptionError) {
657
+ throw storageError('corrupt', error.message, error);
658
+ }
659
+ throw storageError('corrupt', 'Unable to authenticate encrypted blob', error);
660
+ }
661
+ }
662
+ async stat(id, ownerUserId) {
663
+ const opened = await this.openInternal(id, ownerUserId);
664
+ try {
665
+ return publicDescriptor(opened.metadata);
666
+ }
667
+ finally {
668
+ await disposeOpenedBlob(opened);
669
+ }
670
+ }
671
+ /**
672
+ * Offline migration/recovery inventory seam. This authenticates metadata
673
+ * without requiring the caller to trust relational owner metadata. Runtime
674
+ * request paths must continue to use owner-scoped stat/open.
675
+ */
676
+ async inspectAuthenticated(id) {
677
+ const opened = await this.openInternal(id);
678
+ try {
679
+ return publicDescriptor(opened.metadata);
680
+ }
681
+ finally {
682
+ await disposeOpenedBlob(opened);
683
+ }
684
+ }
685
+ async authenticateFullBody(opened, signal) {
686
+ const { metadata } = opened;
687
+ const digest = crypto.createHash('sha256');
688
+ const bodyNonce = Buffer.from(metadata.bodyNonce, 'base64');
689
+ for (let chunkIndex = 0; chunkIndex < metadata.chunkCount; chunkIndex += 1) {
690
+ throwIfAborted(signal);
691
+ const chunkStart = chunkIndex * metadata.chunkBytes;
692
+ const plaintextBytes = Math.min(metadata.chunkBytes, metadata.size - chunkStart);
693
+ const encryptedChunk = await readExactly(opened.handle, plaintextBytes + AUTH_TAG_BYTES, opened.bodyOffset + chunkIndex * (metadata.chunkBytes + AUTH_TAG_BYTES));
694
+ let plaintext;
695
+ try {
696
+ const decipher = crypto.createDecipheriv('aes-256-gcm', opened.dataKey, createChunkIv(bodyNonce, chunkIndex), { authTagLength: AUTH_TAG_BYTES });
697
+ decipher.setAAD(chunkAad(metadata, chunkIndex, plaintextBytes));
698
+ decipher.setAuthTag(encryptedChunk.subarray(plaintextBytes));
699
+ plaintext = Buffer.concat([
700
+ decipher.update(encryptedChunk.subarray(0, plaintextBytes)),
701
+ decipher.final(),
702
+ ]);
703
+ digest.update(plaintext);
704
+ }
705
+ catch (error) {
706
+ throw storageError('corrupt', 'Encrypted blob chunk authentication failed', error);
707
+ }
708
+ finally {
709
+ plaintext?.fill(0);
710
+ }
711
+ }
712
+ if (digest.digest('hex') !== metadata.sha256) {
713
+ throw storageError('corrupt', 'Encrypted blob checksum mismatch');
714
+ }
715
+ }
716
+ normalizeRange(metadata, request) {
717
+ if (!request.range)
718
+ return null;
719
+ if (metadata.size === 0) {
720
+ throw storageError('invalid-range', 'Empty blobs do not support ranges');
721
+ }
722
+ const { start } = request.range;
723
+ const requestedEnd = request.range.end ?? metadata.size - 1;
724
+ if (!Number.isSafeInteger(start) ||
725
+ !Number.isSafeInteger(requestedEnd) ||
726
+ start < 0 ||
727
+ start >= metadata.size ||
728
+ requestedEnd < start) {
729
+ throw storageError('invalid-range', 'Invalid blob byte range');
730
+ }
731
+ const end = Math.min(requestedEnd, metadata.size - 1);
732
+ return { start, end, total: metadata.size, length: end - start + 1 };
733
+ }
734
+ async open(request) {
735
+ throwIfAborted(request.signal);
736
+ const opened = await this.openInternal(request.id, request.ownerUserId);
737
+ let contentRange;
738
+ try {
739
+ contentRange = this.normalizeRange(opened.metadata, request);
740
+ }
741
+ catch (error) {
742
+ await disposeOpenedBlob(opened);
743
+ throw error;
744
+ }
745
+ const metadata = opened.metadata;
746
+ const start = contentRange?.start ?? 0;
747
+ const end = contentRange?.end ?? metadata.size - 1;
748
+ const fullRead = contentRange === null;
749
+ const bodyNonce = Buffer.from(metadata.bodyNonce, 'base64');
750
+ let disposePromise;
751
+ const dispose = () => {
752
+ disposePromise || (disposePromise = disposeOpenedBlob(opened));
753
+ return disposePromise;
754
+ };
755
+ const iterator = (async function* () {
756
+ const digest = fullRead ? crypto.createHash('sha256') : null;
757
+ try {
758
+ if (metadata.size === 0) {
759
+ if (digest?.digest('hex') !== metadata.sha256) {
760
+ throw storageError('corrupt', 'Encrypted blob checksum mismatch');
761
+ }
762
+ return;
763
+ }
764
+ const firstChunk = Math.floor(start / metadata.chunkBytes);
765
+ const finalChunk = Math.floor(end / metadata.chunkBytes);
766
+ for (let chunkIndex = firstChunk; chunkIndex <= finalChunk; chunkIndex += 1) {
767
+ throwIfAborted(request.signal);
768
+ const chunkStart = chunkIndex * metadata.chunkBytes;
769
+ const plaintextBytes = Math.min(metadata.chunkBytes, metadata.size - chunkStart);
770
+ const encryptedBytes = plaintextBytes + AUTH_TAG_BYTES;
771
+ const position = opened.bodyOffset +
772
+ chunkIndex * (metadata.chunkBytes + AUTH_TAG_BYTES);
773
+ const encryptedChunk = await readExactly(opened.handle, encryptedBytes, position);
774
+ let plaintext;
775
+ try {
776
+ const decipher = crypto.createDecipheriv('aes-256-gcm', opened.dataKey, createChunkIv(bodyNonce, chunkIndex), { authTagLength: AUTH_TAG_BYTES });
777
+ decipher.setAAD(chunkAad(metadata, chunkIndex, plaintextBytes));
778
+ decipher.setAuthTag(encryptedChunk.subarray(plaintextBytes));
779
+ plaintext = Buffer.concat([
780
+ decipher.update(encryptedChunk.subarray(0, plaintextBytes)),
781
+ decipher.final(),
782
+ ]);
783
+ }
784
+ catch (error) {
785
+ throw storageError('corrupt', 'Encrypted blob chunk authentication failed', error);
786
+ }
787
+ digest?.update(plaintext);
788
+ const sliceStart = Math.max(start - chunkStart, 0);
789
+ const sliceEnd = Math.min(end - chunkStart + 1, plaintext.length);
790
+ if (sliceEnd > sliceStart) {
791
+ yield plaintext.subarray(sliceStart, sliceEnd);
792
+ }
793
+ }
794
+ if (digest && digest.digest('hex') !== metadata.sha256) {
795
+ throw storageError('corrupt', 'Encrypted blob checksum mismatch');
796
+ }
797
+ }
798
+ finally {
799
+ await dispose();
800
+ }
801
+ })();
802
+ let body;
803
+ try {
804
+ body = Readable.from(iterator, { objectMode: false });
805
+ }
806
+ catch (error) {
807
+ await dispose();
808
+ throw error;
809
+ }
810
+ // Destroying an unconsumed Readable can return an async generator before
811
+ // its body (and therefore its finally block) ever starts. Close is the
812
+ // independent lifetime boundary that guarantees key/file cleanup there.
813
+ body.once('close', () => {
814
+ void dispose().catch(() => undefined);
815
+ });
816
+ return {
817
+ descriptor: publicDescriptor(metadata),
818
+ range: contentRange,
819
+ body,
820
+ };
821
+ }
822
+ async delete(request) {
823
+ throwIfAborted(request.signal);
824
+ let opened;
825
+ try {
826
+ opened = await this.openInternal(request.id, request.ownerUserId);
827
+ }
828
+ catch (error) {
829
+ if (error instanceof BlobNotFoundError) {
830
+ if ('releaseStored' in this.quotaPolicy) {
831
+ await this.quotaPolicy.releaseStored({ id: request.id, ownerUserId: request.ownerUserId });
832
+ }
833
+ return false;
834
+ }
835
+ throw error;
836
+ }
837
+ await disposeOpenedBlob(opened);
838
+ throwIfAborted(request.signal);
839
+ try {
840
+ const removed = await this.unlinkDurably(this.objectPath(request.id));
841
+ if (removed && 'releaseStored' in this.quotaPolicy) {
842
+ await this.quotaPolicy.releaseStored({ id: request.id, ownerUserId: request.ownerUserId });
843
+ }
844
+ return removed;
845
+ }
846
+ catch (error) {
847
+ if (error.code === 'ENOENT')
848
+ return false;
849
+ throw storageError('unavailable', 'Unable to delete encrypted blob', error);
850
+ }
851
+ }
852
+ async integrityDirectoryExists(directory, allowMissing = false) {
853
+ let directoryStat;
854
+ try {
855
+ directoryStat = await lstat(directory);
856
+ }
857
+ catch (error) {
858
+ if (allowMissing && error.code === 'ENOENT') {
859
+ return false;
860
+ }
861
+ throw storageError('unavailable', 'Unable to inspect the local blob-store directory', error);
862
+ }
863
+ if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
864
+ throw storageError('corrupt', 'Local blob storage contains a non-physical directory');
865
+ }
866
+ return true;
867
+ }
868
+ async *integrityDirectoryEntries(directory) {
869
+ let directoryHandle;
870
+ try {
871
+ directoryHandle = await opendir(directory);
872
+ }
873
+ catch (error) {
874
+ throw storageError('unavailable', 'Unable to enumerate the local blob-store directory', error);
875
+ }
876
+ try {
877
+ for await (const entry of directoryHandle)
878
+ yield entry;
879
+ }
880
+ catch (error) {
881
+ throw storageError('unavailable', 'Unable to enumerate the local blob-store directory', error);
882
+ }
883
+ }
884
+ async *integrityCandidates() {
885
+ if (!(await this.integrityDirectoryExists(this.rootDirectory, true)))
886
+ return;
887
+ for await (const entry of this.integrityDirectoryEntries(this.rootDirectory)) {
888
+ if (entry.name !== 'objects' && entry.name !== 'staging') {
889
+ throw storageError('corrupt', 'Local blob storage contains an unexpected root entry');
890
+ }
891
+ await this.integrityDirectoryExists(path.join(this.rootDirectory, entry.name));
892
+ }
893
+ if (!(await this.integrityDirectoryExists(this.objectsDirectory, true))) {
894
+ return;
895
+ }
896
+ for await (const firstShard of this.integrityDirectoryEntries(this.objectsDirectory)) {
897
+ if (!/^[0-9a-f]{2}$/.test(firstShard.name)) {
898
+ throw storageError('corrupt', 'Local blob storage contains an invalid object shard');
899
+ }
900
+ const firstPath = path.join(this.objectsDirectory, firstShard.name);
901
+ await this.integrityDirectoryExists(firstPath);
902
+ for await (const secondShard of this.integrityDirectoryEntries(firstPath)) {
903
+ if (!/^[0-9a-f]{2}$/.test(secondShard.name)) {
904
+ throw storageError('corrupt', 'Local blob storage contains an invalid object shard');
905
+ }
906
+ const secondPath = path.join(firstPath, secondShard.name);
907
+ await this.integrityDirectoryExists(secondPath);
908
+ for await (const objectEntry of this.integrityDirectoryEntries(secondPath)) {
909
+ const match = /^([0-9a-f-]{36})\.blob$/.exec(objectEntry.name);
910
+ const id = match?.[1];
911
+ if (!id ||
912
+ !BLOB_ID_PATTERN.test(id) ||
913
+ id.slice(0, 2) !== firstShard.name ||
914
+ id.slice(2, 4) !== secondShard.name) {
915
+ throw storageError('corrupt', 'Local blob storage contains an invalid object name');
916
+ }
917
+ const objectPath = path.join(secondPath, objectEntry.name);
918
+ let objectStat;
919
+ try {
920
+ objectStat = await lstat(objectPath);
921
+ }
922
+ catch (error) {
923
+ throw storageError('unavailable', 'Unable to inspect a local blob object', error);
924
+ }
925
+ if (!objectStat.isFile() ||
926
+ objectStat.isSymbolicLink() ||
927
+ objectStat.nlink !== 1 ||
928
+ !Number.isSafeInteger(objectStat.size) ||
929
+ objectStat.size <= 0) {
930
+ throw storageError('corrupt', 'Local blob storage contains an invalid physical object');
931
+ }
932
+ yield { id, stat: objectStat };
933
+ }
934
+ }
935
+ }
936
+ }
937
+ /**
938
+ * Authenticates every durable local object without creating directories,
939
+ * changing permissions, deleting or rewriting source data. Work is bounded
940
+ * before each object is opened and plaintext is processed one chunk at a
941
+ * time.
942
+ */
943
+ async verifyIntegrity(options = {}) {
944
+ const maxObjects = options.maxObjects ?? DEFAULT_MAX_INTEGRITY_OBJECTS;
945
+ const maxEncryptedBytes = options.maxEncryptedBytes ?? DEFAULT_MAX_INTEGRITY_ENCRYPTED_BYTES;
946
+ const maxPlaintextBytes = options.maxPlaintextBytes ?? DEFAULT_MAX_INTEGRITY_PLAINTEXT_BYTES;
947
+ validateIntegrityLimit(maxObjects, 'blob integrity object limit');
948
+ validateIntegrityLimit(maxEncryptedBytes, 'blob integrity encrypted-byte limit');
949
+ validateIntegrityLimit(maxPlaintextBytes, 'blob integrity plaintext-byte limit');
950
+ let objects = 0;
951
+ let encryptedBytes = 0;
952
+ let plaintextBytes = 0;
953
+ for await (const candidate of this.integrityCandidates()) {
954
+ throwIfAborted(options.signal);
955
+ objects += 1;
956
+ encryptedBytes += candidate.stat.size;
957
+ if (!Number.isSafeInteger(encryptedBytes) ||
958
+ objects > maxObjects ||
959
+ encryptedBytes > maxEncryptedBytes) {
960
+ throw storageError('verification-limit', 'Local blob storage exceeds bounded integrity verification limits');
961
+ }
962
+ const opened = await this.openInternal(candidate.id, undefined, {
963
+ skipInitialization: true,
964
+ expectedStat: candidate.stat,
965
+ });
966
+ try {
967
+ plaintextBytes += opened.metadata.size;
968
+ if (!Number.isSafeInteger(plaintextBytes) ||
969
+ plaintextBytes > maxPlaintextBytes) {
970
+ throw storageError('verification-limit', 'Local blob storage exceeds bounded integrity verification limits');
971
+ }
972
+ await this.authenticateFullBody(opened, options.signal);
973
+ const after = await opened.handle.stat();
974
+ if (after.dev !== candidate.stat.dev ||
975
+ after.ino !== candidate.stat.ino ||
976
+ after.size !== candidate.stat.size ||
977
+ after.mtimeMs !== candidate.stat.mtimeMs ||
978
+ after.ctimeMs !== candidate.stat.ctimeMs) {
979
+ throw storageError('corrupt', 'Local blob object changed during integrity verification');
980
+ }
981
+ }
982
+ finally {
983
+ await disposeOpenedBlob(opened);
984
+ }
985
+ }
986
+ return { objects, encryptedBytes, plaintextBytes };
987
+ }
988
+ async listObjectFiles(directory) {
989
+ const entries = await readdir(directory, { withFileTypes: true }).catch((error) => {
990
+ if (error.code === 'ENOENT')
991
+ return [];
992
+ throw error;
993
+ });
994
+ const paths = [];
995
+ for (const entry of entries) {
996
+ const entryPath = path.join(directory, entry.name);
997
+ if (entry.isDirectory()) {
998
+ paths.push(...(await this.listObjectFiles(entryPath)));
999
+ }
1000
+ else if (entry.isFile() && entry.name.endsWith('.blob')) {
1001
+ paths.push(entryPath);
1002
+ }
1003
+ }
1004
+ return paths;
1005
+ }
1006
+ decodeReconciliationCursor(token) {
1007
+ if (token === undefined)
1008
+ return { phase: 'objects', after: '' };
1009
+ if (typeof token !== 'string' ||
1010
+ token.length === 0 ||
1011
+ Buffer.byteLength(token, 'utf8') > 4096) {
1012
+ throw storageError('invalid-input', 'Invalid local reconciliation cursor');
1013
+ }
1014
+ try {
1015
+ const parsed = JSON.parse(Buffer.from(token, 'base64url').toString('utf8'));
1016
+ if ((parsed.phase !== 'objects' && parsed.phase !== 'staging') ||
1017
+ typeof parsed.after !== 'string' ||
1018
+ Buffer.byteLength(parsed.after, 'utf8') > 1024 ||
1019
+ parsed.after.includes('\u0000') ||
1020
+ parsed.after.includes('\\') ||
1021
+ path.posix.isAbsolute(parsed.after) ||
1022
+ parsed.after.split('/').some(part => part === '.' || part === '..') ||
1023
+ (parsed.phase === 'staging' && parsed.after.includes('/'))) {
1024
+ throw new Error('invalid');
1025
+ }
1026
+ return { phase: parsed.phase, after: parsed.after };
1027
+ }
1028
+ catch {
1029
+ throw storageError('invalid-input', 'Invalid local reconciliation cursor');
1030
+ }
1031
+ }
1032
+ encodeReconciliationCursor(cursor) {
1033
+ return Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url');
1034
+ }
1035
+ /**
1036
+ * Bounded, restart-safe local lifecycle reconciliation.
1037
+ *
1038
+ * Object names are traversed in their fixed UUID shard order. A cursor may
1039
+ * therefore resume without materializing the whole object tree. New names
1040
+ * that sort before an active cursor are picked up after the scan completes;
1041
+ * the age grace prevents those in-flight writes from being collected.
1042
+ */
1043
+ async reconcileOrphans(options) {
1044
+ await this.initialize();
1045
+ if (!Number.isFinite(options.olderThan.getTime())) {
1046
+ throw storageError('invalid-input', 'Invalid blob orphan cutoff');
1047
+ }
1048
+ if (!Number.isSafeInteger(options.maxEntries) ||
1049
+ options.maxEntries < 1 ||
1050
+ options.maxEntries > 100000) {
1051
+ throw storageError('invalid-input', 'Invalid local reconciliation entry limit');
1052
+ }
1053
+ const cutoff = options.olderThan.getTime();
1054
+ const cursor = this.decodeReconciliationCursor(options.continuationToken);
1055
+ let inspectedEntries = 0;
1056
+ let deletedObjects = 0;
1057
+ let retainedObjects = 0;
1058
+ let deletedStagingFiles = 0;
1059
+ const incomplete = (phase, after) => ({
1060
+ deletedObjects,
1061
+ deletedStagingFiles,
1062
+ retainedObjects,
1063
+ inspectedEntries,
1064
+ complete: false,
1065
+ continuationToken: this.encodeReconciliationCursor({ phase, after }),
1066
+ });
1067
+ if (cursor.phase === 'objects') {
1068
+ const firstShards = (await readdir(this.objectsDirectory, { withFileTypes: true }))
1069
+ .filter(entry => entry.isDirectory())
1070
+ .map(entry => entry.name)
1071
+ .sort();
1072
+ for (const firstShard of firstShards) {
1073
+ const firstDirectory = path.join(this.objectsDirectory, firstShard);
1074
+ const secondShards = (await readdir(firstDirectory, { withFileTypes: true }).catch((error) => {
1075
+ if (error.code === 'ENOENT')
1076
+ return [];
1077
+ throw error;
1078
+ }))
1079
+ .filter(entry => entry.isDirectory())
1080
+ .map(entry => entry.name)
1081
+ .sort();
1082
+ for (const secondShard of secondShards) {
1083
+ const secondDirectory = path.join(firstDirectory, secondShard);
1084
+ const files = (await readdir(secondDirectory, { withFileTypes: true }).catch((error) => {
1085
+ if (error.code === 'ENOENT')
1086
+ return [];
1087
+ throw error;
1088
+ }))
1089
+ .filter(entry => entry.isFile() && entry.name.endsWith('.blob'))
1090
+ .map(entry => entry.name)
1091
+ .sort();
1092
+ for (const filename of files) {
1093
+ const relative = `${firstShard}/${secondShard}/${filename}`;
1094
+ if (relative <= cursor.after)
1095
+ continue;
1096
+ throwIfAborted(options.signal);
1097
+ inspectedEntries += 1;
1098
+ const objectPath = path.join(secondDirectory, filename);
1099
+ let objectStat;
1100
+ try {
1101
+ objectStat = await lstat(objectPath);
1102
+ }
1103
+ catch (error) {
1104
+ if (error.code !== 'ENOENT') {
1105
+ throw error;
1106
+ }
1107
+ }
1108
+ if (objectStat?.isFile() && !objectStat.isSymbolicLink()) {
1109
+ const blobId = path.basename(filename, '.blob');
1110
+ if (objectStat.mtimeMs >= cutoff ||
1111
+ !BLOB_ID_PATTERN.test(blobId) ||
1112
+ (await options.isReferenced(blobId))) {
1113
+ retainedObjects += 1;
1114
+ }
1115
+ else if (await this.unlinkDurably(objectPath)) {
1116
+ deletedObjects += 1;
1117
+ }
1118
+ }
1119
+ if (inspectedEntries >= options.maxEntries) {
1120
+ return incomplete('objects', relative);
1121
+ }
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+ const stagingAfter = cursor.phase === 'staging' ? cursor.after : '';
1127
+ const stagingEntries = (await readdir(this.stagingDirectory, { withFileTypes: true }))
1128
+ .filter(entry => entry.isFile() && entry.name.endsWith('.tmp'))
1129
+ .map(entry => entry.name)
1130
+ .sort();
1131
+ for (const filename of stagingEntries) {
1132
+ if (filename <= stagingAfter)
1133
+ continue;
1134
+ throwIfAborted(options.signal);
1135
+ inspectedEntries += 1;
1136
+ const stagingPath = path.join(this.stagingDirectory, filename);
1137
+ let stagingStat;
1138
+ try {
1139
+ stagingStat = await lstat(stagingPath);
1140
+ }
1141
+ catch (error) {
1142
+ if (error.code !== 'ENOENT')
1143
+ throw error;
1144
+ }
1145
+ if (stagingStat?.isFile() &&
1146
+ !stagingStat.isSymbolicLink() &&
1147
+ stagingStat.mtimeMs < cutoff &&
1148
+ (await this.unlinkDurably(stagingPath))) {
1149
+ deletedStagingFiles += 1;
1150
+ }
1151
+ if (inspectedEntries >= options.maxEntries) {
1152
+ return incomplete('staging', filename);
1153
+ }
1154
+ }
1155
+ return {
1156
+ deletedObjects,
1157
+ deletedStagingFiles,
1158
+ retainedObjects,
1159
+ inspectedEntries,
1160
+ complete: true,
1161
+ };
1162
+ }
1163
+ async cleanupOrphans(options) {
1164
+ await this.initialize();
1165
+ if (!Number.isFinite(options.olderThan.getTime())) {
1166
+ throw storageError('invalid-input', 'Invalid blob orphan cutoff');
1167
+ }
1168
+ const cutoff = options.olderThan.getTime();
1169
+ let deletedObjects = 0;
1170
+ let retainedObjects = 0;
1171
+ let deletedStagingFiles = 0;
1172
+ for (const objectPath of await this.listObjectFiles(this.objectsDirectory)) {
1173
+ throwIfAborted(options.signal);
1174
+ const objectStat = await stat(objectPath);
1175
+ if (objectStat.mtimeMs >= cutoff) {
1176
+ retainedObjects += 1;
1177
+ continue;
1178
+ }
1179
+ const blobId = path.basename(objectPath, '.blob');
1180
+ if (!BLOB_ID_PATTERN.test(blobId) ||
1181
+ (await options.isReferenced(blobId))) {
1182
+ retainedObjects += 1;
1183
+ continue;
1184
+ }
1185
+ if (await this.unlinkDurably(objectPath))
1186
+ deletedObjects += 1;
1187
+ }
1188
+ const stagingEntries = await readdir(this.stagingDirectory, {
1189
+ withFileTypes: true,
1190
+ });
1191
+ for (const entry of stagingEntries) {
1192
+ throwIfAborted(options.signal);
1193
+ if (!entry.isFile() || !entry.name.endsWith('.tmp'))
1194
+ continue;
1195
+ const stagingPath = path.join(this.stagingDirectory, entry.name);
1196
+ const stagingStat = await stat(stagingPath);
1197
+ if (stagingStat.mtimeMs >= cutoff)
1198
+ continue;
1199
+ if (await this.unlinkDurably(stagingPath))
1200
+ deletedStagingFiles += 1;
1201
+ }
1202
+ return { deletedObjects, deletedStagingFiles, retainedObjects };
1203
+ }
1204
+ }
1205
+ //# sourceMappingURL=localEncryptedBlobStore.js.map