@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,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AuditFieldPresence,
|
|
3
|
+
resolveAuditActorId,
|
|
4
|
+
stampAuditOnReplace,
|
|
5
|
+
stampAuditOnUpdate,
|
|
6
|
+
stampAuditOnWrite,
|
|
7
|
+
} from '../persistence/policies/audit.policy.js';
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* Mongoose plugin that automatically sets createdBy/updatedBy fields.
|
|
@@ -16,36 +22,35 @@ import { RequestContext } from '../services/request-context.service.js';
|
|
|
16
22
|
* - Bulk operations: sets createdBy/updatedBy per document/operation
|
|
17
23
|
*
|
|
18
24
|
* Only activates on schemas that have createdBy and/or updatedBy fields defined.
|
|
25
|
+
*
|
|
26
|
+
* The stamping decisions live in the audit policy (`persistence/policies/audit.policy.ts`), which every
|
|
27
|
+
* data store shares; this plugin only applies them to Mongoose's hook shapes.
|
|
19
28
|
*/
|
|
20
29
|
export function mongooseAuditFieldsPlugin(schema) {
|
|
21
|
-
const
|
|
22
|
-
|
|
30
|
+
const fields: AuditFieldPresence = {
|
|
31
|
+
createdBy: !!schema.path('createdBy'),
|
|
32
|
+
updatedBy: !!schema.path('updatedBy'),
|
|
33
|
+
};
|
|
23
34
|
|
|
24
35
|
// Skip schemas without audit fields (e.g. BetterAuth sessions, third-party schemas)
|
|
25
|
-
if (!
|
|
36
|
+
if (!fields.createdBy && !fields.updatedBy) {
|
|
26
37
|
return;
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
// Pre-save hook
|
|
30
41
|
schema.pre('save', function () {
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
42
|
+
const actorId = resolveAuditActorId();
|
|
43
|
+
if (!actorId) {
|
|
33
44
|
return;
|
|
34
45
|
}
|
|
35
|
-
|
|
36
|
-
if (hasCreatedBy && this.isNew && !this['createdBy']) {
|
|
37
|
-
this['createdBy'] = currentUser.id;
|
|
38
|
-
}
|
|
39
|
-
if (hasUpdatedBy) {
|
|
40
|
-
this['updatedBy'] = currentUser.id;
|
|
41
|
-
}
|
|
46
|
+
stampAuditOnWrite(this, actorId, fields, this.isNew);
|
|
42
47
|
});
|
|
43
48
|
|
|
44
49
|
// Pre-update hooks (only needed for updatedBy)
|
|
45
|
-
if (
|
|
50
|
+
if (fields.updatedBy) {
|
|
46
51
|
const updateHook = function () {
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
52
|
+
const actorId = resolveAuditActorId();
|
|
53
|
+
if (!actorId) {
|
|
49
54
|
return;
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -54,22 +59,7 @@ export function mongooseAuditFieldsPlugin(schema) {
|
|
|
54
59
|
return;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
update['updatedBy'] = currentUser.id;
|
|
59
|
-
if (update.$set) {
|
|
60
|
-
update.$set['updatedBy'] = currentUser.id;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Handle upsert: set createdBy on insert via $setOnInsert
|
|
64
|
-
// Only add if createdBy is not already in the update (avoids MongoDB path conflict)
|
|
65
|
-
if (hasCreatedBy && !update['createdBy'] && !update.$set?.['createdBy']) {
|
|
66
|
-
if (!update.$setOnInsert) {
|
|
67
|
-
update.$setOnInsert = {};
|
|
68
|
-
}
|
|
69
|
-
if (!update.$setOnInsert['createdBy']) {
|
|
70
|
-
update.$setOnInsert['createdBy'] = currentUser.id;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
62
|
+
stampAuditOnUpdate(update, actorId, fields);
|
|
73
63
|
};
|
|
74
64
|
|
|
75
65
|
schema.pre('findOneAndUpdate', updateHook);
|
|
@@ -78,8 +68,8 @@ export function mongooseAuditFieldsPlugin(schema) {
|
|
|
78
68
|
|
|
79
69
|
// Replace hooks: flat replacement doc (no $set/$setOnInsert)
|
|
80
70
|
const replaceHook = function () {
|
|
81
|
-
const
|
|
82
|
-
if (!
|
|
71
|
+
const actorId = resolveAuditActorId();
|
|
72
|
+
if (!actorId) {
|
|
83
73
|
return;
|
|
84
74
|
}
|
|
85
75
|
|
|
@@ -88,12 +78,7 @@ export function mongooseAuditFieldsPlugin(schema) {
|
|
|
88
78
|
return;
|
|
89
79
|
}
|
|
90
80
|
|
|
91
|
-
replacement
|
|
92
|
-
|
|
93
|
-
// For upsert replacements: set createdBy if not already present
|
|
94
|
-
if (hasCreatedBy && !replacement['createdBy']) {
|
|
95
|
-
replacement['createdBy'] = currentUser.id;
|
|
96
|
-
}
|
|
81
|
+
stampAuditOnReplace(replacement, actorId, fields);
|
|
97
82
|
};
|
|
98
83
|
|
|
99
84
|
schema.pre('replaceOne', replaceHook);
|
|
@@ -103,55 +88,29 @@ export function mongooseAuditFieldsPlugin(schema) {
|
|
|
103
88
|
// Bulk operation hooks (needed when either createdBy or updatedBy is present)
|
|
104
89
|
// Pre-insertMany hook (Mongoose 9: first arg is docs array)
|
|
105
90
|
schema.pre('insertMany', function (docs) {
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
91
|
+
const actorId = resolveAuditActorId();
|
|
92
|
+
if (!actorId) return;
|
|
108
93
|
if (!Array.isArray(docs)) return;
|
|
109
94
|
|
|
110
95
|
for (const doc of docs) {
|
|
111
|
-
|
|
112
|
-
doc.createdBy = currentUser.id;
|
|
113
|
-
}
|
|
114
|
-
if (hasUpdatedBy) {
|
|
115
|
-
doc.updatedBy = currentUser.id;
|
|
116
|
-
}
|
|
96
|
+
stampAuditOnWrite(doc, actorId, fields, true);
|
|
117
97
|
}
|
|
118
98
|
});
|
|
119
99
|
|
|
120
100
|
// Pre-bulkWrite hook
|
|
121
101
|
schema.pre('bulkWrite', function (ops) {
|
|
122
|
-
const
|
|
123
|
-
if (!
|
|
102
|
+
const actorId = resolveAuditActorId();
|
|
103
|
+
if (!actorId) return;
|
|
124
104
|
|
|
125
105
|
for (const op of ops) {
|
|
126
106
|
if ('insertOne' in op) {
|
|
127
|
-
|
|
128
|
-
op.insertOne.document.createdBy = currentUser.id;
|
|
129
|
-
}
|
|
130
|
-
if (hasUpdatedBy) {
|
|
131
|
-
op.insertOne.document.updatedBy = currentUser.id;
|
|
132
|
-
}
|
|
107
|
+
stampAuditOnWrite(op.insertOne.document, actorId, fields, true);
|
|
133
108
|
} else if ('updateOne' in op || 'updateMany' in op) {
|
|
134
109
|
const update = 'updateOne' in op ? op.updateOne.update : op.updateMany.update;
|
|
135
110
|
if (!update) continue;
|
|
136
|
-
|
|
137
|
-
update['updatedBy'] = currentUser.id;
|
|
138
|
-
if (update.$set) {
|
|
139
|
-
update.$set['updatedBy'] = currentUser.id;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (hasCreatedBy && !update['createdBy'] && !update.$set?.['createdBy']) {
|
|
143
|
-
if (!update.$setOnInsert) update.$setOnInsert = {};
|
|
144
|
-
if (!update.$setOnInsert['createdBy']) {
|
|
145
|
-
update.$setOnInsert['createdBy'] = currentUser.id;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
111
|
+
stampAuditOnUpdate(update, actorId, fields);
|
|
148
112
|
} else if ('replaceOne' in op) {
|
|
149
|
-
|
|
150
|
-
op.replaceOne.replacement['updatedBy'] = currentUser.id;
|
|
151
|
-
}
|
|
152
|
-
if (hasCreatedBy && !op.replaceOne.replacement['createdBy']) {
|
|
153
|
-
op.replaceOne.replacement['createdBy'] = currentUser.id;
|
|
154
|
-
}
|
|
113
|
+
stampAuditOnReplace(op.replaceOne.replacement, actorId, fields);
|
|
155
114
|
}
|
|
156
115
|
}
|
|
157
116
|
});
|
|
@@ -6,6 +6,15 @@ export function mongooseIdPlugin(schema) {
|
|
|
6
6
|
schema.post(/.*/, (docs) => {
|
|
7
7
|
const docsArray = Array.isArray(docs) ? docs : [docs];
|
|
8
8
|
for (const doc of docsArray) {
|
|
9
|
+
// A bare ObjectId is a VALUE, not a document — `distinct()` on an ObjectId field returns an
|
|
10
|
+
// array of them. Mongoose gives `ObjectId.prototype` an `_id` getter returning itself, so the
|
|
11
|
+
// check below matched, and the assignment then hit bson's own `id` SETTER (the 12-byte
|
|
12
|
+
// buffer). bson < 7.3 silently accepted the hex string; bson >= 7.3 (mongodb >= 7.7) throws
|
|
13
|
+
// `BSONError: Cannot create Buffer from the passed potentialBuffer`, turning every
|
|
14
|
+
// `distinct()` over an ObjectId field into a 500.
|
|
15
|
+
if (doc?._bsontype === 'ObjectId') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
9
18
|
if (doc?._id && typeof doc._id.toHexString === 'function') {
|
|
10
19
|
doc.id = doc._id.toHexString();
|
|
11
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { sha256 } from 'js-sha256';
|
|
1
|
+
import { hashPassword, hashUpdatePassword } from '../persistence/policies/password.policy.js';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
// Public API since before the policy extraction — keep every import path working
|
|
4
|
+
export { hashPassword, hashUpdatePassword, resetSkipPatternsCache } from '../persistence/policies/password.policy.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Mongoose plugin that automatically hashes passwords before saving to the database.
|
|
@@ -15,6 +15,9 @@ import { ConfigService } from '../services/config.service.js';
|
|
|
15
15
|
*
|
|
16
16
|
* For sentinel/lock values (e.g. '!LOCKED:REQUIRES_PASSWORD_RESET'), configure
|
|
17
17
|
* skipPatterns in security.mongoosePasswordPlugin to preserve them as-is.
|
|
18
|
+
*
|
|
19
|
+
* The hashing decisions live in the password policy (`persistence/policies/password.policy.ts`), which
|
|
20
|
+
* every data store shares; this plugin only applies them to Mongoose's hook shapes.
|
|
18
21
|
*/
|
|
19
22
|
export function mongoosePasswordPlugin(schema) {
|
|
20
23
|
// Pre-save hook
|
|
@@ -79,62 +82,3 @@ export function mongoosePasswordPlugin(schema) {
|
|
|
79
82
|
}
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
|
-
|
|
83
|
-
export async function hashUpdatePassword(update: any) {
|
|
84
|
-
if (!update) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (update.password) {
|
|
88
|
-
update.password = await hashPassword(update.password);
|
|
89
|
-
}
|
|
90
|
-
if (update.$set?.password) {
|
|
91
|
-
update.$set.password = await hashPassword(update.$set.password);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Compiled RegExp cache (built once on first call)
|
|
96
|
-
let compiledSkipPatterns: RegExp[] | null = null;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Reset the compiled skip patterns cache.
|
|
100
|
-
* Use in test environments where ConfigService is reset between test suites.
|
|
101
|
-
*/
|
|
102
|
-
export function resetSkipPatternsCache(): void {
|
|
103
|
-
compiledSkipPatterns = null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function getSkipPatterns(): RegExp[] {
|
|
107
|
-
if (compiledSkipPatterns !== null) {
|
|
108
|
-
return compiledSkipPatterns;
|
|
109
|
-
}
|
|
110
|
-
const pluginConfig = ConfigService.configFastButReadOnly?.security?.mongoosePasswordPlugin;
|
|
111
|
-
if (pluginConfig && typeof pluginConfig === 'object' && 'skipPatterns' in pluginConfig && pluginConfig.skipPatterns) {
|
|
112
|
-
compiledSkipPatterns = (pluginConfig.skipPatterns as (string | RegExp)[]).map((p) =>
|
|
113
|
-
p instanceof RegExp ? p : new RegExp(p),
|
|
114
|
-
);
|
|
115
|
-
} else {
|
|
116
|
-
compiledSkipPatterns = [];
|
|
117
|
-
}
|
|
118
|
-
return compiledSkipPatterns;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export async function hashPassword(password: string): Promise<string> {
|
|
122
|
-
// Already BCrypt-hashed → skip
|
|
123
|
-
if (/^\$2[aby]\$\d+\$/.test(password)) {
|
|
124
|
-
return password;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Check configured skip patterns (e.g. sentinel/lock values)
|
|
128
|
-
const skipPatterns = getSkipPatterns();
|
|
129
|
-
if (skipPatterns.some((pattern) => pattern.test(password))) {
|
|
130
|
-
return password;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// SHA256 pre-hash if configured and password is not already SHA256
|
|
134
|
-
const sha256Enabled = ConfigService.configFastButReadOnly?.sha256;
|
|
135
|
-
if (sha256Enabled && !/^[a-f0-9]{64}$/i.test(password)) {
|
|
136
|
-
password = sha256(password);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return bcrypt.hash(password, 10);
|
|
140
|
-
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Logger } from '@nestjs/common';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
isRoleChangeAllowed,
|
|
5
|
+
stripRoleChanges,
|
|
6
|
+
updateChangesRoles,
|
|
7
|
+
} from '../persistence/policies/role-guard.policy.js';
|
|
5
8
|
import { RequestContext } from '../services/request-context.service.js';
|
|
6
9
|
|
|
7
10
|
const logger = new Logger('mongooseRoleGuardPlugin');
|
|
@@ -117,8 +120,8 @@ export function mongooseRoleGuardPlugin(schema) {
|
|
|
117
120
|
schema.pre('bulkWrite', function (ops) {
|
|
118
121
|
const hasAnyRoleChange = ops.some((op) => {
|
|
119
122
|
if ('insertOne' in op) return !!op.insertOne.document?.roles?.length;
|
|
120
|
-
if ('updateOne' in op) return
|
|
121
|
-
if ('updateMany' in op) return
|
|
123
|
+
if ('updateOne' in op) return updateChangesRoles(op.updateOne.update);
|
|
124
|
+
if ('updateMany' in op) return updateChangesRoles(op.updateMany.update);
|
|
122
125
|
if ('replaceOne' in op) return !!op.replaceOne.replacement?.roles?.length;
|
|
123
126
|
return false;
|
|
124
127
|
});
|
|
@@ -146,58 +149,15 @@ export function mongooseRoleGuardPlugin(schema) {
|
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* - No user context (system operation)
|
|
152
|
-
* - bypassRoleGuard is active (via RequestContext.runWithBypassRoleGuard())
|
|
153
|
-
* - User has ADMIN role
|
|
154
|
-
* - User has one of the configured allowedRoles
|
|
152
|
+
* Strip an unauthorized role change from an update object. The decisions live in the role-guard policy
|
|
153
|
+
* (`persistence/policies/role-guard.policy.ts`), which every data store shares.
|
|
155
154
|
*/
|
|
156
|
-
function isRoleChangeAllowed(): boolean {
|
|
157
|
-
const currentUser = RequestContext.getCurrentUser();
|
|
158
|
-
// No user context (system operation) → allow
|
|
159
|
-
if (!currentUser) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
// Explicit bypass (e.g. signUp with default roles, authorized service operations)
|
|
163
|
-
if (RequestContext.isBypassRoleGuard()) {
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
// Admin → always allow
|
|
167
|
-
if (currentUser.hasRole?.([RoleEnum.ADMIN]) || currentUser.roles?.includes(RoleEnum.ADMIN)) {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Check configured allowedRoles
|
|
172
|
-
const pluginConfig = ConfigService.configFastButReadOnly?.security?.mongooseRoleGuardPlugin;
|
|
173
|
-
if (pluginConfig && typeof pluginConfig === 'object' && 'allowedRoles' in pluginConfig && pluginConfig.allowedRoles) {
|
|
174
|
-
const allowedRoles: string[] = pluginConfig.allowedRoles as string[];
|
|
175
|
-
if (currentUser.roles?.some((role: string) => allowedRoles.includes(role))) {
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function hasRolesInUpdate(update: any): boolean {
|
|
184
|
-
return !!(
|
|
185
|
-
update?.roles ||
|
|
186
|
-
update?.$set?.roles ||
|
|
187
|
-
update?.$push?.roles ||
|
|
188
|
-
update?.$addToSet?.roles ||
|
|
189
|
-
update?.$pull?.roles
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
155
|
function handleUpdateRoleGuard(update: any) {
|
|
194
156
|
if (!update) {
|
|
195
157
|
return;
|
|
196
158
|
}
|
|
197
159
|
|
|
198
|
-
|
|
199
|
-
update.roles || update.$set?.roles || update?.$push?.roles || update.$addToSet?.roles || update.$pull?.roles;
|
|
200
|
-
if (!hasRolesUpdate) {
|
|
160
|
+
if (!updateChangesRoles(update)) {
|
|
201
161
|
return;
|
|
202
162
|
}
|
|
203
163
|
|
|
@@ -208,17 +168,5 @@ function handleUpdateRoleGuard(update: any) {
|
|
|
208
168
|
// Unauthorized: remove roles changes with debug log
|
|
209
169
|
const currentUser = RequestContext.getCurrentUser();
|
|
210
170
|
logger.debug(`Stripped unauthorized roles change from user ${currentUser?.id || 'unknown'}`);
|
|
211
|
-
|
|
212
|
-
if (update.$set?.roles) {
|
|
213
|
-
delete update.$set.roles;
|
|
214
|
-
}
|
|
215
|
-
if (update.$push?.roles) {
|
|
216
|
-
delete update.$push.roles;
|
|
217
|
-
}
|
|
218
|
-
if (update.$addToSet?.roles) {
|
|
219
|
-
delete update.$addToSet.roles;
|
|
220
|
-
}
|
|
221
|
-
if (update.$pull?.roles) {
|
|
222
|
-
delete update.$pull.roles;
|
|
223
|
-
}
|
|
171
|
+
stripRoleChanges(update);
|
|
224
172
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
assertNoSystemRoles,
|
|
3
|
+
assertUpdateHasNoSystemRoles,
|
|
4
|
+
toRoleArray,
|
|
5
|
+
updateMayIntroduceSystemRoles,
|
|
6
|
+
} from '../persistence/policies/system-role.policy.js';
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Mongoose plugin that refuses to STORE system roles (`s_*`) in a `roles` array.
|
|
@@ -93,38 +96,6 @@ export function mongooseSystemRolePlugin(schema) {
|
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
/** Normalize an unknown value to a string array; anything else becomes an empty baseline. */
|
|
97
|
-
function toRoleArray(value: unknown): string[] {
|
|
98
|
-
return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Throw if the write INTRODUCES a system role.
|
|
103
|
-
*
|
|
104
|
-
* `alreadyStored` is the document's current value. A system role that is already in there is NOT
|
|
105
|
-
* refused, and this is load-bearing rather than lenient: `CrudService.update()` writes the whole
|
|
106
|
-
* object back, so a login (`updateRefreshToken` → `update`) re-sends the stored `roles` verbatim.
|
|
107
|
-
* Refusing that would lock every already-contaminated account out of the system on upgrade — and
|
|
108
|
-
* would do the same, fleet-wide, to any project whose own role name happens to start with `s_`.
|
|
109
|
-
* An upgrade must not cause a login outage; cleaning up stored values is what the migration guide's
|
|
110
|
-
* audit query is for.
|
|
111
|
-
*
|
|
112
|
-
* Accepts anything: a non-array (nothing to check) and non-string elements (cannot be a system
|
|
113
|
-
* role) pass through untouched — type validation is not this plugin's job.
|
|
114
|
-
*/
|
|
115
|
-
function assertNoSystemRoles(roles: unknown, alreadyStored: string[] = []): void {
|
|
116
|
-
if (!Array.isArray(roles)) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const introduced = roles.filter((role) => looksLikeSystemRole(role) && !alreadyStored.includes(role));
|
|
121
|
-
if (introduced.length) {
|
|
122
|
-
throw new BadRequestException(
|
|
123
|
-
`System roles (${SYSTEM_ROLE_PREFIX}*) must never be stored in user.roles: ${introduced.join(', ')}`,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
99
|
/**
|
|
129
100
|
* Query-level variant: resolves the affected document's stored roles before deciding.
|
|
130
101
|
*
|
|
@@ -133,7 +104,7 @@ function assertNoSystemRoles(roles: unknown, alreadyStored: string[] = []): void
|
|
|
133
104
|
*/
|
|
134
105
|
async function assertUpdateIntroducesNoSystemRoles(query: any): Promise<void> {
|
|
135
106
|
const update = query.getUpdate();
|
|
136
|
-
if (!update || !
|
|
107
|
+
if (!update || !updateMayIntroduceSystemRoles(update)) {
|
|
137
108
|
return;
|
|
138
109
|
}
|
|
139
110
|
|
|
@@ -149,45 +120,3 @@ async function assertUpdateIntroducesNoSystemRoles(query: any): Promise<void> {
|
|
|
149
120
|
|
|
150
121
|
assertUpdateHasNoSystemRoles(update, stored);
|
|
151
122
|
}
|
|
152
|
-
|
|
153
|
-
/** Every roles value the update could write, flattened across the operators that can carry one. */
|
|
154
|
-
function collectRoleValues(update: any): unknown[] {
|
|
155
|
-
const values: unknown[] = [
|
|
156
|
-
...toRoleArray(update.roles),
|
|
157
|
-
...toRoleArray(update.$set?.roles),
|
|
158
|
-
...toRoleArray(update.$setOnInsert?.roles),
|
|
159
|
-
];
|
|
160
|
-
|
|
161
|
-
for (const operator of [update.$push?.roles, update.$addToSet?.roles]) {
|
|
162
|
-
if (operator === undefined || operator === null) {
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
values.push(...(Array.isArray(operator?.$each) ? operator.$each : [operator]));
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return values;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Check every operator through which a roles value can reach the document.
|
|
173
|
-
*
|
|
174
|
-
* `$pull` is deliberately NOT checked — removing an `s_*` value from a document that already has
|
|
175
|
-
* one is exactly the cleanup this release asks projects to perform, so it must stay possible.
|
|
176
|
-
*/
|
|
177
|
-
function assertUpdateHasNoSystemRoles(update: any, alreadyStored: string[] = []): void {
|
|
178
|
-
if (!update) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
assertNoSystemRoles(update.roles, alreadyStored);
|
|
183
|
-
assertNoSystemRoles(update.$set?.roles, alreadyStored);
|
|
184
|
-
assertNoSystemRoles(update.$setOnInsert?.roles, alreadyStored);
|
|
185
|
-
|
|
186
|
-
// $push / $addToSet take either a bare value or a { $each: [...] } modifier
|
|
187
|
-
for (const operator of [update.$push?.roles, update.$addToSet?.roles]) {
|
|
188
|
-
if (operator === undefined || operator === null) {
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
assertNoSystemRoles(Array.isArray(operator?.$each) ? operator.$each : [operator], alreadyStored);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
@@ -1,47 +1,12 @@
|
|
|
1
|
-
import { ForbiddenException
|
|
1
|
+
import { ForbiddenException } from '@nestjs/common';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Say out loud that isolation is off for a schema that was built for it.
|
|
11
|
-
*
|
|
12
|
-
* `excludeSchemas` is a legitimate feature — a genuinely global lookup table has no tenant. But this
|
|
13
|
-
* plugin only ever attaches to schemas that DECLARE a `tenantId` field, so reaching here means the
|
|
14
|
-
* author of that schema intended per-tenant rows and the configuration silently overrides them.
|
|
15
|
-
* Nothing said so, and the shape is easy to arrive at by accident: the framework's own documentation
|
|
16
|
-
* carried `excludeSchemas: ['User', 'Session']` in a copyable `@example` from 11.20.0 onwards, which
|
|
17
|
-
* on a project with per-tenant users switches filtering off for the user collection.
|
|
18
|
-
*
|
|
19
|
-
* A warning, not a boot failure. An ambiguous ROLE vocabulary fails the boot because its access
|
|
20
|
-
* decisions cannot be resolved coherently; this configuration is perfectly coherent — it is simply
|
|
21
|
-
* one nobody may make without noticing.
|
|
22
|
-
*
|
|
23
|
-
* The membership model is skipped: `CoreModule` adds it to `excludeSchemas` itself because
|
|
24
|
-
* membership is tenant-spanning by design, so warning about it would be the framework complaining
|
|
25
|
-
* about its own correct default.
|
|
26
|
-
*/
|
|
27
|
-
function warnIsolationDisabled(modelName: string): void {
|
|
28
|
-
if (isolationDisabledWarned.has(modelName)) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
isolationDisabledWarned.add(modelName);
|
|
32
|
-
|
|
33
|
-
const membershipModel = ConfigService.configFastButReadOnly?.multiTenancy?.membershipModel ?? 'TenantMember';
|
|
34
|
-
if (modelName === membershipModel) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
new Logger('mongooseTenantPlugin').warn(
|
|
39
|
-
`Tenant isolation is DISABLED for "${modelName}": the schema declares a tenantId field, but ` +
|
|
40
|
-
`"${modelName}" is listed in multiTenancy.excludeSchemas — so no tenant filter is applied and ` +
|
|
41
|
-
`every query on it sees every tenant's rows. Remove it from excludeSchemas unless this ` +
|
|
42
|
-
`collection is genuinely global.`,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
3
|
+
import {
|
|
4
|
+
assertOwnTenant,
|
|
5
|
+
assertRowsInTenantScope,
|
|
6
|
+
assertUnfilterableCountAllowed,
|
|
7
|
+
resolveSingleTenantId,
|
|
8
|
+
resolveTenantFilter,
|
|
9
|
+
} from '../persistence/policies/tenant.policy.js';
|
|
45
10
|
|
|
46
11
|
/**
|
|
47
12
|
* Mongoose plugin that provides automatic tenant-based data isolation.
|
|
@@ -71,7 +36,7 @@ export function mongooseTenantPlugin(schema) {
|
|
|
71
36
|
// Only activate on schemas with a tenantId path.
|
|
72
37
|
// CoreTenantMemberModel uses 'tenant' (not 'tenantId') intentionally, so this check
|
|
73
38
|
// excludes it at registration time. Additionally, 'TenantMember' is auto-added to
|
|
74
|
-
// excludeSchemas in CoreModule as defense-in-depth (see
|
|
39
|
+
// excludeSchemas in CoreModule as defense-in-depth (see isTenantPolicyBypassed() in the tenant policy).
|
|
75
40
|
if (!schema.path('tenantId')) {
|
|
76
41
|
return;
|
|
77
42
|
}
|
|
@@ -119,6 +84,19 @@ export function mongooseTenantPlugin(schema) {
|
|
|
119
84
|
});
|
|
120
85
|
}
|
|
121
86
|
|
|
87
|
+
// === After-layer: every returned row must belong to the caller's scope ===
|
|
88
|
+
// The pre hooks above decide WHICH rows a query may touch; this checks what actually came back, with
|
|
89
|
+
// the same policy a SQL store applies after its reads. Populated references are checked by their own
|
|
90
|
+
// model's hooks. Aggregations are not checked here: their output is reshaped and need not carry tenantId.
|
|
91
|
+
const rowCheckHooks = ['find', 'findOne', 'findOneAndUpdate', 'findOneAndDelete', 'findOneAndReplace'];
|
|
92
|
+
for (const hookName of rowCheckHooks) {
|
|
93
|
+
schema.post(hookName, function (result: any) {
|
|
94
|
+
// includeResultMetadata: findOneAnd* resolves to { value, lastErrorObject, ok }
|
|
95
|
+
const rows = result && typeof result === 'object' && 'lastErrorObject' in result ? result.value : result;
|
|
96
|
+
assertRowsInTenantScope(this.model?.modelName, rows);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
122
100
|
// === Save: set tenantId automatically on new documents ===
|
|
123
101
|
// Intentional asymmetry: writes only set tenantId when truthy (not null).
|
|
124
102
|
// Only uses single tenantId from header — tenantIds array is for reads only.
|
|
@@ -194,18 +172,7 @@ export function mongooseTenantPlugin(schema) {
|
|
|
194
172
|
// collection, i.e. every other tenant's volume. Throwing is the only honest option; callers that
|
|
195
173
|
// want a tenant's own count use countDocuments(), which IS filtered.
|
|
196
174
|
schema.pre('estimatedDocumentCount', function () {
|
|
197
|
-
|
|
198
|
-
if (shouldBypass(modelName)) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
const context = RequestContext.get();
|
|
202
|
-
if (context?.isAdminBypass && !context?.tenantId) {
|
|
203
|
-
return; // platform admin without a tenant header legitimately sees everything
|
|
204
|
-
}
|
|
205
|
-
throw new ForbiddenException(
|
|
206
|
-
"estimatedDocumentCount() cannot be tenant-filtered and would expose other tenants' row counts — " +
|
|
207
|
-
'use countDocuments() instead',
|
|
208
|
-
);
|
|
175
|
+
assertUnfilterableCountAllowed((this as any).model?.modelName);
|
|
209
176
|
});
|
|
210
177
|
|
|
211
178
|
// === Aggregate: prepend $match stage, and secure every cross-collection stage ===
|
|
@@ -340,91 +307,3 @@ function filterForCollection(collectionName: unknown, sourceModel: any): Record<
|
|
|
340
307
|
|
|
341
308
|
return undefined;
|
|
342
309
|
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Refuse a tenantId that is not the caller's own.
|
|
346
|
-
*
|
|
347
|
-
* Covers both directions of the same boundary:
|
|
348
|
-
* - creating a row with a FOREIGN tenantId → planting data in someone else's tenant;
|
|
349
|
-
* - changing an existing row's tenantId → moving data out of this one.
|
|
350
|
-
*
|
|
351
|
-
* Throwing rather than overwriting is deliberate. Silently rewriting the value would make a request
|
|
352
|
-
* that asked for something impossible look like it succeeded, and for tenant-scoped medical data
|
|
353
|
-
* "the write went somewhere other than you asked" is not a recoverable ambiguity.
|
|
354
|
-
*/
|
|
355
|
-
function assertOwnTenant(value: unknown, ownTenantId: string, isNew: boolean): void {
|
|
356
|
-
if (value === undefined || value === null || value === ownTenantId) {
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
throw new ForbiddenException(
|
|
360
|
-
isNew
|
|
361
|
-
? `Cannot create a document in a foreign tenant (got "${String(value)}", own tenant is "${ownTenantId}")`
|
|
362
|
-
: `Cannot move a document to a foreign tenant (got "${String(value)}", own tenant is "${ownTenantId}")`,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Check common bypass conditions.
|
|
368
|
-
*
|
|
369
|
-
* @returns `true` if filtering should be skipped, `false` otherwise
|
|
370
|
-
*/
|
|
371
|
-
function shouldBypass(modelName?: string): boolean {
|
|
372
|
-
const mtConfig = ConfigService.configFastButReadOnly?.multiTenancy;
|
|
373
|
-
if (!mtConfig || mtConfig.enabled === false) return true;
|
|
374
|
-
|
|
375
|
-
const context = RequestContext.get();
|
|
376
|
-
if (!context) return true;
|
|
377
|
-
if (context.bypassTenantGuard) return true;
|
|
378
|
-
if (modelName && mtConfig.excludeSchemas?.includes(modelName)) {
|
|
379
|
-
warnIsolationDisabled(modelName);
|
|
380
|
-
return true;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Resolve tenant filter from RequestContext for read operations (queries, aggregates).
|
|
388
|
-
*
|
|
389
|
-
* Defense-in-depth: If a schema has tenantId but there is no valid tenant context,
|
|
390
|
-
* throws ForbiddenException instead of returning unfiltered data (Safety Net).
|
|
391
|
-
*
|
|
392
|
-
* @returns
|
|
393
|
-
* - `undefined` → no filter should be applied (bypass active or plugin disabled)
|
|
394
|
-
* - `{}` → empty filter (admin bypass without header — sees all data)
|
|
395
|
-
* - `{ tenantId: string }` → filter by single validated tenant
|
|
396
|
-
* - `{ tenantId: { $in: string[] } }` → filter by user's tenant memberships
|
|
397
|
-
* @throws ForbiddenException when tenantId-schema is accessed without valid tenant context
|
|
398
|
-
*/
|
|
399
|
-
function resolveTenantFilter(modelName?: string): Record<string, any> | undefined {
|
|
400
|
-
if (shouldBypass(modelName)) return undefined;
|
|
401
|
-
|
|
402
|
-
const context = RequestContext.get();
|
|
403
|
-
|
|
404
|
-
// Validated tenant ID (set by CoreTenantGuard) → filter by it
|
|
405
|
-
const tenantId = context?.tenantId;
|
|
406
|
-
if (tenantId) return { tenantId };
|
|
407
|
-
|
|
408
|
-
// User has resolved memberships → filter by their tenants
|
|
409
|
-
const tenantIds = context?.tenantIds;
|
|
410
|
-
if (tenantIds) return { tenantId: { $in: tenantIds } };
|
|
411
|
-
|
|
412
|
-
// Admin bypass without header → no filter, sees all data
|
|
413
|
-
if (context?.isAdminBypass) return {};
|
|
414
|
-
|
|
415
|
-
// SAFETY NET: Schema has tenantId but no valid tenant context.
|
|
416
|
-
// Throw instead of returning unfiltered data to prevent data leaks.
|
|
417
|
-
throw new ForbiddenException(
|
|
418
|
-
'Tenant context required: this data is tenant-scoped but no valid tenant context was provided',
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Resolve single tenant ID for write operations (save, insertMany).
|
|
424
|
-
* Only returns a value when a specific tenant header is set.
|
|
425
|
-
*/
|
|
426
|
-
function resolveSingleTenantId(modelName?: string): string | undefined {
|
|
427
|
-
if (shouldBypass(modelName)) return undefined;
|
|
428
|
-
|
|
429
|
-
return RequestContext.get()?.tenantId || undefined;
|
|
430
|
-
}
|