libre-webui 0.21.3 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +308 -328
- package/backend/dist/cli/migrateSqliteToPostgres.d.ts +2 -0
- package/backend/dist/cli/migrateSqliteToPostgres.d.ts.map +1 -0
- package/backend/dist/cli/migrateSqliteToPostgres.js +113 -0
- package/backend/dist/cli/migrateSqliteToPostgres.js.map +1 -0
- package/backend/dist/cli/recoveryBackup.d.ts +3 -0
- package/backend/dist/cli/recoveryBackup.d.ts.map +1 -0
- package/backend/dist/cli/recoveryBackup.js +251 -0
- package/backend/dist/cli/recoveryBackup.js.map +1 -0
- package/backend/dist/cli/recoveryInventory.d.ts +2 -0
- package/backend/dist/cli/recoveryInventory.d.ts.map +1 -0
- package/backend/dist/cli/recoveryInventory.js +109 -0
- package/backend/dist/cli/recoveryInventory.js.map +1 -0
- package/backend/dist/db.d.ts +27 -0
- package/backend/dist/db.d.ts.map +1 -1
- package/backend/dist/db.js +333 -16
- package/backend/dist/db.js.map +1 -1
- package/backend/dist/env.d.ts.map +1 -1
- package/backend/dist/env.js +12 -2
- package/backend/dist/env.js.map +1 -1
- package/backend/dist/index.d.ts.map +1 -1
- package/backend/dist/index.js +235 -47
- package/backend/dist/index.js.map +1 -1
- package/backend/dist/main.d.ts +2 -0
- package/backend/dist/main.d.ts.map +1 -0
- package/backend/dist/main.js +137 -0
- package/backend/dist/main.js.map +1 -0
- package/backend/dist/middleware/auth.d.ts.map +1 -1
- package/backend/dist/middleware/auth.js +7 -3
- package/backend/dist/middleware/auth.js.map +1 -1
- package/backend/dist/middleware/chatCancellationAdmission.d.ts +7 -0
- package/backend/dist/middleware/chatCancellationAdmission.d.ts.map +1 -0
- package/backend/dist/middleware/chatCancellationAdmission.js +17 -0
- package/backend/dist/middleware/chatCancellationAdmission.js.map +1 -0
- package/backend/dist/middleware/coordinatedRateLimit.d.ts +18 -0
- package/backend/dist/middleware/coordinatedRateLimit.d.ts.map +1 -0
- package/backend/dist/middleware/coordinatedRateLimit.js +52 -0
- package/backend/dist/middleware/coordinatedRateLimit.js.map +1 -0
- package/backend/dist/middleware/sharedRateLimit.d.ts +26 -0
- package/backend/dist/middleware/sharedRateLimit.d.ts.map +1 -0
- package/backend/dist/middleware/sharedRateLimit.js +99 -0
- package/backend/dist/middleware/sharedRateLimit.js.map +1 -0
- package/backend/dist/models/personaModel.d.ts +1 -26
- package/backend/dist/models/personaModel.d.ts.map +1 -1
- package/backend/dist/models/personaModel.js +54 -247
- package/backend/dist/models/personaModel.js.map +1 -1
- package/backend/dist/models/userModel.d.ts +23 -66
- package/backend/dist/models/userModel.d.ts.map +1 -1
- package/backend/dist/models/userModel.js +110 -187
- package/backend/dist/models/userModel.js.map +1 -1
- package/backend/dist/persistence/chatGenerationTypes.d.ts +24 -0
- package/backend/dist/persistence/chatGenerationTypes.d.ts.map +1 -0
- package/backend/dist/persistence/chatGenerationTypes.js +7 -0
- package/backend/dist/persistence/chatGenerationTypes.js.map +1 -0
- package/backend/dist/persistence/extensionTypes.d.ts +185 -0
- package/backend/dist/persistence/extensionTypes.d.ts.map +1 -0
- package/backend/dist/persistence/extensionTypes.js +13 -0
- package/backend/dist/persistence/extensionTypes.js.map +1 -0
- package/backend/dist/persistence/identityDeletionTypes.d.ts +16 -0
- package/backend/dist/persistence/identityDeletionTypes.d.ts.map +1 -0
- package/backend/dist/persistence/identityDeletionTypes.js +7 -0
- package/backend/dist/persistence/identityDeletionTypes.js.map +1 -0
- package/backend/dist/persistence/index.d.ts +48 -0
- package/backend/dist/persistence/index.d.ts.map +1 -0
- package/backend/dist/persistence/index.js +159 -0
- package/backend/dist/persistence/index.js.map +1 -0
- package/backend/dist/persistence/postgresConfig.d.ts +32 -0
- package/backend/dist/persistence/postgresConfig.d.ts.map +1 -0
- package/backend/dist/persistence/postgresConfig.js +91 -0
- package/backend/dist/persistence/postgresConfig.js.map +1 -0
- package/backend/dist/persistence/postgresCoreMigration.d.ts +8 -0
- package/backend/dist/persistence/postgresCoreMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresCoreMigration.js +179 -0
- package/backend/dist/persistence/postgresCoreMigration.js.map +1 -0
- package/backend/dist/persistence/postgresDatabase.d.ts +40 -0
- package/backend/dist/persistence/postgresDatabase.d.ts.map +1 -0
- package/backend/dist/persistence/postgresDatabase.js +148 -0
- package/backend/dist/persistence/postgresDatabase.js.map +1 -0
- package/backend/dist/persistence/postgresExtensionMigration.d.ts +4 -0
- package/backend/dist/persistence/postgresExtensionMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresExtensionMigration.js +143 -0
- package/backend/dist/persistence/postgresExtensionMigration.js.map +1 -0
- package/backend/dist/persistence/postgresExtensionRepositories.d.ts +6 -0
- package/backend/dist/persistence/postgresExtensionRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/postgresExtensionRepositories.js +550 -0
- package/backend/dist/persistence/postgresExtensionRepositories.js.map +1 -0
- package/backend/dist/persistence/postgresImportState.d.ts +9 -0
- package/backend/dist/persistence/postgresImportState.d.ts.map +1 -0
- package/backend/dist/persistence/postgresImportState.js +64 -0
- package/backend/dist/persistence/postgresImportState.js.map +1 -0
- package/backend/dist/persistence/postgresMigrationRegistry.d.ts +4 -0
- package/backend/dist/persistence/postgresMigrationRegistry.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrationRegistry.js +33 -0
- package/backend/dist/persistence/postgresMigrationRegistry.js.map +1 -0
- package/backend/dist/persistence/postgresMigrationTypes.d.ts +24 -0
- package/backend/dist/persistence/postgresMigrationTypes.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrationTypes.js +7 -0
- package/backend/dist/persistence/postgresMigrationTypes.js.map +1 -0
- package/backend/dist/persistence/postgresMigrations.d.ts +15 -0
- package/backend/dist/persistence/postgresMigrations.d.ts.map +1 -0
- package/backend/dist/persistence/postgresMigrations.js +333 -0
- package/backend/dist/persistence/postgresMigrations.js.map +1 -0
- package/backend/dist/persistence/postgresPersistence.d.ts +17 -0
- package/backend/dist/persistence/postgresPersistence.d.ts.map +1 -0
- package/backend/dist/persistence/postgresPersistence.js +332 -0
- package/backend/dist/persistence/postgresPersistence.js.map +1 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts +4 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.d.ts.map +1 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.js +40 -0
- package/backend/dist/persistence/postgresPluginDefinitionMigration.js.map +1 -0
- package/backend/dist/persistence/postgresResourceRepositories.d.ts +7 -0
- package/backend/dist/persistence/postgresResourceRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/postgresResourceRepositories.js +776 -0
- package/backend/dist/persistence/postgresResourceRepositories.js.map +1 -0
- package/backend/dist/persistence/postgresSchemaInspector.d.ts +14 -0
- package/backend/dist/persistence/postgresSchemaInspector.d.ts.map +1 -0
- package/backend/dist/persistence/postgresSchemaInspector.js +817 -0
- package/backend/dist/persistence/postgresSchemaInspector.js.map +1 -0
- package/backend/dist/persistence/resourceTypes.d.ts +207 -0
- package/backend/dist/persistence/resourceTypes.d.ts.map +1 -0
- package/backend/dist/persistence/resourceTypes.js +38 -0
- package/backend/dist/persistence/resourceTypes.js.map +1 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.d.ts +4 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.js +494 -0
- package/backend/dist/persistence/sqliteExtensionRepositories.js.map +1 -0
- package/backend/dist/persistence/sqliteMigrations.d.ts +93 -0
- package/backend/dist/persistence/sqliteMigrations.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteMigrations.js +2232 -0
- package/backend/dist/persistence/sqliteMigrations.js.map +1 -0
- package/backend/dist/persistence/sqlitePersistence.d.ts +23 -0
- package/backend/dist/persistence/sqlitePersistence.d.ts.map +1 -0
- package/backend/dist/persistence/sqlitePersistence.js +596 -0
- package/backend/dist/persistence/sqlitePersistence.js.map +1 -0
- package/backend/dist/persistence/sqliteResourceRepositories.d.ts +4 -0
- package/backend/dist/persistence/sqliteResourceRepositories.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteResourceRepositories.js +663 -0
- package/backend/dist/persistence/sqliteResourceRepositories.js.map +1 -0
- package/backend/dist/persistence/sqliteSyncExecutor.d.ts +5 -0
- package/backend/dist/persistence/sqliteSyncExecutor.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteSyncExecutor.js +19 -0
- package/backend/dist/persistence/sqliteSyncExecutor.js.map +1 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.d.ts +80 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.d.ts.map +1 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.js +1543 -0
- package/backend/dist/persistence/sqliteToPostgresMigration.js.map +1 -0
- package/backend/dist/persistence/types.d.ts +131 -0
- package/backend/dist/persistence/types.d.ts.map +1 -0
- package/backend/dist/persistence/types.js +18 -0
- package/backend/dist/persistence/types.js.map +1 -0
- package/backend/dist/persistence/voiceProfileNameLookup.d.ts +9 -0
- package/backend/dist/persistence/voiceProfileNameLookup.d.ts.map +1 -0
- package/backend/dist/persistence/voiceProfileNameLookup.js +15 -0
- package/backend/dist/persistence/voiceProfileNameLookup.js.map +1 -0
- package/backend/dist/platform/coordination/index.d.ts +7 -0
- package/backend/dist/platform/coordination/index.d.ts.map +1 -0
- package/backend/dist/platform/coordination/index.js +24 -0
- package/backend/dist/platform/coordination/index.js.map +1 -0
- package/backend/dist/platform/coordination/localCoordinator.d.ts +49 -0
- package/backend/dist/platform/coordination/localCoordinator.d.ts.map +1 -0
- package/backend/dist/platform/coordination/localCoordinator.js +380 -0
- package/backend/dist/platform/coordination/localCoordinator.js.map +1 -0
- package/backend/dist/platform/coordination/redisCoordinator.d.ts +83 -0
- package/backend/dist/platform/coordination/redisCoordinator.d.ts.map +1 -0
- package/backend/dist/platform/coordination/redisCoordinator.js +726 -0
- package/backend/dist/platform/coordination/redisCoordinator.js.map +1 -0
- package/backend/dist/platform/coordination/service.d.ts +11 -0
- package/backend/dist/platform/coordination/service.d.ts.map +1 -0
- package/backend/dist/platform/coordination/service.js +55 -0
- package/backend/dist/platform/coordination/service.js.map +1 -0
- package/backend/dist/platform/coordination/sharedAdmission.d.ts +53 -0
- package/backend/dist/platform/coordination/sharedAdmission.d.ts.map +1 -0
- package/backend/dist/platform/coordination/sharedAdmission.js +194 -0
- package/backend/dist/platform/coordination/sharedAdmission.js.map +1 -0
- package/backend/dist/platform/coordination/types.d.ts +76 -0
- package/backend/dist/platform/coordination/types.d.ts.map +1 -0
- package/backend/dist/platform/coordination/types.js +32 -0
- package/backend/dist/platform/coordination/types.js.map +1 -0
- package/backend/dist/platform/events/durableEventGateway.d.ts +54 -0
- package/backend/dist/platform/events/durableEventGateway.d.ts.map +1 -0
- package/backend/dist/platform/events/durableEventGateway.js +262 -0
- package/backend/dist/platform/events/durableEventGateway.js.map +1 -0
- package/backend/dist/platform/events/index.d.ts +3 -0
- package/backend/dist/platform/events/index.d.ts.map +1 -0
- package/backend/dist/platform/events/index.js +8 -0
- package/backend/dist/platform/events/index.js.map +1 -0
- package/backend/dist/platform/events/service.d.ts +8 -0
- package/backend/dist/platform/events/service.d.ts.map +1 -0
- package/backend/dist/platform/events/service.js +25 -0
- package/backend/dist/platform/events/service.js.map +1 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.js +55 -0
- package/backend/dist/platform/jobs/chatGenerationEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.js +38 -0
- package/backend/dist/platform/jobs/documentIngestionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/domainJobContracts.d.ts +30 -0
- package/backend/dist/platform/jobs/domainJobContracts.d.ts.map +1 -0
- package/backend/dist/platform/jobs/domainJobContracts.js +53 -0
- package/backend/dist/platform/jobs/domainJobContracts.js.map +1 -0
- package/backend/dist/platform/jobs/domainJobHandlers.d.ts +11 -0
- package/backend/dist/platform/jobs/domainJobHandlers.d.ts.map +1 -0
- package/backend/dist/platform/jobs/domainJobHandlers.js +612 -0
- package/backend/dist/platform/jobs/domainJobHandlers.js.map +1 -0
- package/backend/dist/platform/jobs/durableEventIdentity.d.ts +8 -0
- package/backend/dist/platform/jobs/durableEventIdentity.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableEventIdentity.js +33 -0
- package/backend/dist/platform/jobs/durableEventIdentity.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntime.d.ts +57 -0
- package/backend/dist/platform/jobs/durableJobRuntime.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntime.js +131 -0
- package/backend/dist/platform/jobs/durableJobRuntime.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts +28 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.js +62 -0
- package/backend/dist/platform/jobs/durableJobRuntimeBackend.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobService.d.ts +85 -0
- package/backend/dist/platform/jobs/durableJobService.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobService.js +726 -0
- package/backend/dist/platform/jobs/durableJobService.js.map +1 -0
- package/backend/dist/platform/jobs/durableJobTypes.d.ts +195 -0
- package/backend/dist/platform/jobs/durableJobTypes.d.ts.map +1 -0
- package/backend/dist/platform/jobs/durableJobTypes.js +72 -0
- package/backend/dist/platform/jobs/durableJobTypes.js.map +1 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts +87 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.d.ts.map +1 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.js +429 -0
- package/backend/dist/platform/jobs/embeddedDurableJobWorker.js.map +1 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.js +36 -0
- package/backend/dist/platform/jobs/identityDeletionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/index.d.ts +18 -0
- package/backend/dist/platform/jobs/index.d.ts.map +1 -0
- package/backend/dist/platform/jobs/index.js +34 -0
- package/backend/dist/platform/jobs/index.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts +4 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js +25 -0
- package/backend/dist/platform/jobs/postgresDurableEventIdempotencyMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts +4 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js +23 -0
- package/backend/dist/platform/jobs/postgresDurableEventReplayIndexMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts +11 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.js +106 -0
- package/backend/dist/platform/jobs/postgresDurableJobMigration.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts +88 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.js +1185 -0
- package/backend/dist/platform/jobs/postgresDurableJobRepository.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.d.ts +86 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.js +696 -0
- package/backend/dist/platform/jobs/postgresDurableJobService.js.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts +53 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.d.ts.map +1 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.js +393 -0
- package/backend/dist/platform/jobs/postgresDurableJobWorker.js.map +1 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js +43 -0
- package/backend/dist/platform/jobs/resourceDeletionEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts +166 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.d.ts.map +1 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.js +1008 -0
- package/backend/dist/platform/jobs/sqliteDurableJobRepository.js.map +1 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts +4 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.js +46 -0
- package/backend/dist/platform/jobs/videoGenerationEnqueuer.js.map +1 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts +3 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.d.ts.map +1 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.js +38 -0
- package/backend/dist/platform/jobs/workExecutionEnqueuer.js.map +1 -0
- package/backend/dist/platform/ollamaRuntimeConfig.d.ts +40 -0
- package/backend/dist/platform/ollamaRuntimeConfig.d.ts.map +1 -0
- package/backend/dist/platform/ollamaRuntimeConfig.js +72 -0
- package/backend/dist/platform/ollamaRuntimeConfig.js.map +1 -0
- package/backend/dist/platform/recovery/backupArchive.d.ts +120 -0
- package/backend/dist/platform/recovery/backupArchive.d.ts.map +1 -0
- package/backend/dist/platform/recovery/backupArchive.js +842 -0
- package/backend/dist/platform/recovery/backupArchive.js.map +1 -0
- package/backend/dist/platform/recovery/index.d.ts +3 -0
- package/backend/dist/platform/recovery/index.d.ts.map +1 -0
- package/backend/dist/platform/recovery/index.js +8 -0
- package/backend/dist/platform/recovery/index.js.map +1 -0
- package/backend/dist/platform/recovery/teamBackupArchive.d.ts +98 -0
- package/backend/dist/platform/recovery/teamBackupArchive.d.ts.map +1 -0
- package/backend/dist/platform/recovery/teamBackupArchive.js +1203 -0
- package/backend/dist/platform/recovery/teamBackupArchive.js.map +1 -0
- package/backend/dist/platform/runtimeConfig.d.ts +70 -0
- package/backend/dist/platform/runtimeConfig.d.ts.map +1 -0
- package/backend/dist/platform/runtimeConfig.js +205 -0
- package/backend/dist/platform/runtimeConfig.js.map +1 -0
- package/backend/dist/platform/storage/aesGcmKeyring.d.ts +26 -0
- package/backend/dist/platform/storage/aesGcmKeyring.d.ts.map +1 -0
- package/backend/dist/platform/storage/aesGcmKeyring.js +135 -0
- package/backend/dist/platform/storage/aesGcmKeyring.js.map +1 -0
- package/backend/dist/platform/storage/blobReferenceRepository.d.ts +36 -0
- package/backend/dist/platform/storage/blobReferenceRepository.d.ts.map +1 -0
- package/backend/dist/platform/storage/blobReferenceRepository.js +117 -0
- package/backend/dist/platform/storage/blobReferenceRepository.js.map +1 -0
- package/backend/dist/platform/storage/blobStore.d.ts +111 -0
- package/backend/dist/platform/storage/blobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/blobStore.js +46 -0
- package/backend/dist/platform/storage/blobStore.js.map +1 -0
- package/backend/dist/platform/storage/documentVectorIndex.d.ts +44 -0
- package/backend/dist/platform/storage/documentVectorIndex.d.ts.map +1 -0
- package/backend/dist/platform/storage/documentVectorIndex.js +110 -0
- package/backend/dist/platform/storage/documentVectorIndex.js.map +1 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts +82 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.d.ts.map +1 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.js +583 -0
- package/backend/dist/platform/storage/durableBlobQuotaPolicy.js.map +1 -0
- package/backend/dist/platform/storage/index.d.ts +19 -0
- package/backend/dist/platform/storage/index.d.ts.map +1 -0
- package/backend/dist/platform/storage/index.js +35 -0
- package/backend/dist/platform/storage/index.js.map +1 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts +120 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.js +1205 -0
- package/backend/dist/platform/storage/localEncryptedBlobStore.js.map +1 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.d.ts +12 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.d.ts.map +1 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.js +25 -0
- package/backend/dist/platform/storage/personaMemoryIndexing.js.map +1 -0
- package/backend/dist/platform/storage/pgVectorStore.d.ts +37 -0
- package/backend/dist/platform/storage/pgVectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/pgVectorStore.js +493 -0
- package/backend/dist/platform/storage/pgVectorStore.js.map +1 -0
- package/backend/dist/platform/storage/platformDomainRepositories.d.ts +244 -0
- package/backend/dist/platform/storage/platformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/platformDomainRepositories.js +7 -0
- package/backend/dist/platform/storage/platformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/platformStorageRuntime.d.ts +35 -0
- package/backend/dist/platform/storage/platformStorageRuntime.d.ts.map +1 -0
- package/backend/dist/platform/storage/platformStorageRuntime.js +299 -0
- package/backend/dist/platform/storage/platformStorageRuntime.js.map +1 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts +4 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js +1017 -0
- package/backend/dist/platform/storage/postgresPlatformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts +4 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.d.ts.map +1 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js +40 -0
- package/backend/dist/platform/storage/postgresResourceDeletionLifecycleMigration.js.map +1 -0
- package/backend/dist/platform/storage/resourceContentCleanup.d.ts +29 -0
- package/backend/dist/platform/storage/resourceContentCleanup.d.ts.map +1 -0
- package/backend/dist/platform/storage/resourceContentCleanup.js +100 -0
- package/backend/dist/platform/storage/resourceContentCleanup.js.map +1 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts +14 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.d.ts.map +1 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.js +31 -0
- package/backend/dist/platform/storage/resourceDeletionLifecycle.js.map +1 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts +140 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.js +1309 -0
- package/backend/dist/platform/storage/s3EncryptedBlobStore.js.map +1 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts +71 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js +766 -0
- package/backend/dist/platform/storage/sqliteEncryptedVectorStore.js.map +1 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts +4 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js +1037 -0
- package/backend/dist/platform/storage/sqlitePlatformDomainRepositories.js.map +1 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts +25 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.d.ts.map +1 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js +1292 -0
- package/backend/dist/platform/storage/sqliteToTeamStorageMigration.js.map +1 -0
- package/backend/dist/platform/storage/storageFactory.d.ts +81 -0
- package/backend/dist/platform/storage/storageFactory.d.ts.map +1 -0
- package/backend/dist/platform/storage/storageFactory.js +518 -0
- package/backend/dist/platform/storage/storageFactory.js.map +1 -0
- package/backend/dist/platform/storage/storageSchemaContracts.d.ts +22 -0
- package/backend/dist/platform/storage/storageSchemaContracts.d.ts.map +1 -0
- package/backend/dist/platform/storage/storageSchemaContracts.js +299 -0
- package/backend/dist/platform/storage/storageSchemaContracts.js.map +1 -0
- package/backend/dist/platform/storage/vectorStore.d.ts +117 -0
- package/backend/dist/platform/storage/vectorStore.d.ts.map +1 -0
- package/backend/dist/platform/storage/vectorStore.js +40 -0
- package/backend/dist/platform/storage/vectorStore.js.map +1 -0
- package/backend/dist/platform/workPersistence/index.d.ts +9 -0
- package/backend/dist/platform/workPersistence/index.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/index.js +14 -0
- package/backend/dist/platform/workPersistence/index.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts +9 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js +47 -0
- package/backend/dist/platform/workPersistence/postgresWorkLifecycleMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts +3 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js +28 -0
- package/backend/dist/platform/workPersistence/postgresWorkMessageContentMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts +3 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.js +101 -0
- package/backend/dist/platform/workPersistence/postgresWorkMigration.js.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts +79 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.js +521 -0
- package/backend/dist/platform/workPersistence/postgresWorkPersistence.js.map +1 -0
- package/backend/dist/platform/workPersistence/service.d.ts +6 -0
- package/backend/dist/platform/workPersistence/service.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/service.js +27 -0
- package/backend/dist/platform/workPersistence/service.js.map +1 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts +77 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js +463 -0
- package/backend/dist/platform/workPersistence/sqliteWorkPersistence.js.map +1 -0
- package/backend/dist/platform/workPersistence/types.d.ts +159 -0
- package/backend/dist/platform/workPersistence/types.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/types.js +13 -0
- package/backend/dist/platform/workPersistence/types.js.map +1 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts +13 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.js +7 -0
- package/backend/dist/platform/workPersistence/workExecutionTypes.js.map +1 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts +8 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.js +25 -0
- package/backend/dist/platform/workPersistence/workMessageContentCodec.js.map +1 -0
- package/backend/dist/platform/workPersistence/workTextSafety.d.ts +3 -0
- package/backend/dist/platform/workPersistence/workTextSafety.d.ts.map +1 -0
- package/backend/dist/platform/workPersistence/workTextSafety.js +8 -0
- package/backend/dist/platform/workPersistence/workTextSafety.js.map +1 -0
- package/backend/dist/routes/agentCli.js +1 -1
- package/backend/dist/routes/agentCli.js.map +1 -1
- package/backend/dist/routes/artifacts.d.ts.map +1 -1
- package/backend/dist/routes/artifacts.js +2 -1
- package/backend/dist/routes/artifacts.js.map +1 -1
- package/backend/dist/routes/auth.d.ts.map +1 -1
- package/backend/dist/routes/auth.js +64 -18
- package/backend/dist/routes/auth.js.map +1 -1
- package/backend/dist/routes/chat.d.ts.map +1 -1
- package/backend/dist/routes/chat.js +519 -85
- package/backend/dist/routes/chat.js.map +1 -1
- package/backend/dist/routes/documents.d.ts.map +1 -1
- package/backend/dist/routes/documents.js +134 -28
- package/backend/dist/routes/documents.js.map +1 -1
- package/backend/dist/routes/embeddings.d.ts.map +1 -1
- package/backend/dist/routes/embeddings.js +2 -1
- package/backend/dist/routes/embeddings.js.map +1 -1
- package/backend/dist/routes/health.d.ts +3 -0
- package/backend/dist/routes/health.d.ts.map +1 -0
- package/backend/dist/routes/health.js +52 -0
- package/backend/dist/routes/health.js.map +1 -0
- package/backend/dist/routes/huggingfaceHub.d.ts.map +1 -1
- package/backend/dist/routes/huggingfaceHub.js +2 -1
- package/backend/dist/routes/huggingfaceHub.js.map +1 -1
- package/backend/dist/routes/imageGen.d.ts.map +1 -1
- package/backend/dist/routes/imageGen.js +42 -10
- package/backend/dist/routes/imageGen.js.map +1 -1
- package/backend/dist/routes/jobs.d.ts +3 -0
- package/backend/dist/routes/jobs.d.ts.map +1 -0
- package/backend/dist/routes/jobs.js +117 -0
- package/backend/dist/routes/jobs.js.map +1 -0
- package/backend/dist/routes/libreClaw.d.ts.map +1 -1
- package/backend/dist/routes/libreClaw.js +10 -7
- package/backend/dist/routes/libreClaw.js.map +1 -1
- package/backend/dist/routes/media.d.ts.map +1 -1
- package/backend/dist/routes/media.js +523 -77
- package/backend/dist/routes/media.js.map +1 -1
- package/backend/dist/routes/notes.d.ts.map +1 -1
- package/backend/dist/routes/notes.js +21 -21
- package/backend/dist/routes/notes.js.map +1 -1
- package/backend/dist/routes/ollama.d.ts.map +1 -1
- package/backend/dist/routes/ollama.js +40 -12
- package/backend/dist/routes/ollama.js.map +1 -1
- package/backend/dist/routes/personas.d.ts.map +1 -1
- package/backend/dist/routes/personas.js +4 -2
- package/backend/dist/routes/personas.js.map +1 -1
- package/backend/dist/routes/plugins.d.ts.map +1 -1
- package/backend/dist/routes/plugins.js +79 -51
- package/backend/dist/routes/plugins.js.map +1 -1
- package/backend/dist/routes/preferences.d.ts.map +1 -1
- package/backend/dist/routes/preferences.js +290 -25
- package/backend/dist/routes/preferences.js.map +1 -1
- package/backend/dist/routes/search.d.ts.map +1 -1
- package/backend/dist/routes/search.js +23 -14
- package/backend/dist/routes/search.js.map +1 -1
- package/backend/dist/routes/stt.d.ts +9 -0
- package/backend/dist/routes/stt.d.ts.map +1 -0
- package/backend/dist/routes/stt.js +217 -0
- package/backend/dist/routes/stt.js.map +1 -0
- package/backend/dist/routes/systemDiagnostics.d.ts.map +1 -1
- package/backend/dist/routes/systemDiagnostics.js +2 -1
- package/backend/dist/routes/systemDiagnostics.js.map +1 -1
- package/backend/dist/routes/tts.d.ts.map +1 -1
- package/backend/dist/routes/tts.js +577 -28
- package/backend/dist/routes/tts.js.map +1 -1
- package/backend/dist/routes/users.d.ts.map +1 -1
- package/backend/dist/routes/users.js +16 -25
- package/backend/dist/routes/users.js.map +1 -1
- package/backend/dist/routes/work.d.ts.map +1 -1
- package/backend/dist/routes/work.js +167 -113
- package/backend/dist/routes/work.js.map +1 -1
- package/backend/dist/services/agentAccessService.d.ts +2 -2
- package/backend/dist/services/agentAccessService.d.ts.map +1 -1
- package/backend/dist/services/agentAccessService.js +5 -14
- package/backend/dist/services/agentAccessService.js.map +1 -1
- package/backend/dist/services/agentCliService.d.ts +3 -2
- package/backend/dist/services/agentCliService.d.ts.map +1 -1
- package/backend/dist/services/agentCliService.js +44 -16
- package/backend/dist/services/agentCliService.js.map +1 -1
- package/backend/dist/services/assistantCompletionService.d.ts +2 -1
- package/backend/dist/services/assistantCompletionService.d.ts.map +1 -1
- package/backend/dist/services/assistantCompletionService.js +7 -3
- package/backend/dist/services/assistantCompletionService.js.map +1 -1
- package/backend/dist/services/authService.d.ts +7 -2
- package/backend/dist/services/authService.d.ts.map +1 -1
- package/backend/dist/services/authService.js +23 -10
- package/backend/dist/services/authService.js.map +1 -1
- package/backend/dist/services/chatGenerationService.d.ts +5 -4
- package/backend/dist/services/chatGenerationService.d.ts.map +1 -1
- package/backend/dist/services/chatGenerationService.js +23 -17
- package/backend/dist/services/chatGenerationService.js.map +1 -1
- package/backend/dist/services/chatRequestService.d.ts +4 -3
- package/backend/dist/services/chatRequestService.d.ts.map +1 -1
- package/backend/dist/services/chatRequestService.js +3 -3
- package/backend/dist/services/chatRequestService.js.map +1 -1
- package/backend/dist/services/chatService.d.ts +66 -16
- package/backend/dist/services/chatService.d.ts.map +1 -1
- package/backend/dist/services/chatService.js +402 -111
- package/backend/dist/services/chatService.js.map +1 -1
- package/backend/dist/services/codexOAuthService.d.ts +2 -2
- package/backend/dist/services/codexOAuthService.d.ts.map +1 -1
- package/backend/dist/services/codexOAuthService.js +63 -7
- package/backend/dist/services/codexOAuthService.js.map +1 -1
- package/backend/dist/services/dataArchiveService.d.ts +88 -0
- package/backend/dist/services/dataArchiveService.d.ts.map +1 -0
- package/backend/dist/services/dataArchiveService.js +1027 -0
- package/backend/dist/services/dataArchiveService.js.map +1 -0
- package/backend/dist/services/documentService.d.ts +67 -14
- package/backend/dist/services/documentService.d.ts.map +1 -1
- package/backend/dist/services/documentService.js +938 -193
- package/backend/dist/services/documentService.js.map +1 -1
- package/backend/dist/services/durableChatCompletion.d.ts +16 -0
- package/backend/dist/services/durableChatCompletion.d.ts.map +1 -0
- package/backend/dist/services/durableChatCompletion.js +34 -0
- package/backend/dist/services/durableChatCompletion.js.map +1 -0
- package/backend/dist/services/durableChatGenerationService.d.ts +19 -0
- package/backend/dist/services/durableChatGenerationService.d.ts.map +1 -0
- package/backend/dist/services/durableChatGenerationService.js +341 -0
- package/backend/dist/services/durableChatGenerationService.js.map +1 -0
- package/backend/dist/services/embeddingService.d.ts +1 -1
- package/backend/dist/services/embeddingService.d.ts.map +1 -1
- package/backend/dist/services/embeddingService.js +16 -13
- package/backend/dist/services/embeddingService.js.map +1 -1
- package/backend/dist/services/encryptionService.d.ts +28 -1
- package/backend/dist/services/encryptionService.d.ts.map +1 -1
- package/backend/dist/services/encryptionService.js +131 -51
- package/backend/dist/services/encryptionService.js.map +1 -1
- package/backend/dist/services/followUpService.d.ts +1 -1
- package/backend/dist/services/followUpService.d.ts.map +1 -1
- package/backend/dist/services/followUpService.js +1 -1
- package/backend/dist/services/followUpService.js.map +1 -1
- package/backend/dist/services/galleryService.d.ts +38 -37
- package/backend/dist/services/galleryService.d.ts.map +1 -1
- package/backend/dist/services/galleryService.js +356 -251
- package/backend/dist/services/galleryService.js.map +1 -1
- package/backend/dist/services/healthService.d.ts +65 -0
- package/backend/dist/services/healthService.d.ts.map +1 -0
- package/backend/dist/services/healthService.js +379 -0
- package/backend/dist/services/healthService.js.map +1 -0
- package/backend/dist/services/legacyCiphertextIntegrity.d.ts +40 -0
- package/backend/dist/services/legacyCiphertextIntegrity.d.ts.map +1 -0
- package/backend/dist/services/legacyCiphertextIntegrity.js +406 -0
- package/backend/dist/services/legacyCiphertextIntegrity.js.map +1 -0
- package/backend/dist/services/mediaGenerationJobService.d.ts +27 -5
- package/backend/dist/services/mediaGenerationJobService.d.ts.map +1 -1
- package/backend/dist/services/mediaGenerationJobService.js +185 -55
- package/backend/dist/services/mediaGenerationJobService.js.map +1 -1
- package/backend/dist/services/memoryService.d.ts +7 -83
- package/backend/dist/services/memoryService.d.ts.map +1 -1
- package/backend/dist/services/memoryService.js +428 -573
- package/backend/dist/services/memoryService.js.map +1 -1
- package/backend/dist/services/memoryUtils.d.ts.map +1 -1
- package/backend/dist/services/memoryUtils.js +8 -1
- package/backend/dist/services/memoryUtils.js.map +1 -1
- package/backend/dist/services/modelAccessService.d.ts +3 -3
- package/backend/dist/services/modelAccessService.d.ts.map +1 -1
- package/backend/dist/services/modelAccessService.js +8 -16
- package/backend/dist/services/modelAccessService.js.map +1 -1
- package/backend/dist/services/mutationEngineService.d.ts +0 -7
- package/backend/dist/services/mutationEngineService.d.ts.map +1 -1
- package/backend/dist/services/mutationEngineService.js +7 -78
- package/backend/dist/services/mutationEngineService.js.map +1 -1
- package/backend/dist/services/ollamaService.d.ts +4 -4
- package/backend/dist/services/ollamaService.d.ts.map +1 -1
- package/backend/dist/services/ollamaService.js +62 -31
- package/backend/dist/services/ollamaService.js.map +1 -1
- package/backend/dist/services/personaService.d.ts.map +1 -1
- package/backend/dist/services/personaService.js +19 -54
- package/backend/dist/services/personaService.js.map +1 -1
- package/backend/dist/services/pluginActivationService.d.ts +6 -5
- package/backend/dist/services/pluginActivationService.d.ts.map +1 -1
- package/backend/dist/services/pluginActivationService.js +36 -76
- package/backend/dist/services/pluginActivationService.js.map +1 -1
- package/backend/dist/services/pluginAudioGenerationService.d.ts +11 -6
- package/backend/dist/services/pluginAudioGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginAudioGenerationService.js +74 -16
- package/backend/dist/services/pluginAudioGenerationService.js.map +1 -1
- package/backend/dist/services/pluginCacheInvalidation.d.ts +38 -0
- package/backend/dist/services/pluginCacheInvalidation.d.ts.map +1 -0
- package/backend/dist/services/pluginCacheInvalidation.js +198 -0
- package/backend/dist/services/pluginCacheInvalidation.js.map +1 -0
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts +3 -3
- package/backend/dist/services/pluginCapabilityRegistryService.d.ts.map +1 -1
- package/backend/dist/services/pluginCapabilityRegistryService.js +11 -7
- package/backend/dist/services/pluginCapabilityRegistryService.js.map +1 -1
- package/backend/dist/services/pluginCredentialsService.d.ts +9 -8
- package/backend/dist/services/pluginCredentialsService.d.ts.map +1 -1
- package/backend/dist/services/pluginCredentialsService.js +48 -89
- package/backend/dist/services/pluginCredentialsService.js.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.d.ts +8 -7
- package/backend/dist/services/pluginEmbeddingService.d.ts.map +1 -1
- package/backend/dist/services/pluginEmbeddingService.js +13 -11
- package/backend/dist/services/pluginEmbeddingService.js.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.d.ts +10 -8
- package/backend/dist/services/pluginImageGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginImageGenerationService.js +119 -14
- package/backend/dist/services/pluginImageGenerationService.js.map +1 -1
- package/backend/dist/services/pluginSTTService.d.ts +47 -0
- package/backend/dist/services/pluginSTTService.d.ts.map +1 -0
- package/backend/dist/services/pluginSTTService.js +199 -0
- package/backend/dist/services/pluginSTTService.js.map +1 -0
- package/backend/dist/services/pluginService.d.ts +94 -40
- package/backend/dist/services/pluginService.d.ts.map +1 -1
- package/backend/dist/services/pluginService.js +799 -274
- package/backend/dist/services/pluginService.js.map +1 -1
- package/backend/dist/services/pluginTTSService.d.ts +26 -8
- package/backend/dist/services/pluginTTSService.d.ts.map +1 -1
- package/backend/dist/services/pluginTTSService.js +277 -25
- package/backend/dist/services/pluginTTSService.js.map +1 -1
- package/backend/dist/services/pluginUsageService.d.ts +4 -4
- package/backend/dist/services/pluginUsageService.d.ts.map +1 -1
- package/backend/dist/services/pluginUsageService.js +44 -93
- package/backend/dist/services/pluginUsageService.js.map +1 -1
- package/backend/dist/services/pluginVariablesService.d.ts +14 -7
- package/backend/dist/services/pluginVariablesService.d.ts.map +1 -1
- package/backend/dist/services/pluginVariablesService.js +116 -81
- package/backend/dist/services/pluginVariablesService.js.map +1 -1
- package/backend/dist/services/pluginVideoGenerationService.d.ts +19 -8
- package/backend/dist/services/pluginVideoGenerationService.d.ts.map +1 -1
- package/backend/dist/services/pluginVideoGenerationService.js +116 -20
- package/backend/dist/services/pluginVideoGenerationService.js.map +1 -1
- package/backend/dist/services/preferencesService.d.ts +31 -21
- package/backend/dist/services/preferencesService.d.ts.map +1 -1
- package/backend/dist/services/preferencesService.js +104 -102
- package/backend/dist/services/preferencesService.js.map +1 -1
- package/backend/dist/services/recoveryInventoryService.d.ts +244 -0
- package/backend/dist/services/recoveryInventoryService.d.ts.map +1 -0
- package/backend/dist/services/recoveryInventoryService.js +1436 -0
- package/backend/dist/services/recoveryInventoryService.js.map +1 -0
- package/backend/dist/services/simpleGitHubOAuth.js +3 -3
- package/backend/dist/services/simpleGitHubOAuth.js.map +1 -1
- package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -1
- package/backend/dist/services/simpleHuggingFaceOAuth.js +3 -3
- package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -1
- package/backend/dist/services/systemDiagnosticsService.d.ts.map +1 -1
- package/backend/dist/services/systemDiagnosticsService.js +2 -2
- package/backend/dist/services/systemDiagnosticsService.js.map +1 -1
- package/backend/dist/services/systemSettingsService.d.ts +5 -0
- package/backend/dist/services/systemSettingsService.d.ts.map +1 -0
- package/backend/dist/services/systemSettingsService.js +24 -0
- package/backend/dist/services/systemSettingsService.js.map +1 -0
- package/backend/dist/services/titleGenerationService.d.ts +1 -1
- package/backend/dist/services/titleGenerationService.d.ts.map +1 -1
- package/backend/dist/services/titleGenerationService.js +1 -1
- package/backend/dist/services/titleGenerationService.js.map +1 -1
- package/backend/dist/services/voiceProfileService.d.ts +44 -0
- package/backend/dist/services/voiceProfileService.d.ts.map +1 -0
- package/backend/dist/services/voiceProfileService.js +195 -0
- package/backend/dist/services/voiceProfileService.js.map +1 -0
- package/backend/dist/services/webSearchService.d.ts +7 -7
- package/backend/dist/services/webSearchService.d.ts.map +1 -1
- package/backend/dist/services/webSearchService.js +40 -35
- package/backend/dist/services/webSearchService.js.map +1 -1
- package/backend/dist/services/websocketTicketService.d.ts +39 -0
- package/backend/dist/services/websocketTicketService.d.ts.map +1 -0
- package/backend/dist/services/websocketTicketService.js +183 -0
- package/backend/dist/services/websocketTicketService.js.map +1 -0
- package/backend/dist/services/workAccessService.d.ts +3 -3
- package/backend/dist/services/workAccessService.d.ts.map +1 -1
- package/backend/dist/services/workAccessService.js +8 -16
- package/backend/dist/services/workAccessService.js.map +1 -1
- package/backend/dist/services/workAdminService.d.ts +3 -3
- package/backend/dist/services/workAdminService.d.ts.map +1 -1
- package/backend/dist/services/workAdminService.js +4 -4
- package/backend/dist/services/workAdminService.js.map +1 -1
- package/backend/dist/services/workAgentService.d.ts +25 -1
- package/backend/dist/services/workAgentService.d.ts.map +1 -1
- package/backend/dist/services/workAgentService.js +294 -126
- package/backend/dist/services/workAgentService.js.map +1 -1
- package/backend/dist/services/workEventService.d.ts +15 -2
- package/backend/dist/services/workEventService.d.ts.map +1 -1
- package/backend/dist/services/workEventService.js +201 -3
- package/backend/dist/services/workEventService.js.map +1 -1
- package/backend/dist/services/workKubernetesDriver.d.ts +8 -7
- package/backend/dist/services/workKubernetesDriver.d.ts.map +1 -1
- package/backend/dist/services/workKubernetesDriver.js +65 -21
- package/backend/dist/services/workKubernetesDriver.js.map +1 -1
- package/backend/dist/services/workModelProviderService.d.ts +2 -2
- package/backend/dist/services/workModelProviderService.d.ts.map +1 -1
- package/backend/dist/services/workModelProviderService.js +38 -34
- package/backend/dist/services/workModelProviderService.js.map +1 -1
- package/backend/dist/services/workPolicyService.d.ts +7 -7
- package/backend/dist/services/workPolicyService.d.ts.map +1 -1
- package/backend/dist/services/workPolicyService.js +50 -51
- package/backend/dist/services/workPolicyService.js.map +1 -1
- package/backend/dist/services/workPreviewProxyService.d.ts +8 -8
- package/backend/dist/services/workPreviewProxyService.d.ts.map +1 -1
- package/backend/dist/services/workPreviewProxyService.js +47 -44
- package/backend/dist/services/workPreviewProxyService.js.map +1 -1
- package/backend/dist/services/workRuntimeDriver.d.ts +21 -18
- package/backend/dist/services/workRuntimeDriver.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeDriver.js +69 -20
- package/backend/dist/services/workRuntimeDriver.js.map +1 -1
- package/backend/dist/services/workRuntimeService.d.ts +18 -13
- package/backend/dist/services/workRuntimeService.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeService.js +438 -194
- package/backend/dist/services/workRuntimeService.js.map +1 -1
- package/backend/dist/services/workRuntimeShared.d.ts +2 -0
- package/backend/dist/services/workRuntimeShared.d.ts.map +1 -1
- package/backend/dist/services/workRuntimeShared.js.map +1 -1
- package/backend/dist/services/workTaskService.d.ts +42 -36
- package/backend/dist/services/workTaskService.d.ts.map +1 -1
- package/backend/dist/services/workTaskService.js +445 -350
- package/backend/dist/services/workTaskService.js.map +1 -1
- package/backend/dist/services/workTerminalService.d.ts +1 -1
- package/backend/dist/services/workTerminalService.d.ts.map +1 -1
- package/backend/dist/services/workTerminalService.js +33 -6
- package/backend/dist/services/workTerminalService.js.map +1 -1
- package/backend/dist/storage.d.ts +72 -40
- package/backend/dist/storage.d.ts.map +1 -1
- package/backend/dist/storage.js +312 -660
- package/backend/dist/storage.js.map +1 -1
- package/backend/dist/types/index.d.ts +28 -0
- package/backend/dist/types/index.d.ts.map +1 -1
- package/backend/dist/types/index.js.map +1 -1
- package/backend/dist/types/work.d.ts +7 -2
- package/backend/dist/types/work.d.ts.map +1 -1
- package/backend/dist/utils/chatCancellation.d.ts +48 -0
- package/backend/dist/utils/chatCancellation.d.ts.map +1 -0
- package/backend/dist/utils/chatCancellation.js +152 -0
- package/backend/dist/utils/chatCancellation.js.map +1 -0
- package/backend/dist/utils/chatDocumentContext.d.ts +1 -1
- package/backend/dist/utils/chatDocumentContext.d.ts.map +1 -1
- package/backend/dist/utils/chatDocumentContext.js +11 -5
- package/backend/dist/utils/chatDocumentContext.js.map +1 -1
- package/backend/dist/utils/chatStreamCoalescer.d.ts +15 -0
- package/backend/dist/utils/chatStreamCoalescer.d.ts.map +1 -0
- package/backend/dist/utils/chatStreamCoalescer.js +59 -0
- package/backend/dist/utils/chatStreamCoalescer.js.map +1 -0
- package/backend/dist/utils/dataDirectory.d.ts +49 -0
- package/backend/dist/utils/dataDirectory.d.ts.map +1 -0
- package/backend/dist/utils/dataDirectory.js +291 -0
- package/backend/dist/utils/dataDirectory.js.map +1 -0
- package/backend/dist/utils/generationUtils.d.ts.map +1 -1
- package/backend/dist/utils/generationUtils.js +18 -6
- package/backend/dist/utils/generationUtils.js.map +1 -1
- package/backend/dist/utils/jwt.d.ts.map +1 -1
- package/backend/dist/utils/jwt.js +2 -3
- package/backend/dist/utils/jwt.js.map +1 -1
- package/backend/dist/utils/ollamaModelDefaults.d.ts.map +1 -1
- package/backend/dist/utils/ollamaModelDefaults.js +2 -7
- package/backend/dist/utils/ollamaModelDefaults.js.map +1 -1
- package/backend/dist/utils/ollamaStreaming.d.ts +2 -1
- package/backend/dist/utils/ollamaStreaming.d.ts.map +1 -1
- package/backend/dist/utils/ollamaStreaming.js +49 -11
- package/backend/dist/utils/ollamaStreaming.js.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.d.ts.map +1 -1
- package/backend/dist/utils/pluginConnectionVariables.js +11 -3
- package/backend/dist/utils/pluginConnectionVariables.js.map +1 -1
- package/backend/dist/utils/pluginDefinitionTrust.d.ts.map +1 -1
- package/backend/dist/utils/pluginDefinitionTrust.js +4 -3
- package/backend/dist/utils/pluginDefinitionTrust.js.map +1 -1
- package/backend/dist/utils/pluginStreaming.d.ts +2 -1
- package/backend/dist/utils/pluginStreaming.d.ts.map +1 -1
- package/backend/dist/utils/pluginStreaming.js +5 -1
- package/backend/dist/utils/pluginStreaming.js.map +1 -1
- package/backend/dist/utils/pluginUpload.d.ts +1 -0
- package/backend/dist/utils/pluginUpload.d.ts.map +1 -1
- package/backend/dist/utils/pluginUpload.js +9 -2
- package/backend/dist/utils/pluginUpload.js.map +1 -1
- package/backend/dist/utils/pluginValidation.d.ts.map +1 -1
- package/backend/dist/utils/pluginValidation.js +29 -1
- package/backend/dist/utils/pluginValidation.js.map +1 -1
- package/backend/dist/utils/sttAudioUpload.d.ts +24 -0
- package/backend/dist/utils/sttAudioUpload.d.ts.map +1 -0
- package/backend/dist/utils/sttAudioUpload.js +500 -0
- package/backend/dist/utils/sttAudioUpload.js.map +1 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.d.ts +34 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.d.ts.map +1 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.js +224 -0
- package/backend/dist/utils/ttsVoiceCloneUpload.js.map +1 -0
- package/backend/dist/utils/websocketMessages.d.ts +2 -1
- package/backend/dist/utils/websocketMessages.d.ts.map +1 -1
- package/backend/dist/utils/websocketMessages.js +16 -2
- package/backend/dist/utils/websocketMessages.js.map +1 -1
- package/backend/dist/websocketServer.d.ts +4 -1
- package/backend/dist/websocketServer.d.ts.map +1 -1
- package/backend/dist/websocketServer.js +290 -44
- package/backend/dist/websocketServer.js.map +1 -1
- package/backend/dist/workTerminalServer.d.ts +9 -0
- package/backend/dist/workTerminalServer.d.ts.map +1 -1
- package/backend/dist/workTerminalServer.js +221 -52
- package/backend/dist/workTerminalServer.js.map +1 -1
- package/backend/dist/worker.d.ts +2 -0
- package/backend/dist/worker.d.ts.map +1 -0
- package/backend/dist/worker.js +250 -0
- package/backend/dist/worker.js.map +1 -0
- package/backend/package.json +19 -9
- package/bin/cli.js +126 -99
- package/bin/runtime-paths.js +108 -0
- package/frontend/dist/artifact-runtime/.build-fingerprint +1 -1
- package/frontend/dist/artifact-runtime/framer-motion.js +5 -5
- package/frontend/dist/artifact-runtime/lucide-react.js +1 -1
- package/frontend/dist/assets/index-CUhEG7E2.js +33 -0
- package/frontend/dist/assets/index-kxtZQLV6.css +1 -0
- package/frontend/dist/assets/{markdown-math-ClQbWekD.css → markdown-math-ClTedVi7.css} +1 -1
- package/frontend/dist/index.html +18 -18
- package/frontend/dist/js/{ArtifactContainer-Dy2Q0iIL.js → ArtifactContainer-BTEDhBnv.js} +1 -1
- package/frontend/dist/js/{ArtifactDemoPage-K79dWshB.js → ArtifactDemoPage-B0gN3YTl.js} +1 -1
- package/frontend/dist/js/{ArtifactSandboxFrame-DhqLNUtY.js → ArtifactSandboxFrame-CLBXQkZs.js} +3 -3
- package/frontend/dist/js/{ArtifactSlideOutPanel-Cl8JG7bz.js → ArtifactSlideOutPanel-CfqHPFdE.js} +1 -1
- package/frontend/dist/js/{Button-CTXHujOd.js → Button-BV44cTnj.js} +1 -1
- package/frontend/dist/js/ChatPage-DIkAXZWA.js +23 -0
- package/frontend/dist/js/{FirstTimeSetup-kHhRzGJ8.js → FirstTimeSetup-B8phXGNA.js} +1 -1
- package/frontend/dist/js/GalleryPage-W4uI043I.js +1 -0
- package/frontend/dist/js/{HomePage-C1L8WAXL.js → HomePage-DlxehbyO.js} +1 -1
- package/frontend/dist/js/{LibreClawPage-Dyua8IUu.js → LibreClawPage-CgD0_G_F.js} +1 -1
- package/frontend/dist/js/{ModelManagerModals-CuMRGUd-.js → ModelManagerModals-D7jIT3v1.js} +1 -1
- package/frontend/dist/js/{ModelSelector-CqHc-Ln4.js → ModelSelector-BYxJU1UV.js} +1 -1
- package/frontend/dist/js/ModelsPage-C4XdCKP5.js +2 -0
- package/frontend/dist/js/NotesPage-CDECOl4V.js +1 -0
- package/frontend/dist/js/{OptimizedSyntaxHighlighter-CWYUn9Oe.js → OptimizedSyntaxHighlighter-XwqZEoTf.js} +1 -1
- package/frontend/dist/js/{PersonasPage-D_6WBCH5.js → PersonasPage-CjSLPrgS.js} +2 -2
- package/frontend/dist/js/PluginUsagePage-DJOXJuH4.js +1 -0
- package/frontend/dist/js/RichMessageContent-Debeh6bi.js +3 -0
- package/frontend/dist/js/SettingsModal-cUqAeYUP.js +1 -0
- package/frontend/dist/js/{SettingsToggle-DLHlCDBl.js → SettingsToggle-WTa0rgvY.js} +1 -1
- package/frontend/dist/js/{SystemPage-BMWEet9e.js → SystemPage-DxPw0GS7.js} +1 -1
- package/frontend/dist/js/UserManagementPage-CEdYFe_Z.js +1 -0
- package/frontend/dist/js/WorkPage-DDVeuG_9.js +6 -0
- package/frontend/dist/js/api-IzobHGND.js +14 -0
- package/frontend/dist/js/appStore-DKwC2vgn.js +2 -0
- package/frontend/dist/js/ar-xTSvTq05.js +2 -0
- package/frontend/dist/js/authStore-OaTuapL7.js +4 -0
- package/frontend/dist/js/{babel-CmENXdZw.js → babel-D24oDI9y.js} +1 -1
- package/frontend/dist/js/bn-iYAsohEA.js +2 -0
- package/frontend/dist/js/chatStore-DXGUVLXD.js +3 -0
- package/frontend/dist/js/{config-DkV1ka7I.js → config-DPEEuTAe.js} +1 -1
- package/frontend/dist/js/cs-YBHN88Hb.js +2 -0
- package/frontend/dist/js/da-D7qlLy_k.js +2 -0
- package/frontend/dist/js/de-DV671k2c.js +2 -0
- package/frontend/dist/js/es-kyBgzNq-.js +2 -0
- package/frontend/dist/js/{estree-D5KP-qbw.js → estree-ChwJsD2w.js} +1 -1
- package/frontend/dist/js/fr-Cw1vut7I.js +2 -0
- package/frontend/dist/js/hi-DWEFC024.js +2 -0
- package/frontend/dist/js/{html-Cm9c2akd.js → html-DFrVjciF.js} +1 -1
- package/frontend/dist/js/id-DlMHjjy0.js +2 -0
- package/frontend/dist/js/is-B9E_a7dG.js +2 -0
- package/frontend/dist/js/it-DawmVbLC.js +2 -0
- package/frontend/dist/js/ja-DmVvwY3W.js +2 -0
- package/frontend/dist/js/ko-DzOPpkVs.js +2 -0
- package/frontend/dist/js/{markdown-B2u7CnKN.js → markdown-FLLx7b67.js} +1 -1
- package/frontend/dist/js/markdown-core-BmPPZiuD.js +31 -0
- package/frontend/dist/js/{markdown-math-B7FlYsmr.js → markdown-math-mH7AZ_mb.js} +6 -6
- package/frontend/dist/js/{messageCodeStyles-DalG2j6U.js → messageCodeStyles-CBkkZY4n.js} +1 -1
- package/frontend/dist/js/ms-DpsaOPht.js +2 -0
- package/frontend/dist/js/nl-B1d8W22n.js +2 -0
- package/frontend/dist/js/pl-nCncRVgt.js +2 -0
- package/frontend/dist/js/{postcss-B5WIGhAY.js → postcss-Bx9CTcIc.js} +1 -1
- package/frontend/dist/js/pt-DHw8fGuu.js +2 -0
- package/frontend/dist/js/{react-vendor-DPNXrO-8.js → react-vendor-C5yShNlM.js} +1 -1
- package/frontend/dist/js/{router-vendor-Ca9zqOqT.js → router-vendor-CbPDks39.js} +1 -1
- package/frontend/dist/js/ru-Derl_YP_.js +2 -0
- package/frontend/dist/js/{standalone-Dwm1daef.js → standalone-i8-5bg5p.js} +1 -1
- package/frontend/dist/js/sv-pJAfBVo0.js +2 -0
- package/frontend/dist/js/{syntax-highlight-Ca9bHsaz.js → syntax-highlight-3EEX6CGL.js} +3 -3
- package/frontend/dist/js/th-C_7fIGnk.js +2 -0
- package/frontend/dist/js/tr-CPqsJvaP.js +2 -0
- package/frontend/dist/js/{typescript-CwieSptM.js → typescript-CQ3x-Uni.js} +1 -1
- package/frontend/dist/js/{ui-BnDZpjfc.js → ui-BHhR3Vok.js} +2 -2
- package/frontend/dist/js/ui-vendor-D3Ahl1x5.js +177 -0
- package/frontend/dist/js/uk-3o8P_kFi.js +2 -0
- package/frontend/dist/js/{useTranslation-CXY69qNk.js → useTranslation-C3ei3mJq.js} +1 -1
- package/frontend/dist/js/{utils-BM0_0iFj.js → utils-CuC1beTY.js} +1 -1
- package/frontend/dist/js/{utils-vendor-1zob7nK9.js → utils-vendor-BBa8OxtB.js} +1 -1
- package/frontend/dist/js/vi-Dv6N7OVD.js +2 -0
- package/frontend/dist/js/{workApi-BOS7crs9.js → workApi-Czu69yWS.js} +2 -2
- package/frontend/dist/js/{yaml-QD4znPfZ.js → yaml-DioTxVLA.js} +1 -1
- package/frontend/dist/js/zh-qg5iqtPi.js +2 -0
- package/package.json +16 -5
- package/plugins/huggingface.json +12 -3
- package/plugins/llama-cpp.json +18 -6
- package/plugins/longcat-audiodit.json +114 -0
- package/plugins/openai.json +18 -0
- package/frontend/dist/assets/index-BBpNbfKW.js +0 -16
- package/frontend/dist/assets/index-BLATyFmD.css +0 -1
- package/frontend/dist/js/ChatPage-BBayfMLS.js +0 -16
- package/frontend/dist/js/GalleryPage-By8VI39Q.js +0 -1
- package/frontend/dist/js/ModelsPage-ODeXhDDk.js +0 -2
- package/frontend/dist/js/NotesPage-CApzDjOq.js +0 -1
- package/frontend/dist/js/PluginUsagePage-kutS6SOd.js +0 -1
- package/frontend/dist/js/RichMessageContent-g6WT75Te.js +0 -3
- package/frontend/dist/js/SettingsModal-B7z51BCx.js +0 -1
- package/frontend/dist/js/UserManagementPage-D08lM51c.js +0 -1
- package/frontend/dist/js/WorkPage-DdVLefsK.js +0 -6
- package/frontend/dist/js/api-CLEmGcEh.js +0 -14
- package/frontend/dist/js/appStore-CGdhvp9P.js +0 -2
- package/frontend/dist/js/ar-BTmB2WVm.js +0 -2
- package/frontend/dist/js/authStore-Dh3beEOq.js +0 -4
- package/frontend/dist/js/bn-CQnH7YVT.js +0 -2
- package/frontend/dist/js/chatStore-CDeYWL_q.js +0 -3
- package/frontend/dist/js/cs-oTTZkQXr.js +0 -2
- package/frontend/dist/js/da-Br0gB6J6.js +0 -2
- package/frontend/dist/js/de-DE2iztTF.js +0 -2
- package/frontend/dist/js/es-DgthfVtl.js +0 -2
- package/frontend/dist/js/fr-BjxjFwPh.js +0 -2
- package/frontend/dist/js/hi-D1q7E-9N.js +0 -2
- package/frontend/dist/js/id-CDJZqLTF.js +0 -2
- package/frontend/dist/js/is-BU7Um_Tq.js +0 -2
- package/frontend/dist/js/it-CdAxr8P_.js +0 -2
- package/frontend/dist/js/ja-BLbQwz9u.js +0 -2
- package/frontend/dist/js/ko-CY5lpkAe.js +0 -2
- package/frontend/dist/js/markdown-core-DHnR5Hw8.js +0 -16
- package/frontend/dist/js/ms-tQ8AYXEQ.js +0 -2
- package/frontend/dist/js/nl-CRNi2oWT.js +0 -2
- package/frontend/dist/js/pl-CWtFRS_W.js +0 -2
- package/frontend/dist/js/pt-C7SPoLF8.js +0 -2
- package/frontend/dist/js/ru-Dz4AX8xc.js +0 -2
- package/frontend/dist/js/sv-ETy5-boa.js +0 -2
- package/frontend/dist/js/th-DpuMqvxU.js +0 -2
- package/frontend/dist/js/tr-C-1AYAqg.js +0 -2
- package/frontend/dist/js/ui-vendor-xUzKqAXI.js +0 -177
- package/frontend/dist/js/uk-CyS680gr.js +0 -2
- package/frontend/dist/js/vi-BG8HuiTz.js +0 -2
- package/frontend/dist/js/zh-NCs2mkHj.js +0 -2
|
@@ -0,0 +1,1543 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Libre WebUI
|
|
3
|
+
* Copyright (C) 2025 Kroonen AI, Inc.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import Database from 'better-sqlite3';
|
|
11
|
+
import { createPostgresDatabase, } from './postgresDatabase.js';
|
|
12
|
+
import { POSTGRES_MIGRATIONS } from './postgresMigrationRegistry.js';
|
|
13
|
+
import { PostgresMigrationError, runPostgresMigrationCoordinator, } from './postgresMigrations.js';
|
|
14
|
+
import { inspectPostgresSchema } from './postgresSchemaInspector.js';
|
|
15
|
+
import { POSTGRES_SQLITE_IMPORT_SCHEMA_SQL, SQLITE_IMPORT_TABLE as IMPORT_TABLE, SQLITE_IMPORT_TABLE_STATE as IMPORT_TABLE_STATE, SQLITE_STORAGE_IMPORT_TABLE as STORAGE_IMPORT_TABLE, } from './postgresImportState.js';
|
|
16
|
+
import { preflightSQLiteMigrationLedger, SQLITE_MIGRATION_CONTRACT, } from './sqliteMigrations.js';
|
|
17
|
+
import { getPluginDefinitionFingerprint } from '../utils/pluginDefinitionTrust.js';
|
|
18
|
+
import { encodePostgresWorkMessageContent } from '../platform/workPersistence/workMessageContentCodec.js';
|
|
19
|
+
const IMPORT_LOCK = '6840141877227442765';
|
|
20
|
+
const BATCH_SIZE = 250;
|
|
21
|
+
const POSTGRES_TARGET_SCHEMA_VERSION = POSTGRES_MIGRATIONS[POSTGRES_MIGRATIONS.length - 1].version;
|
|
22
|
+
export class SQLiteToPostgresMigrationError extends Error {
|
|
23
|
+
constructor(message, report) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.report = report;
|
|
26
|
+
this.name = 'SQLiteToPostgresMigrationError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const quote = (identifier) => {
|
|
30
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(identifier)) {
|
|
31
|
+
throw new Error('Unsafe persistence identifier');
|
|
32
|
+
}
|
|
33
|
+
return `"${identifier}"`;
|
|
34
|
+
};
|
|
35
|
+
const mappedColumns = (names, options = {}) => {
|
|
36
|
+
const integers = new Set(options.integers ?? []);
|
|
37
|
+
const numbers = new Set(options.numbers ?? []);
|
|
38
|
+
const binary = new Set(options.binary ?? []);
|
|
39
|
+
return names.map(source => ({
|
|
40
|
+
source,
|
|
41
|
+
target: options.rename?.[source] ?? source,
|
|
42
|
+
kind: binary.has(source)
|
|
43
|
+
? 'binary'
|
|
44
|
+
: integers.has(source)
|
|
45
|
+
? 'integer'
|
|
46
|
+
: numbers.has(source)
|
|
47
|
+
? 'number'
|
|
48
|
+
: 'text',
|
|
49
|
+
}));
|
|
50
|
+
};
|
|
51
|
+
const table = (source, target, names, key, options = {}) => ({
|
|
52
|
+
source,
|
|
53
|
+
target,
|
|
54
|
+
columns: mappedColumns(names, options),
|
|
55
|
+
sourceKey: key,
|
|
56
|
+
targetKey: key.map(column => options.rename?.[column] ?? column),
|
|
57
|
+
...(options.deferredColumns
|
|
58
|
+
? { deferredColumns: options.deferredColumns }
|
|
59
|
+
: {}),
|
|
60
|
+
...(options.projectSourceRow
|
|
61
|
+
? { projectSourceRow: options.projectSourceRow }
|
|
62
|
+
: {}),
|
|
63
|
+
...(options.overridingSystemValue ? { overridingSystemValue: true } : {}),
|
|
64
|
+
...(options.afterImport ? { afterImport: options.afterImport } : {}),
|
|
65
|
+
});
|
|
66
|
+
const sessionMessageParentLookups = new WeakMap();
|
|
67
|
+
const projectSessionMessageRow = (database, row) => {
|
|
68
|
+
const parentId = row.parent_id;
|
|
69
|
+
if (parentId === null || parentId === undefined)
|
|
70
|
+
return row;
|
|
71
|
+
let parentExists = sessionMessageParentLookups.get(database);
|
|
72
|
+
if (!parentExists) {
|
|
73
|
+
const statement = database.prepare('SELECT 1 FROM session_messages WHERE id = ?');
|
|
74
|
+
parentExists = candidate => Boolean(statement.get(candidate));
|
|
75
|
+
sessionMessageParentLookups.set(database, parentExists);
|
|
76
|
+
}
|
|
77
|
+
// SQLite never constrained this legacy branch-group pointer. PostgreSQL
|
|
78
|
+
// does, so preserve every resolvable value and deterministically clear only
|
|
79
|
+
// references whose message no longer exists.
|
|
80
|
+
return parentExists(parentId) ? row : { ...row, parent_id: null };
|
|
81
|
+
};
|
|
82
|
+
const projectWorkMessageRow = (_database, row) => {
|
|
83
|
+
if (typeof row.content !== 'string')
|
|
84
|
+
return row;
|
|
85
|
+
return { ...row, content: encodePostgresWorkMessageContent(row.content) };
|
|
86
|
+
};
|
|
87
|
+
const timestamps = [
|
|
88
|
+
'created_at',
|
|
89
|
+
'updated_at',
|
|
90
|
+
'uploaded_at',
|
|
91
|
+
'timestamp',
|
|
92
|
+
'approved_at',
|
|
93
|
+
'approved_at',
|
|
94
|
+
'activated_at',
|
|
95
|
+
'consent_confirmed_at',
|
|
96
|
+
'started_at',
|
|
97
|
+
'finished_at',
|
|
98
|
+
'available_at',
|
|
99
|
+
'lease_expires_at',
|
|
100
|
+
'cancellation_requested_at',
|
|
101
|
+
'last_heartbeat_at',
|
|
102
|
+
'occurred_at',
|
|
103
|
+
'last_accessed',
|
|
104
|
+
'last_updated',
|
|
105
|
+
];
|
|
106
|
+
const TABLE_MAPPINGS = Object.freeze([
|
|
107
|
+
table('users', 'users', [
|
|
108
|
+
'id',
|
|
109
|
+
'username',
|
|
110
|
+
'email',
|
|
111
|
+
'email_lookup',
|
|
112
|
+
'password_hash',
|
|
113
|
+
'role',
|
|
114
|
+
'account_status',
|
|
115
|
+
'approved_at',
|
|
116
|
+
'approved_by',
|
|
117
|
+
'avatar',
|
|
118
|
+
'created_at',
|
|
119
|
+
'updated_at',
|
|
120
|
+
], ['id'], { integers: timestamps }),
|
|
121
|
+
table('personas', 'personas', [
|
|
122
|
+
'id',
|
|
123
|
+
'user_id',
|
|
124
|
+
'name',
|
|
125
|
+
'description',
|
|
126
|
+
'model',
|
|
127
|
+
'parameters',
|
|
128
|
+
'avatar',
|
|
129
|
+
'background',
|
|
130
|
+
'embedding_model',
|
|
131
|
+
'memory_settings',
|
|
132
|
+
'mutation_settings',
|
|
133
|
+
'created_at',
|
|
134
|
+
'updated_at',
|
|
135
|
+
], ['id'], { integers: timestamps }),
|
|
136
|
+
table('session_folders', 'session_folders', ['id', 'user_id', 'name', 'created_at', 'updated_at'], ['id'], { integers: timestamps }),
|
|
137
|
+
table('knowledge_collections', 'knowledge_collections', ['id', 'user_id', 'name', 'created_at', 'updated_at'], ['id'], { integers: timestamps }),
|
|
138
|
+
table('sessions', 'sessions', [
|
|
139
|
+
'id',
|
|
140
|
+
'user_id',
|
|
141
|
+
'title',
|
|
142
|
+
'model',
|
|
143
|
+
'persona_id',
|
|
144
|
+
'provider_type',
|
|
145
|
+
'provider_id',
|
|
146
|
+
'created_at',
|
|
147
|
+
'updated_at',
|
|
148
|
+
'archived',
|
|
149
|
+
'settings',
|
|
150
|
+
'folder_id',
|
|
151
|
+
'pinned',
|
|
152
|
+
], ['id'], { integers: [...timestamps, 'archived', 'pinned'] }),
|
|
153
|
+
table('session_messages', 'session_messages', [
|
|
154
|
+
'id',
|
|
155
|
+
'session_id',
|
|
156
|
+
'role',
|
|
157
|
+
'content',
|
|
158
|
+
'thinking',
|
|
159
|
+
'timestamp',
|
|
160
|
+
'message_index',
|
|
161
|
+
'model',
|
|
162
|
+
'provider_metadata',
|
|
163
|
+
'images',
|
|
164
|
+
'statistics',
|
|
165
|
+
'artifacts',
|
|
166
|
+
'parent_id',
|
|
167
|
+
'branch_index',
|
|
168
|
+
'is_active',
|
|
169
|
+
'rating',
|
|
170
|
+
], ['id'], {
|
|
171
|
+
integers: [
|
|
172
|
+
...timestamps,
|
|
173
|
+
'message_index',
|
|
174
|
+
'branch_index',
|
|
175
|
+
'is_active',
|
|
176
|
+
'rating',
|
|
177
|
+
],
|
|
178
|
+
deferredColumns: ['parent_id'],
|
|
179
|
+
projectSourceRow: projectSessionMessageRow,
|
|
180
|
+
}),
|
|
181
|
+
table('notes', 'notes', ['id', 'user_id', 'title', 'content', 'created_at', 'updated_at'], ['id'], { integers: timestamps }),
|
|
182
|
+
table('documents', 'documents', [
|
|
183
|
+
'id',
|
|
184
|
+
'user_id',
|
|
185
|
+
'filename',
|
|
186
|
+
'title',
|
|
187
|
+
'content',
|
|
188
|
+
'file_type',
|
|
189
|
+
'size',
|
|
190
|
+
'session_id',
|
|
191
|
+
'collection_id',
|
|
192
|
+
'metadata',
|
|
193
|
+
'uploaded_at',
|
|
194
|
+
'created_at',
|
|
195
|
+
'updated_at',
|
|
196
|
+
], ['id'], { integers: [...timestamps, 'size'] }),
|
|
197
|
+
table('document_chunks', 'document_chunks', [
|
|
198
|
+
'id',
|
|
199
|
+
'document_id',
|
|
200
|
+
'chunk_index',
|
|
201
|
+
'content',
|
|
202
|
+
'start_char',
|
|
203
|
+
'end_char',
|
|
204
|
+
'embedding',
|
|
205
|
+
'created_at',
|
|
206
|
+
], ['id'], {
|
|
207
|
+
integers: [...timestamps, 'chunk_index', 'start_char', 'end_char'],
|
|
208
|
+
}),
|
|
209
|
+
table('user_preferences', 'user_preferences', ['id', 'user_id', 'key', 'value', 'created_at', 'updated_at'], ['id'], { integers: timestamps }),
|
|
210
|
+
table('system_settings', 'system_settings', ['key', 'value', 'updated_at'], ['key'], { integers: timestamps }),
|
|
211
|
+
table('plugin_credentials', 'plugin_credentials', [
|
|
212
|
+
'id',
|
|
213
|
+
'user_id',
|
|
214
|
+
'plugin_id',
|
|
215
|
+
'api_key',
|
|
216
|
+
'routing_auth_fingerprint',
|
|
217
|
+
'created_at',
|
|
218
|
+
'updated_at',
|
|
219
|
+
], ['id'], { integers: timestamps }),
|
|
220
|
+
table('plugin_variables', 'plugin_variables', [
|
|
221
|
+
'id',
|
|
222
|
+
'user_id',
|
|
223
|
+
'plugin_id',
|
|
224
|
+
'variable_name',
|
|
225
|
+
'variable_value',
|
|
226
|
+
'is_encrypted',
|
|
227
|
+
'created_at',
|
|
228
|
+
'updated_at',
|
|
229
|
+
], ['id'], { integers: [...timestamps, 'is_encrypted'] }),
|
|
230
|
+
table('plugin_discovered_models', 'plugin_discovered_models', ['user_id', 'plugin_id', 'models_json', 'updated_at'], ['user_id', 'plugin_id'], { integers: timestamps }),
|
|
231
|
+
table('plugin_discovered_capability_models', 'plugin_discovered_capability_models', ['user_id', 'plugin_id', 'capability', 'models_json', 'updated_at'], ['user_id', 'plugin_id', 'capability'], { integers: timestamps }),
|
|
232
|
+
table('plugin_activations', 'plugin_activations', ['user_id', 'plugin_id', 'activated_at'], ['user_id', 'plugin_id'], { integers: timestamps }),
|
|
233
|
+
table('plugin_definition_approvals', 'plugin_definition_approvals', [
|
|
234
|
+
'plugin_id',
|
|
235
|
+
'definition_fingerprint',
|
|
236
|
+
'source_path',
|
|
237
|
+
'approved_by_user_id',
|
|
238
|
+
'approved_at',
|
|
239
|
+
], ['plugin_id'], { integers: timestamps }),
|
|
240
|
+
table('plugin_definitions', 'plugin_definitions', [
|
|
241
|
+
'plugin_id',
|
|
242
|
+
'definition_json',
|
|
243
|
+
'definition_fingerprint',
|
|
244
|
+
'approved_by_user_id',
|
|
245
|
+
'approved_at',
|
|
246
|
+
'created_at',
|
|
247
|
+
'updated_at',
|
|
248
|
+
], ['plugin_id'], { integers: timestamps }),
|
|
249
|
+
table('plugin_usage_events', 'plugin_usage_events', [
|
|
250
|
+
'id',
|
|
251
|
+
'user_id',
|
|
252
|
+
'plugin_id',
|
|
253
|
+
'plugin_name',
|
|
254
|
+
'capability',
|
|
255
|
+
'model',
|
|
256
|
+
'status',
|
|
257
|
+
'prompt_tokens',
|
|
258
|
+
'completion_tokens',
|
|
259
|
+
'total_tokens',
|
|
260
|
+
'input_units',
|
|
261
|
+
'output_units',
|
|
262
|
+
'unit_kind',
|
|
263
|
+
'duration_ms',
|
|
264
|
+
'created_at',
|
|
265
|
+
], ['id'], {
|
|
266
|
+
integers: [
|
|
267
|
+
...timestamps,
|
|
268
|
+
'prompt_tokens',
|
|
269
|
+
'completion_tokens',
|
|
270
|
+
'total_tokens',
|
|
271
|
+
'input_units',
|
|
272
|
+
'output_units',
|
|
273
|
+
'duration_ms',
|
|
274
|
+
],
|
|
275
|
+
}),
|
|
276
|
+
table('voice_profiles', 'voice_profiles', [
|
|
277
|
+
'id',
|
|
278
|
+
'user_id',
|
|
279
|
+
'name',
|
|
280
|
+
'name_lookup',
|
|
281
|
+
'plugin_id',
|
|
282
|
+
'model',
|
|
283
|
+
'routing_fingerprint',
|
|
284
|
+
'reference_audio',
|
|
285
|
+
'reference_text',
|
|
286
|
+
'audio_mime_type',
|
|
287
|
+
'audio_format',
|
|
288
|
+
'audio_size',
|
|
289
|
+
'consent_confirmed_at',
|
|
290
|
+
'created_at',
|
|
291
|
+
'updated_at',
|
|
292
|
+
], ['id'], {
|
|
293
|
+
integers: [...timestamps, 'audio_size'],
|
|
294
|
+
binary: ['name', 'reference_audio', 'reference_text'],
|
|
295
|
+
}),
|
|
296
|
+
table('persona_memories', 'platform_persona_memories', [
|
|
297
|
+
'id',
|
|
298
|
+
'user_id',
|
|
299
|
+
'persona_id',
|
|
300
|
+
'content',
|
|
301
|
+
'timestamp',
|
|
302
|
+
'context',
|
|
303
|
+
'importance_score',
|
|
304
|
+
'memory_type',
|
|
305
|
+
'access_count',
|
|
306
|
+
'last_accessed',
|
|
307
|
+
'decay_factor',
|
|
308
|
+
'consolidated_from',
|
|
309
|
+
], ['id'], {
|
|
310
|
+
rename: {
|
|
311
|
+
content: 'encrypted_content',
|
|
312
|
+
context: 'encrypted_context',
|
|
313
|
+
consolidated_from: 'encrypted_consolidated_from',
|
|
314
|
+
},
|
|
315
|
+
integers: [...timestamps, 'access_count'],
|
|
316
|
+
numbers: ['importance_score', 'decay_factor'],
|
|
317
|
+
}),
|
|
318
|
+
table('persona_states', 'platform_persona_states', [
|
|
319
|
+
'persona_id',
|
|
320
|
+
'user_id',
|
|
321
|
+
'runtime_state',
|
|
322
|
+
'mutation_log',
|
|
323
|
+
'last_updated',
|
|
324
|
+
'version',
|
|
325
|
+
], ['persona_id'], {
|
|
326
|
+
rename: {
|
|
327
|
+
runtime_state: 'encrypted_runtime_state',
|
|
328
|
+
mutation_log: 'encrypted_mutation_log',
|
|
329
|
+
},
|
|
330
|
+
integers: [...timestamps, 'version'],
|
|
331
|
+
}),
|
|
332
|
+
table('media_generation_jobs', 'platform_media_generation_jobs', [
|
|
333
|
+
'id',
|
|
334
|
+
'user_id',
|
|
335
|
+
'provider_job_id',
|
|
336
|
+
'plugin_id',
|
|
337
|
+
'model',
|
|
338
|
+
'prompt',
|
|
339
|
+
'status',
|
|
340
|
+
'options_json',
|
|
341
|
+
'gallery_id',
|
|
342
|
+
'error',
|
|
343
|
+
'created_at',
|
|
344
|
+
'updated_at',
|
|
345
|
+
], ['id'], {
|
|
346
|
+
rename: {
|
|
347
|
+
prompt: 'encrypted_prompt',
|
|
348
|
+
options_json: 'encrypted_options',
|
|
349
|
+
error: 'encrypted_error',
|
|
350
|
+
},
|
|
351
|
+
integers: timestamps,
|
|
352
|
+
}),
|
|
353
|
+
table('platform_event_stream_heads', 'platform_event_stream_heads', ['stream_id', 'last_sequence'], ['stream_id'], { integers: ['last_sequence'] }),
|
|
354
|
+
table('platform_jobs', 'platform_jobs', [
|
|
355
|
+
'id',
|
|
356
|
+
'job_type',
|
|
357
|
+
'actor_user_id',
|
|
358
|
+
'state',
|
|
359
|
+
'payload_format',
|
|
360
|
+
'payload',
|
|
361
|
+
'idempotency_scope',
|
|
362
|
+
'idempotency_key_hash',
|
|
363
|
+
'request_fingerprint',
|
|
364
|
+
'priority',
|
|
365
|
+
'attempt_count',
|
|
366
|
+
'max_attempts',
|
|
367
|
+
'available_at',
|
|
368
|
+
'lease_owner',
|
|
369
|
+
'lease_token',
|
|
370
|
+
'lease_expires_at',
|
|
371
|
+
'cancellation_requested_at',
|
|
372
|
+
'cancellation_reason',
|
|
373
|
+
'progress_current',
|
|
374
|
+
'progress_total',
|
|
375
|
+
'progress_message',
|
|
376
|
+
'result_reference',
|
|
377
|
+
'error_code',
|
|
378
|
+
'error_summary',
|
|
379
|
+
'created_at',
|
|
380
|
+
'updated_at',
|
|
381
|
+
'started_at',
|
|
382
|
+
'finished_at',
|
|
383
|
+
], ['id'], {
|
|
384
|
+
integers: [
|
|
385
|
+
...timestamps,
|
|
386
|
+
'priority',
|
|
387
|
+
'attempt_count',
|
|
388
|
+
'max_attempts',
|
|
389
|
+
'lease_token',
|
|
390
|
+
'progress_current',
|
|
391
|
+
'progress_total',
|
|
392
|
+
],
|
|
393
|
+
}),
|
|
394
|
+
table('platform_job_attempts', 'platform_job_attempts', [
|
|
395
|
+
'job_id',
|
|
396
|
+
'attempt_number',
|
|
397
|
+
'lease_token',
|
|
398
|
+
'worker_id',
|
|
399
|
+
'started_at',
|
|
400
|
+
'last_heartbeat_at',
|
|
401
|
+
'finished_at',
|
|
402
|
+
'outcome',
|
|
403
|
+
'error_code',
|
|
404
|
+
'error_summary',
|
|
405
|
+
], ['job_id', 'attempt_number'], {
|
|
406
|
+
integers: [...timestamps, 'attempt_number', 'lease_token'],
|
|
407
|
+
}),
|
|
408
|
+
table('platform_events', 'platform_events', [
|
|
409
|
+
'global_cursor',
|
|
410
|
+
'event_id',
|
|
411
|
+
'request_fingerprint',
|
|
412
|
+
'stream_id',
|
|
413
|
+
'stream_sequence',
|
|
414
|
+
'event_type',
|
|
415
|
+
'subject_id',
|
|
416
|
+
'actor_user_id',
|
|
417
|
+
'payload_format',
|
|
418
|
+
'payload',
|
|
419
|
+
'occurred_at',
|
|
420
|
+
], ['global_cursor'], {
|
|
421
|
+
integers: [...timestamps, 'global_cursor', 'stream_sequence'],
|
|
422
|
+
overridingSystemValue: true,
|
|
423
|
+
afterImport: async (client) => {
|
|
424
|
+
await client.query(`SELECT setval(
|
|
425
|
+
pg_get_serial_sequence('platform_events', 'global_cursor'),
|
|
426
|
+
GREATEST(COALESCE((SELECT MAX(global_cursor) FROM platform_events), 0), 1),
|
|
427
|
+
EXISTS(SELECT 1 FROM platform_events)
|
|
428
|
+
)`);
|
|
429
|
+
},
|
|
430
|
+
}),
|
|
431
|
+
table('platform_resource_deletion_tombstones', 'platform_resource_deletion_tombstones', [
|
|
432
|
+
'resource_type',
|
|
433
|
+
'resource_id',
|
|
434
|
+
'owner_user_id',
|
|
435
|
+
'deletion_incarnation',
|
|
436
|
+
'deletion_token',
|
|
437
|
+
'deleted_at',
|
|
438
|
+
'completed_at',
|
|
439
|
+
], ['resource_type', 'resource_id'], {
|
|
440
|
+
integers: ['deletion_incarnation', 'deleted_at', 'completed_at'],
|
|
441
|
+
}),
|
|
442
|
+
table('work_policies', 'work_policies', [
|
|
443
|
+
'id',
|
|
444
|
+
'name',
|
|
445
|
+
'image',
|
|
446
|
+
'memory_limit',
|
|
447
|
+
'cpu_limit',
|
|
448
|
+
'pids_limit',
|
|
449
|
+
'network_default',
|
|
450
|
+
'workspace_size',
|
|
451
|
+
'idle_timeout_ms',
|
|
452
|
+
'created_at',
|
|
453
|
+
'updated_at',
|
|
454
|
+
], ['id'], {
|
|
455
|
+
integers: [
|
|
456
|
+
...timestamps,
|
|
457
|
+
'pids_limit',
|
|
458
|
+
'network_default',
|
|
459
|
+
'idle_timeout_ms',
|
|
460
|
+
],
|
|
461
|
+
}),
|
|
462
|
+
table('work_tasks', 'work_tasks', [
|
|
463
|
+
'id',
|
|
464
|
+
'user_id',
|
|
465
|
+
'title',
|
|
466
|
+
'model',
|
|
467
|
+
'provider_type',
|
|
468
|
+
'provider_id',
|
|
469
|
+
'status',
|
|
470
|
+
'network_enabled',
|
|
471
|
+
'volume_name',
|
|
472
|
+
'container_name',
|
|
473
|
+
'host_path',
|
|
474
|
+
'policy_id',
|
|
475
|
+
'preview_url',
|
|
476
|
+
'preview_status',
|
|
477
|
+
'created_at',
|
|
478
|
+
'updated_at',
|
|
479
|
+
], ['id'], { integers: [...timestamps, 'network_enabled'] }),
|
|
480
|
+
table('work_runs', 'work_runs', [
|
|
481
|
+
'id',
|
|
482
|
+
'task_id',
|
|
483
|
+
'model',
|
|
484
|
+
'provider_type',
|
|
485
|
+
'provider_id',
|
|
486
|
+
'status',
|
|
487
|
+
'error',
|
|
488
|
+
'created_at',
|
|
489
|
+
'started_at',
|
|
490
|
+
'finished_at',
|
|
491
|
+
], ['id'], { integers: timestamps }),
|
|
492
|
+
table('work_messages', 'work_messages', [
|
|
493
|
+
'id',
|
|
494
|
+
'task_id',
|
|
495
|
+
'run_id',
|
|
496
|
+
'role',
|
|
497
|
+
'kind',
|
|
498
|
+
'content',
|
|
499
|
+
'metadata',
|
|
500
|
+
'message_index',
|
|
501
|
+
'created_at',
|
|
502
|
+
], ['id'], {
|
|
503
|
+
integers: [...timestamps, 'message_index'],
|
|
504
|
+
projectSourceRow: projectWorkMessageRow,
|
|
505
|
+
}),
|
|
506
|
+
]);
|
|
507
|
+
const sourceTextNulInventoryCache = new WeakMap();
|
|
508
|
+
const sourceTextNulInventory = (database) => {
|
|
509
|
+
const cached = sourceTextNulInventoryCache.get(database);
|
|
510
|
+
if (cached)
|
|
511
|
+
return cached;
|
|
512
|
+
const inventory = [];
|
|
513
|
+
for (const mapping of TABLE_MAPPINGS) {
|
|
514
|
+
const columns = mapping.columns.filter(column => column.kind === 'text');
|
|
515
|
+
if (columns.length === 0)
|
|
516
|
+
continue;
|
|
517
|
+
const counts = database
|
|
518
|
+
.prepare(`SELECT ${columns
|
|
519
|
+
.map(column => `COUNT(*) FILTER (WHERE instr(${quote(column.source)}, char(0)) > 0) AS ${quote(column.source)}`)
|
|
520
|
+
.join(', ')}
|
|
521
|
+
FROM ${quote(mapping.source)}`)
|
|
522
|
+
.get();
|
|
523
|
+
for (const column of columns) {
|
|
524
|
+
const rows = safeCount(counts[column.source]);
|
|
525
|
+
if (rows > 0) {
|
|
526
|
+
inventory.push({ table: mapping.source, column: column.source, rows });
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
sourceTextNulInventoryCache.set(database, inventory);
|
|
531
|
+
return inventory;
|
|
532
|
+
};
|
|
533
|
+
const TARGET_DOMAIN_TABLES = Object.freeze([
|
|
534
|
+
...new Set([
|
|
535
|
+
...TABLE_MAPPINGS.map(mapping => mapping.target),
|
|
536
|
+
'platform_blob_objects',
|
|
537
|
+
'platform_generated_media',
|
|
538
|
+
'platform_blob_references',
|
|
539
|
+
'platform_blob_quota_usage',
|
|
540
|
+
'platform_blob_quota_reservations',
|
|
541
|
+
'platform_blob_quota_objects',
|
|
542
|
+
'platform_vector_entries',
|
|
543
|
+
'platform_vector_acl',
|
|
544
|
+
]),
|
|
545
|
+
]);
|
|
546
|
+
const TARGET_CONTROL_TABLES = new Set([
|
|
547
|
+
'libre_schema_migrations',
|
|
548
|
+
'libre_schema_compatibility',
|
|
549
|
+
IMPORT_TABLE,
|
|
550
|
+
IMPORT_TABLE_STATE,
|
|
551
|
+
STORAGE_IMPORT_TABLE,
|
|
552
|
+
]);
|
|
553
|
+
const canonical = (value, kind) => {
|
|
554
|
+
if (value === null || value === undefined)
|
|
555
|
+
return 'null';
|
|
556
|
+
if (kind === 'binary') {
|
|
557
|
+
if (!Buffer.isBuffer(value))
|
|
558
|
+
throw new Error('Expected binary SQLite value');
|
|
559
|
+
return `binary:${value.toString('base64')}`;
|
|
560
|
+
}
|
|
561
|
+
if (kind === 'integer') {
|
|
562
|
+
if (typeof value === 'bigint')
|
|
563
|
+
return `integer:${value.toString()}`;
|
|
564
|
+
if (typeof value === 'number' && Number.isSafeInteger(value)) {
|
|
565
|
+
return `integer:${value}`;
|
|
566
|
+
}
|
|
567
|
+
if (typeof value === 'string' && /^-?\d+$/.test(value)) {
|
|
568
|
+
return `integer:${BigInt(value).toString()}`;
|
|
569
|
+
}
|
|
570
|
+
throw new Error('Expected an exact integer persistence value');
|
|
571
|
+
}
|
|
572
|
+
if (kind === 'number') {
|
|
573
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
574
|
+
if (!Number.isFinite(parsed))
|
|
575
|
+
throw new Error('Expected a finite number');
|
|
576
|
+
return `number:${parsed}`;
|
|
577
|
+
}
|
|
578
|
+
if (typeof value !== 'string')
|
|
579
|
+
throw new Error('Expected text persistence value');
|
|
580
|
+
return `text:${value}`;
|
|
581
|
+
};
|
|
582
|
+
const checksumRows = (rows, columns, side) => {
|
|
583
|
+
const hash = createHash('sha256');
|
|
584
|
+
let count = 0;
|
|
585
|
+
for (const row of rows) {
|
|
586
|
+
hash.update(JSON.stringify(columns.map(column => canonical(row[side === 'source' ? column.source : column.target], column.kind))));
|
|
587
|
+
hash.update('\n');
|
|
588
|
+
count += 1;
|
|
589
|
+
}
|
|
590
|
+
return { rows: count, checksum: hash.digest('hex') };
|
|
591
|
+
};
|
|
592
|
+
const sourceManifest = (database, mapping) => {
|
|
593
|
+
const selected = mapping.columns
|
|
594
|
+
.map(column => quote(column.source))
|
|
595
|
+
.join(', ');
|
|
596
|
+
const order = mapping.sourceKey.map(quote).join(', ');
|
|
597
|
+
const rows = database
|
|
598
|
+
.prepare(`SELECT ${selected} FROM ${quote(mapping.source)} ORDER BY ${order}`)
|
|
599
|
+
.iterate();
|
|
600
|
+
const source = checksumRows(rows, mapping.columns, 'source');
|
|
601
|
+
if (!mapping.projectSourceRow) {
|
|
602
|
+
return { mapping, ...source, targetChecksum: source.checksum };
|
|
603
|
+
}
|
|
604
|
+
const projectedRows = database
|
|
605
|
+
.prepare(`SELECT ${selected} FROM ${quote(mapping.source)} ORDER BY ${order}`)
|
|
606
|
+
.iterate();
|
|
607
|
+
const target = checksumRows((function* () {
|
|
608
|
+
for (const row of projectedRows) {
|
|
609
|
+
yield mapping.projectSourceRow(database, row);
|
|
610
|
+
}
|
|
611
|
+
})(), mapping.columns, 'source');
|
|
612
|
+
if (target.rows !== source.rows) {
|
|
613
|
+
throw new Error('SQLite import projection changed a table row count');
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
mapping,
|
|
617
|
+
...source,
|
|
618
|
+
targetChecksum: target.checksum,
|
|
619
|
+
};
|
|
620
|
+
};
|
|
621
|
+
const safeCount = (value) => {
|
|
622
|
+
const parsed = typeof value === 'bigint' ? Number(value) : Number(value);
|
|
623
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
624
|
+
throw new Error('Persistence row count exceeds the supported range');
|
|
625
|
+
}
|
|
626
|
+
return parsed;
|
|
627
|
+
};
|
|
628
|
+
const sqliteCount = (database, sql) => {
|
|
629
|
+
const row = database.prepare(sql).get();
|
|
630
|
+
return safeCount(row.count);
|
|
631
|
+
};
|
|
632
|
+
const sourceBlockers = (database, storagePhaseConfigured) => {
|
|
633
|
+
const blockers = [];
|
|
634
|
+
const blockedTables = [
|
|
635
|
+
['generated_images', 'gallery media requires coordinated blob transfer'],
|
|
636
|
+
[
|
|
637
|
+
'platform_blob_references',
|
|
638
|
+
'blob references require coordinated blob transfer',
|
|
639
|
+
],
|
|
640
|
+
[
|
|
641
|
+
'platform_blob_quota_usage',
|
|
642
|
+
'blob quota state requires coordinated blob transfer',
|
|
643
|
+
],
|
|
644
|
+
[
|
|
645
|
+
'platform_blob_quota_reservations',
|
|
646
|
+
'blob reservations require coordinated blob transfer',
|
|
647
|
+
],
|
|
648
|
+
[
|
|
649
|
+
'platform_blob_quota_objects',
|
|
650
|
+
'blob quota objects require coordinated blob transfer',
|
|
651
|
+
],
|
|
652
|
+
[
|
|
653
|
+
'platform_vector_entries',
|
|
654
|
+
'encrypted embedded vectors require authenticated decrypt-and-reindex',
|
|
655
|
+
],
|
|
656
|
+
['platform_vector_acl', 'vector ACL rows depend on converted vectors'],
|
|
657
|
+
[
|
|
658
|
+
'platform_vector_attributes',
|
|
659
|
+
'vector attributes depend on converted vectors',
|
|
660
|
+
],
|
|
661
|
+
];
|
|
662
|
+
if (!storagePhaseConfigured) {
|
|
663
|
+
for (const [tableName, reason] of blockedTables) {
|
|
664
|
+
const count = sqliteCount(database, `SELECT COUNT(*) AS count FROM ${quote(tableName)}`);
|
|
665
|
+
if (count > 0)
|
|
666
|
+
blockers.push(`${tableName}: ${count} row(s); ${reason}`);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
const linkedMediaJobs = sqliteCount(database, 'SELECT COUNT(*) AS count FROM media_generation_jobs WHERE gallery_id IS NOT NULL');
|
|
670
|
+
if (!storagePhaseConfigured && linkedMediaJobs > 0) {
|
|
671
|
+
blockers.push(`media_generation_jobs: ${linkedMediaJobs} row(s) reference gallery media that must be transferred first`);
|
|
672
|
+
}
|
|
673
|
+
const missingVoiceLookups = sqliteCount(database, 'SELECT COUNT(*) AS count FROM voice_profiles WHERE name_lookup IS NULL');
|
|
674
|
+
if (missingVoiceLookups > 0) {
|
|
675
|
+
blockers.push(`voice_profiles: ${missingVoiceLookups} row(s) lack keyed name lookups; start the current SQLite release once with the correct encryption key before migration`);
|
|
676
|
+
}
|
|
677
|
+
const unsupportedNulFields = sourceTextNulInventory(database).filter(field => !(field.table === 'work_messages' && field.column === 'content'));
|
|
678
|
+
if (unsupportedNulFields.length > 0) {
|
|
679
|
+
const maximumDetails = 8;
|
|
680
|
+
const details = unsupportedNulFields
|
|
681
|
+
.slice(0, maximumDetails)
|
|
682
|
+
.map(field => `${field.table}.${field.column}: ${field.rows} row(s)`)
|
|
683
|
+
.join(', ');
|
|
684
|
+
const remainder = unsupportedNulFields.length - maximumDetails;
|
|
685
|
+
blockers.push(`PostgreSQL text cannot represent U+0000 in mapped source fields: ${details}${remainder > 0 ? `, and ${remainder} more field(s)` : ''}`);
|
|
686
|
+
}
|
|
687
|
+
return blockers;
|
|
688
|
+
};
|
|
689
|
+
const sourceWarnings = (database, storagePhaseConfigured) => {
|
|
690
|
+
const warnings = [];
|
|
691
|
+
const danglingMessageParents = sqliteCount(database, `SELECT COUNT(*) AS count
|
|
692
|
+
FROM session_messages AS child
|
|
693
|
+
LEFT JOIN session_messages AS parent ON parent.id = child.parent_id
|
|
694
|
+
WHERE child.parent_id IS NOT NULL AND parent.id IS NULL`);
|
|
695
|
+
if (danglingMessageParents > 0) {
|
|
696
|
+
const subject = danglingMessageParents === 1
|
|
697
|
+
? 'session-message parent reference points'
|
|
698
|
+
: 'session-message parent references point';
|
|
699
|
+
warnings.push(`${danglingMessageParents} ${subject} to absent messages and will be imported as NULL; source rows and source checksums remain unchanged.`);
|
|
700
|
+
}
|
|
701
|
+
const nulWorkMessages = sourceTextNulInventory(database).find(field => field.table === 'work_messages' && field.column === 'content')?.rows;
|
|
702
|
+
if (nulWorkMessages) {
|
|
703
|
+
const subject = nulWorkMessages === 1
|
|
704
|
+
? 'Work-message content row contains'
|
|
705
|
+
: 'Work-message content rows contain';
|
|
706
|
+
warnings.push(`${nulWorkMessages} ${subject} U+0000 and will use PostgreSQL's reversible JSON-string storage; logical content and raw source checksums remain unchanged.`);
|
|
707
|
+
}
|
|
708
|
+
if (!storagePhaseConfigured) {
|
|
709
|
+
const embeddedMemories = sqliteCount(database, 'SELECT COUNT(*) AS count FROM persona_memories WHERE embedding IS NOT NULL');
|
|
710
|
+
if (embeddedMemories > 0) {
|
|
711
|
+
warnings.push(`${embeddedMemories} legacy persona-memory embedding(s) are derived data and must be rebuilt in the selected PostgreSQL vector store; encrypted memory payloads are preserved exactly.`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return warnings;
|
|
715
|
+
};
|
|
716
|
+
const sameFileState = (left, right) => left.dev === right.dev &&
|
|
717
|
+
left.ino === right.ino &&
|
|
718
|
+
left.nlink === right.nlink &&
|
|
719
|
+
left.size === right.size &&
|
|
720
|
+
left.mtimeNs === right.mtimeNs &&
|
|
721
|
+
left.ctimeNs === right.ctimeNs;
|
|
722
|
+
const sourceFiles = (sourcePath) => {
|
|
723
|
+
const result = [];
|
|
724
|
+
for (const suffix of ['', '-wal']) {
|
|
725
|
+
const candidate = `${sourcePath}${suffix}`;
|
|
726
|
+
let stat;
|
|
727
|
+
try {
|
|
728
|
+
stat = fs.lstatSync(candidate, { bigint: true });
|
|
729
|
+
}
|
|
730
|
+
catch (error) {
|
|
731
|
+
if (suffix === '-wal' &&
|
|
732
|
+
error.code === 'ENOENT') {
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
throw new Error('Unable to inspect the SQLite migration source');
|
|
736
|
+
}
|
|
737
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1n) {
|
|
738
|
+
throw new Error('SQLite migration sources must be single-link regular files');
|
|
739
|
+
}
|
|
740
|
+
result.push({ suffix, path: candidate, stat });
|
|
741
|
+
}
|
|
742
|
+
return result;
|
|
743
|
+
};
|
|
744
|
+
const copySourceFile = (source, destination) => {
|
|
745
|
+
const sourceDescriptor = fs.openSync(source.path, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
|
746
|
+
let destinationDescriptor;
|
|
747
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
748
|
+
try {
|
|
749
|
+
const opened = fs.fstatSync(sourceDescriptor, { bigint: true });
|
|
750
|
+
if (!sameFileState(opened, source.stat)) {
|
|
751
|
+
throw new Error('SQLite migration source changed before snapshot');
|
|
752
|
+
}
|
|
753
|
+
destinationDescriptor = fs.openSync(destination, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, 0o600);
|
|
754
|
+
let bytesRead = 0;
|
|
755
|
+
while ((bytesRead = fs.readSync(sourceDescriptor, buffer, 0, buffer.length, null)) > 0) {
|
|
756
|
+
let offset = 0;
|
|
757
|
+
while (offset < bytesRead) {
|
|
758
|
+
offset += fs.writeSync(destinationDescriptor, buffer, offset, bytesRead - offset);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
fs.fsyncSync(destinationDescriptor);
|
|
762
|
+
const after = fs.fstatSync(sourceDescriptor, { bigint: true });
|
|
763
|
+
if (!sameFileState(after, source.stat)) {
|
|
764
|
+
throw new Error('SQLite migration source changed during snapshot');
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
finally {
|
|
768
|
+
buffer.fill(0);
|
|
769
|
+
if (destinationDescriptor !== undefined)
|
|
770
|
+
fs.closeSync(destinationDescriptor);
|
|
771
|
+
fs.closeSync(sourceDescriptor);
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
const PLUGIN_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
775
|
+
const MAX_PLUGIN_DEFINITION_BYTES = 8 * 1024 * 1024;
|
|
776
|
+
const readStablePluginDefinition = (filePath, expected) => {
|
|
777
|
+
if (!expected.isFile() ||
|
|
778
|
+
expected.isSymbolicLink() ||
|
|
779
|
+
expected.nlink !== 1n ||
|
|
780
|
+
expected.size > BigInt(MAX_PLUGIN_DEFINITION_BYTES)) {
|
|
781
|
+
throw new Error('Plugin migration sources must be bounded single-link regular files');
|
|
782
|
+
}
|
|
783
|
+
const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
|
|
784
|
+
try {
|
|
785
|
+
const opened = fs.fstatSync(descriptor, { bigint: true });
|
|
786
|
+
if (!sameFileState(expected, opened)) {
|
|
787
|
+
throw new Error('Plugin definition changed before migration snapshot');
|
|
788
|
+
}
|
|
789
|
+
const content = fs.readFileSync(descriptor, 'utf8');
|
|
790
|
+
const after = fs.fstatSync(descriptor, { bigint: true });
|
|
791
|
+
if (!sameFileState(expected, after)) {
|
|
792
|
+
throw new Error('Plugin definition changed during migration snapshot');
|
|
793
|
+
}
|
|
794
|
+
return content;
|
|
795
|
+
}
|
|
796
|
+
finally {
|
|
797
|
+
fs.closeSync(descriptor);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
/** Capture node-local definitions into the private SQLite snapshot only. */
|
|
801
|
+
const capturePluginDefinitions = (database, configuredDirectory) => {
|
|
802
|
+
const directory = path.resolve(configuredDirectory);
|
|
803
|
+
let directoryStat;
|
|
804
|
+
try {
|
|
805
|
+
directoryStat = fs.lstatSync(directory, { bigint: true });
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
if (error.code === 'ENOENT')
|
|
809
|
+
return;
|
|
810
|
+
throw new Error('Unable to inspect the plugin migration source directory');
|
|
811
|
+
}
|
|
812
|
+
if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) {
|
|
813
|
+
throw new Error('Plugin migration source must be a physical directory, not a link');
|
|
814
|
+
}
|
|
815
|
+
const entries = fs
|
|
816
|
+
.readdirSync(directory, { withFileTypes: true })
|
|
817
|
+
.filter(entry => entry.name.endsWith('.json') && !entry.name.startsWith('.'))
|
|
818
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
819
|
+
const approval = database.prepare(`SELECT definition_fingerprint, source_path, approved_by_user_id, approved_at
|
|
820
|
+
FROM plugin_definition_approvals WHERE plugin_id = ?`);
|
|
821
|
+
const upsert = database.prepare(`INSERT INTO plugin_definitions
|
|
822
|
+
(plugin_id, definition_json, definition_fingerprint,
|
|
823
|
+
approved_by_user_id, approved_at, created_at, updated_at)
|
|
824
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
825
|
+
ON CONFLICT(plugin_id) DO UPDATE SET
|
|
826
|
+
definition_json = excluded.definition_json,
|
|
827
|
+
definition_fingerprint = excluded.definition_fingerprint,
|
|
828
|
+
approved_by_user_id = excluded.approved_by_user_id,
|
|
829
|
+
approved_at = excluded.approved_at,
|
|
830
|
+
created_at = excluded.created_at,
|
|
831
|
+
updated_at = excluded.updated_at`);
|
|
832
|
+
const capture = database.transaction(() => {
|
|
833
|
+
for (const entry of entries) {
|
|
834
|
+
const pluginId = path.basename(entry.name, '.json');
|
|
835
|
+
if (!PLUGIN_ID_PATTERN.test(pluginId)) {
|
|
836
|
+
throw new Error('Plugin migration source has an invalid definition ID');
|
|
837
|
+
}
|
|
838
|
+
const filePath = path.join(directory, entry.name);
|
|
839
|
+
const stat = fs.lstatSync(filePath, { bigint: true });
|
|
840
|
+
if (!entry.isFile() || entry.isSymbolicLink()) {
|
|
841
|
+
throw new Error('Plugin migration source contains an unsafe definition');
|
|
842
|
+
}
|
|
843
|
+
const content = readStablePluginDefinition(filePath, stat);
|
|
844
|
+
let fingerprint = createHash('sha256').update(content).digest('hex');
|
|
845
|
+
let createdAt = Number(stat.birthtimeMs);
|
|
846
|
+
let updatedAt = Number(stat.mtimeMs);
|
|
847
|
+
let definitionMatchesId = false;
|
|
848
|
+
try {
|
|
849
|
+
const parsed = JSON.parse(content);
|
|
850
|
+
definitionMatchesId =
|
|
851
|
+
typeof parsed === 'object' &&
|
|
852
|
+
parsed !== null &&
|
|
853
|
+
parsed.id === pluginId;
|
|
854
|
+
if (definitionMatchesId) {
|
|
855
|
+
fingerprint = getPluginDefinitionFingerprint(parsed);
|
|
856
|
+
if (Number.isSafeInteger(parsed.created_at)) {
|
|
857
|
+
createdAt = parsed.created_at;
|
|
858
|
+
}
|
|
859
|
+
if (Number.isSafeInteger(parsed.updated_at)) {
|
|
860
|
+
updatedAt = parsed.updated_at;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
catch {
|
|
865
|
+
// Preserve malformed bytes as an unapproved quarantine shadow.
|
|
866
|
+
}
|
|
867
|
+
const existingApproval = approval.get(pluginId);
|
|
868
|
+
const approved = definitionMatchesId &&
|
|
869
|
+
existingApproval?.definition_fingerprint === fingerprint &&
|
|
870
|
+
path.resolve(existingApproval.source_path) === path.resolve(filePath);
|
|
871
|
+
upsert.run(pluginId, content, fingerprint, approved ? existingApproval.approved_by_user_id : null, approved ? existingApproval.approved_at : null, createdAt, updatedAt);
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
capture();
|
|
875
|
+
};
|
|
876
|
+
const withSourceSnapshot = async (inputPath, inputPluginsPath, operation) => {
|
|
877
|
+
const resolved = path.resolve(inputPath);
|
|
878
|
+
const before = sourceFiles(resolved);
|
|
879
|
+
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'libre-sqlite-import-'));
|
|
880
|
+
fs.chmodSync(directory, 0o700);
|
|
881
|
+
const snapshotPath = path.join(directory, 'source.sqlite');
|
|
882
|
+
let database;
|
|
883
|
+
try {
|
|
884
|
+
for (const source of before) {
|
|
885
|
+
copySourceFile(source, `${snapshotPath}${source.suffix}`);
|
|
886
|
+
}
|
|
887
|
+
const after = sourceFiles(resolved);
|
|
888
|
+
if (after.length !== before.length ||
|
|
889
|
+
before.some((source, index) => source.suffix !== after[index]?.suffix ||
|
|
890
|
+
!sameFileState(source.stat, after[index].stat))) {
|
|
891
|
+
throw new Error('SQLite migration source changed while it was being snapshotted; stop Libre and every worker before retrying');
|
|
892
|
+
}
|
|
893
|
+
database = new Database(snapshotPath, { fileMustExist: true });
|
|
894
|
+
if (database.pragma('quick_check', { simple: true }) !== 'ok') {
|
|
895
|
+
throw new Error('SQLite migration snapshot failed quick_check');
|
|
896
|
+
}
|
|
897
|
+
capturePluginDefinitions(database, inputPluginsPath ?? path.join(path.dirname(resolved), 'plugins'));
|
|
898
|
+
database.pragma('query_only = ON');
|
|
899
|
+
if (database.prepare('SELECT * FROM pragma_foreign_key_check LIMIT 1').get()) {
|
|
900
|
+
throw new Error('SQLite migration snapshot has a foreign-key violation');
|
|
901
|
+
}
|
|
902
|
+
return await operation(database);
|
|
903
|
+
}
|
|
904
|
+
finally {
|
|
905
|
+
database?.close();
|
|
906
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const analyzeSource = async (database, sourcePath, storagePhase) => {
|
|
910
|
+
const compatibility = preflightSQLiteMigrationLedger(database);
|
|
911
|
+
if (compatibility.status !== 'compatible' ||
|
|
912
|
+
compatibility.currentVersion !== compatibility.targetVersion) {
|
|
913
|
+
throw new Error('SQLite source must be started and fully migrated by this Libre release before PostgreSQL import');
|
|
914
|
+
}
|
|
915
|
+
// Application timestamps/counters are safe JS integers, but reading them as
|
|
916
|
+
// bigint avoids any accidental coercion while producing the migration
|
|
917
|
+
// checksum. Run the existing schema inspector first because its PRAGMA sort
|
|
918
|
+
// callbacks intentionally operate on ordinary numbers.
|
|
919
|
+
database.defaultSafeIntegers(true);
|
|
920
|
+
const tables = TABLE_MAPPINGS.map(mapping => sourceManifest(database, mapping));
|
|
921
|
+
const phases = storagePhase
|
|
922
|
+
? [
|
|
923
|
+
{
|
|
924
|
+
implementation: storagePhase,
|
|
925
|
+
analysis: await storagePhase.analyze({
|
|
926
|
+
sourceDatabase: database,
|
|
927
|
+
sourcePath,
|
|
928
|
+
}),
|
|
929
|
+
},
|
|
930
|
+
]
|
|
931
|
+
: [];
|
|
932
|
+
for (const phase of phases) {
|
|
933
|
+
if (!/^[a-z][a-z0-9._-]{0,63}$/.test(phase.analysis.name) ||
|
|
934
|
+
!Number.isSafeInteger(phase.analysis.items) ||
|
|
935
|
+
phase.analysis.items < 0 ||
|
|
936
|
+
!/^[0-9a-f]{64}$/.test(phase.analysis.checksum)) {
|
|
937
|
+
throw new Error('Storage migration phase returned an invalid manifest');
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
const warnings = [
|
|
941
|
+
...sourceWarnings(database, Boolean(storagePhase)),
|
|
942
|
+
...phases.flatMap(phase => phase.analysis.warnings),
|
|
943
|
+
];
|
|
944
|
+
const blockers = [
|
|
945
|
+
...sourceBlockers(database, Boolean(storagePhase)),
|
|
946
|
+
...phases.flatMap(phase => phase.analysis.blockers),
|
|
947
|
+
];
|
|
948
|
+
const fingerprint = createHash('sha256')
|
|
949
|
+
.update(JSON.stringify({
|
|
950
|
+
format: 1,
|
|
951
|
+
sqliteMigrations: SQLITE_MIGRATION_CONTRACT,
|
|
952
|
+
tables: tables.map(manifest => ({
|
|
953
|
+
source: manifest.mapping.source,
|
|
954
|
+
target: manifest.mapping.target,
|
|
955
|
+
rows: manifest.rows,
|
|
956
|
+
checksum: manifest.checksum,
|
|
957
|
+
})),
|
|
958
|
+
phases: phases.map(phase => ({
|
|
959
|
+
name: phase.analysis.name,
|
|
960
|
+
items: phase.analysis.items,
|
|
961
|
+
checksum: phase.analysis.checksum,
|
|
962
|
+
})),
|
|
963
|
+
}))
|
|
964
|
+
.digest('hex');
|
|
965
|
+
return {
|
|
966
|
+
database,
|
|
967
|
+
sourcePath,
|
|
968
|
+
schemaVersion: compatibility.currentVersion,
|
|
969
|
+
fingerprint,
|
|
970
|
+
tables,
|
|
971
|
+
phases,
|
|
972
|
+
warnings,
|
|
973
|
+
blockers,
|
|
974
|
+
};
|
|
975
|
+
};
|
|
976
|
+
const targetTablesPresent = async (database) => {
|
|
977
|
+
const result = await database.query(`SELECT table_name
|
|
978
|
+
FROM information_schema.tables
|
|
979
|
+
WHERE table_schema = current_schema()
|
|
980
|
+
AND table_type = 'BASE TABLE'`);
|
|
981
|
+
return new Set(result.rows.map(row => row.table_name));
|
|
982
|
+
};
|
|
983
|
+
const targetIsEmpty = async (database, present) => {
|
|
984
|
+
const knownTables = new Set([
|
|
985
|
+
...TARGET_DOMAIN_TABLES,
|
|
986
|
+
...TARGET_CONTROL_TABLES,
|
|
987
|
+
]);
|
|
988
|
+
if ([...present].some(tableName => !knownTables.has(tableName))) {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
for (const tableName of TARGET_DOMAIN_TABLES) {
|
|
992
|
+
if (!present.has(tableName))
|
|
993
|
+
continue;
|
|
994
|
+
const result = await database.query(`SELECT COUNT(*)::text AS count FROM ${quote(tableName)}`);
|
|
995
|
+
if (result.rows[0]?.count !== '0')
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
998
|
+
return true;
|
|
999
|
+
};
|
|
1000
|
+
const inspectTarget = async (database) => {
|
|
1001
|
+
const tables = await database.query(`SELECT to_regclass('libre_schema_migrations')::text AS ledger,
|
|
1002
|
+
to_regclass('${IMPORT_TABLE}')::text AS imports`);
|
|
1003
|
+
const ledgerExists = Boolean(tables.rows[0]?.ledger);
|
|
1004
|
+
const importsExist = Boolean(tables.rows[0]?.imports);
|
|
1005
|
+
const present = await targetTablesPresent(database);
|
|
1006
|
+
// Before Libre has initialized the schema, *any* base table is structural
|
|
1007
|
+
// drift that the migration coordinator would reject. Once the exact ledger
|
|
1008
|
+
// exists, the application/control tables themselves are expected and
|
|
1009
|
+
// emptiness means they contain no imported domain rows and no unknown table.
|
|
1010
|
+
const empty = ledgerExists
|
|
1011
|
+
? await targetIsEmpty(database, present)
|
|
1012
|
+
: present.size === 0;
|
|
1013
|
+
let schemaVersion = null;
|
|
1014
|
+
let structurallyCompatible = false;
|
|
1015
|
+
let resumableSchemaPrefix = false;
|
|
1016
|
+
if (ledgerExists) {
|
|
1017
|
+
const ledger = await database.query(`SELECT version, name, checksum
|
|
1018
|
+
FROM libre_schema_migrations
|
|
1019
|
+
ORDER BY version ASC`);
|
|
1020
|
+
const ledgerCompatible = ledger.rows.length === POSTGRES_MIGRATIONS.length &&
|
|
1021
|
+
POSTGRES_MIGRATIONS.every((migration, index) => Number(ledger.rows[index]?.version) === migration.version &&
|
|
1022
|
+
ledger.rows[index]?.name === migration.name &&
|
|
1023
|
+
ledger.rows[index]?.checksum === migration.checksum);
|
|
1024
|
+
const prefixMigrations = POSTGRES_MIGRATIONS.slice(0, ledger.rows.length);
|
|
1025
|
+
const workMessageContentVersion = POSTGRES_MIGRATIONS.find(migration => migration.name === 'work-message-content-json')?.version;
|
|
1026
|
+
const supportedResumablePrefixes = new Set([
|
|
1027
|
+
POSTGRES_MIGRATIONS.length - 1,
|
|
1028
|
+
...(workMessageContentVersion === undefined
|
|
1029
|
+
? []
|
|
1030
|
+
: [workMessageContentVersion - 1]),
|
|
1031
|
+
]);
|
|
1032
|
+
const ledgerPrefixCompatible = ledger.rows.length > 0 &&
|
|
1033
|
+
ledger.rows.length < POSTGRES_MIGRATIONS.length &&
|
|
1034
|
+
supportedResumablePrefixes.has(ledger.rows.length) &&
|
|
1035
|
+
prefixMigrations.every((migration, index) => Number(ledger.rows[index]?.version) === migration.version &&
|
|
1036
|
+
ledger.rows[index]?.name === migration.name &&
|
|
1037
|
+
ledger.rows[index]?.checksum === migration.checksum);
|
|
1038
|
+
schemaVersion = Number(ledger.rows[ledger.rows.length - 1]?.version ?? 0);
|
|
1039
|
+
if (ledgerCompatible) {
|
|
1040
|
+
structurallyCompatible = (await inspectPostgresSchema(database, POSTGRES_MIGRATIONS)).compatible;
|
|
1041
|
+
}
|
|
1042
|
+
else if (ledgerPrefixCompatible) {
|
|
1043
|
+
resumableSchemaPrefix = (await inspectPostgresSchema(database, prefixMigrations)).compatible;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
let importStatus = 'absent';
|
|
1047
|
+
let importFingerprint = null;
|
|
1048
|
+
if (importsExist) {
|
|
1049
|
+
const imports = await database.query(`SELECT source_fingerprint, status
|
|
1050
|
+
FROM ${IMPORT_TABLE}
|
|
1051
|
+
ORDER BY created_at DESC
|
|
1052
|
+
LIMIT 2`);
|
|
1053
|
+
if (imports.rows.length > 1) {
|
|
1054
|
+
throw new Error('PostgreSQL contains multiple SQLite import identities');
|
|
1055
|
+
}
|
|
1056
|
+
const row = imports.rows[0];
|
|
1057
|
+
if (row) {
|
|
1058
|
+
importStatus = row.status;
|
|
1059
|
+
importFingerprint = row.source_fingerprint;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return {
|
|
1063
|
+
initialized: ledgerExists,
|
|
1064
|
+
schemaVersion,
|
|
1065
|
+
structurallyCompatible,
|
|
1066
|
+
resumableSchemaPrefix,
|
|
1067
|
+
empty,
|
|
1068
|
+
importStatus,
|
|
1069
|
+
importFingerprint,
|
|
1070
|
+
};
|
|
1071
|
+
};
|
|
1072
|
+
const baseReport = (mode, source, target, status, resume) => {
|
|
1073
|
+
const hasImportIdentity = target.importStatus !== 'absent';
|
|
1074
|
+
const matchingImport = hasImportIdentity && target.importFingerprint === source.fingerprint;
|
|
1075
|
+
const completedImport = matchingImport && target.importStatus === 'complete';
|
|
1076
|
+
const incompleteImport = matchingImport &&
|
|
1077
|
+
(target.importStatus === 'running' || target.importStatus === 'failed');
|
|
1078
|
+
const resumableSchemaCandidate = target.resumableSchemaPrefix && incompleteImport;
|
|
1079
|
+
const resumableUpgrade = resumableSchemaCandidate && resume;
|
|
1080
|
+
const uninitializedTargetIsDirty = !target.initialized && !target.empty;
|
|
1081
|
+
const unjournaledInitializedTargetIsDirty = target.initialized &&
|
|
1082
|
+
target.structurallyCompatible &&
|
|
1083
|
+
!hasImportIdentity &&
|
|
1084
|
+
!target.empty;
|
|
1085
|
+
const mismatchedImport = hasImportIdentity && !matchingImport;
|
|
1086
|
+
const incompleteImportNeedsResume = incompleteImport && !resume;
|
|
1087
|
+
const currentSchemaCanApply = target.structurallyCompatible &&
|
|
1088
|
+
((!hasImportIdentity && target.empty) ||
|
|
1089
|
+
completedImport ||
|
|
1090
|
+
(incompleteImport && resume));
|
|
1091
|
+
const targetCompatible = mode === 'validate'
|
|
1092
|
+
? target.structurallyCompatible && completedImport
|
|
1093
|
+
: (!target.initialized && target.empty) ||
|
|
1094
|
+
currentSchemaCanApply ||
|
|
1095
|
+
resumableUpgrade;
|
|
1096
|
+
const unsupportedInitializedSchema = target.initialized &&
|
|
1097
|
+
!target.structurallyCompatible &&
|
|
1098
|
+
!resumableSchemaCandidate;
|
|
1099
|
+
return {
|
|
1100
|
+
mode,
|
|
1101
|
+
sourceSchemaVersion: source.schemaVersion,
|
|
1102
|
+
sourceFingerprint: source.fingerprint,
|
|
1103
|
+
targetSchemaVersion: target.schemaVersion,
|
|
1104
|
+
targetInitialized: target.initialized,
|
|
1105
|
+
targetEmpty: target.empty,
|
|
1106
|
+
compatible: source.blockers.length === 0 && targetCompatible,
|
|
1107
|
+
resumed: false,
|
|
1108
|
+
tables: source.tables.map(manifest => ({
|
|
1109
|
+
sourceTable: manifest.mapping.source,
|
|
1110
|
+
targetTable: manifest.mapping.target,
|
|
1111
|
+
rows: manifest.rows,
|
|
1112
|
+
checksum: manifest.checksum,
|
|
1113
|
+
status,
|
|
1114
|
+
})),
|
|
1115
|
+
phases: source.phases.map(phase => ({
|
|
1116
|
+
name: phase.analysis.name,
|
|
1117
|
+
items: phase.analysis.items,
|
|
1118
|
+
checksum: phase.analysis.checksum,
|
|
1119
|
+
status,
|
|
1120
|
+
})),
|
|
1121
|
+
warnings: [
|
|
1122
|
+
...source.warnings,
|
|
1123
|
+
...(resumableUpgrade
|
|
1124
|
+
? [
|
|
1125
|
+
`PostgreSQL has the exact version ${target.schemaVersion} migration-ledger prefix and matching incomplete SQLite import; --resume can safely apply through version ${POSTGRES_TARGET_SCHEMA_VERSION} before continuing.`,
|
|
1126
|
+
]
|
|
1127
|
+
: []),
|
|
1128
|
+
],
|
|
1129
|
+
blockers: [
|
|
1130
|
+
...source.blockers,
|
|
1131
|
+
...(uninitializedTargetIsDirty
|
|
1132
|
+
? [
|
|
1133
|
+
'PostgreSQL target schema is not empty; use a clean schema or the exact matching resumable import.',
|
|
1134
|
+
]
|
|
1135
|
+
: []),
|
|
1136
|
+
...(unjournaledInitializedTargetIsDirty
|
|
1137
|
+
? [
|
|
1138
|
+
'PostgreSQL target contains domain rows without a SQLite import identity; use a clean schema or validate the original completed import.',
|
|
1139
|
+
]
|
|
1140
|
+
: []),
|
|
1141
|
+
...(mismatchedImport
|
|
1142
|
+
? [
|
|
1143
|
+
'PostgreSQL target is associated with a different SQLite snapshot; use the exact matching source or a clean target.',
|
|
1144
|
+
]
|
|
1145
|
+
: []),
|
|
1146
|
+
...(incompleteImportNeedsResume
|
|
1147
|
+
? [
|
|
1148
|
+
'PostgreSQL contains a matching incomplete SQLite import; rerun with resume enabled because this operation requires --resume.',
|
|
1149
|
+
]
|
|
1150
|
+
: []),
|
|
1151
|
+
...(unsupportedInitializedSchema
|
|
1152
|
+
? [
|
|
1153
|
+
'PostgreSQL target schema is not structurally compatible with this SQLite import.',
|
|
1154
|
+
]
|
|
1155
|
+
: []),
|
|
1156
|
+
...(mode === 'validate' && !targetCompatible
|
|
1157
|
+
? [
|
|
1158
|
+
'Validation requires the current PostgreSQL schema and the completed import identity for this SQLite snapshot.',
|
|
1159
|
+
]
|
|
1160
|
+
: []),
|
|
1161
|
+
],
|
|
1162
|
+
};
|
|
1163
|
+
};
|
|
1164
|
+
const createImportJournal = async (client) => {
|
|
1165
|
+
await client.query(POSTGRES_SQLITE_IMPORT_SCHEMA_SQL);
|
|
1166
|
+
};
|
|
1167
|
+
const updateCompatibility = async (client, status, failureCode, schemaFingerprint) => {
|
|
1168
|
+
await client.query(`UPDATE libre_schema_compatibility
|
|
1169
|
+
SET status = $1, failure_code = $2,
|
|
1170
|
+
schema_fingerprint = COALESCE($3, schema_fingerprint),
|
|
1171
|
+
updated_at = $4
|
|
1172
|
+
WHERE singleton = 1`, [status, failureCode, schemaFingerprint ?? null, Date.now()]);
|
|
1173
|
+
};
|
|
1174
|
+
const readJournalTables = async (client, fingerprint) => {
|
|
1175
|
+
const result = await client.query(`SELECT source_table, target_table, row_count, checksum, status
|
|
1176
|
+
FROM ${IMPORT_TABLE_STATE}
|
|
1177
|
+
WHERE source_fingerprint = $1
|
|
1178
|
+
ORDER BY source_table ASC`, [fingerprint]);
|
|
1179
|
+
return new Map(result.rows.map(row => [row.source_table, row]));
|
|
1180
|
+
};
|
|
1181
|
+
const targetManifest = async (executor, mapping) => {
|
|
1182
|
+
const selected = mapping.columns
|
|
1183
|
+
.map(column => quote(column.target))
|
|
1184
|
+
.join(', ');
|
|
1185
|
+
const order = mapping.targetKey.map(quote).join(', ');
|
|
1186
|
+
const hash = createHash('sha256');
|
|
1187
|
+
let offset = 0;
|
|
1188
|
+
let count = 0;
|
|
1189
|
+
while (true) {
|
|
1190
|
+
const result = await executor.query(`SELECT ${selected}
|
|
1191
|
+
FROM ${quote(mapping.target)}
|
|
1192
|
+
ORDER BY ${order}
|
|
1193
|
+
LIMIT $1 OFFSET $2`, [BATCH_SIZE, offset]);
|
|
1194
|
+
for (const row of result.rows) {
|
|
1195
|
+
hash.update(JSON.stringify(mapping.columns.map(column => canonical(row[column.target], column.kind))));
|
|
1196
|
+
hash.update('\n');
|
|
1197
|
+
count += 1;
|
|
1198
|
+
}
|
|
1199
|
+
if (result.rows.length < BATCH_SIZE)
|
|
1200
|
+
break;
|
|
1201
|
+
offset += result.rows.length;
|
|
1202
|
+
}
|
|
1203
|
+
return { rows: count, checksum: hash.digest('hex') };
|
|
1204
|
+
};
|
|
1205
|
+
const assertManifest = (source, actual) => {
|
|
1206
|
+
if (actual.rows !== source.rows ||
|
|
1207
|
+
actual.checksum !== source.targetChecksum) {
|
|
1208
|
+
throw new Error(`PostgreSQL verification failed for imported table ${source.mapping.target}`);
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
const insertSourceRows = async (database, client, mapping) => {
|
|
1212
|
+
const selected = mapping.columns
|
|
1213
|
+
.map(column => quote(column.source))
|
|
1214
|
+
.join(', ');
|
|
1215
|
+
const order = mapping.sourceKey.map(quote).join(', ');
|
|
1216
|
+
let offset = 0;
|
|
1217
|
+
while (true) {
|
|
1218
|
+
const sourceRows = database
|
|
1219
|
+
.prepare(`SELECT ${selected}
|
|
1220
|
+
FROM ${quote(mapping.source)}
|
|
1221
|
+
ORDER BY ${order}
|
|
1222
|
+
LIMIT ? OFFSET ?`)
|
|
1223
|
+
.all(BATCH_SIZE, offset);
|
|
1224
|
+
if (sourceRows.length === 0)
|
|
1225
|
+
break;
|
|
1226
|
+
const values = [];
|
|
1227
|
+
const tuples = sourceRows.map(sourceRow => {
|
|
1228
|
+
const row = mapping.projectSourceRow
|
|
1229
|
+
? mapping.projectSourceRow(database, sourceRow)
|
|
1230
|
+
: sourceRow;
|
|
1231
|
+
const parameters = mapping.columns.map(column => {
|
|
1232
|
+
values.push(mapping.deferredColumns?.includes(column.target)
|
|
1233
|
+
? null
|
|
1234
|
+
: row[column.source]);
|
|
1235
|
+
return `$${values.length}`;
|
|
1236
|
+
});
|
|
1237
|
+
return `(${parameters.join(', ')})`;
|
|
1238
|
+
});
|
|
1239
|
+
await client.query(`INSERT INTO ${quote(mapping.target)}
|
|
1240
|
+
(${mapping.columns.map(column => quote(column.target)).join(', ')})
|
|
1241
|
+
${mapping.overridingSystemValue ? 'OVERRIDING SYSTEM VALUE' : ''}
|
|
1242
|
+
VALUES ${tuples.join(', ')}`, values);
|
|
1243
|
+
offset += sourceRows.length;
|
|
1244
|
+
}
|
|
1245
|
+
for (const targetColumn of mapping.deferredColumns ?? []) {
|
|
1246
|
+
const column = mapping.columns.find(item => item.target === targetColumn);
|
|
1247
|
+
if (!column)
|
|
1248
|
+
throw new Error('Invalid deferred import column');
|
|
1249
|
+
const primarySource = mapping.sourceKey[0];
|
|
1250
|
+
const primaryTarget = mapping.targetKey[0];
|
|
1251
|
+
if (!primarySource || !primaryTarget) {
|
|
1252
|
+
throw new Error('Deferred import requires a primary key');
|
|
1253
|
+
}
|
|
1254
|
+
const updates = database
|
|
1255
|
+
.prepare(`SELECT ${selected}
|
|
1256
|
+
FROM ${quote(mapping.source)}
|
|
1257
|
+
WHERE ${quote(column.source)} IS NOT NULL
|
|
1258
|
+
ORDER BY ${quote(primarySource)}`)
|
|
1259
|
+
.iterate();
|
|
1260
|
+
for (const sourceRow of updates) {
|
|
1261
|
+
const update = mapping.projectSourceRow
|
|
1262
|
+
? mapping.projectSourceRow(database, sourceRow)
|
|
1263
|
+
: sourceRow;
|
|
1264
|
+
if (update[column.source] === null)
|
|
1265
|
+
continue;
|
|
1266
|
+
await client.query(`UPDATE ${quote(mapping.target)}
|
|
1267
|
+
SET ${quote(targetColumn)} = $1
|
|
1268
|
+
WHERE ${quote(primaryTarget)} = $2`, [update[column.source], update[primarySource]]);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
await mapping.afterImport?.(client);
|
|
1272
|
+
};
|
|
1273
|
+
const importOneTable = async (client, source, manifest) => {
|
|
1274
|
+
await client.query('BEGIN ISOLATION LEVEL SERIALIZABLE');
|
|
1275
|
+
try {
|
|
1276
|
+
const current = await targetManifest(client, manifest.mapping);
|
|
1277
|
+
if (current.rows !== 0) {
|
|
1278
|
+
throw new Error(`PostgreSQL target table ${manifest.mapping.target} is not empty before import`);
|
|
1279
|
+
}
|
|
1280
|
+
await insertSourceRows(source.database, client, manifest.mapping);
|
|
1281
|
+
assertManifest(manifest, await targetManifest(client, manifest.mapping));
|
|
1282
|
+
await client.query(`INSERT INTO ${IMPORT_TABLE_STATE}
|
|
1283
|
+
(source_fingerprint, source_table, target_table, row_count,
|
|
1284
|
+
checksum, status, updated_at)
|
|
1285
|
+
VALUES ($1, $2, $3, $4, $5, 'complete', $6)`, [
|
|
1286
|
+
source.fingerprint,
|
|
1287
|
+
manifest.mapping.source,
|
|
1288
|
+
manifest.mapping.target,
|
|
1289
|
+
manifest.rows,
|
|
1290
|
+
manifest.checksum,
|
|
1291
|
+
Date.now(),
|
|
1292
|
+
]);
|
|
1293
|
+
await client.query('COMMIT');
|
|
1294
|
+
}
|
|
1295
|
+
catch (error) {
|
|
1296
|
+
await client.query('ROLLBACK').catch(() => undefined);
|
|
1297
|
+
throw error;
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
const validateCompletedImport = async (client, source, report) => {
|
|
1301
|
+
const completed = await readJournalTables(client, source.fingerprint);
|
|
1302
|
+
for (const [index, manifest] of source.tables.entries()) {
|
|
1303
|
+
const journal = completed.get(manifest.mapping.source);
|
|
1304
|
+
if (!journal ||
|
|
1305
|
+
journal.target_table !== manifest.mapping.target ||
|
|
1306
|
+
safeCount(journal.row_count) !== manifest.rows ||
|
|
1307
|
+
journal.checksum !== manifest.checksum) {
|
|
1308
|
+
throw new Error(`SQLite import journal is incomplete for ${manifest.mapping.source}`);
|
|
1309
|
+
}
|
|
1310
|
+
assertManifest(manifest, await targetManifest(client, manifest.mapping));
|
|
1311
|
+
report.tables[index].status = 'verified';
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
const phaseContext = (source, target) => ({
|
|
1315
|
+
sourceDatabase: source.database,
|
|
1316
|
+
sourcePath: source.sourcePath,
|
|
1317
|
+
target,
|
|
1318
|
+
sourceFingerprint: source.fingerprint,
|
|
1319
|
+
});
|
|
1320
|
+
const applyStoragePhases = async (client, source, report, resume) => {
|
|
1321
|
+
for (const [index, phase] of source.phases.entries()) {
|
|
1322
|
+
await phase.implementation.apply({
|
|
1323
|
+
...phaseContext(source, client),
|
|
1324
|
+
resume,
|
|
1325
|
+
});
|
|
1326
|
+
report.phases[index].status = resume ? 'resumed' : 'imported';
|
|
1327
|
+
await phase.implementation.validate(phaseContext(source, client));
|
|
1328
|
+
report.phases[index].status = 'verified';
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
const validateStoragePhases = async (client, source, report) => {
|
|
1332
|
+
for (const [index, phase] of source.phases.entries()) {
|
|
1333
|
+
await phase.implementation.validate(phaseContext(source, client));
|
|
1334
|
+
report.phases[index].status = 'verified';
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
const applyImport = async (database, source, report, resume) => {
|
|
1338
|
+
await database.withClient(async (client) => {
|
|
1339
|
+
await client.query('SELECT pg_advisory_lock($1::bigint)', [IMPORT_LOCK]);
|
|
1340
|
+
let primaryError;
|
|
1341
|
+
let ownsImportIdentity = false;
|
|
1342
|
+
try {
|
|
1343
|
+
await createImportJournal(client);
|
|
1344
|
+
const imports = await client.query(`SELECT source_fingerprint, status FROM ${IMPORT_TABLE} FOR UPDATE`);
|
|
1345
|
+
if (imports.rows.length > 1) {
|
|
1346
|
+
throw new Error('PostgreSQL contains multiple SQLite import identities');
|
|
1347
|
+
}
|
|
1348
|
+
const existing = imports.rows[0];
|
|
1349
|
+
if (existing && existing.source_fingerprint !== source.fingerprint) {
|
|
1350
|
+
throw new Error('PostgreSQL was already associated with a different SQLite snapshot');
|
|
1351
|
+
}
|
|
1352
|
+
ownsImportIdentity = existing !== undefined;
|
|
1353
|
+
if (!existing) {
|
|
1354
|
+
const present = await targetTablesPresent(client);
|
|
1355
|
+
if (!(await targetIsEmpty(client, present))) {
|
|
1356
|
+
throw new Error('PostgreSQL target is not empty and has no matching SQLite import journal');
|
|
1357
|
+
}
|
|
1358
|
+
await client.query(`INSERT INTO ${IMPORT_TABLE}
|
|
1359
|
+
(source_fingerprint, source_schema_version, status, table_count,
|
|
1360
|
+
created_at, updated_at)
|
|
1361
|
+
VALUES ($1, $2, 'running', $3, $4, $4)`, [
|
|
1362
|
+
source.fingerprint,
|
|
1363
|
+
source.schemaVersion,
|
|
1364
|
+
source.tables.length,
|
|
1365
|
+
Date.now(),
|
|
1366
|
+
]);
|
|
1367
|
+
ownsImportIdentity = true;
|
|
1368
|
+
}
|
|
1369
|
+
else if (existing.status === 'complete') {
|
|
1370
|
+
report.resumed = true;
|
|
1371
|
+
await validateCompletedImport(client, source, report);
|
|
1372
|
+
await validateStoragePhases(client, source, report);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
else if (!resume) {
|
|
1376
|
+
throw new Error('A matching SQLite import is incomplete; rerun explicitly with resume enabled');
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
report.resumed = true;
|
|
1380
|
+
await client.query(`UPDATE ${IMPORT_TABLE}
|
|
1381
|
+
SET status = 'running', updated_at = $2
|
|
1382
|
+
WHERE source_fingerprint = $1`, [source.fingerprint, Date.now()]);
|
|
1383
|
+
}
|
|
1384
|
+
await updateCompatibility(client, 'migrating', 'sqlite_import_running');
|
|
1385
|
+
const completed = await readJournalTables(client, source.fingerprint);
|
|
1386
|
+
let storageApplied = false;
|
|
1387
|
+
for (const [index, manifest] of source.tables.entries()) {
|
|
1388
|
+
const journal = completed.get(manifest.mapping.source);
|
|
1389
|
+
if (journal) {
|
|
1390
|
+
if (journal.target_table !== manifest.mapping.target ||
|
|
1391
|
+
safeCount(journal.row_count) !== manifest.rows ||
|
|
1392
|
+
journal.checksum !== manifest.checksum) {
|
|
1393
|
+
throw new Error(`SQLite import journal mismatch for ${manifest.mapping.source}`);
|
|
1394
|
+
}
|
|
1395
|
+
assertManifest(manifest, await targetManifest(client, manifest.mapping));
|
|
1396
|
+
report.tables[index].status = 'resumed';
|
|
1397
|
+
}
|
|
1398
|
+
else {
|
|
1399
|
+
await importOneTable(client, source, manifest);
|
|
1400
|
+
report.tables[index].status = 'imported';
|
|
1401
|
+
}
|
|
1402
|
+
if (manifest.mapping.source === 'users') {
|
|
1403
|
+
await applyStoragePhases(client, source, report, resume);
|
|
1404
|
+
storageApplied = true;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
if (!storageApplied) {
|
|
1408
|
+
throw new Error('SQLite import did not reach the storage phase boundary');
|
|
1409
|
+
}
|
|
1410
|
+
await validateCompletedImport(client, source, report);
|
|
1411
|
+
await validateStoragePhases(client, source, report);
|
|
1412
|
+
const finishedAt = Date.now();
|
|
1413
|
+
await client.query(`UPDATE ${IMPORT_TABLE}
|
|
1414
|
+
SET status = 'complete', updated_at = $2, completed_at = $2
|
|
1415
|
+
WHERE source_fingerprint = $1`, [source.fingerprint, finishedAt]);
|
|
1416
|
+
const completedStructure = await inspectPostgresSchema(client, POSTGRES_MIGRATIONS);
|
|
1417
|
+
if (!completedStructure.compatible) {
|
|
1418
|
+
throw new Error(`Completed SQLite import produced incompatible PostgreSQL structure: ${completedStructure.problems
|
|
1419
|
+
.slice(0, 8)
|
|
1420
|
+
.join(', ')}`);
|
|
1421
|
+
}
|
|
1422
|
+
await updateCompatibility(client, 'compatible', null, completedStructure.fingerprint);
|
|
1423
|
+
}
|
|
1424
|
+
catch (error) {
|
|
1425
|
+
primaryError = error;
|
|
1426
|
+
if (ownsImportIdentity) {
|
|
1427
|
+
await client
|
|
1428
|
+
.query(`UPDATE ${IMPORT_TABLE}
|
|
1429
|
+
SET status = 'failed', updated_at = $2
|
|
1430
|
+
WHERE source_fingerprint = $1`, [source.fingerprint, Date.now()])
|
|
1431
|
+
.catch(() => undefined);
|
|
1432
|
+
await updateCompatibility(client, 'incompatible', 'sqlite_import_incomplete').catch(() => undefined);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
try {
|
|
1436
|
+
await client.query('SELECT pg_advisory_unlock($1::bigint)', [
|
|
1437
|
+
IMPORT_LOCK,
|
|
1438
|
+
]);
|
|
1439
|
+
}
|
|
1440
|
+
catch (unlockError) {
|
|
1441
|
+
if (!primaryError)
|
|
1442
|
+
throw unlockError;
|
|
1443
|
+
}
|
|
1444
|
+
if (primaryError)
|
|
1445
|
+
throw primaryError;
|
|
1446
|
+
});
|
|
1447
|
+
};
|
|
1448
|
+
/**
|
|
1449
|
+
* Copy the relational SQLite domains into a clean PostgreSQL schema. The
|
|
1450
|
+
* source is inspected through a private immutable snapshot, ciphertext is
|
|
1451
|
+
* copied as opaque bytes/text, and each target table is verified before its
|
|
1452
|
+
* journal row commits. Physical blobs and encrypted embedded vectors require
|
|
1453
|
+
* their storage-aware migration and therefore fail closed here.
|
|
1454
|
+
*/
|
|
1455
|
+
export const migrateSQLiteToPostgres = async (options) => withSourceSnapshot(options.sourcePath, options.sourcePluginsPath, async (sourceDatabase) => {
|
|
1456
|
+
try {
|
|
1457
|
+
const source = await analyzeSource(sourceDatabase, path.resolve(options.sourcePath), options.storagePhase);
|
|
1458
|
+
const database = createPostgresDatabase(options.postgres);
|
|
1459
|
+
try {
|
|
1460
|
+
let target = await inspectTarget(database);
|
|
1461
|
+
let report = baseReport(options.mode, source, target, 'planned', options.resume === true);
|
|
1462
|
+
if (options.mode === 'dry-run')
|
|
1463
|
+
return report;
|
|
1464
|
+
if (source.blockers.length > 0) {
|
|
1465
|
+
throw new SQLiteToPostgresMigrationError('SQLite source failed PostgreSQL migration preflight; inspect the reported blockers', report);
|
|
1466
|
+
}
|
|
1467
|
+
if (options.mode === 'validate') {
|
|
1468
|
+
if (!target.initialized || !target.structurallyCompatible) {
|
|
1469
|
+
throw new SQLiteToPostgresMigrationError('PostgreSQL target schema is not structurally compatible', report);
|
|
1470
|
+
}
|
|
1471
|
+
if (target.importStatus !== 'complete' ||
|
|
1472
|
+
target.importFingerprint !== source.fingerprint) {
|
|
1473
|
+
throw new SQLiteToPostgresMigrationError('PostgreSQL target does not contain the completed import for this SQLite snapshot', report);
|
|
1474
|
+
}
|
|
1475
|
+
await database.withClient(async (client) => {
|
|
1476
|
+
await validateCompletedImport(client, source, report);
|
|
1477
|
+
await validateStoragePhases(client, source, report);
|
|
1478
|
+
});
|
|
1479
|
+
report.compatible = true;
|
|
1480
|
+
return report;
|
|
1481
|
+
}
|
|
1482
|
+
if (!report.compatible) {
|
|
1483
|
+
throw new SQLiteToPostgresMigrationError(`PostgreSQL target failed SQLite import preflight: ${report.blockers.join('; ')}`, report);
|
|
1484
|
+
}
|
|
1485
|
+
if (!target.initialized) {
|
|
1486
|
+
await runPostgresMigrationCoordinator(database, {
|
|
1487
|
+
migrationMode: 'apply',
|
|
1488
|
+
migrationLockTimeoutMs: options.postgres.migrationLockTimeoutMs,
|
|
1489
|
+
}, POSTGRES_MIGRATIONS);
|
|
1490
|
+
target = await inspectTarget(database);
|
|
1491
|
+
report = baseReport(options.mode, source, target, 'planned', options.resume === true);
|
|
1492
|
+
}
|
|
1493
|
+
else if (!target.structurallyCompatible) {
|
|
1494
|
+
const resumableUpgrade = target.resumableSchemaPrefix &&
|
|
1495
|
+
(target.importStatus === 'running' ||
|
|
1496
|
+
target.importStatus === 'failed') &&
|
|
1497
|
+
target.importFingerprint === source.fingerprint;
|
|
1498
|
+
if (!resumableUpgrade || options.resume !== true) {
|
|
1499
|
+
throw new SQLiteToPostgresMigrationError(resumableUpgrade
|
|
1500
|
+
? 'The matching incomplete SQLite import requires --resume before its PostgreSQL schema can be upgraded'
|
|
1501
|
+
: 'PostgreSQL target schema is not structurally compatible', report);
|
|
1502
|
+
}
|
|
1503
|
+
try {
|
|
1504
|
+
await runPostgresMigrationCoordinator(database, {
|
|
1505
|
+
migrationMode: 'apply',
|
|
1506
|
+
migrationLockTimeoutMs: options.postgres.migrationLockTimeoutMs,
|
|
1507
|
+
}, POSTGRES_MIGRATIONS);
|
|
1508
|
+
}
|
|
1509
|
+
catch (error) {
|
|
1510
|
+
if (!(error instanceof PostgresMigrationError) ||
|
|
1511
|
+
!/incomplete SQLite import/i.test(error.compatibility.reason ?? error.message)) {
|
|
1512
|
+
throw error;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
target = await inspectTarget(database);
|
|
1516
|
+
report = baseReport(options.mode, source, target, 'planned', options.resume === true);
|
|
1517
|
+
if (!target.structurallyCompatible) {
|
|
1518
|
+
throw new SQLiteToPostgresMigrationError('PostgreSQL target schema did not reach the resumable import version', report);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
if (!report.compatible) {
|
|
1522
|
+
throw new SQLiteToPostgresMigrationError(`PostgreSQL target failed SQLite import preflight after schema initialization: ${report.blockers.join('; ')}`, report);
|
|
1523
|
+
}
|
|
1524
|
+
await applyImport(database, source, report, options.resume === true);
|
|
1525
|
+
report.compatible = true;
|
|
1526
|
+
report.targetInitialized = true;
|
|
1527
|
+
report.targetSchemaVersion = POSTGRES_TARGET_SCHEMA_VERSION;
|
|
1528
|
+
return report;
|
|
1529
|
+
}
|
|
1530
|
+
catch (error) {
|
|
1531
|
+
if (error instanceof SQLiteToPostgresMigrationError)
|
|
1532
|
+
throw error;
|
|
1533
|
+
throw new SQLiteToPostgresMigrationError(error instanceof Error ? error.message : 'SQLite import failed');
|
|
1534
|
+
}
|
|
1535
|
+
finally {
|
|
1536
|
+
await database.close().catch(() => undefined);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
finally {
|
|
1540
|
+
await options.storagePhase?.close?.().catch(() => undefined);
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
//# sourceMappingURL=sqliteToPostgresMigration.js.map
|