@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,21 +1,36 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { hostname } from 'node:os';
|
|
3
|
+
|
|
1
4
|
import { ForbiddenException, Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
|
|
2
|
-
import { InjectConnection } from '
|
|
5
|
+
import { InjectConnection } from '../../common/persistence/mongo/mongoose-compat.js';
|
|
3
6
|
import { isEmail } from 'class-validator';
|
|
7
|
+
import type { Collection } from 'mongodb';
|
|
4
8
|
import type { Connection } from 'mongoose';
|
|
5
9
|
|
|
10
|
+
import {
|
|
11
|
+
defaultSqlLockStore,
|
|
12
|
+
SYSTEM_SETUP_CLAIM_STALE_AFTER_MS,
|
|
13
|
+
SYSTEM_SETUP_LOCK_COLLECTION,
|
|
14
|
+
SYSTEM_SETUP_LOCK_KEY,
|
|
15
|
+
systemSetupMongoLocks,
|
|
16
|
+
} from '../../common/persistence/infrastructure-locks.js';
|
|
17
|
+
import type { LockStore } from '../../common/persistence/lock-store.interface.js';
|
|
6
18
|
import { ConfigService } from '../../common/services/config.service.js';
|
|
7
19
|
import { legacyCredentialAccountIssuer } from '../better-auth/core-better-auth-account-issuer.helper.js';
|
|
8
20
|
import { CoreBetterAuthUserMapper } from '../better-auth/core-better-auth-user.mapper.js';
|
|
9
21
|
import { CoreBetterAuthService } from '../better-auth/core-better-auth.service.js';
|
|
10
22
|
import { ErrorCode } from '../error-code/error-codes.js';
|
|
23
|
+
import { getPersistenceRuntime } from '../../common/persistence/persistence-runtime.registry.js';
|
|
24
|
+
import { getBetterAuthSqlStore } from '../better-auth/core-better-auth-sql.registry.js';
|
|
11
25
|
|
|
12
26
|
/**
|
|
13
|
-
* Collection holding the bootstrap claim
|
|
27
|
+
* Collection holding the bootstrap claim marker on MongoDB — the 12.0.0 document (`{ _id, claimedAt }`), kept so
|
|
28
|
+
* an older replica in a rolling deploy claims the same marker (see `infrastructure-locks.ts`).
|
|
14
29
|
*
|
|
15
30
|
* Native collection access is intentional here: no Mongoose schema exists for it
|
|
16
31
|
* (see docs/native-driver-security.md).
|
|
17
32
|
*/
|
|
18
|
-
const SETUP_LOCK_COLLECTION =
|
|
33
|
+
const SETUP_LOCK_COLLECTION = SYSTEM_SETUP_LOCK_COLLECTION;
|
|
19
34
|
|
|
20
35
|
/**
|
|
21
36
|
* How long an initial-admin claim may stand before another replica takes it over.
|
|
@@ -23,10 +38,7 @@ const SETUP_LOCK_COLLECTION = 'system-setup-locks';
|
|
|
23
38
|
* Long enough that a slow but live creation is never stolen, short enough that a crashed
|
|
24
39
|
* claimer does not lock the deployment out for good.
|
|
25
40
|
*/
|
|
26
|
-
const INITIAL_ADMIN_CLAIM_STALE_AFTER_MS =
|
|
27
|
-
|
|
28
|
-
/** `_id` of the marker claiming the initial-admin creation */
|
|
29
|
-
const INITIAL_ADMIN_LOCK_ID = 'initial-admin';
|
|
41
|
+
const INITIAL_ADMIN_CLAIM_STALE_AFTER_MS = SYSTEM_SETUP_CLAIM_STALE_AFTER_MS;
|
|
30
42
|
|
|
31
43
|
/**
|
|
32
44
|
* Input for creating the initial admin user
|
|
@@ -70,6 +82,9 @@ export interface SystemSetupStatus {
|
|
|
70
82
|
export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
71
83
|
private readonly logger = new Logger(CoreSystemSetupService.name);
|
|
72
84
|
|
|
85
|
+
/** Who holds the claim: one owner per instance, so a second concurrent claim of the same process is refused too */
|
|
86
|
+
private readonly claimOwner = `${hostname()}:${process.pid}:${randomUUID()}`;
|
|
87
|
+
|
|
73
88
|
constructor(
|
|
74
89
|
@InjectConnection() private readonly connection: Connection,
|
|
75
90
|
private readonly betterAuthService: CoreBetterAuthService,
|
|
@@ -149,39 +164,19 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
149
164
|
/**
|
|
150
165
|
* Try to claim the initial-admin creation for this instance
|
|
151
166
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
167
|
+
* A lease (`LockStore`), so exactly one of N concurrently booting replicas — or of N anonymous
|
|
168
|
+
* `POST /system-setup/init` callers — wins the claim.
|
|
154
169
|
*
|
|
155
170
|
* @returns true when this instance may create the initial admin
|
|
156
171
|
*/
|
|
157
172
|
protected async claimInitialAdminSetup(): Promise<boolean> {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// A stale claim is therefore taken over rather than obeyed.
|
|
166
|
-
const staleBefore = new Date(Date.now() - INITIAL_ADMIN_CLAIM_STALE_AFTER_MS);
|
|
167
|
-
await collection.deleteOne({ _id: INITIAL_ADMIN_LOCK_ID as any, claimedAt: { $lt: staleBefore } });
|
|
168
|
-
|
|
169
|
-
const previous = await collection.findOneAndUpdate(
|
|
170
|
-
{ _id: INITIAL_ADMIN_LOCK_ID as any },
|
|
171
|
-
{ $setOnInsert: { claimedAt: new Date() } },
|
|
172
|
-
{ returnDocument: 'before', upsert: true },
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
// No previous document → this instance inserted the marker and owns the setup
|
|
176
|
-
return !previous;
|
|
177
|
-
} catch (error) {
|
|
178
|
-
// Two replicas upserting the same `_id` at the very same moment: one insert wins,
|
|
179
|
-
// the other gets a duplicate key error — which means the claim is taken.
|
|
180
|
-
if (error instanceof Error && (error.message?.includes('duplicate key') || error.message?.includes('E11000'))) {
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
throw error;
|
|
184
|
-
}
|
|
173
|
+
// The marker is a CLAIM, not a permanent record: a replica SIGKILLed between claiming and
|
|
174
|
+
// creating (OOM, node drain, a failed first rollout — all ordinary) never reaches the
|
|
175
|
+
// release in createInitialAdmin(). Without an expiry that leaves a deployment with zero users
|
|
176
|
+
// and no way in, recoverable only by deleting a document from an undocumented collection.
|
|
177
|
+
// A stale claim is therefore taken over rather than obeyed.
|
|
178
|
+
const locks = await this.setupLocks();
|
|
179
|
+
return locks.tryAcquire(SYSTEM_SETUP_LOCK_KEY, this.claimOwner, INITIAL_ADMIN_CLAIM_STALE_AFTER_MS / 1000);
|
|
185
180
|
}
|
|
186
181
|
|
|
187
182
|
/**
|
|
@@ -189,7 +184,7 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
189
184
|
*/
|
|
190
185
|
protected async releaseInitialAdminSetupClaim(): Promise<void> {
|
|
191
186
|
try {
|
|
192
|
-
await this.
|
|
187
|
+
await (await this.setupLocks()).release(SYSTEM_SETUP_LOCK_KEY, this.claimOwner);
|
|
193
188
|
} catch (error) {
|
|
194
189
|
// Never mask the failure that triggered the release
|
|
195
190
|
this.logger.warn(
|
|
@@ -198,11 +193,42 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
198
193
|
}
|
|
199
194
|
}
|
|
200
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Where the claim lives: the lease table when the default data source is a SQL database, else the MongoDB marker
|
|
198
|
+
*/
|
|
199
|
+
protected async setupLocks(): Promise<LockStore> {
|
|
200
|
+
return (
|
|
201
|
+
(await defaultSqlLockStore('system-setup')) ??
|
|
202
|
+
systemSetupMongoLocks(this.connection.collection(SETUP_LOCK_COLLECTION) as unknown as Collection<any>)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Where the claim lives, in the words an operator needs to clear it: the lease row on a SQL default source, the
|
|
208
|
+
* marker collection on MongoDB. The refusal log names it, so it must name the store `setupLocks()` actually uses.
|
|
209
|
+
*/
|
|
210
|
+
protected async setupClaimLocation(): Promise<{ remedy: string; where: string }> {
|
|
211
|
+
if (await defaultSqlLockStore('system-setup')) {
|
|
212
|
+
const row = `system-setup:${SYSTEM_SETUP_LOCK_KEY}`;
|
|
213
|
+
return { remedy: `delete the row "${row}" from "lt_locks"`, where: `"lt_locks" (row "${row}")` };
|
|
214
|
+
}
|
|
215
|
+
return { remedy: `drop "${SETUP_LOCK_COLLECTION}"`, where: `"${SETUP_LOCK_COLLECTION}"` };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* How many users exist, wherever the `users` table lives: a user model on a SQL source is counted there — counting the
|
|
220
|
+
* MongoDB collection instead would find none and let an anonymous caller create an administrator
|
|
221
|
+
*/
|
|
222
|
+
protected async countUsers(): Promise<number> {
|
|
223
|
+
const users = getBetterAuthSqlStore()?.users ?? (await getPersistenceRuntime()?.iamStorage())?.users;
|
|
224
|
+
return users ? users.count({}) : this.connection.collection('users').countDocuments({});
|
|
225
|
+
}
|
|
226
|
+
|
|
201
227
|
/**
|
|
202
228
|
* Check if the system needs initial setup (zero users)
|
|
203
229
|
*/
|
|
204
230
|
async getSetupStatus(): Promise<SystemSetupStatus> {
|
|
205
|
-
const userCount = await this.
|
|
231
|
+
const userCount = await this.countUsers();
|
|
206
232
|
return {
|
|
207
233
|
betterAuthEnabled: this.betterAuthService.isEnabled(),
|
|
208
234
|
needsSetup: userCount === 0,
|
|
@@ -217,7 +243,7 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
217
243
|
*/
|
|
218
244
|
async createInitialAdmin(input: SystemSetupInitInput): Promise<SystemSetupInitResult> {
|
|
219
245
|
// Pre-check: only allow when zero users exist
|
|
220
|
-
const userCount = await this.
|
|
246
|
+
const userCount = await this.countUsers();
|
|
221
247
|
if (userCount > 0) {
|
|
222
248
|
throw new ForbiddenException(ErrorCode.SYSTEM_SETUP_NOT_AVAILABLE);
|
|
223
249
|
}
|
|
@@ -253,11 +279,12 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
253
279
|
// Two records with contradictory severity for one non-event trains operators to ignore the
|
|
254
280
|
// louder one. The HTTP caller is not left without a diagnosis: the message is unchanged and
|
|
255
281
|
// an operator investigating a 403 reads it at the default level.
|
|
282
|
+
const claim = await this.setupClaimLocation();
|
|
256
283
|
this.logger.log(
|
|
257
|
-
`System setup refused: the initial-admin claim in
|
|
284
|
+
`System setup refused: the initial-admin claim in ${claim.where} is held. ` +
|
|
258
285
|
'Either another instance is running the setup right now, or a previous SUCCESSFUL setup ' +
|
|
259
286
|
'left the marker behind — it is removed only when creation FAILS. If you reset the ' +
|
|
260
|
-
`database to replay the setup,
|
|
287
|
+
`database to replay the setup, ${claim.remedy} alongside "users"; ` +
|
|
261
288
|
`otherwise setup stays refused until the claim goes stale after ` +
|
|
262
289
|
`${INITIAL_ADMIN_CLAIM_STALE_AFTER_MS / 60_000} minutes.`,
|
|
263
290
|
);
|
|
@@ -334,10 +361,15 @@ export class CoreSystemSetupService implements OnApplicationBootstrap {
|
|
|
334
361
|
throw new Error('Failed to sync user to nest-server collection');
|
|
335
362
|
}
|
|
336
363
|
|
|
337
|
-
// Set admin role directly
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
.
|
|
364
|
+
// Set admin role directly — the framework's own decision, as system work
|
|
365
|
+
const sql = getBetterAuthSqlStore();
|
|
366
|
+
if (sql) {
|
|
367
|
+
await sql.updateUserAsSystem(String(syncedUser._id), { roles: ['admin'] });
|
|
368
|
+
} else {
|
|
369
|
+
await this.connection
|
|
370
|
+
.collection('users')
|
|
371
|
+
.updateOne({ _id: syncedUser._id }, { $set: { roles: ['admin'], updatedAt: new Date() } });
|
|
372
|
+
}
|
|
341
373
|
|
|
342
374
|
// Sync password to Legacy Auth for backwards compatibility
|
|
343
375
|
await this.userMapper.syncPasswordToLegacy(iamUser.id, input.email, input.password);
|
|
@@ -247,11 +247,18 @@ for members, API tokens and the header-less tenant list — unless the project t
|
|
|
247
247
|
```typescript
|
|
248
248
|
// config.env.ts
|
|
249
249
|
multiTenancy: {
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
// Any database: the project's tenant model, registered with CorePersistenceModule.forFeature()
|
|
251
|
+
isTenantActive: async (tenantId, { store }) => (await store('Tenant').findById(tenantId))?.active !== false,
|
|
252
252
|
}
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
+
`store(modelName)` returns the data store of a model registered with `CorePersistenceModule.forFeature()` in the
|
|
256
|
+
running application, wherever `database` routes it. For a model registered any other way (`MongooseModule.forFeature()`,
|
|
257
|
+
which `lt server module` generates) it throws a `DataSourceConfigError`, and the request is refused: answering
|
|
258
|
+
`undefined` would make a hook written with `?.` count every deactivated tenant as active. `context.connection` (the MongoDB connection) is still passed
|
|
259
|
+
for a lookup on MongoDB only:
|
|
260
|
+
`(await connection.collection('tenants').findOne({ _id: new Types.ObjectId(tenantId) }))?.active !== false`.
|
|
261
|
+
|
|
255
262
|
| Path | Deactivated tenant |
|
|
256
263
|
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
257
264
|
| Header + tenant role, or `S_USER` / `S_VERIFIED` with a header | **403** `#LTNS_0106: Tenant is inactive` |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ObjectType } from '@nestjs/graphql';
|
|
2
|
-
import { Schema } from '
|
|
2
|
+
import { Schema } from '../../common/persistence/mongo/mongoose-compat.js';
|
|
3
3
|
|
|
4
4
|
import { Restricted } from '../../common/decorators/restricted.decorator.js';
|
|
5
5
|
import { UnifiedField } from '../../common/decorators/unified-field.decorator.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DataStore } from '../../common/persistence/data-store.interface.js';
|
|
2
|
+
import { getStoreForModel } from '../../common/persistence/persistence-runtime.registry.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The store serving the membership model when it is routed to a SQL database; `undefined` on MongoDB, where the
|
|
6
|
+
* guard and the service keep their Mongoose path unchanged.
|
|
7
|
+
*
|
|
8
|
+
* Read from the model INSTANCE the guard and the service were given, so it is the store of their own application.
|
|
9
|
+
*/
|
|
10
|
+
export function routedMemberStore(memberModel: unknown): DataStore<any> | undefined {
|
|
11
|
+
const store = getStoreForModel(memberModel);
|
|
12
|
+
return store && !store.capabilities.mongoosePopulate ? store : undefined;
|
|
13
|
+
}
|
|
@@ -9,18 +9,23 @@ import {
|
|
|
9
9
|
Optional,
|
|
10
10
|
UnauthorizedException,
|
|
11
11
|
} from '@nestjs/common';
|
|
12
|
-
import { Reflector } from '@nestjs/core';
|
|
12
|
+
import { ModuleRef, Reflector } from '@nestjs/core';
|
|
13
13
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
|
14
|
-
import { InjectModel } from '
|
|
15
|
-
import { Model } from 'mongoose';
|
|
14
|
+
import { InjectModel } from '../../common/persistence/mongo/mongoose-compat.js';
|
|
15
|
+
import type { Model } from 'mongoose';
|
|
16
|
+
import { firstValueFrom, isObservable } from 'rxjs';
|
|
16
17
|
|
|
17
18
|
import { RoleEnum } from '../../common/enums/role.enum.js';
|
|
19
|
+
import { ROLE_GUARD } from '../auth/guards/role-guard.token.js';
|
|
18
20
|
import { resolveGuardRequest } from '../../common/helpers/execution-context-request.helper.js';
|
|
19
21
|
import {
|
|
20
22
|
revalidateAllWsConnections,
|
|
21
23
|
revalidateWsConnectionsForTenant,
|
|
22
24
|
revalidateWsConnectionsOf,
|
|
23
25
|
} from '../../common/helpers/graphql-ws-connection.helper.js';
|
|
26
|
+
import { DataSourceConfigError } from '../../common/persistence/data-source.config.js';
|
|
27
|
+
import type { DataStore } from '../../common/persistence/data-store.interface.js';
|
|
28
|
+
import { getStoreToken } from '../../common/persistence/persistence.tokens.js';
|
|
24
29
|
import { ConfigService } from '../../common/services/config.service.js';
|
|
25
30
|
import { ResolvedTenantContext, setTenantContextResolver } from '../../common/services/core-tenant-context.registry.js';
|
|
26
31
|
import { CoreRedisService } from '../../common/services/core-redis.service.js';
|
|
@@ -33,6 +38,7 @@ import {
|
|
|
33
38
|
} from '../api-token/core-api-token.helpers.js';
|
|
34
39
|
import { ErrorCode } from '../error-code/error-codes.js';
|
|
35
40
|
import { CoreTenantMemberModel } from './core-tenant-member.model.js';
|
|
41
|
+
import { routedMemberStore } from './core-tenant-member.store.js';
|
|
36
42
|
import { registerActiveTenantGuard } from './core-tenant-guard.registry.js';
|
|
37
43
|
import { SKIP_TENANT_CHECK_KEY } from './core-tenant.decorators.js';
|
|
38
44
|
import { TENANT_MEMBER_MODEL_TOKEN, TenantMemberStatus } from './core-tenant.enums.js';
|
|
@@ -171,6 +177,7 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
171
177
|
private readonly reflector: Reflector,
|
|
172
178
|
@InjectModel(TENANT_MEMBER_MODEL_TOKEN) private readonly memberModel: Model<CoreTenantMemberModel>,
|
|
173
179
|
@Optional() protected readonly redisService?: CoreRedisService,
|
|
180
|
+
@Optional() protected readonly moduleRef?: ModuleRef,
|
|
174
181
|
) {
|
|
175
182
|
// Clean up expired cache entries every 60 seconds
|
|
176
183
|
this.cleanupInterval = setInterval(() => this.evictExpired(), 60_000);
|
|
@@ -189,6 +196,31 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
189
196
|
this.releaseTenantGuard = registerActiveTenantGuard();
|
|
190
197
|
}
|
|
191
198
|
|
|
199
|
+
/**
|
|
200
|
+
* The data store of a model registered with `CorePersistenceModule.forFeature()` in THIS application, for the
|
|
201
|
+
* `isTenantActive` hook — the tenant model may live in a SQL database, where `connection` cannot reach it.
|
|
202
|
+
*
|
|
203
|
+
* Throws for a model that is not registered that way, never answers `undefined`: the hook decides whether a
|
|
204
|
+
* deactivated tenant stays locked, and `store('Tenant')?.findById(id)` on an unregistered model would read as
|
|
205
|
+
* "active" — every tenant open, without a log line. A thrown error refuses the request instead.
|
|
206
|
+
*/
|
|
207
|
+
protected readonly storeOf = (modelName: string): DataStore<any> => {
|
|
208
|
+
let store: DataStore<any> | undefined;
|
|
209
|
+
try {
|
|
210
|
+
store = this.moduleRef?.get(getStoreToken(modelName), { strict: false });
|
|
211
|
+
} catch {
|
|
212
|
+
store = undefined;
|
|
213
|
+
}
|
|
214
|
+
if (!store) {
|
|
215
|
+
throw new DataSourceConfigError(
|
|
216
|
+
`multiTenancy.isTenantActive asked for the store of '${modelName}', which is not registered with ` +
|
|
217
|
+
'CorePersistenceModule.forFeature() in this application — register it there, or look the tenant up ' +
|
|
218
|
+
'through context.connection',
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
return store;
|
|
222
|
+
};
|
|
223
|
+
|
|
192
224
|
/** Releases this guard's registration (see core-tenant-guard.registry.ts). */
|
|
193
225
|
private releaseTenantGuard?: () => void;
|
|
194
226
|
|
|
@@ -458,6 +490,14 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
458
490
|
return true;
|
|
459
491
|
}
|
|
460
492
|
|
|
493
|
+
// Global guards run in registration order, and CoreModule registers this module AHEAD of a project's AuthModule:
|
|
494
|
+
// with legacy JWTs (no middleware identifies them) the role guard has not run yet and nobody is on the request.
|
|
495
|
+
// The documented order is role guard, then tenant guard — so let this application's role guard identify the
|
|
496
|
+
// caller first. It decides exactly what it would decide right after this guard, so its 401/403 is the answer.
|
|
497
|
+
if (!request.user) {
|
|
498
|
+
await this.identifyThroughRoleGuard(context);
|
|
499
|
+
}
|
|
500
|
+
|
|
461
501
|
const user = request.user;
|
|
462
502
|
const adminBypass = config.adminBypass !== false;
|
|
463
503
|
const isAdmin = adminBypass && user?.roles?.includes(RoleEnum.ADMIN);
|
|
@@ -679,14 +719,11 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
679
719
|
}
|
|
680
720
|
}
|
|
681
721
|
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
.select('tenant role')
|
|
688
|
-
.lean()
|
|
689
|
-
.exec();
|
|
722
|
+
const active = { status: TenantMemberStatus.ACTIVE, user: userId };
|
|
723
|
+
const memberStore = routedMemberStore(this.memberModel);
|
|
724
|
+
const memberships = memberStore
|
|
725
|
+
? await memberStore.find(active, { select: ['tenant', 'role'] })
|
|
726
|
+
: await this.memberModel.find(active).select('tenant role').lean().exec();
|
|
690
727
|
|
|
691
728
|
let ids: string[];
|
|
692
729
|
if (minLevel !== undefined) {
|
|
@@ -823,6 +860,32 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
823
860
|
}
|
|
824
861
|
}
|
|
825
862
|
|
|
863
|
+
/**
|
|
864
|
+
* Run this application's role guard when no caller is identified yet — see canActivate(). A no-op without one (a
|
|
865
|
+
* custom guard chain) and when the role guard is this guard.
|
|
866
|
+
*/
|
|
867
|
+
protected async identifyThroughRoleGuard(context: ExecutionContext): Promise<void> {
|
|
868
|
+
let roleGuard: CanActivate | undefined;
|
|
869
|
+
try {
|
|
870
|
+
roleGuard = this.moduleRef?.get<CanActivate>(ROLE_GUARD, { strict: false });
|
|
871
|
+
} catch {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
if (roleGuard && roleGuard !== (this as CanActivate)) {
|
|
875
|
+
const result = roleGuard.canActivate(context);
|
|
876
|
+
await (isObservable(result) ? firstValueFrom(result) : result);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/** The active membership, from the membership store of the database the model is routed to */
|
|
881
|
+
private async findActiveMembership(userId: string, tenantId: string): Promise<CoreTenantMemberModel | null> {
|
|
882
|
+
const where = { status: TenantMemberStatus.ACTIVE, tenant: tenantId, user: userId };
|
|
883
|
+
const memberStore = routedMemberStore(this.memberModel);
|
|
884
|
+
return (
|
|
885
|
+
memberStore ? await memberStore.findOne(where) : await this.memberModel.findOne(where).lean().exec()
|
|
886
|
+
) as CoreTenantMemberModel | null;
|
|
887
|
+
}
|
|
888
|
+
|
|
826
889
|
/**
|
|
827
890
|
* Look up a membership with process-level TTL cache.
|
|
828
891
|
* Avoids repeated DB queries when the same user accesses the same tenant repeatedly.
|
|
@@ -832,10 +895,7 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
832
895
|
|
|
833
896
|
// Cache disabled (ttl = 0): always query DB
|
|
834
897
|
if (ttl <= 0) {
|
|
835
|
-
return this.
|
|
836
|
-
.findOne({ status: TenantMemberStatus.ACTIVE, tenant: tenantId, user: userId })
|
|
837
|
-
.lean()
|
|
838
|
-
.exec() as Promise<CoreTenantMemberModel | null>;
|
|
898
|
+
return this.findActiveMembership(userId, tenantId);
|
|
839
899
|
}
|
|
840
900
|
|
|
841
901
|
const key = `${userId}:${tenantId}`;
|
|
@@ -846,14 +906,7 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
846
906
|
return cached.result;
|
|
847
907
|
}
|
|
848
908
|
|
|
849
|
-
const result =
|
|
850
|
-
.findOne({
|
|
851
|
-
status: TenantMemberStatus.ACTIVE,
|
|
852
|
-
tenant: tenantId,
|
|
853
|
-
user: userId,
|
|
854
|
-
})
|
|
855
|
-
.lean()
|
|
856
|
-
.exec()) as CoreTenantMemberModel | null;
|
|
909
|
+
const result = await this.findActiveMembership(userId, tenantId);
|
|
857
910
|
|
|
858
911
|
// Only cache positive results (active membership found).
|
|
859
912
|
// Negative results (null) are NOT cached to ensure that:
|
|
@@ -928,7 +981,7 @@ export class CoreTenantGuard implements CanActivate, OnApplicationBootstrap, OnM
|
|
|
928
981
|
return cached.active;
|
|
929
982
|
}
|
|
930
983
|
}
|
|
931
|
-
const active = (await hook(tenantId, { connection: this.memberModel.db })) !== false;
|
|
984
|
+
const active = (await hook(tenantId, { connection: this.memberModel.db, store: this.storeOf })) !== false;
|
|
932
985
|
if (ttl > 0) {
|
|
933
986
|
this.evictIfOverCapacity(this.tenantActiveCache);
|
|
934
987
|
this.tenantActiveCache.set(tenantId, { active, expiresAt: now + ttl });
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { CanActivate, DynamicModule, Global, Module, OnModuleDestroy, OnModuleInit, Type } from '@nestjs/common';
|
|
2
2
|
import { APP_GUARD } from '@nestjs/core';
|
|
3
|
-
import {
|
|
4
|
-
import { Model } from 'mongoose';
|
|
3
|
+
import { getModelToken, SchemaFactory } from '../../common/persistence/mongo/mongoose-compat.js';
|
|
4
|
+
import type { Model } from 'mongoose';
|
|
5
5
|
|
|
6
|
+
import { CorePersistenceModule } from '../../common/persistence/core-persistence.module.js';
|
|
6
7
|
import { roleScopeRegistry } from './core-role-scope.registry.js';
|
|
7
8
|
import { registerActiveTenantGuard } from './core-tenant-guard.registry.js';
|
|
8
9
|
import { CoreTenantMemberModel } from './core-tenant-member.model.js';
|
|
@@ -127,7 +128,9 @@ export class CoreTenantModule implements OnModuleDestroy, OnModuleInit {
|
|
|
127
128
|
return {
|
|
128
129
|
exports: [CoreTenantService],
|
|
129
130
|
global: true,
|
|
130
|
-
|
|
131
|
+
// Database-neutral registration: the membership model follows `database` like every other model, and the guard
|
|
132
|
+
// and the service switch to its store when it is routed to a SQL database
|
|
133
|
+
imports: [CorePersistenceModule.forFeature([{ name: modelName, schema: memberSchema }])],
|
|
131
134
|
module: CoreTenantModule,
|
|
132
135
|
providers,
|
|
133
136
|
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { BadRequestException, Injectable, Logger, NotFoundException, Optional } from '@nestjs/common';
|
|
2
|
-
import { InjectModel } from '
|
|
3
|
-
import { Model } from 'mongoose';
|
|
2
|
+
import { InjectModel } from '../../common/persistence/mongo/mongoose-compat.js';
|
|
3
|
+
import type { Model } from 'mongoose';
|
|
4
4
|
|
|
5
5
|
import { looksLikeGlobalOnlyRole, looksLikeSystemRole, SYSTEM_ROLE_PREFIX } from '../../common/enums/role.enum.js';
|
|
6
|
+
import type { DataStore } from '../../common/persistence/data-store.interface.js';
|
|
6
7
|
import { ConfigService } from '../../common/services/config.service.js';
|
|
7
8
|
import { RequestContext } from '../../common/services/request-context.service.js';
|
|
8
9
|
import { CoreTenantMemberModel } from './core-tenant-member.model.js';
|
|
10
|
+
import { routedMemberStore } from './core-tenant-member.store.js';
|
|
9
11
|
import { DEFAULT_ROLE_HIERARCHY, TENANT_MEMBER_MODEL_TOKEN, TenantMemberStatus } from './core-tenant.enums.js';
|
|
10
12
|
import { CoreTenantGuard } from './core-tenant.guard.js';
|
|
11
13
|
|
|
@@ -37,6 +39,11 @@ export class CoreTenantService {
|
|
|
37
39
|
@Optional() protected readonly tenantGuard?: CoreTenantGuard,
|
|
38
40
|
) {}
|
|
39
41
|
|
|
42
|
+
/** The membership store when the model is routed to SQL; `undefined` keeps the Mongoose path (MongoDB) */
|
|
43
|
+
protected get memberStore(): DataStore<any> | undefined {
|
|
44
|
+
return routedMemberStore(this.memberModel);
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Get the configured role hierarchy.
|
|
42
49
|
*/
|
|
@@ -68,6 +75,11 @@ export class CoreTenantService {
|
|
|
68
75
|
* Find all active tenant memberships for a user.
|
|
69
76
|
*/
|
|
70
77
|
async findMemberships(userId: string): Promise<CoreTenantMemberModel[]> {
|
|
78
|
+
if (this.memberStore) {
|
|
79
|
+
return this.memberStore.find({ status: TenantMemberStatus.ACTIVE, user: userId }) as Promise<
|
|
80
|
+
CoreTenantMemberModel[]
|
|
81
|
+
>;
|
|
82
|
+
}
|
|
71
83
|
return this.memberModel.find({ status: TenantMemberStatus.ACTIVE, user: userId }).lean().exec() as Promise<
|
|
72
84
|
CoreTenantMemberModel[]
|
|
73
85
|
>;
|
|
@@ -92,6 +104,9 @@ export class CoreTenantService {
|
|
|
92
104
|
* For an authorization check use {@link getActiveMembership}.
|
|
93
105
|
*/
|
|
94
106
|
async getMembership(tenantId: string, userId: string): Promise<CoreTenantMemberModel | null> {
|
|
107
|
+
if (this.memberStore) {
|
|
108
|
+
return this.memberStore.findOne({ tenant: tenantId, user: userId }) as Promise<CoreTenantMemberModel | null>;
|
|
109
|
+
}
|
|
95
110
|
return this.memberModel
|
|
96
111
|
.findOne({ tenant: tenantId, user: userId })
|
|
97
112
|
.lean()
|
|
@@ -111,10 +126,11 @@ export class CoreTenantService {
|
|
|
111
126
|
return null;
|
|
112
127
|
}
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
.
|
|
117
|
-
|
|
129
|
+
const where = { status: TenantMemberStatus.ACTIVE, tenant: tenantId, user: userId };
|
|
130
|
+
if (this.memberStore) {
|
|
131
|
+
return this.memberStore.findOne(where) as Promise<CoreTenantMemberModel | null>;
|
|
132
|
+
}
|
|
133
|
+
return this.memberModel.findOne(where).lean().exec() as Promise<CoreTenantMemberModel | null>;
|
|
118
134
|
}
|
|
119
135
|
|
|
120
136
|
/**
|
|
@@ -146,33 +162,40 @@ export class CoreTenantService {
|
|
|
146
162
|
}
|
|
147
163
|
// Reactivate suspended/invited membership
|
|
148
164
|
return RequestContext.runWithBypassTenantGuard(async () => {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
const reactivation = {
|
|
166
|
+
invitedBy: invitedById,
|
|
167
|
+
joinedAt: new Date(),
|
|
168
|
+
role: effectiveRole,
|
|
169
|
+
status: TenantMemberStatus.ACTIVE,
|
|
170
|
+
};
|
|
171
|
+
const result = (
|
|
172
|
+
this.memberStore
|
|
173
|
+
? await this.memberStore.updateOne({ tenant: tenantId, user: userId }, reactivation)
|
|
174
|
+
: await this.memberModel
|
|
175
|
+
.findOneAndUpdate({ tenant: tenantId, user: userId }, reactivation, { returnDocument: 'after' })
|
|
176
|
+
.lean()
|
|
177
|
+
.exec()
|
|
178
|
+
) as CoreTenantMemberModel;
|
|
162
179
|
this.tenantGuard?.invalidateUser(userId);
|
|
163
180
|
return result;
|
|
164
181
|
});
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
return RequestContext.runWithBypassTenantGuard(async () => {
|
|
168
|
-
const
|
|
185
|
+
const member = {
|
|
169
186
|
invitedBy: invitedById,
|
|
170
187
|
joinedAt: new Date(),
|
|
171
188
|
role: effectiveRole,
|
|
172
189
|
status: TenantMemberStatus.ACTIVE,
|
|
173
190
|
tenant: tenantId,
|
|
174
191
|
user: userId,
|
|
175
|
-
}
|
|
192
|
+
};
|
|
193
|
+
if (this.memberStore) {
|
|
194
|
+
const created = await this.memberStore.insert(member);
|
|
195
|
+
this.tenantGuard?.invalidateUser(userId);
|
|
196
|
+
return created as CoreTenantMemberModel;
|
|
197
|
+
}
|
|
198
|
+
const doc = await this.memberModel.create(member);
|
|
176
199
|
this.tenantGuard?.invalidateUser(userId);
|
|
177
200
|
return doc.toObject() as CoreTenantMemberModel;
|
|
178
201
|
});
|
|
@@ -192,14 +215,13 @@ export class CoreTenantService {
|
|
|
192
215
|
await this.assertNotLastOwner(tenantId, userId);
|
|
193
216
|
|
|
194
217
|
return RequestContext.runWithBypassTenantGuard(async () => {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
.exec();
|
|
218
|
+
const where = { status: TenantMemberStatus.ACTIVE, tenant: tenantId, user: userId };
|
|
219
|
+
const result = this.memberStore
|
|
220
|
+
? await this.memberStore.updateOne(where, { status: TenantMemberStatus.SUSPENDED })
|
|
221
|
+
: await this.memberModel
|
|
222
|
+
.findOneAndUpdate(where, { status: TenantMemberStatus.SUSPENDED }, { returnDocument: 'after' })
|
|
223
|
+
.lean()
|
|
224
|
+
.exec();
|
|
203
225
|
|
|
204
226
|
if (!result) {
|
|
205
227
|
throw new NotFoundException('Membership not found');
|
|
@@ -237,14 +259,10 @@ export class CoreTenantService {
|
|
|
237
259
|
}
|
|
238
260
|
|
|
239
261
|
return RequestContext.runWithBypassTenantGuard(async () => {
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
{ returnDocument: 'after' },
|
|
245
|
-
)
|
|
246
|
-
.lean()
|
|
247
|
-
.exec();
|
|
262
|
+
const where = { status: TenantMemberStatus.ACTIVE, tenant: tenantId, user: userId };
|
|
263
|
+
const result = this.memberStore
|
|
264
|
+
? await this.memberStore.updateOne(where, { role })
|
|
265
|
+
: await this.memberModel.findOneAndUpdate(where, { role }, { returnDocument: 'after' }).lean().exec();
|
|
248
266
|
|
|
249
267
|
if (!result) {
|
|
250
268
|
throw new NotFoundException('Active membership not found');
|
|
@@ -267,11 +285,10 @@ export class CoreTenantService {
|
|
|
267
285
|
const highestRole = this.getHighestRole();
|
|
268
286
|
|
|
269
287
|
return RequestContext.runWithBypassTenantGuard(async () => {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
});
|
|
288
|
+
const owners = { role: highestRole, status: TenantMemberStatus.ACTIVE, tenant: tenantId };
|
|
289
|
+
const ownerCount = this.memberStore
|
|
290
|
+
? await this.memberStore.count(owners)
|
|
291
|
+
: await this.memberModel.countDocuments(owners);
|
|
275
292
|
|
|
276
293
|
if (ownerCount <= 1) {
|
|
277
294
|
const membership = await this.getActiveMembership(tenantId, userId);
|