@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
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type * as NestMongoose from '@nestjs/mongoose';
|
|
5
|
+
import type * as Mongodb from 'mongodb';
|
|
6
|
+
import type * as Mongoose from 'mongoose';
|
|
7
|
+
|
|
8
|
+
import { callerDirectory } from '../../helpers/module-location.helper.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* MongoDB's libraries — `mongoose`, `@nestjs/mongoose` and `mongodb` — are OPTIONAL peers since 12.1.0: a project that
|
|
12
|
+
* keeps its data in PostgreSQL installs none of them. Every module of the core that needs one at runtime takes it from
|
|
13
|
+
* here instead of importing it, because a static import of a package that is not installed fails the moment the
|
|
14
|
+
* barrel is loaded — long before anything could say which feature wanted it.
|
|
15
|
+
*
|
|
16
|
+
* Loaded synchronously: `@Prop()` and `@Schema()` run while a model class is DEFINED, and a project's own model file
|
|
17
|
+
* calls `SchemaFactory.createForClass()` right after — the decorators of the core's base classes must have reached
|
|
18
|
+
* Mongoose's metadata storage by then. `createRequire()` from this file's location resolves the packages the way a
|
|
19
|
+
* static import of the core would (the package's own peers in npm mode, the project's dependencies in vendor mode),
|
|
20
|
+
* and Node hands `require()` and `import` the same module instance: `mongoose` and `mongodb` are CommonJS, and
|
|
21
|
+
* `@nestjs/mongoose` (ESM only) is loaded through `require(esm)`, which shares the ESM loader's cache.
|
|
22
|
+
*
|
|
23
|
+
* Import-free leaf apart from the location helper — `import type` only — so it can sit below every module that needs
|
|
24
|
+
* it without joining an import cycle.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** The three packages, when installed */
|
|
28
|
+
export interface MongoPackages {
|
|
29
|
+
/** The MongoDB driver: the project's own `mongodb`, else the one Mongoose ships (`mongoose.mongo`) */
|
|
30
|
+
mongodb: typeof Mongodb;
|
|
31
|
+
mongoose: typeof Mongoose;
|
|
32
|
+
nestMongoose: typeof NestMongoose;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** MongoDB support was needed, and its libraries are not installed */
|
|
36
|
+
export class MongoPackagesMissingError extends Error {
|
|
37
|
+
override readonly name = 'MongoPackagesMissingError';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const PACKAGE_SPECIFIERS = ['mongoose', '@nestjs/mongoose'] as const;
|
|
41
|
+
|
|
42
|
+
/** Resolves like a static import of this module would */
|
|
43
|
+
const requireHere = createRequire(join(callerDirectory(), 'mongo-packages.js'));
|
|
44
|
+
|
|
45
|
+
/** `undefined` until the first look, `null` when the packages are not installed */
|
|
46
|
+
let cached: MongoPackages | null | undefined;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The packages when installed, else `undefined`. Throws when only one of `mongoose` / `@nestjs/mongoose` is installed:
|
|
50
|
+
* that is a broken installation, not a choice, and guessing either way would hide it.
|
|
51
|
+
*/
|
|
52
|
+
export function optionalMongoPackages(): MongoPackages | undefined {
|
|
53
|
+
if (cached === undefined) {
|
|
54
|
+
cached = loadMongoPackages() ?? null;
|
|
55
|
+
}
|
|
56
|
+
return cached ?? undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The packages, or a named error saying which feature needed them and what to install.
|
|
61
|
+
*
|
|
62
|
+
* @param feature what needs MongoDB, in the words of the configuration ("the `mongoose` configuration", "GridFS")
|
|
63
|
+
*/
|
|
64
|
+
export function requireMongoPackages(feature: string): MongoPackages {
|
|
65
|
+
const packages = optionalMongoPackages();
|
|
66
|
+
if (!packages) {
|
|
67
|
+
throw new MongoPackagesMissingError(
|
|
68
|
+
`${feature} needs MongoDB, and its libraries are not installed. They are optional peer dependencies of ` +
|
|
69
|
+
'@lenne.tech/nest-server since 12.1.0 — add them to the project: `pnpm add mongoose @nestjs/mongoose mongodb` ' +
|
|
70
|
+
'(the versions in the migration guide 12.0.x → 12.1.x).',
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return packages;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Better-Auth's MongoDB adapter — imported only where Better-Auth keeps its data in MongoDB, because it loads the
|
|
78
|
+
* MongoDB driver as it is evaluated
|
|
79
|
+
*/
|
|
80
|
+
export function requireBetterAuthMongoAdapter(): (db: unknown) => unknown {
|
|
81
|
+
requireMongoPackages('Better-Auth on MongoDB (the user model is not routed to a SQL source)');
|
|
82
|
+
return (requireHere('better-auth/adapters/mongodb') as { mongodbAdapter: (db: unknown) => unknown }).mongodbAdapter;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Whether MongoDB's libraries are installed */
|
|
86
|
+
export function hasMongoPackages(): boolean {
|
|
87
|
+
return !!optionalMongoPackages();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function loadMongoPackages(): MongoPackages | undefined {
|
|
91
|
+
const [mongoose, nestMongoose] = PACKAGE_SPECIFIERS.map((specifier) => optionalRequire(specifier));
|
|
92
|
+
if (!mongoose && !nestMongoose) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
if (!mongoose || !nestMongoose) {
|
|
96
|
+
const missing = mongoose ? '@nestjs/mongoose' : 'mongoose';
|
|
97
|
+
throw new MongoPackagesMissingError(
|
|
98
|
+
`MongoDB support needs both mongoose and @nestjs/mongoose; ${missing} is not installed. Install it, or remove ` +
|
|
99
|
+
'the other one if the project keeps no data in MongoDB.',
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const mongodb = optionalRequire('mongodb') ?? (mongoose as typeof Mongoose).mongo;
|
|
103
|
+
return {
|
|
104
|
+
mongodb: mongodb as typeof Mongodb,
|
|
105
|
+
mongoose: mongoose as typeof Mongoose,
|
|
106
|
+
nestMongoose: nestMongoose as typeof NestMongoose,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The package, or `undefined` when it is not installed — any other loading error is a real one and propagates */
|
|
111
|
+
function optionalRequire(specifier: string): unknown {
|
|
112
|
+
try {
|
|
113
|
+
return requireHere(specifier);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (isNotInstalled(error, specifier)) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** A "module not found" for the package itself — not for something the package failed to load */
|
|
123
|
+
function isNotInstalled(error: unknown, specifier: string): boolean {
|
|
124
|
+
const { code, message } = (error ?? {}) as { code?: string; message?: string };
|
|
125
|
+
return (
|
|
126
|
+
(code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') &&
|
|
127
|
+
typeof message === 'string' &&
|
|
128
|
+
(message.includes(`'${specifier}'`) || message.includes(`"${specifier}"`))
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
2
|
+
import type { Query } from 'mongoose';
|
|
3
|
+
|
|
4
|
+
import { HexObjectId } from './hex-object-id.js';
|
|
5
|
+
import {
|
|
6
|
+
DeclaredSchema,
|
|
7
|
+
declaredSchema,
|
|
8
|
+
markRaw,
|
|
9
|
+
recordModelDeclaration,
|
|
10
|
+
recordPropDeclaration,
|
|
11
|
+
} from './model-declarations.js';
|
|
12
|
+
import { optionalMongoPackages, requireMongoPackages } from './mongo-packages.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The parts of `@nestjs/mongoose` and `mongoose` the core declares its models, injections and ids with — usable
|
|
16
|
+
* whether or not MongoDB's libraries are installed (`mongo-packages.ts`). Since 12.1.0 the same names are exported for
|
|
17
|
+
* projects: a model file that imports `Prop`, `Schema` and `SchemaFactory` from `@lenne.tech/nest-server` works on
|
|
18
|
+
* MongoDB and on PostgreSQL alike, and installs nothing of MongoDB's where it is not used.
|
|
19
|
+
*
|
|
20
|
+
* - The decorators always RECORD what they declare (`model-declarations.ts`): that record is where a model's
|
|
21
|
+
* descriptor comes from when Mongoose is not there to build a schema. With Mongoose installed they also apply the
|
|
22
|
+
* real decorator, at the moment the original would have run — so a project's own `SchemaFactory.createForClass()`
|
|
23
|
+
* sees the core's fields exactly as before.
|
|
24
|
+
* - The injection tokens are computed here, identically to `@nestjs/mongoose` (pinned by
|
|
25
|
+
* `tests/unit/mongoose-compat.spec.ts`): a token is a string, and a service of the core must be constructible in a
|
|
26
|
+
* project that has no MongoDB at all.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** `@nestjs/mongoose`'s name for the default connection */
|
|
30
|
+
export const DEFAULT_CONNECTION_NAME = 'DatabaseConnection';
|
|
31
|
+
|
|
32
|
+
/** The DI token of a connection — `getConnectionToken()` of `@nestjs/mongoose` */
|
|
33
|
+
export function getConnectionToken(name?: string): string {
|
|
34
|
+
return name && name !== DEFAULT_CONNECTION_NAME ? `${name}Connection` : DEFAULT_CONNECTION_NAME;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The DI token of a model — `getModelToken()` of `@nestjs/mongoose` */
|
|
38
|
+
export function getModelToken(model: string, connectionName?: string): string {
|
|
39
|
+
return connectionName === undefined ? `${model}Model` : `${getConnectionToken(connectionName)}/${model}Model`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `@InjectModel()` — the model's Mongoose model where MongoDB is installed, else a stand-in that refuses data access;
|
|
44
|
+
* either way bound to the model's data store, which a `CrudService` follows (`CorePersistenceModule.forFeature()`)
|
|
45
|
+
*/
|
|
46
|
+
export function InjectModel(model: string, connectionName?: string): ParameterDecorator & PropertyDecorator {
|
|
47
|
+
return Inject(getModelToken(model, connectionName));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** `@InjectConnection()` — the Mongoose connection, `null` where no MongoDB is configured */
|
|
51
|
+
export function InjectConnection(name?: string): ParameterDecorator & PropertyDecorator {
|
|
52
|
+
return Inject(getConnectionToken(name));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** `@Schema()` of `@nestjs/mongoose` */
|
|
56
|
+
export function Schema(options?: Record<string, any>): ClassDecorator {
|
|
57
|
+
return (target) => {
|
|
58
|
+
recordModelDeclaration(target, options);
|
|
59
|
+
optionalMongoPackages()?.nestMongoose.Schema(options as any)(target);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** `@Prop()` of `@nestjs/mongoose` */
|
|
64
|
+
export function Prop(options?: Record<string, any>): PropertyDecorator {
|
|
65
|
+
return (target, propertyKey) => {
|
|
66
|
+
recordPropDeclaration(target, propertyKey, options);
|
|
67
|
+
optionalMongoPackages()?.nestMongoose.Prop(options as any)(target, propertyKey);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** `raw()` of `@nestjs/mongoose` — an inline object definition, kept as written where Mongoose is not installed */
|
|
72
|
+
export function raw(definition: Record<string, any>): Record<string, any> {
|
|
73
|
+
const packages = optionalMongoPackages();
|
|
74
|
+
return packages ? packages.nestMongoose.raw(definition) : markRaw(definition);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* `SchemaFactory.createForClass()` of `@nestjs/mongoose` — the Mongoose schema, or the recorded declaration
|
|
79
|
+
* (`DeclaredSchema`) where Mongoose is not installed
|
|
80
|
+
*/
|
|
81
|
+
export const SchemaFactory = {
|
|
82
|
+
createForClass(target: abstract new (...args: any[]) => any): any {
|
|
83
|
+
const packages = optionalMongoPackages();
|
|
84
|
+
return packages ? packages.nestMongoose.SchemaFactory.createForClass(target as any) : declaredSchema(target);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* `new Schema(definition, options)` of `mongoose` — for a model declared inline rather than through a class. A field
|
|
90
|
+
* whose shape is free-form is declared `{ type: Object }`, which Mongoose stores as `Mixed`.
|
|
91
|
+
*/
|
|
92
|
+
export function createSchema(definition: Record<string, any>, options: Record<string, any> = {}): any {
|
|
93
|
+
const packages = optionalMongoPackages();
|
|
94
|
+
return packages
|
|
95
|
+
? new packages.mongoose.Schema(definition, options)
|
|
96
|
+
: new DeclaredSchema({ definition: { ...definition }, options: { ...options } });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The type to declare an ObjectId field with (`@Prop({ type: ObjectIdType, ref })`): Mongoose's `Schema.Types.ObjectId`
|
|
101
|
+
* where installed, else the class the descriptor recognises as an id
|
|
102
|
+
*/
|
|
103
|
+
export function objectIdType(): unknown {
|
|
104
|
+
return optionalMongoPackages()?.mongoose.Schema.Types.ObjectId ?? HexObjectId;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A new ObjectId, or one for the given hex string / ObjectId — `new Types.ObjectId(value)` */
|
|
108
|
+
export function newObjectId(value?: { toHexString(): string } | string): any {
|
|
109
|
+
const packages = optionalMongoPackages();
|
|
110
|
+
return packages ? new packages.mongoose.Types.ObjectId(value as any) : new HexObjectId(value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** `Types.ObjectId.isValid()` — accepts what an ObjectId can be built from */
|
|
114
|
+
export function isValidObjectId(value: unknown): boolean {
|
|
115
|
+
const packages = optionalMongoPackages();
|
|
116
|
+
return packages ? packages.mongoose.Types.ObjectId.isValid(value as any) : HexObjectId.isValid(value);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Whether a value is a Mongoose query (`instanceof Query`) — never where Mongoose is not installed */
|
|
120
|
+
export function isMongooseQuery(value: unknown): value is Query<any, any> {
|
|
121
|
+
const Query = optionalMongoPackages()?.mongoose.Query;
|
|
122
|
+
return !!Query && value instanceof Query;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** A GridFS bucket on a MongoDB database — GridFS IS MongoDB, so its absence is a configuration error, named as such */
|
|
126
|
+
export function createGridFsBucket(db: unknown, options?: { bucketName?: string }): any {
|
|
127
|
+
const { mongodb } = requireMongoPackages('GridFS (file.storage: gridfs)');
|
|
128
|
+
return new mongodb.GridFSBucket(db as any, options);
|
|
129
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Global, Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { getConnectionToken } from './mongoose-compat.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The Mongoose connection token where no MongoDB is configured (`database` names no MongoDB source): `null`.
|
|
7
|
+
*
|
|
8
|
+
* Services of the core receive the connection through `@InjectConnection()` and use it only on their MongoDB path —
|
|
9
|
+
* on a SQL source they work through the data store. Without this provider every one of them would fail DI in a project
|
|
10
|
+
* that keeps its data in PostgreSQL alone; with it, a MongoDB path that is reached anyway fails with a named error
|
|
11
|
+
* (`CorePersistenceModule` stand-ins, `requireMongoPackages()`) instead of a missing-provider stack trace at boot.
|
|
12
|
+
*/
|
|
13
|
+
@Global()
|
|
14
|
+
@Module({
|
|
15
|
+
exports: [getConnectionToken()],
|
|
16
|
+
providers: [{ provide: getConnectionToken(), useValue: null }],
|
|
17
|
+
})
|
|
18
|
+
export class NoMongoConnectionModule {}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Collection } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
import type { LockStore } from './lock-store.interface.js';
|
|
4
|
+
|
|
5
|
+
/** The duplicate-key error code, decided by code rather than by matching message text. */
|
|
6
|
+
const DUPLICATE_KEY = 11000;
|
|
7
|
+
|
|
8
|
+
export interface MongoLockStoreOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Field holding the lease key — `_id` by default. Any other field gets a unique index before the first claim: the
|
|
11
|
+
* claim's atomicity rests on it, exactly as it rests on `_id` otherwise.
|
|
12
|
+
*/
|
|
13
|
+
keyField?: string;
|
|
14
|
+
/**
|
|
15
|
+
* A lock format older versions wrote: a timestamp and no `expiresAt`. Such a lock counts as expired once the
|
|
16
|
+
* timestamp is older than `staleAfterMs` — the rule those versions apply themselves — and every lock this store
|
|
17
|
+
* writes or renews carries the timestamp too, so an older replica applies its rule to it in a rolling deploy. Both
|
|
18
|
+
* sides then decide on one document, and a lease is never held twice.
|
|
19
|
+
*/
|
|
20
|
+
legacyTimestamp?: { field: string; staleAfterMs: number };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Leases in a MongoDB collection: one document per key (`_id` by default), with `owner` and `expiresAt`.
|
|
25
|
+
*
|
|
26
|
+
* Works on the native collection on purpose — a lease collection has no Mongoose schema and no tenant,
|
|
27
|
+
* audit or password semantics a plugin could add. A TTL index on `expiresAt` may be added for garbage
|
|
28
|
+
* collection; correctness never depends on it, because every claim compares `expiresAt` itself.
|
|
29
|
+
*/
|
|
30
|
+
export class MongoLockStore implements LockStore {
|
|
31
|
+
protected readonly keyField: string;
|
|
32
|
+
private keyIndex?: Promise<unknown>;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
protected readonly collection: Collection<any>,
|
|
36
|
+
protected readonly options: MongoLockStoreOptions = {},
|
|
37
|
+
) {
|
|
38
|
+
this.keyField = options.keyField ?? '_id';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async release(key: string, owner: string): Promise<boolean> {
|
|
42
|
+
const result = await this.collection.deleteOne({ [this.keyField]: key, owner });
|
|
43
|
+
return result.deletedCount === 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async renew(key: string, owner: string, ttlSeconds: number): Promise<boolean> {
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const result = await this.collection.updateOne(
|
|
49
|
+
{ [this.keyField]: key, expiresAt: { $gt: now }, owner },
|
|
50
|
+
{ $set: { ...this.legacyStamp(now), expiresAt: new Date(now.getTime() + ttlSeconds * 1000) } },
|
|
51
|
+
);
|
|
52
|
+
return result.matchedCount === 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async tryAcquire(key: string, owner: string, ttlSeconds: number): Promise<boolean> {
|
|
56
|
+
await this.ensureKeyIndex();
|
|
57
|
+
const now = new Date();
|
|
58
|
+
const legacy = this.options.legacyTimestamp;
|
|
59
|
+
// Matches only an EXPIRED lease, which is taken over in one atomic step. A held lease does not
|
|
60
|
+
// match, so the upsert tries to insert the same key and fails with a duplicate key: lost. A missing
|
|
61
|
+
// lease is inserted: won. Two contenders for one expired lease cannot both match — the first update
|
|
62
|
+
// moves expiresAt into the future before the second is evaluated.
|
|
63
|
+
const expired = legacy
|
|
64
|
+
? {
|
|
65
|
+
$or: [
|
|
66
|
+
{ expiresAt: { $lte: now } },
|
|
67
|
+
{
|
|
68
|
+
expiresAt: { $exists: false },
|
|
69
|
+
[legacy.field]: { $lt: new Date(now.getTime() - legacy.staleAfterMs) },
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
}
|
|
73
|
+
: { expiresAt: { $lte: now } };
|
|
74
|
+
try {
|
|
75
|
+
await this.collection.updateOne(
|
|
76
|
+
{ [this.keyField]: key, ...expired },
|
|
77
|
+
{
|
|
78
|
+
$set: {
|
|
79
|
+
...(this.keyField === '_id' ? {} : { [this.keyField]: key }),
|
|
80
|
+
...this.legacyStamp(now),
|
|
81
|
+
acquiredAt: now,
|
|
82
|
+
expiresAt: new Date(now.getTime() + ttlSeconds * 1000),
|
|
83
|
+
owner,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{ upsert: true },
|
|
87
|
+
);
|
|
88
|
+
return true;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if ((error as { code?: number })?.code !== DUPLICATE_KEY) {
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
if (legacy) {
|
|
94
|
+
// A lock of a version that wrote no timestamp at all: start its clock now — as those versions did — rather
|
|
95
|
+
// than obeying it forever or breaking it at once (its holder may well be alive)
|
|
96
|
+
await this.collection.updateOne(
|
|
97
|
+
{ [this.keyField]: key, expiresAt: { $exists: false }, [legacy.field]: { $exists: false } },
|
|
98
|
+
{ $set: { [legacy.field]: now } },
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The timestamp older versions read, refreshed with every claim and renewal */
|
|
106
|
+
private legacyStamp(now: Date): Record<string, Date> {
|
|
107
|
+
return this.options.legacyTimestamp ? { [this.options.legacyTimestamp.field]: now } : {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private async ensureKeyIndex(): Promise<void> {
|
|
111
|
+
if (this.keyField === '_id') {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.keyIndex ??= this.collection.createIndex({ [this.keyField]: 1 }, { unique: true }).catch((error) => {
|
|
115
|
+
// Retried on the next claim: without the index a second contender could insert a second lock
|
|
116
|
+
this.keyIndex = undefined;
|
|
117
|
+
throw error;
|
|
118
|
+
});
|
|
119
|
+
await this.keyIndex;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
import type { Model } from 'mongoose';
|
|
3
|
+
|
|
4
|
+
import { getStringIds } from '../helpers/id.helper.js';
|
|
5
|
+
import {
|
|
6
|
+
assertAccessReason,
|
|
7
|
+
assertArrayField,
|
|
8
|
+
assertProjection,
|
|
9
|
+
assertSampleSize,
|
|
10
|
+
assertSelectFields,
|
|
11
|
+
} from './store-guards.js';
|
|
12
|
+
import type {
|
|
13
|
+
DataStore,
|
|
14
|
+
DataStoreUpdate,
|
|
15
|
+
FindOptions,
|
|
16
|
+
PushOptions,
|
|
17
|
+
StoreCapabilities,
|
|
18
|
+
StoredRecord,
|
|
19
|
+
UpdateOptions,
|
|
20
|
+
Where,
|
|
21
|
+
} from './data-store.interface.js';
|
|
22
|
+
|
|
23
|
+
/** What MongoDB offers through Mongoose. Transactions need a replica set and are not assumed. */
|
|
24
|
+
export const MONGOOSE_STORE_CAPABILITIES: Readonly<StoreCapabilities> = Object.freeze({
|
|
25
|
+
aggregatePipeline: true,
|
|
26
|
+
changeFeed: false,
|
|
27
|
+
gridfs: true,
|
|
28
|
+
idType: 'objectId',
|
|
29
|
+
mongoosePopulate: true,
|
|
30
|
+
rawFilterArm: true,
|
|
31
|
+
rls: false,
|
|
32
|
+
textSearch: true,
|
|
33
|
+
transactions: false,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The MongoDB data store: the neutral port over a Mongoose model.
|
|
38
|
+
*
|
|
39
|
+
* Every operation runs through a Model method, never the native collection, so the security plugins
|
|
40
|
+
* (tenant isolation before and after, audit fields, role guard, system roles, password hashing) fire
|
|
41
|
+
* exactly as for any other Mongoose call. Filters and updates pass through untouched — they already
|
|
42
|
+
* are the Mongo-operator form — except that the neutral `id` is addressed as `_id`.
|
|
43
|
+
*/
|
|
44
|
+
export class MongooseDataStore<T = Record<string, any>> implements DataStore<T> {
|
|
45
|
+
readonly capabilities = MONGOOSE_STORE_CAPABILITIES;
|
|
46
|
+
readonly driver = 'mongodb';
|
|
47
|
+
protected readonly logger = new Logger(MongooseDataStore.name);
|
|
48
|
+
|
|
49
|
+
constructor(protected readonly model: Model<any>) {}
|
|
50
|
+
|
|
51
|
+
get modelName(): string {
|
|
52
|
+
return this.model.modelName;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async count(where?: Where<T>): Promise<number> {
|
|
56
|
+
return this.model.countDocuments(toMongoFilter(where)).exec();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async sum(field: string, where?: Where<T>): Promise<{ count: number; sum: number }> {
|
|
60
|
+
assertSelectFields([field]);
|
|
61
|
+
// An aggregation's $match is not cast like a query: cast it through a query of the model first
|
|
62
|
+
const match = this.model.find().cast(this.model, toMongoFilter(where));
|
|
63
|
+
const [row] = await this.model
|
|
64
|
+
.aggregate<{ count: number; sum: number }>([
|
|
65
|
+
{ $match: match },
|
|
66
|
+
{ $group: { _id: null, count: { $sum: 1 }, sum: { $sum: { $ifNull: [`$${field}`, 0] } } } },
|
|
67
|
+
])
|
|
68
|
+
.exec();
|
|
69
|
+
return { count: row?.count ?? 0, sum: row?.sum ?? 0 };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async deleteById(id: string): Promise<null | StoredRecord<T>> {
|
|
73
|
+
return toRecord<T>(await this.model.findByIdAndDelete(id).lean().exec());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async deleteMany(where: Where<T>): Promise<number> {
|
|
77
|
+
const result = await this.model.deleteMany(toMongoFilter(where)).exec();
|
|
78
|
+
return result.deletedCount;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async deleteOne(where: Where<T>): Promise<null | StoredRecord<T>> {
|
|
82
|
+
return toRecord<T>(await this.model.findOneAndDelete(toMongoFilter(where)).lean().exec());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async distinct(field: string, where?: Where<T>): Promise<unknown[]> {
|
|
86
|
+
return this.model.distinct(field, toMongoFilter(where)).exec();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async find(where?: Where<T>, options: FindOptions = {}): Promise<StoredRecord<T>[]> {
|
|
90
|
+
const sample = options.sample === undefined ? undefined : assertSampleSize(options.sample);
|
|
91
|
+
let query = this.model.find(toMongoFilter(where));
|
|
92
|
+
if (options.select || options.exclude) query = query.select(toProjection(options));
|
|
93
|
+
if (options.sort) query = query.sort(options.sort);
|
|
94
|
+
if (options.skip !== undefined) query = query.skip(options.skip);
|
|
95
|
+
if (options.limit !== undefined) query = query.limit(options.limit);
|
|
96
|
+
if (options.collation) query = query.collation(options.collation as any);
|
|
97
|
+
const docs = await query.lean().exec();
|
|
98
|
+
const records = (docs as unknown[]).map((doc) => toRecord<T>(doc));
|
|
99
|
+
// Drawn from the page this query returned, like `$sample` after `$limit`. CrudService.findAndCount() on MongoDB
|
|
100
|
+
// keeps its own aggregation; this path serves callers of the port.
|
|
101
|
+
return sample === undefined ? records : randomSample(records, sample);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async findById(id: string, options: Pick<FindOptions, 'exclude' | 'select'> = {}): Promise<null | StoredRecord<T>> {
|
|
105
|
+
let query = this.model.findById(id);
|
|
106
|
+
if (options.select || options.exclude) query = query.select(toProjection(options));
|
|
107
|
+
return toRecord<T>(await query.lean().exec());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async findOne(where: Where<T>, options: Omit<FindOptions, 'limit' | 'skip'> = {}): Promise<null | StoredRecord<T>> {
|
|
111
|
+
let query = this.model.findOne(toMongoFilter(where));
|
|
112
|
+
if (options.select || options.exclude) query = query.select(toProjection(options));
|
|
113
|
+
if (options.sort) query = query.sort(options.sort);
|
|
114
|
+
if (options.collation) query = query.collation(options.collation as any);
|
|
115
|
+
return toRecord<T>(await query.lean().exec());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async insert(record: Partial<T>): Promise<StoredRecord<T>> {
|
|
119
|
+
// `create()` runs the save hooks, so tenant stamping, audit fields and password hashing apply
|
|
120
|
+
const created = await this.model.create(record);
|
|
121
|
+
return toRecord<T>(created.toObject());
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
native<N = unknown>(reason: string): N {
|
|
125
|
+
assertAccessReason(reason, 'native');
|
|
126
|
+
this.logger.debug(`Native model access: ${reason} (Model: ${this.modelName})`);
|
|
127
|
+
return this.model as unknown as N;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async pullFromArray(id: string, field: string, condition: unknown): Promise<void> {
|
|
131
|
+
assertArrayField(field, 'pullFromArray');
|
|
132
|
+
await this.model
|
|
133
|
+
.findByIdAndUpdate(id, { $pull: { [field]: condition } } as any)
|
|
134
|
+
.lean()
|
|
135
|
+
.exec();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async pushToArray(id: string, field: string, items: readonly unknown[], options: PushOptions = {}): Promise<void> {
|
|
139
|
+
assertArrayField(field, 'pushToArray');
|
|
140
|
+
if (!items.length) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const push: Record<string, unknown> = { $each: [...items] };
|
|
144
|
+
if (options.slice !== undefined) push.$slice = options.slice;
|
|
145
|
+
if (options.position !== undefined) push.$position = options.position;
|
|
146
|
+
if (options.sort) push.$sort = options.sort;
|
|
147
|
+
await this.model
|
|
148
|
+
.findByIdAndUpdate(id, { $push: { [field]: push } } as any)
|
|
149
|
+
.lean()
|
|
150
|
+
.exec();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
raw<N = unknown>(reason: string): N {
|
|
154
|
+
assertAccessReason(reason, 'raw');
|
|
155
|
+
this.logger.warn(`[SECURITY] Native collection access: ${reason} (Model: ${this.modelName})`);
|
|
156
|
+
return this.model.collection as unknown as N;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async updateById(
|
|
160
|
+
id: string,
|
|
161
|
+
update: DataStoreUpdate<T>,
|
|
162
|
+
options: UpdateOptions = {},
|
|
163
|
+
): Promise<null | StoredRecord<T>> {
|
|
164
|
+
const updated = await this.model
|
|
165
|
+
.findByIdAndUpdate(id, update as any, {
|
|
166
|
+
returnDocument: 'after',
|
|
167
|
+
...(options.timestamps === false ? { timestamps: false } : {}),
|
|
168
|
+
})
|
|
169
|
+
.lean()
|
|
170
|
+
.exec();
|
|
171
|
+
return toRecord<T>(updated);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async updateMany(where: Where<T>, update: DataStoreUpdate<T>): Promise<number> {
|
|
175
|
+
const result = await this.model.updateMany(toMongoFilter(where), update as any).exec();
|
|
176
|
+
return result.matchedCount;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async updateOne(where: Where<T>, update: DataStoreUpdate<T>): Promise<null | StoredRecord<T>> {
|
|
180
|
+
const updated = await this.model
|
|
181
|
+
.findOneAndUpdate(toMongoFilter(where), update as any, { returnDocument: 'after' })
|
|
182
|
+
.lean()
|
|
183
|
+
.exec();
|
|
184
|
+
return toRecord<T>(updated);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The neutral `id` is `_id` in MongoDB — at the top level and inside `$and` / `$or` / `$nor`. */
|
|
189
|
+
export function toMongoFilter(where: undefined | Where<any>): Record<string, any> {
|
|
190
|
+
if (!where) {
|
|
191
|
+
return {};
|
|
192
|
+
}
|
|
193
|
+
const filter: Record<string, any> = {};
|
|
194
|
+
for (const [key, value] of Object.entries(where)) {
|
|
195
|
+
if (key === 'id') {
|
|
196
|
+
filter._id = value;
|
|
197
|
+
} else if ((key === '$and' || key === '$or' || key === '$nor') && Array.isArray(value)) {
|
|
198
|
+
filter[key] = value.map((entry) => toMongoFilter(entry));
|
|
199
|
+
} else {
|
|
200
|
+
filter[key] = value;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return filter;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** A lean document as a neutral record: the id as a string under `id`, no `_id`, no version key. */
|
|
207
|
+
function toRecord<T>(doc: unknown): StoredRecord<T> {
|
|
208
|
+
if (!doc) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const { __v: _version, _id, ...fields } = doc as Record<string, any>;
|
|
212
|
+
return { ...fields, id: _id === undefined ? fields.id : getStringIds(_id) } as StoredRecord<T>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function toProjection(options: Pick<FindOptions, 'exclude' | 'select'>): string {
|
|
216
|
+
assertProjection(options);
|
|
217
|
+
if (options.exclude?.length) {
|
|
218
|
+
return options.exclude.map((field) => `-${field}`).join(' ');
|
|
219
|
+
}
|
|
220
|
+
return (options.select ?? []).map((field) => (field === 'id' ? '_id' : field)).join(' ');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** `size` items of `items` in random order (a partial Fisher–Yates shuffle) */
|
|
224
|
+
function randomSample<I>(items: I[], size: number): I[] {
|
|
225
|
+
const pool = [...items];
|
|
226
|
+
const count = Math.min(size, pool.length);
|
|
227
|
+
for (let index = 0; index < count; index++) {
|
|
228
|
+
const pick = index + Math.floor(Math.random() * (pool.length - index));
|
|
229
|
+
[pool[index], pool[pick]] = [pool[pick], pool[index]];
|
|
230
|
+
}
|
|
231
|
+
return pool.slice(0, count);
|
|
232
|
+
}
|