@lenne.tech/nest-server 12.0.0 → 12.1.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/.claude/rules/architecture.md +6 -1
- package/.claude/rules/better-auth.md +46 -0
- package/.claude/rules/configurable-features.md +3 -2
- package/.claude/rules/package-management.md +24 -2
- package/.claude/rules/persistence.md +100 -0
- package/.claude/rules/role-system.md +9 -0
- package/.claude/rules/testing.md +116 -18
- package/CLAUDE.md +21 -2
- package/FRAMEWORK-API.md +6 -4
- package/README.md +106 -34
- package/dist/core/common/decorators/unified-field.decorator.d.ts +2 -1
- package/dist/core/common/decorators/unified-field.decorator.js +4 -1
- package/dist/core/common/decorators/unified-field.decorator.js.map +1 -1
- package/dist/core/common/filters/mongoose-cast-error.filter.d.ts +7 -5
- package/dist/core/common/filters/mongoose-cast-error.filter.js +3 -2
- package/dist/core/common/filters/mongoose-cast-error.filter.js.map +1 -1
- package/dist/core/common/helpers/db.helper.d.ts +2 -1
- package/dist/core/common/helpers/db.helper.js +32 -26
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/decorator.helper.d.ts +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +2 -1
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/gridfs.helper.d.ts +4 -4
- package/dist/core/common/helpers/gridfs.helper.js +14 -6
- package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
- package/dist/core/common/helpers/id.helper.d.ts +4 -1
- package/dist/core/common/helpers/id.helper.js +10 -4
- package/dist/core/common/helpers/id.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.js +5 -5
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +3 -3
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +18 -2
- package/dist/core/common/interfaces/service-options.interface.d.ts +2 -2
- package/dist/core/common/models/core-persistence.model.d.ts +1 -2
- package/dist/core/common/models/core-persistence.model.js +3 -3
- package/dist/core/common/models/core-persistence.model.js.map +1 -1
- package/dist/core/common/persistence/core-persistence.lifecycle.d.ts +9 -0
- package/dist/core/common/persistence/core-persistence.lifecycle.js +38 -0
- package/dist/core/common/persistence/core-persistence.lifecycle.js.map +1 -0
- package/dist/core/common/persistence/core-persistence.module.d.ts +9 -0
- package/dist/core/common/persistence/core-persistence.module.js +76 -0
- package/dist/core/common/persistence/core-persistence.module.js.map +1 -0
- package/dist/core/common/persistence/data-source.config.d.ts +33 -0
- package/dist/core/common/persistence/data-source.config.js +151 -0
- package/dist/core/common/persistence/data-source.config.js.map +1 -0
- package/dist/core/common/persistence/data-source.runtime.d.ts +45 -0
- package/dist/core/common/persistence/data-source.runtime.js +278 -0
- package/dist/core/common/persistence/data-source.runtime.js.map +1 -0
- package/dist/core/common/persistence/data-store.interface.d.ts +73 -0
- package/dist/core/common/persistence/data-store.interface.js +2 -0
- package/dist/core/common/persistence/data-store.interface.js.map +1 -0
- package/dist/core/common/persistence/expiry-sweep.d.ts +12 -0
- package/dist/core/common/persistence/expiry-sweep.js +55 -0
- package/dist/core/common/persistence/expiry-sweep.js.map +1 -0
- package/dist/core/common/persistence/id-format.d.ts +3 -0
- package/dist/core/common/persistence/id-format.js +21 -0
- package/dist/core/common/persistence/id-format.js.map +1 -0
- package/dist/core/common/persistence/infrastructure-locks.d.ts +13 -0
- package/dist/core/common/persistence/infrastructure-locks.js +35 -0
- package/dist/core/common/persistence/infrastructure-locks.js.map +1 -0
- package/dist/core/common/persistence/inject-store.decorator.d.ts +1 -0
- package/dist/core/common/persistence/inject-store.decorator.js +6 -0
- package/dist/core/common/persistence/inject-store.decorator.js.map +1 -0
- package/dist/core/common/persistence/lock-store.interface.d.ts +5 -0
- package/dist/core/common/persistence/lock-store.interface.js +2 -0
- package/dist/core/common/persistence/lock-store.interface.js.map +1 -0
- package/dist/core/common/persistence/model-descriptor.interface.d.ts +36 -0
- package/dist/core/common/persistence/model-descriptor.interface.js +2 -0
- package/dist/core/common/persistence/model-descriptor.interface.js.map +1 -0
- package/dist/core/common/persistence/model-metadata.registry.d.ts +14 -0
- package/dist/core/common/persistence/model-metadata.registry.js +194 -0
- package/dist/core/common/persistence/model-metadata.registry.js.map +1 -0
- package/dist/core/common/persistence/mongo/collection-name.d.ts +2 -0
- package/dist/core/common/persistence/mongo/collection-name.js +73 -0
- package/dist/core/common/persistence/mongo/collection-name.js.map +1 -0
- package/dist/core/common/persistence/mongo/declared-schema.view.d.ts +11 -0
- package/dist/core/common/persistence/mongo/declared-schema.view.js +292 -0
- package/dist/core/common/persistence/mongo/declared-schema.view.js.map +1 -0
- package/dist/core/common/persistence/mongo/hex-object-id.d.ts +13 -0
- package/dist/core/common/persistence/mongo/hex-object-id.js +54 -0
- package/dist/core/common/persistence/mongo/hex-object-id.js.map +1 -0
- package/dist/core/common/persistence/mongo/model-declarations.d.ts +35 -0
- package/dist/core/common/persistence/mongo/model-declarations.js +80 -0
- package/dist/core/common/persistence/mongo/model-declarations.js.map +1 -0
- package/dist/core/common/persistence/mongo/mongo-packages.d.ts +15 -0
- package/dist/core/common/persistence/mongo/mongo-packages.js +66 -0
- package/dist/core/common/persistence/mongo/mongo-packages.js.map +1 -0
- package/dist/core/common/persistence/mongo/mongoose-compat.d.ts +22 -0
- package/dist/core/common/persistence/mongo/mongoose-compat.js +65 -0
- package/dist/core/common/persistence/mongo/mongoose-compat.js.map +1 -0
- package/dist/core/common/persistence/mongo/no-mongo-connection.module.d.ts +2 -0
- package/dist/core/common/persistence/mongo/no-mongo-connection.module.js +19 -0
- package/dist/core/common/persistence/mongo/no-mongo-connection.module.js.map +1 -0
- package/dist/core/common/persistence/mongo-lock-store.d.ts +21 -0
- package/dist/core/common/persistence/mongo-lock-store.js +72 -0
- package/dist/core/common/persistence/mongo-lock-store.js.map +1 -0
- package/dist/core/common/persistence/mongoose-data-store.d.ts +33 -0
- package/dist/core/common/persistence/mongoose-data-store.js +187 -0
- package/dist/core/common/persistence/mongoose-data-store.js.map +1 -0
- package/dist/core/common/persistence/neutral-populate.d.ts +6 -0
- package/dist/core/common/persistence/neutral-populate.js +72 -0
- package/dist/core/common/persistence/neutral-populate.js.map +1 -0
- package/dist/core/common/persistence/persisted-model.decorator.d.ts +6 -0
- package/dist/core/common/persistence/persisted-model.decorator.js +24 -0
- package/dist/core/common/persistence/persisted-model.decorator.js.map +1 -0
- package/dist/core/common/persistence/persistence-runtime.registry.d.ts +61 -0
- package/dist/core/common/persistence/persistence-runtime.registry.js +47 -0
- package/dist/core/common/persistence/persistence-runtime.registry.js.map +1 -0
- package/dist/core/common/persistence/persistence.tokens.d.ts +1 -0
- package/dist/core/common/persistence/persistence.tokens.js +4 -0
- package/dist/core/common/persistence/persistence.tokens.js.map +1 -0
- package/dist/core/common/persistence/policies/audit.policy.d.ts +8 -0
- package/dist/core/common/persistence/policies/audit.policy.js +37 -0
- package/dist/core/common/persistence/policies/audit.policy.js.map +1 -0
- package/dist/core/common/persistence/policies/password.policy.d.ts +3 -0
- package/dist/core/common/persistence/policies/password.policy.js +46 -0
- package/dist/core/common/persistence/policies/password.policy.js.map +1 -0
- package/dist/core/common/persistence/policies/role-guard.policy.d.ts +3 -0
- package/dist/core/common/persistence/policies/role-guard.policy.js +46 -0
- package/dist/core/common/persistence/policies/role-guard.policy.js.map +1 -0
- package/dist/core/common/persistence/policies/system-role.policy.d.ts +5 -0
- package/dist/core/common/persistence/policies/system-role.policy.js +46 -0
- package/dist/core/common/persistence/policies/system-role.policy.js.map +1 -0
- package/dist/core/common/persistence/policies/tenant.policy.d.ts +19 -0
- package/dist/core/common/persistence/policies/tenant.policy.js +120 -0
- package/dist/core/common/persistence/policies/tenant.policy.js.map +1 -0
- package/dist/core/common/persistence/routed-model.guard.d.ts +4 -0
- package/dist/core/common/persistence/routed-model.guard.js +73 -0
- package/dist/core/common/persistence/routed-model.guard.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-data-store.d.ts +46 -0
- package/dist/core/common/persistence/sql/mysql/mysql-data-store.js +350 -0
- package/dist/core/common/persistence/sql/mysql/mysql-data-store.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-executor.d.ts +13 -0
- package/dist/core/common/persistence/sql/mysql/mysql-executor.js +194 -0
- package/dist/core/common/persistence/sql/mysql/mysql-executor.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-lock-store.d.ts +11 -0
- package/dist/core/common/persistence/sql/mysql/mysql-lock-store.js +55 -0
- package/dist/core/common/persistence/sql/mysql/mysql-lock-store.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.d.ts +36 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.js +288 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.d.ts +19 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.js +328 -0
- package/dist/core/common/persistence/sql/mysql/mysql-schema.migrator.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-session.d.ts +13 -0
- package/dist/core/common/persistence/sql/mysql/mysql-session.js +85 -0
- package/dist/core/common/persistence/sql/mysql/mysql-session.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.d.ts +9 -0
- package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.js +264 -0
- package/dist/core/common/persistence/sql/mysql/mysql-update.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.d.ts +20 -0
- package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.js +519 -0
- package/dist/core/common/persistence/sql/mysql/mysql-where.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/postgres/postgres-lock-store.d.ts +11 -0
- package/dist/core/common/persistence/sql/postgres/postgres-lock-store.js +44 -0
- package/dist/core/common/persistence/sql/postgres/postgres-lock-store.js.map +1 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.d.ts +42 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.js +220 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.d.ts +12 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.js +315 -0
- package/dist/core/common/persistence/sql/postgres/postgres-schema.migrator.js.map +1 -0
- package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.d.ts +5 -0
- package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.js +225 -0
- package/dist/core/common/persistence/sql/postgres/postgres-update.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.d.ts +13 -0
- package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.js +484 -0
- package/dist/core/common/persistence/sql/postgres/postgres-where.compiler.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-cast.d.ts +2 -0
- package/dist/core/common/persistence/sql/sql-cast.js +194 -0
- package/dist/core/common/persistence/sql/sql-cast.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-data-store.d.ts +79 -0
- package/dist/core/common/persistence/sql/sql-data-store.js +592 -0
- package/dist/core/common/persistence/sql/sql-data-store.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-dialect.d.ts +20 -0
- package/dist/core/common/persistence/sql/sql-dialect.js +38 -0
- package/dist/core/common/persistence/sql/sql-dialect.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-errors.d.ts +17 -0
- package/dist/core/common/persistence/sql/sql-errors.js +25 -0
- package/dist/core/common/persistence/sql/sql-errors.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-executor.factory.d.ts +11 -0
- package/dist/core/common/persistence/sql/sql-executor.factory.js +199 -0
- package/dist/core/common/persistence/sql/sql-executor.factory.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-executor.interface.d.ts +32 -0
- package/dist/core/common/persistence/sql/sql-executor.interface.js +2 -0
- package/dist/core/common/persistence/sql/sql-executor.interface.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-naming.d.ts +15 -0
- package/dist/core/common/persistence/sql/sql-naming.js +90 -0
- package/dist/core/common/persistence/sql/sql-naming.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-schema.shared.d.ts +25 -0
- package/dist/core/common/persistence/sql/sql-schema.shared.js +69 -0
- package/dist/core/common/persistence/sql/sql-schema.shared.js.map +1 -0
- package/dist/core/common/persistence/sql/sql-session.d.ts +6 -0
- package/dist/core/common/persistence/sql/sql-session.js +78 -0
- package/dist/core/common/persistence/sql/sql-session.js.map +1 -0
- package/dist/core/common/persistence/sql/where-shared.d.ts +18 -0
- package/dist/core/common/persistence/sql/where-shared.js +93 -0
- package/dist/core/common/persistence/sql/where-shared.js.map +1 -0
- package/dist/core/common/persistence/store-guards.d.ts +10 -0
- package/dist/core/common/persistence/store-guards.js +49 -0
- package/dist/core/common/persistence/store-guards.js.map +1 -0
- package/dist/core/common/persistence/store-upsert.d.ts +2 -0
- package/dist/core/common/persistence/store-upsert.js +20 -0
- package/dist/core/common/persistence/store-upsert.js.map +1 -0
- package/dist/core/common/persistence/unavailable-store.d.ts +2 -0
- package/dist/core/common/persistence/unavailable-store.js +53 -0
- package/dist/core/common/persistence/unavailable-store.js.map +1 -0
- package/dist/core/common/persistence/unsupported-capability.error.d.ts +3 -0
- package/dist/core/common/persistence/unsupported-capability.error.js +4 -0
- package/dist/core/common/persistence/unsupported-capability.error.js.map +1 -0
- package/dist/core/common/plugins/mongoose-audit-fields.plugin.js +24 -68
- package/dist/core/common/plugins/mongoose-audit-fields.plugin.js.map +1 -1
- package/dist/core/common/plugins/mongoose-id.plugin.js +3 -0
- package/dist/core/common/plugins/mongoose-id.plugin.js.map +1 -1
- package/dist/core/common/plugins/mongoose-password.plugin.d.ts +1 -3
- package/dist/core/common/plugins/mongoose-password.plugin.js +2 -45
- package/dist/core/common/plugins/mongoose-password.plugin.js.map +1 -1
- package/dist/core/common/plugins/mongoose-role-guard.plugin.js +5 -46
- package/dist/core/common/plugins/mongoose-role-guard.plugin.js.map +1 -1
- package/dist/core/common/plugins/mongoose-system-role.plugin.js +2 -43
- package/dist/core/common/plugins/mongoose-system-role.plugin.js.map +1 -1
- package/dist/core/common/plugins/mongoose-tenant.plugin.js +10 -70
- package/dist/core/common/plugins/mongoose-tenant.plugin.js.map +1 -1
- package/dist/core/common/scalars/upload.scalar.js +1 -1
- package/dist/core/common/scalars/upload.scalar.js.map +1 -1
- package/dist/core/common/services/core-cron-jobs.initializer.js +1 -1
- package/dist/core/common/services/core-cron-jobs.initializer.js.map +1 -1
- package/dist/core/common/services/core-cron-jobs.service.d.ts +1 -0
- package/dist/core/common/services/core-cron-jobs.service.js +23 -14
- package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
- package/dist/core/common/services/crud.service.d.ts +4 -1
- package/dist/core/common/services/crud.service.js +132 -23
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/services/model-doc.service.js +1 -1
- package/dist/core/common/services/model-doc.service.js.map +1 -1
- package/dist/core/common/services/module.service.d.ts +9 -2
- package/dist/core/common/services/module.service.js +51 -6
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/common/types/field-selection.type.d.ts +1 -1
- package/dist/core/common/types/id.type.d.ts +4 -4
- package/dist/core/common/types/object-id-like.type.d.ts +3 -0
- package/dist/core/common/types/object-id-like.type.js +2 -0
- package/dist/core/common/types/object-id-like.type.js.map +1 -0
- package/dist/core/common/types/populate-config.type.d.ts +1 -1
- package/dist/core/common/types/string-or-object-id.type.d.ts +2 -2
- package/dist/core/modules/ai/core-ai.constants.d.ts +4 -0
- package/dist/core/modules/ai/core-ai.constants.js +4 -0
- package/dist/core/modules/ai/core-ai.constants.js.map +1 -1
- package/dist/core/modules/ai/core-ai.module.js +21 -17
- package/dist/core/modules/ai/core-ai.module.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.d.ts +2 -92
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.d.ts +2 -87
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-connection.model.d.ts +2 -177
- package/dist/core/modules/ai/models/core-ai-connection.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-connection.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +2 -92
- package/dist/core/modules/ai/models/core-ai-conversation.model.js +3 -4
- package/dist/core/modules/ai/models/core-ai-conversation.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-interaction.model.d.ts +2 -120
- package/dist/core/modules/ai/models/core-ai-interaction.model.js +2 -3
- package/dist/core/modules/ai/models/core-ai-interaction.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.d.ts +3 -0
- package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.js +21 -0
- package/dist/core/modules/ai/models/core-ai-mcp-oauth.models.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-mode.model.d.ts +2 -102
- package/dist/core/modules/ai/models/core-ai-mode.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-mode.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.d.ts +2 -97
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-prompt.model.d.ts +2 -112
- package/dist/core/modules/ai/models/core-ai-prompt.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-prompt.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-slot.model.d.ts +2 -112
- package/dist/core/modules/ai/models/core-ai-slot.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-slot.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.d.ts +2 -97
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.js.map +1 -1
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.d.ts +2 -103
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.js +1 -1
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +3 -1
- package/dist/core/modules/ai/services/core-ai-budget.service.js +15 -5
- package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +6 -10
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-connection.service.js +20 -42
- package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-conversation.service.js +28 -29
- package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-interaction.service.js +3 -4
- package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.d.ts +8 -0
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js +70 -18
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-mode.service.js +3 -7
- package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +8 -1
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +32 -26
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-prompt.service.js +10 -13
- package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-slot.service.js +14 -25
- package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +6 -18
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +1 -1
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +4 -8
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -1
- package/dist/core/modules/api-token/core-api-token.model.js +1 -1
- package/dist/core/modules/api-token/core-api-token.model.js.map +1 -1
- package/dist/core/modules/api-token/core-api-token.module.js +3 -2
- package/dist/core/modules/api-token/core-api-token.module.js.map +1 -1
- package/dist/core/modules/api-token/core-api-token.service.d.ts +8 -2
- package/dist/core/modules/api-token/core-api-token.service.js +106 -39
- package/dist/core/modules/api-token/core-api-token.service.js.map +1 -1
- package/dist/core/modules/auth/core-auth.module.js +2 -0
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +1 -2
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -1
- package/dist/core/modules/auth/guards/role-guard.token.d.ts +1 -0
- package/dist/core/modules/auth/guards/role-guard.token.js +2 -0
- package/dist/core/modules/auth/guards/role-guard.token.js.map +1 -0
- package/dist/core/modules/auth/services/core-auth.service.js +4 -2
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-sql.helper.d.ts +6 -0
- package/dist/core/modules/better-auth/better-auth-sql.helper.js +113 -0
- package/dist/core/modules/better-auth/better-auth-sql.helper.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-token.service.d.ts +3 -1
- package/dist/core/modules/better-auth/better-auth-token.service.js +15 -24
- package/dist/core/modules/better-auth/better-auth-token.service.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.config.d.ts +7 -0
- package/dist/core/modules/better-auth/better-auth.config.js +16 -5
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.types.d.ts +1 -1
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.d.ts +1 -0
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +6 -1
- package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-challenge.service.js +30 -15
- package/dist/core/modules/better-auth/core-better-auth-challenge.service.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth-mongo.users.d.ts +10 -0
- package/dist/core/modules/better-auth/core-better-auth-mongo.users.js +24 -0
- package/dist/core/modules/better-auth/core-better-auth-mongo.users.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.registry.d.ts +3 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.registry.js +8 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.registry.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.store.d.ts +71 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.store.js +190 -0
- package/dist/core/modules/better-auth/core-better-auth-sql.store.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.d.ts +24 -1
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +308 -32
- package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.module.d.ts +2 -0
- package/dist/core/modules/better-auth/core-better-auth.module.js +54 -32
- package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.service.d.ts +7 -2
- package/dist/core/modules/better-auth/core-better-auth.service.js +61 -9
- package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -1
- package/dist/core/modules/file/core-file-info.model.d.ts +1 -2
- package/dist/core/modules/file/core-file-info.model.js +2 -2
- package/dist/core/modules/file/core-file-info.model.js.map +1 -1
- package/dist/core/modules/file/core-file.service.d.ts +5 -3
- package/dist/core/modules/file/core-file.service.js +16 -9
- package/dist/core/modules/file/core-file.service.js.map +1 -1
- package/dist/core/modules/file/file-metadata.helper.d.ts +1 -1
- package/dist/core/modules/file/file-metadata.helper.js +2 -2
- package/dist/core/modules/file/file-metadata.helper.js.map +1 -1
- package/dist/core/modules/file/file-metadata.models.d.ts +35 -0
- package/dist/core/modules/file/file-metadata.models.js +20 -0
- package/dist/core/modules/file/file-metadata.models.js.map +1 -0
- package/dist/core/modules/file/file-metadata.store.d.ts +6 -0
- package/dist/core/modules/file/file-metadata.store.js +77 -0
- package/dist/core/modules/file/file-metadata.store.js.map +1 -0
- package/dist/core/modules/file/file-storage.helper.d.ts +1 -0
- package/dist/core/modules/file/file-storage.helper.js +34 -0
- package/dist/core/modules/file/file-storage.helper.js.map +1 -1
- package/dist/core/modules/file/filesystem-file.helper.d.ts +1 -1
- package/dist/core/modules/file/filesystem-file.helper.js +4 -4
- package/dist/core/modules/file/filesystem-file.helper.js.map +1 -1
- package/dist/core/modules/file/s3-file.helper.d.ts +1 -1
- package/dist/core/modules/file/s3-file.helper.js +5 -5
- package/dist/core/modules/file/s3-file.helper.js.map +1 -1
- package/dist/core/modules/health-check/core-health-check.module.js +12 -2
- package/dist/core/modules/health-check/core-health-check.module.js.map +1 -1
- package/dist/core/modules/health-check/core-health-check.service.d.ts +4 -3
- package/dist/core/modules/health-check/core-health-check.service.js +26 -5
- package/dist/core/modules/health-check/core-health-check.service.js.map +1 -1
- package/dist/core/modules/hub/core-hub.controller.d.ts +1 -0
- package/dist/core/modules/hub/core-hub.controller.js +10 -0
- package/dist/core/modules/hub/core-hub.controller.js.map +1 -1
- package/dist/core/modules/hub/core-hub.service.js +1 -1
- package/dist/core/modules/hub/core-hub.service.js.map +1 -1
- package/dist/core/modules/hub/helpers/hub-client-js.helper.js +23 -0
- package/dist/core/modules/hub/helpers/hub-client-js.helper.js.map +1 -1
- package/dist/core/modules/hub/hub-action-messages.d.ts +2 -0
- package/dist/core/modules/hub/hub-action-messages.js +2 -0
- package/dist/core/modules/hub/hub-action-messages.js.map +1 -1
- package/dist/core/modules/hub/hub-nav.js +1 -0
- package/dist/core/modules/hub/hub-nav.js.map +1 -1
- package/dist/core/modules/hub/interfaces/hub-panels.interface.d.ts +17 -1
- package/dist/core/modules/hub/services/core-hub-db.service.d.ts +6 -1
- package/dist/core/modules/hub/services/core-hub-db.service.js +16 -14
- package/dist/core/modules/hub/services/core-hub-db.service.js.map +1 -1
- package/dist/core/modules/hub/services/core-hub-migrations.service.d.ts +5 -0
- package/dist/core/modules/hub/services/core-hub-migrations.service.js +74 -1
- package/dist/core/modules/hub/services/core-hub-migrations.service.js.map +1 -1
- package/dist/core/modules/hub/services/core-hub-sources.service.d.ts +2 -1
- package/dist/core/modules/hub/services/core-hub-sources.service.js +32 -0
- package/dist/core/modules/hub/services/core-hub-sources.service.js.map +1 -1
- package/dist/core/modules/hub/services/hub-query-profiler.service.js +1 -1
- package/dist/core/modules/hub/services/hub-query-profiler.service.js.map +1 -1
- package/dist/core/modules/migrate/cli/migrate-cli.d.ts +2 -0
- package/dist/core/modules/migrate/cli/migrate-cli.js +35 -1
- package/dist/core/modules/migrate/cli/migrate-cli.js.map +1 -1
- package/dist/core/modules/migrate/index.d.ts +3 -0
- package/dist/core/modules/migrate/index.js +3 -0
- package/dist/core/modules/migrate/index.js.map +1 -1
- package/dist/core/modules/migrate/migration-runner.d.ts +2 -2
- package/dist/core/modules/migrate/migration-runner.js.map +1 -1
- package/dist/core/modules/migrate/migration-state-store.interface.d.ts +16 -0
- package/dist/core/modules/migrate/migration-state-store.interface.js +2 -0
- package/dist/core/modules/migrate/migration-state-store.interface.js.map +1 -0
- package/dist/core/modules/migrate/migration.helper.d.ts +3 -2
- package/dist/core/modules/migrate/migration.helper.js +21 -6
- package/dist/core/modules/migrate/migration.helper.js.map +1 -1
- package/dist/core/modules/migrate/mongo-state-store.d.ts +5 -12
- package/dist/core/modules/migrate/mongo-state-store.js +30 -24
- package/dist/core/modules/migrate/mongo-state-store.js.map +1 -1
- package/dist/core/modules/migrate/sql-migration.helper.d.ts +4 -0
- package/dist/core/modules/migrate/sql-migration.helper.js +34 -0
- package/dist/core/modules/migrate/sql-migration.helper.js.map +1 -0
- package/dist/core/modules/migrate/sql-state-store.d.ts +24 -0
- package/dist/core/modules/migrate/sql-state-store.js +129 -0
- package/dist/core/modules/migrate/sql-state-store.js.map +1 -0
- package/dist/core/modules/system-setup/core-system-setup.service.d.ts +8 -0
- package/dist/core/modules/system-setup/core-system-setup.service.js +41 -25
- package/dist/core/modules/system-setup/core-system-setup.service.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant-member.model.js +1 -1
- package/dist/core/modules/tenant/core-tenant-member.model.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant-member.store.d.ts +2 -0
- package/dist/core/modules/tenant/core-tenant-member.store.js +6 -0
- package/dist/core/modules/tenant/core-tenant-member.store.js.map +1 -0
- package/dist/core/modules/tenant/core-tenant.guard.d.ts +8 -3
- package/dist/core/modules/tenant/core-tenant.guard.js +57 -28
- package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.module.js +3 -2
- package/dist/core/modules/tenant/core-tenant.module.js.map +1 -1
- package/dist/core/modules/tenant/core-tenant.service.d.ts +3 -1
- package/dist/core/modules/tenant/core-tenant.service.js +48 -28
- package/dist/core/modules/tenant/core-tenant.service.js.map +1 -1
- package/dist/core/modules/tus/core-tus.service.d.ts +1 -1
- package/dist/core/modules/tus/core-tus.service.js +8 -7
- package/dist/core/modules/tus/core-tus.service.js.map +1 -1
- package/dist/core/modules/tus/tus.module.js +1 -1
- package/dist/core/modules/tus/tus.module.js.map +1 -1
- package/dist/core/modules/user/core-user.model.d.ts +1 -1
- package/dist/core/modules/user/core-user.model.js +1 -1
- package/dist/core/modules/user/core-user.model.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +3 -1
- package/dist/core/modules/user/core-user.service.js +71 -16
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core.module.js +39 -5
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/dist/server/common/models/persistence.model.d.ts +1 -1
- package/dist/server/common/models/persistence.model.js +3 -3
- package/dist/server/common/models/persistence.model.js.map +1 -1
- package/dist/server/modules/file/file-info.model.d.ts +1 -77
- package/dist/server/modules/file/file-info.model.js +1 -1
- package/dist/server/modules/file/file-info.model.js.map +1 -1
- package/dist/server/modules/file/file.service.js +1 -1
- package/dist/server/modules/file/file.service.js.map +1 -1
- package/dist/server/modules/user/user.model.d.ts +2 -186
- package/dist/server/modules/user/user.model.js +4 -5
- package/dist/server/modules/user/user.model.js.map +1 -1
- package/dist/server/modules/user/user.module.js +4 -3
- package/dist/server/modules/user/user.module.js.map +1 -1
- package/dist/server/modules/user/user.service.d.ts +1 -1
- package/dist/server/modules/user/user.service.js +5 -8
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/test/test.helper.js +2 -2
- package/dist/test/test.helper.js.map +1 -1
- package/dist/types/graphql-upload.d.ts +10 -7
- package/docs/REQUEST-LIFECYCLE.md +6 -3
- package/docs/choosing-a-database.md +107 -0
- package/docs/native-driver-security.md +29 -0
- package/docs/security-overrides.md +15 -6
- package/migration-guides/12.0.x-to-12.1.x.md +255 -0
- package/package.json +75 -29
- package/src/core/common/decorators/unified-field.decorator.ts +11 -1
- package/src/core/common/filters/mongoose-cast-error.filter.ts +12 -6
- package/src/core/common/helpers/db.helper.ts +40 -25
- package/src/core/common/helpers/decorator.helper.ts +1 -1
- package/src/core/common/helpers/filter.helper.ts +2 -1
- package/src/core/common/helpers/gridfs.helper.ts +28 -9
- package/src/core/common/helpers/id.helper.ts +21 -4
- package/src/core/common/helpers/model.helper.ts +5 -6
- package/src/core/common/helpers/service.helper.ts +3 -3
- package/src/core/common/interfaces/server-options.interface.ts +118 -10
- package/src/core/common/interfaces/service-options.interface.ts +2 -2
- package/src/core/common/models/core-persistence.model.ts +3 -3
- package/src/core/common/persistence/core-persistence.lifecycle.ts +47 -0
- package/src/core/common/persistence/core-persistence.module.ts +109 -0
- package/src/core/common/persistence/data-source.config.ts +271 -0
- package/src/core/common/persistence/data-source.runtime.ts +351 -0
- package/src/core/common/persistence/data-store.interface.ts +155 -0
- package/src/core/common/persistence/expiry-sweep.ts +105 -0
- package/src/core/common/persistence/id-format.ts +43 -0
- package/src/core/common/persistence/infrastructure-locks.ts +66 -0
- package/src/core/common/persistence/inject-store.decorator.ts +16 -0
- package/src/core/common/persistence/lock-store.interface.ts +17 -0
- package/src/core/common/persistence/model-descriptor.interface.ts +90 -0
- package/src/core/common/persistence/model-metadata.registry.ts +285 -0
- package/src/core/common/persistence/mongo/collection-name.ts +87 -0
- package/src/core/common/persistence/mongo/declared-schema.view.ts +378 -0
- package/src/core/common/persistence/mongo/hex-object-id.ts +75 -0
- package/src/core/common/persistence/mongo/model-declarations.ts +135 -0
- package/src/core/common/persistence/mongo/mongo-packages.ts +130 -0
- package/src/core/common/persistence/mongo/mongoose-compat.ts +129 -0
- package/src/core/common/persistence/mongo/no-mongo-connection.module.ts +18 -0
- package/src/core/common/persistence/mongo-lock-store.ts +121 -0
- package/src/core/common/persistence/mongoose-data-store.ts +232 -0
- package/src/core/common/persistence/neutral-populate.ts +98 -0
- package/src/core/common/persistence/persisted-model.decorator.ts +61 -0
- package/src/core/common/persistence/persistence-runtime.registry.ts +152 -0
- package/src/core/common/persistence/persistence.tokens.ts +9 -0
- package/src/core/common/persistence/policies/audit.policy.ts +80 -0
- package/src/core/common/persistence/policies/password.policy.ts +69 -0
- package/src/core/common/persistence/policies/role-guard.policy.ts +74 -0
- package/src/core/common/persistence/policies/system-role.policy.ts +90 -0
- package/src/core/common/persistence/policies/tenant.policy.ts +245 -0
- package/src/core/common/persistence/routed-model.guard.ts +107 -0
- package/src/core/common/persistence/sql/mysql/mysql-data-store.ts +503 -0
- package/src/core/common/persistence/sql/mysql/mysql-executor.ts +281 -0
- package/src/core/common/persistence/sql/mysql/mysql-lock-store.ts +87 -0
- package/src/core/common/persistence/sql/mysql/mysql-schema.compiler.ts +424 -0
- package/src/core/common/persistence/sql/mysql/mysql-schema.migrator.ts +453 -0
- package/src/core/common/persistence/sql/mysql/mysql-session.ts +131 -0
- package/src/core/common/persistence/sql/mysql/mysql-update.compiler.ts +379 -0
- package/src/core/common/persistence/sql/mysql/mysql-where.compiler.ts +686 -0
- package/src/core/common/persistence/sql/postgres/postgres-lock-store.ts +76 -0
- package/src/core/common/persistence/sql/postgres/postgres-schema.compiler.ts +328 -0
- package/src/core/common/persistence/sql/postgres/postgres-schema.migrator.ts +448 -0
- package/src/core/common/persistence/sql/postgres/postgres-update.compiler.ts +310 -0
- package/src/core/common/persistence/sql/postgres/postgres-where.compiler.ts +638 -0
- package/src/core/common/persistence/sql/sql-cast.ts +227 -0
- package/src/core/common/persistence/sql/sql-data-store.ts +762 -0
- package/src/core/common/persistence/sql/sql-dialect.ts +85 -0
- package/src/core/common/persistence/sql/sql-errors.ts +49 -0
- package/src/core/common/persistence/sql/sql-executor.factory.ts +282 -0
- package/src/core/common/persistence/sql/sql-executor.interface.ts +57 -0
- package/src/core/common/persistence/sql/sql-naming.ts +133 -0
- package/src/core/common/persistence/sql/sql-schema.shared.ts +105 -0
- package/src/core/common/persistence/sql/sql-session.ts +158 -0
- package/src/core/common/persistence/sql/where-shared.ts +118 -0
- package/src/core/common/persistence/store-guards.ts +73 -0
- package/src/core/common/persistence/store-upsert.ts +36 -0
- package/src/core/common/persistence/unavailable-store.ts +63 -0
- package/src/core/common/persistence/unsupported-capability.error.ts +7 -0
- package/src/core/common/plugins/mongoose-audit-fields.plugin.ts +33 -74
- package/src/core/common/plugins/mongoose-id.plugin.ts +9 -0
- package/src/core/common/plugins/mongoose-password.plugin.ts +6 -62
- package/src/core/common/plugins/mongoose-role-guard.plugin.ts +11 -63
- package/src/core/common/plugins/mongoose-system-role.plugin.ts +7 -78
- package/src/core/common/plugins/mongoose-tenant.plugin.ts +23 -144
- package/src/core/common/scalars/upload.scalar.ts +8 -3
- package/src/core/common/services/core-cron-jobs.initializer.ts +1 -1
- package/src/core/common/services/core-cron-jobs.service.ts +33 -22
- package/src/core/common/services/crud.service.ts +166 -35
- package/src/core/common/services/model-doc.service.ts +1 -1
- package/src/core/common/services/module.service.ts +78 -6
- package/src/core/common/types/field-selection.type.ts +1 -1
- package/src/core/common/types/id.type.ts +2 -2
- package/src/core/common/types/object-id-like.type.ts +11 -0
- package/src/core/common/types/populate-config.type.ts +1 -1
- package/src/core/common/types/string-or-object-id.type.ts +2 -2
- package/src/core/modules/ai/README.md +15 -2
- package/src/core/modules/ai/core-ai.constants.ts +10 -0
- package/src/core/modules/ai/core-ai.module.ts +32 -17
- package/src/core/modules/ai/models/core-ai-budget-limit.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-connection-preference.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-connection.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-conversation.model.ts +8 -4
- package/src/core/modules/ai/models/core-ai-interaction.model.ts +3 -3
- package/src/core/modules/ai/models/core-ai-mcp-oauth.models.ts +46 -0
- package/src/core/modules/ai/models/core-ai-mode.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-prompt-hint.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-prompt.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-slot.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-tool-grant.model.ts +2 -2
- package/src/core/modules/ai/models/core-ai-tool-policy.model.ts +2 -2
- package/src/core/modules/ai/services/core-ai-budget.service.ts +22 -4
- package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +6 -13
- package/src/core/modules/ai/services/core-ai-connection.service.ts +34 -44
- package/src/core/modules/ai/services/core-ai-conversation.service.ts +31 -29
- package/src/core/modules/ai/services/core-ai-interaction.service.ts +3 -3
- package/src/core/modules/ai/services/core-ai-mcp-oauth.service.ts +93 -20
- package/src/core/modules/ai/services/core-ai-mode.service.ts +3 -6
- package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +43 -26
- package/src/core/modules/ai/services/core-ai-prompt.service.ts +15 -12
- package/src/core/modules/ai/services/core-ai-slot.service.ts +20 -24
- package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +17 -27
- package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +7 -10
- package/src/core/modules/api-token/core-api-token.model.ts +1 -1
- package/src/core/modules/api-token/core-api-token.module.ts +4 -2
- package/src/core/modules/api-token/core-api-token.service.ts +118 -43
- package/src/core/modules/auth/core-auth.module.ts +2 -0
- package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +4 -3
- package/src/core/modules/auth/guards/role-guard.token.ts +7 -0
- package/src/core/modules/auth/services/core-auth.service.ts +16 -2
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +1 -1
- package/src/core/modules/better-auth/README.md +10 -1
- package/src/core/modules/better-auth/better-auth-sql.helper.ts +191 -0
- package/src/core/modules/better-auth/better-auth-token.service.ts +26 -35
- package/src/core/modules/better-auth/better-auth.config.ts +43 -7
- package/src/core/modules/better-auth/better-auth.types.ts +1 -1
- package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +13 -1
- package/src/core/modules/better-auth/core-better-auth-challenge.service.ts +36 -18
- package/src/core/modules/better-auth/core-better-auth-mongo.users.ts +35 -0
- package/src/core/modules/better-auth/core-better-auth-sql.registry.ts +20 -0
- package/src/core/modules/better-auth/core-better-auth-sql.store.ts +309 -0
- package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +418 -40
- package/src/core/modules/better-auth/core-better-auth.module.ts +71 -35
- package/src/core/modules/better-auth/core-better-auth.service.ts +81 -12
- package/src/core/modules/file/README.md +16 -3
- package/src/core/modules/file/core-file-info.model.ts +2 -2
- package/src/core/modules/file/core-file.service.ts +27 -18
- package/src/core/modules/file/file-metadata.helper.ts +7 -3
- package/src/core/modules/file/file-metadata.models.ts +44 -0
- package/src/core/modules/file/file-metadata.store.ts +109 -0
- package/src/core/modules/file/file-storage.helper.ts +47 -2
- package/src/core/modules/file/filesystem-file.helper.ts +11 -8
- package/src/core/modules/file/s3-file.helper.ts +11 -7
- package/src/core/modules/health-check/core-health-check.module.ts +16 -2
- package/src/core/modules/health-check/core-health-check.service.ts +25 -3
- package/src/core/modules/hub/README.md +20 -11
- package/src/core/modules/hub/core-hub.controller.ts +5 -0
- package/src/core/modules/hub/core-hub.service.ts +1 -1
- package/src/core/modules/hub/helpers/hub-client-js.helper.ts +23 -0
- package/src/core/modules/hub/hub-action-messages.ts +6 -0
- package/src/core/modules/hub/hub-nav.ts +1 -0
- package/src/core/modules/hub/interfaces/hub-panels.interface.ts +8 -1
- package/src/core/modules/hub/services/core-hub-db.service.ts +35 -17
- package/src/core/modules/hub/services/core-hub-migrations.service.ts +96 -2
- package/src/core/modules/hub/services/core-hub-sources.service.ts +47 -1
- package/src/core/modules/hub/services/hub-query-profiler.service.ts +1 -1
- package/src/core/modules/migrate/README.md +54 -0
- package/src/core/modules/migrate/cli/migrate-cli.ts +44 -3
- package/src/core/modules/migrate/index.ts +3 -0
- package/src/core/modules/migrate/migration-runner.ts +3 -2
- package/src/core/modules/migrate/migration-state-store.interface.ts +24 -0
- package/src/core/modules/migrate/migration.helper.ts +35 -10
- package/src/core/modules/migrate/mongo-state-store.ts +64 -65
- package/src/core/modules/migrate/sql-migration.helper.ts +48 -0
- package/src/core/modules/migrate/sql-state-store.ts +198 -0
- package/src/core/modules/system-setup/README.md +14 -2
- package/src/core/modules/system-setup/core-system-setup.service.ts +77 -45
- package/src/core/modules/tenant/README.md +9 -2
- package/src/core/modules/tenant/core-tenant-member.model.ts +1 -1
- package/src/core/modules/tenant/core-tenant-member.store.ts +13 -0
- package/src/core/modules/tenant/core-tenant.guard.ts +77 -24
- package/src/core/modules/tenant/core-tenant.module.ts +6 -3
- package/src/core/modules/tenant/core-tenant.service.ts +59 -42
- package/src/core/modules/tus/core-tus.service.ts +11 -12
- package/src/core/modules/tus/tus.module.ts +1 -1
- package/src/core/modules/user/core-user.model.ts +2 -2
- package/src/core/modules/user/core-user.service.ts +98 -20
- package/src/core.module.ts +60 -5
- package/src/index.ts +26 -0
- package/src/server/common/models/persistence.model.ts +4 -4
- package/src/server/modules/file/file-info.model.ts +1 -1
- package/src/server/modules/file/file.service.ts +1 -1
- package/src/server/modules/user/user.model.ts +10 -5
- package/src/server/modules/user/user.module.ts +9 -3
- package/src/server/modules/user/user.service.ts +9 -11
- package/src/test/test.helper.ts +2 -2
- package/src/types/graphql-upload.d.ts +10 -7
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import { Db, MongoClient } from 'mongodb';
|
|
2
|
+
import type { Db, MongoClient } from 'mongodb';
|
|
3
3
|
import { hostname } from 'os';
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
|
|
6
|
+
import type { MigrationSet, MigrationStateStore } from './migration-state-store.interface.js';
|
|
7
|
+
import {
|
|
8
|
+
MIGRATION_LOCK_KEY,
|
|
9
|
+
MIGRATION_LOCK_STALE_AFTER_MS,
|
|
10
|
+
migrationMongoLocks,
|
|
11
|
+
} from '../../common/persistence/infrastructure-locks.js';
|
|
12
|
+
import { requireMongoPackages } from '../../common/persistence/mongo/mongo-packages.js';
|
|
13
|
+
|
|
6
14
|
/**
|
|
7
15
|
* Migration options interface (compatible with migrate package)
|
|
8
16
|
*/
|
|
9
17
|
export interface MigrationOptions {
|
|
10
18
|
[key: string]: unknown;
|
|
11
|
-
stateStore:
|
|
19
|
+
stateStore: MigrationStateStore;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
* Migration set interface (compatible with migrate package)
|
|
16
|
-
*/
|
|
17
|
-
export interface MigrationSet {
|
|
18
|
-
down?: (done?: (err?: Error) => void) => void;
|
|
19
|
-
lastRun?: string;
|
|
20
|
-
migrations: Array<{ timestamp?: number; title: string }>;
|
|
21
|
-
up: (done?: (err?: Error) => void) => void;
|
|
22
|
-
}
|
|
22
|
+
export type { MigrationSet, MigrationStateStore };
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Options for MongoStateStore configuration
|
|
@@ -58,7 +58,7 @@ export interface MongoStateStoreOptions {
|
|
|
58
58
|
* });
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
|
-
export class MongoStateStore {
|
|
61
|
+
export class MongoStateStore implements MigrationStateStore {
|
|
62
62
|
/** Collection name for storing migration state */
|
|
63
63
|
private readonly collectionName: string;
|
|
64
64
|
|
|
@@ -173,6 +173,12 @@ export async function synchronizedMigration(
|
|
|
173
173
|
|
|
174
174
|
const stateStore = opts.stateStore;
|
|
175
175
|
|
|
176
|
+
// A store with its own lock (SqlStateStore) serialises the run itself
|
|
177
|
+
if (!(stateStore instanceof MongoStateStore) && typeof stateStore?.withLock === 'function') {
|
|
178
|
+
await stateStore.withLock(async () => callback(await stateStore.loadAsync()));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
176
182
|
if (!(stateStore instanceof MongoStateStore)) {
|
|
177
183
|
throw new Error('Given `stateStore` is not `MongoStateStore`');
|
|
178
184
|
}
|
|
@@ -238,7 +244,11 @@ export async function synchronizedUp(opts: MigrationOptions): Promise<void> {
|
|
|
238
244
|
* @param fn - Work to execute under the lock
|
|
239
245
|
* @returns Promise with the result of `fn`
|
|
240
246
|
*/
|
|
241
|
-
export async function withMigrationLock<T>(stateStore:
|
|
247
|
+
export async function withMigrationLock<T>(stateStore: MigrationStateStore, fn: () => Promise<T>): Promise<T> {
|
|
248
|
+
if (!(stateStore instanceof MongoStateStore)) {
|
|
249
|
+
// Another database's store brings its own lock; without one, fn runs unsynchronized
|
|
250
|
+
return typeof stateStore.withLock === 'function' ? stateStore.withLock(fn) : fn();
|
|
251
|
+
}
|
|
242
252
|
const lockCollectionName = stateStore.lockCollectionName;
|
|
243
253
|
|
|
244
254
|
if (!lockCollectionName) {
|
|
@@ -262,7 +272,7 @@ export async function withMigrationLock<T>(stateStore: MongoStateStore, fn: () =
|
|
|
262
272
|
* on migration runtime — a migration running for hours keeps its lock as long as the
|
|
263
273
|
* process lives.
|
|
264
274
|
*/
|
|
265
|
-
const LOCK_STALE_AFTER_MS =
|
|
275
|
+
const LOCK_STALE_AFTER_MS = MIGRATION_LOCK_STALE_AFTER_MS;
|
|
266
276
|
|
|
267
277
|
/** Heartbeat interval — comfortably below {@link LOCK_STALE_AFTER_MS} */
|
|
268
278
|
const LOCK_HEARTBEAT_INTERVAL_MS = 15_000;
|
|
@@ -271,11 +281,12 @@ const LOCK_HEARTBEAT_INTERVAL_MS = 15_000;
|
|
|
271
281
|
const LOCK_WAIT_TIMEOUT_MS = 15 * 60_000;
|
|
272
282
|
|
|
273
283
|
/**
|
|
274
|
-
* Keep
|
|
284
|
+
* Keep renewing the lease while the migration runs.
|
|
275
285
|
*
|
|
276
286
|
* This is what makes lock-breaking safe: a lock is only ever taken over when its holder
|
|
277
|
-
* stopped
|
|
278
|
-
* breaking a stale lock and a long-running migration would be indistinguishable.
|
|
287
|
+
* stopped renewing it, which for a live process cannot happen. Without the heartbeat,
|
|
288
|
+
* breaking a stale lock and a long-running migration would be indistinguishable. The renewal
|
|
289
|
+
* also refreshes `acquiredAt`, the heartbeat an older replica's waiter reads.
|
|
279
290
|
*/
|
|
280
291
|
function startLockHeartbeat(url: string, lockCollectionName: string, token: string): { stop: () => void } {
|
|
281
292
|
// ONE connection for the whole heartbeat, rather than `dbRequest()`'s connect-and-close per
|
|
@@ -284,13 +295,14 @@ function startLockHeartbeat(url: string, lockCollectionName: string, token: stri
|
|
|
284
295
|
// on the first tick (so a heartbeat that never fires costs nothing) and closed by stop().
|
|
285
296
|
let client: MongoClient | undefined;
|
|
286
297
|
let stopped = false;
|
|
298
|
+
let lostReported = false;
|
|
287
299
|
|
|
288
300
|
const beat = async (): Promise<void> => {
|
|
289
301
|
if (stopped) {
|
|
290
302
|
return;
|
|
291
303
|
}
|
|
292
304
|
if (!client) {
|
|
293
|
-
const connected = await MongoClient.connect(url);
|
|
305
|
+
const connected = await mongoDriver().MongoClient.connect(url);
|
|
294
306
|
if (stopped) {
|
|
295
307
|
// stop() ran while we were connecting — nothing would ever close this one.
|
|
296
308
|
await connected.close();
|
|
@@ -298,12 +310,20 @@ function startLockHeartbeat(url: string, lockCollectionName: string, token: stri
|
|
|
298
310
|
}
|
|
299
311
|
client = connected;
|
|
300
312
|
}
|
|
301
|
-
// Scoped: once our lock has been broken and re-taken, our heartbeat must not
|
|
302
|
-
// holder's lock alive on our behalf.
|
|
303
|
-
await client
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
313
|
+
// Scoped to our token: once our lock has been broken and re-taken, our heartbeat must not
|
|
314
|
+
// keep the NEW holder's lock alive on our behalf.
|
|
315
|
+
const renewed = await migrationMongoLocks(client.db().collection(lockCollectionName)).renew(
|
|
316
|
+
MIGRATION_LOCK_KEY,
|
|
317
|
+
token,
|
|
318
|
+
LOCK_STALE_AFTER_MS / 1000,
|
|
319
|
+
);
|
|
320
|
+
if (!renewed && !lostReported) {
|
|
321
|
+
lostReported = true;
|
|
322
|
+
console.warn(
|
|
323
|
+
`Migration lock in "${lockCollectionName}" was taken over by another replica while this one was migrating ` +
|
|
324
|
+
'(missed heartbeats). The migration continues, but no longer exclusively.',
|
|
325
|
+
);
|
|
326
|
+
}
|
|
307
327
|
};
|
|
308
328
|
|
|
309
329
|
const timer = setInterval(() => {
|
|
@@ -333,62 +353,34 @@ function startLockHeartbeat(url: string, lockCollectionName: string, token: stri
|
|
|
333
353
|
/**
|
|
334
354
|
* Acquires a lock in MongoDB to ensure only one migration runs at a time
|
|
335
355
|
*
|
|
356
|
+
* A lease (`LockStore`) on the 12.0.0 document `{ lock: 'lock', owner, acquiredAt }`, so a replica
|
|
357
|
+
* still running an older version waits for this one and vice versa (`infrastructure-locks.ts`).
|
|
358
|
+
*
|
|
336
359
|
* @param url - MongoDB connection URI
|
|
337
360
|
* @param lockCollectionName - Name of the collection to use for locking
|
|
338
361
|
*/
|
|
339
362
|
async function acquireLock(url: string, lockCollectionName: string): Promise<string> {
|
|
340
363
|
return dbRequest(url, async (db) => {
|
|
341
364
|
const collection = db.collection(lockCollectionName);
|
|
342
|
-
|
|
343
|
-
// Create unique index for atomicity
|
|
344
|
-
// https://docs.mongodb.com/manual/reference/method/db.collection.update/#use-unique-indexes
|
|
345
|
-
// https://groups.google.com/forum/#!topic/mongodb-user/-fucdS-7kIU
|
|
346
|
-
// https://stackoverflow.com/questions/33346175/mongodb-upsert-operation-seems-not-atomic-which-throws-duplicatekeyexception/34784533
|
|
347
|
-
await collection.createIndex({ lock: 1 }, { unique: true });
|
|
348
|
-
|
|
365
|
+
const locks = migrationMongoLocks(collection);
|
|
349
366
|
const token = lockOwnerId();
|
|
350
367
|
const deadline = Date.now() + LOCK_WAIT_TIMEOUT_MS;
|
|
351
368
|
let showMessage = true;
|
|
352
369
|
|
|
353
370
|
for (;;) {
|
|
354
|
-
|
|
355
|
-
// `$setOnInsert` stamps the acquisition time only for the winner, so a loser's
|
|
356
|
-
// update never refreshes the holder's staleness clock.
|
|
357
|
-
const result = await collection.updateOne(
|
|
358
|
-
{ lock: 'lock' },
|
|
359
|
-
{ $set: { lock: 'lock' }, $setOnInsert: { acquiredAt: new Date(), owner: token } },
|
|
360
|
-
{ upsert: true },
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
if (result.upsertedCount > 0) {
|
|
364
|
-
return token;
|
|
365
|
-
}
|
|
366
|
-
|
|
371
|
+
const holder = await collection.findOne({ lock: MIGRATION_LOCK_KEY });
|
|
367
372
|
// The holder may be gone: migrations run on every container boot, so a replica
|
|
368
373
|
// SIGKILLed mid-migration (OOM, node drain, failed deploy) would otherwise leave a
|
|
369
|
-
// lock nobody holds
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const acquiredAt = holder.acquiredAt instanceof Date ? holder.acquiredAt : undefined;
|
|
374
|
-
if (!acquiredAt) {
|
|
375
|
-
// Written by a version that did not stamp the lock. Start its clock now rather
|
|
376
|
-
// than breaking it immediately — the holder may well be alive.
|
|
377
|
-
await collection.updateOne(
|
|
378
|
-
{ _id: holder._id, acquiredAt: { $exists: false } },
|
|
379
|
-
{ $set: { acquiredAt: new Date() } },
|
|
380
|
-
);
|
|
381
|
-
} else if (Date.now() - acquiredAt.getTime() > LOCK_STALE_AFTER_MS) {
|
|
374
|
+
// lock nobody holds. The lease breaks only a lock that stopped heart-beating.
|
|
375
|
+
if (await locks.tryAcquire(MIGRATION_LOCK_KEY, token, LOCK_STALE_AFTER_MS / 1000)) {
|
|
376
|
+
if (holder) {
|
|
377
|
+
const lastBeat = holder.acquiredAt instanceof Date ? holder.acquiredAt.toISOString() : 'never';
|
|
382
378
|
console.warn(
|
|
383
|
-
`
|
|
379
|
+
`Broke stale migration lock in "${lockCollectionName}" (last heartbeat ${lastBeat}, ` +
|
|
384
380
|
`owner ${holder.owner ?? 'unknown'}) — its holder is gone.`,
|
|
385
381
|
);
|
|
386
|
-
// Matching on acquiredAt makes the break safe under concurrency: if another
|
|
387
|
-
// waiter already broke and re-acquired the lock, the timestamp differs and this
|
|
388
|
-
// deletes nothing.
|
|
389
|
-
await collection.deleteOne({ _id: holder._id, acquiredAt });
|
|
390
|
-
continue;
|
|
391
382
|
}
|
|
383
|
+
return token;
|
|
392
384
|
}
|
|
393
385
|
|
|
394
386
|
if (Date.now() > deadline) {
|
|
@@ -429,7 +421,7 @@ function lockOwnerId(): string {
|
|
|
429
421
|
async function dbRequest<T>(url: string, callback: (db: Db) => Promise<T> | T): Promise<T> {
|
|
430
422
|
let client: MongoClient | undefined;
|
|
431
423
|
try {
|
|
432
|
-
client = await MongoClient.connect(url);
|
|
424
|
+
client = await mongoDriver().MongoClient.connect(url);
|
|
433
425
|
const db = client.db();
|
|
434
426
|
return await callback(db);
|
|
435
427
|
} finally {
|
|
@@ -447,5 +439,12 @@ async function releaseLock(url: string, lockCollectionName: string, token: strin
|
|
|
447
439
|
// Scoped to OUR token. An unscoped delete removes whatever lock exists — so after a missed
|
|
448
440
|
// heartbeat let another replica break and re-take the lock, the original holder's `finally`
|
|
449
441
|
// would delete the NEW holder's lock and let a third replica start a concurrent migration.
|
|
450
|
-
await dbRequest(url, (db) =>
|
|
442
|
+
await dbRequest(url, (db) =>
|
|
443
|
+
migrationMongoLocks(db.collection(lockCollectionName)).release(MIGRATION_LOCK_KEY, token),
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** The MongoDB driver — a MongoDB migration needs it, a project without MongoDB never reaches this */
|
|
448
|
+
function mongoDriver() {
|
|
449
|
+
return requireMongoPackages('A MongoDB migration (store or helper)').mongodb;
|
|
451
450
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { DatabaseSqlEngine } from '../../common/interfaces/server-options.interface.js';
|
|
2
|
+
import { withMysqlSchemaLock } from '../../common/persistence/sql/mysql/mysql-schema.migrator.js';
|
|
3
|
+
import { SCHEMA_LOCK_SQL } from '../../common/persistence/sql/postgres/postgres-schema.migrator.js';
|
|
4
|
+
import { createSqlExecutor } from '../../common/persistence/sql/sql-executor.factory.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Run the reviewed statements of a SQL migration (`migrate create <name> --sql`) as the table OWNER, under the lock the
|
|
8
|
+
* boot's schema migration takes, so a replica booting meanwhile waits and then sees the result. On PostgreSQL in one
|
|
9
|
+
* transaction: either every statement applies or none does. MySQL and MariaDB commit every DDL statement on its own, so
|
|
10
|
+
* there a failure leaves the statements before it applied — write such a migration so it can run again.
|
|
11
|
+
*
|
|
12
|
+
* The statements are the ones a refused boot suggested (`SchemaMigrationRequiredError`) — after review: a narrowed
|
|
13
|
+
* type, a new unique index or a rename collision can reject or rewrite stored rows, which is why the framework never
|
|
14
|
+
* runs them on its own (plan §3.12).
|
|
15
|
+
*/
|
|
16
|
+
export async function runSqlMigration(
|
|
17
|
+
ownerUrl: string,
|
|
18
|
+
statements: readonly string[],
|
|
19
|
+
options: { engine?: DatabaseSqlEngine } = {},
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
if (!ownerUrl) {
|
|
22
|
+
throw new Error('runSqlMigration() needs the connection URL of the table owner (database.ownerUrl)');
|
|
23
|
+
}
|
|
24
|
+
const executor = await createSqlExecutor({
|
|
25
|
+
applicationName: 'nest-server-migration',
|
|
26
|
+
engine: options.engine ?? 'typeorm',
|
|
27
|
+
maxConnections: 1,
|
|
28
|
+
url: ownerUrl,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
if (/^(mysql|mariadb):/i.test(ownerUrl)) {
|
|
32
|
+
await withMysqlSchemaLock(executor, async (run) => {
|
|
33
|
+
for (const text of statements) {
|
|
34
|
+
await run({ params: [], text });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await executor.transaction(async (tx) => {
|
|
40
|
+
await tx.run({ params: [], text: SCHEMA_LOCK_SQL }, { kind: 'system' });
|
|
41
|
+
for (const text of statements) {
|
|
42
|
+
await tx.run({ params: [], text }, { kind: 'system' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
} finally {
|
|
46
|
+
await executor.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { DatabaseSqlEngine } from '../../common/interfaces/server-options.interface.js';
|
|
2
|
+
import { createSqlExecutor, installedSqlEngine } from '../../common/persistence/sql/sql-executor.factory.js';
|
|
3
|
+
import type { SqlExecutor, SqlTenantScope } from '../../common/persistence/sql/sql-executor.interface.js';
|
|
4
|
+
import { quoteIdentifier, quoteMysqlIdentifier } from '../../common/persistence/sql/sql-naming.js';
|
|
5
|
+
import type { MigrationSet, MigrationStateStore } from './migration-state-store.interface.js';
|
|
6
|
+
|
|
7
|
+
const SYSTEM: SqlTenantScope = { kind: 'system' };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Serialises migration runs of every replica: a transaction-scoped advisory lock, held by the transaction that
|
|
11
|
+
* surrounds the whole run. It ends with that transaction — and with its connection, so a replica killed mid-migration
|
|
12
|
+
* leaves nothing behind that another one would have to break (MongoDB needs a heartbeat and a stale-lock rule for
|
|
13
|
+
* that). A key of its own: the boot's schema evolution (`SCHEMA_LOCK_SQL`) must stay possible while a run waits.
|
|
14
|
+
*/
|
|
15
|
+
const MIGRATION_RUN_LOCK_SQL = "SELECT pg_advisory_xact_lock(hashtext('lenne.tech:migrations'))";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* MySQL / MariaDB: a named lock per database, held by the session of the locking connection. It ends with that
|
|
19
|
+
* connection too, so a killed replica leaves nothing behind; released explicitly at the end of a run. The wait is
|
|
20
|
+
* bounded at a day — a run that takes longer is not waited for
|
|
21
|
+
*/
|
|
22
|
+
const MYSQL_RUN_LOCK_NAME = "CONCAT('lenne.tech:migrations:', SHA1(DATABASE()))";
|
|
23
|
+
const MYSQL_RUN_LOCK_TIMEOUT_SECONDS = 86_400;
|
|
24
|
+
|
|
25
|
+
export interface SqlStateStoreOptions {
|
|
26
|
+
/**
|
|
27
|
+
* SQL engine of the connection, the project's configured one. Without it the first INSTALLED engine is used
|
|
28
|
+
* (`typeorm`, `kysely`, `drizzle`): `createMigrationStore()` runs in the migrate CLI, which has no configuration to
|
|
29
|
+
* read it from. @default the first installed engine
|
|
30
|
+
*/
|
|
31
|
+
engine?: DatabaseSqlEngine;
|
|
32
|
+
/** `false` runs migrations without the run lock — one replica only. @default true */
|
|
33
|
+
lock?: boolean;
|
|
34
|
+
/** Table holding the migration state. @default 'lt_migrations' */
|
|
35
|
+
tableName?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Connection URL of the table OWNER (`database.ownerUrl`): migrations change the schema and the data of every
|
|
38
|
+
* tenant, which the application role may not
|
|
39
|
+
*/
|
|
40
|
+
url: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Migration state on PostgreSQL, MySQL and MariaDB (the URL's scheme decides) — the counterpart of `MongoStateStore`:
|
|
45
|
+
* one row with the last run and the applied migrations, read and written by `MigrationRunner` and the `migrate` CLI,
|
|
46
|
+
* with every run serialised across replicas.
|
|
47
|
+
*
|
|
48
|
+
* Each call opens and closes its own connection, as `MongoStateStore` does: the CLI and the container entrypoint run it
|
|
49
|
+
* once per boot, and a pool kept open would hold the process.
|
|
50
|
+
*/
|
|
51
|
+
export class SqlStateStore implements MigrationStateStore {
|
|
52
|
+
readonly url: string;
|
|
53
|
+
protected readonly engine: DatabaseSqlEngine | undefined;
|
|
54
|
+
protected readonly locked: boolean;
|
|
55
|
+
/** MySQL and MariaDB share one dialect here */
|
|
56
|
+
protected readonly mysql: boolean;
|
|
57
|
+
protected readonly table: string;
|
|
58
|
+
|
|
59
|
+
constructor(options: SqlStateStoreOptions | string) {
|
|
60
|
+
const resolved = typeof options === 'string' ? { url: options } : options;
|
|
61
|
+
if (!resolved.url) {
|
|
62
|
+
throw new Error('SqlStateStore needs the connection URL of the table owner (database.ownerUrl)');
|
|
63
|
+
}
|
|
64
|
+
this.url = resolved.url;
|
|
65
|
+
this.engine = resolved.engine;
|
|
66
|
+
this.locked = resolved.lock !== false;
|
|
67
|
+
this.mysql = /^(mysql|mariadb):/i.test(resolved.url);
|
|
68
|
+
this.table = (this.mysql ? quoteMysqlIdentifier : quoteIdentifier)(resolved.tableName ?? 'lt_migrations');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
load(fn: (err?: Error, set?: MigrationSet) => void): void {
|
|
72
|
+
this.loadAsync()
|
|
73
|
+
.then((result) => fn(undefined, result))
|
|
74
|
+
.catch((err) => fn(err));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async loadAsync(): Promise<MigrationSet> {
|
|
78
|
+
return this.request(async (executor) => {
|
|
79
|
+
const { rows } = await executor.run<{ last_run: null | string; migrations: MigrationSet['migrations'] | string }>(
|
|
80
|
+
{
|
|
81
|
+
params: [],
|
|
82
|
+
text: this.mysql
|
|
83
|
+
? `SELECT \`last_run\`, \`migrations\` FROM ${this.table} WHERE \`id\` = 'state'`
|
|
84
|
+
: `SELECT "last_run", "migrations" FROM ${this.table} WHERE "id" = 'state'`,
|
|
85
|
+
},
|
|
86
|
+
SYSTEM,
|
|
87
|
+
);
|
|
88
|
+
if (!rows.length) {
|
|
89
|
+
console.debug('No migrations found, probably running the very first time');
|
|
90
|
+
// An empty object, as MongoStateStore returns for a first run
|
|
91
|
+
return {} as MigrationSet;
|
|
92
|
+
}
|
|
93
|
+
const migrations = rows[0].migrations;
|
|
94
|
+
return {
|
|
95
|
+
lastRun: rows[0].last_run ?? undefined,
|
|
96
|
+
// MariaDB's JSON is text where the driver does not recognise it
|
|
97
|
+
migrations: typeof migrations === 'string' ? JSON.parse(migrations) : migrations,
|
|
98
|
+
} as MigrationSet;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
save(set: MigrationSet, fn: (err?: Error) => void): void {
|
|
103
|
+
this.saveAsync(set)
|
|
104
|
+
.then(() => fn())
|
|
105
|
+
.catch((err) => fn(err));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async saveAsync(set: MigrationSet): Promise<void> {
|
|
109
|
+
const { lastRun, migrations } = set;
|
|
110
|
+
await this.request((executor) =>
|
|
111
|
+
executor.run(
|
|
112
|
+
{
|
|
113
|
+
params: [lastRun ?? null, JSON.stringify(migrations ?? [])],
|
|
114
|
+
text: this.mysql
|
|
115
|
+
? `INSERT INTO ${this.table} (\`id\`, \`last_run\`, \`migrations\`, \`updated_at\`) VALUES ('state', $1, $2, UTC_TIMESTAMP(3))
|
|
116
|
+
ON DUPLICATE KEY UPDATE \`last_run\` = $1, \`migrations\` = $2, \`updated_at\` = UTC_TIMESTAMP(3)`
|
|
117
|
+
: `INSERT INTO ${this.table} ("id", "last_run", "migrations", "updated_at") VALUES ('state', $1, $2::jsonb, now())
|
|
118
|
+
ON CONFLICT ("id") DO UPDATE SET "last_run" = EXCLUDED."last_run", "migrations" = EXCLUDED."migrations", "updated_at" = now()`,
|
|
119
|
+
},
|
|
120
|
+
SYSTEM,
|
|
121
|
+
),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async withLock<T>(fn: () => Promise<T>): Promise<T> {
|
|
126
|
+
if (!this.locked) {
|
|
127
|
+
return fn();
|
|
128
|
+
}
|
|
129
|
+
const executor = await this.open();
|
|
130
|
+
try {
|
|
131
|
+
// The work itself runs on other connections (the runner reads and saves the state, migrations open their own);
|
|
132
|
+
// this transaction only holds the lock for as long as the work takes
|
|
133
|
+
return await executor.transaction(async (tx) => {
|
|
134
|
+
if (!this.mysql) {
|
|
135
|
+
await tx.run({ params: [], text: MIGRATION_RUN_LOCK_SQL }, SYSTEM);
|
|
136
|
+
return fn();
|
|
137
|
+
}
|
|
138
|
+
const { rows } = await tx.run<{ locked: number | string }>(
|
|
139
|
+
{
|
|
140
|
+
params: [MYSQL_RUN_LOCK_TIMEOUT_SECONDS],
|
|
141
|
+
text: `SELECT GET_LOCK(${MYSQL_RUN_LOCK_NAME}, $1) AS locked`,
|
|
142
|
+
},
|
|
143
|
+
SYSTEM,
|
|
144
|
+
);
|
|
145
|
+
if (Number(rows[0]?.locked) !== 1) {
|
|
146
|
+
throw new Error('Timed out waiting for the migration run of another process');
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
return await fn();
|
|
150
|
+
} finally {
|
|
151
|
+
await tx
|
|
152
|
+
.run({ params: [], text: `SELECT RELEASE_LOCK(${MYSQL_RUN_LOCK_NAME})` }, SYSTEM)
|
|
153
|
+
.catch(() => undefined);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
} finally {
|
|
157
|
+
await executor.close();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
protected async request<R>(work: (executor: SqlExecutor) => Promise<R>): Promise<R> {
|
|
162
|
+
const executor = await this.open();
|
|
163
|
+
try {
|
|
164
|
+
return await work(executor);
|
|
165
|
+
} finally {
|
|
166
|
+
await executor.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** A connection of its own, with the state table in place */
|
|
171
|
+
protected async open(): Promise<SqlExecutor> {
|
|
172
|
+
const executor = await createSqlExecutor({
|
|
173
|
+
applicationName: 'nest-server-migrations',
|
|
174
|
+
engine: this.engine ?? (await installedSqlEngine()),
|
|
175
|
+
maxConnections: 1,
|
|
176
|
+
url: this.url,
|
|
177
|
+
});
|
|
178
|
+
try {
|
|
179
|
+
await executor.run(
|
|
180
|
+
{
|
|
181
|
+
params: [],
|
|
182
|
+
text: this.mysql
|
|
183
|
+
? `CREATE TABLE IF NOT EXISTS ${this.table} (\`id\` varchar(255) NOT NULL PRIMARY KEY, \`last_run\` longtext, \`migrations\` json NOT NULL, \`updated_at\` datetime(3) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin`
|
|
184
|
+
: `CREATE TABLE IF NOT EXISTS ${this.table} ("id" text PRIMARY KEY, "last_run" text, "migrations" jsonb NOT NULL DEFAULT '[]'::jsonb, "updated_at" timestamptz NOT NULL DEFAULT now())`,
|
|
185
|
+
},
|
|
186
|
+
SYSTEM,
|
|
187
|
+
);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
// Two replicas creating the table at the same moment: IF NOT EXISTS is not atomic in PostgreSQL, the loser fails
|
|
190
|
+
// with a duplicate of the table (42P07) or of its row type (23505) — and the table exists, which is all it asked
|
|
191
|
+
if (!['23505', '42P07'].includes((error as { code?: string })?.code)) {
|
|
192
|
+
await executor.close();
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return executor;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -172,6 +172,9 @@ NEST_SERVER_CONFIG='{ "systemSetup": { "initialAdmin": { "email": "admin@example
|
|
|
172
172
|
After a SUCCESSFUL setup the marker REMAINS — setup must never run twice in a deployment. Test
|
|
173
173
|
suites that reset the database to replay the setup flow therefore have to drop `system-setup-locks`
|
|
174
174
|
alongside `users`; clearing only `users` leaves setup refused until the claim goes stale (5 min).
|
|
175
|
+
- **On a PostgreSQL default source** (`database`) the claim is the row `system-setup:initial-admin` in
|
|
176
|
+
the lease table `lt_locks`, with the same semantics: one replica wins, released on failure, kept
|
|
177
|
+
after success, taken over once stale. Where this README names `system-setup-locks`, read that row.
|
|
175
178
|
|
|
176
179
|
### Security Best Practices
|
|
177
180
|
|
|
@@ -248,8 +251,10 @@ confirms a state that is not the problem, and step 2 confirms an empty database
|
|
|
248
251
|
empty.
|
|
249
252
|
|
|
250
253
|
1. Look at the server log. Since 11.36.5 the service logs a warning naming the collection, the
|
|
251
|
-
release-on-failure semantics and the stale window
|
|
252
|
-
|
|
254
|
+
release-on-failure semantics and the stale window — on a PostgreSQL default source the
|
|
255
|
+
`lt_locks` row instead.
|
|
256
|
+
2. Check the collection directly: `db.getCollection('system-setup-locks').find()` — on PostgreSQL
|
|
257
|
+
`SELECT * FROM lt_locks WHERE id = 'system-setup:initial-admin'`
|
|
253
258
|
3. If you reset the database to replay the setup, drop `system-setup-locks` alongside `users` -
|
|
254
259
|
see **Resetting for tests** below. Otherwise wait for the claim to go stale (5 minutes after it
|
|
255
260
|
was taken).
|
|
@@ -267,6 +272,13 @@ for (const col of ['users', 'account', 'session', 'system-setup-locks']) {
|
|
|
267
272
|
}
|
|
268
273
|
```
|
|
269
274
|
|
|
275
|
+
On a PostgreSQL default source, the same reset (run there by the same suite in the `postgres` project):
|
|
276
|
+
|
|
277
|
+
```sql
|
|
278
|
+
DELETE FROM session; DELETE FROM account; DELETE FROM users;
|
|
279
|
+
DELETE FROM lt_locks WHERE id = 'system-setup:initial-admin';
|
|
280
|
+
```
|
|
281
|
+
|
|
270
282
|
### Init returns 403 "System setup requires BetterAuth"
|
|
271
283
|
|
|
272
284
|
**Cause:** BetterAuth is not configured or not enabled.
|