@solidxai/core 0.1.13-beta.2 → 0.1.13-beta.20
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/CHANGELOG.md +9517 -0
- package/README.md +19 -0
- package/dist/commands/run-tests.command.d.ts +9 -1
- package/dist/commands/run-tests.command.d.ts.map +1 -1
- package/dist/commands/run-tests.command.js +69 -6
- package/dist/commands/run-tests.command.js.map +1 -1
- package/dist/commands/seed.command.d.ts +2 -0
- package/dist/commands/seed.command.d.ts.map +1 -1
- package/dist/commands/seed.command.js +21 -0
- package/dist/commands/seed.command.js.map +1 -1
- package/dist/config/cache.options.d.ts.map +1 -1
- package/dist/config/cache.options.js +2 -2
- package/dist/config/cache.options.js.map +1 -1
- package/dist/constants/chatter-message.constants.d.ts +1 -0
- package/dist/constants/chatter-message.constants.d.ts.map +1 -1
- package/dist/constants/chatter-message.constants.js +3 -1
- package/dist/constants/chatter-message.constants.js.map +1 -1
- package/dist/constants/draft-publish-fields.d.ts +2 -0
- package/dist/constants/draft-publish-fields.d.ts.map +1 -0
- package/dist/constants/draft-publish-fields.js +5 -0
- package/dist/constants/draft-publish-fields.js.map +1 -0
- package/dist/constants/error-messages.d.ts +7 -0
- package/dist/constants/error-messages.d.ts.map +1 -1
- package/dist/constants/error-messages.js +7 -0
- package/dist/constants/error-messages.js.map +1 -1
- package/dist/constants/media-file-types.d.ts +12 -0
- package/dist/constants/media-file-types.d.ts.map +1 -1
- package/dist/constants/media-file-types.js +65 -1
- package/dist/constants/media-file-types.js.map +1 -1
- package/dist/constants/success-messages.d.ts +3 -0
- package/dist/constants/success-messages.d.ts.map +1 -1
- package/dist/constants/success-messages.js +3 -0
- package/dist/constants/success-messages.js.map +1 -1
- package/dist/constants/user.constants.d.ts +2 -0
- package/dist/constants/user.constants.d.ts.map +1 -0
- package/dist/constants/user.constants.js +5 -0
- package/dist/constants/user.constants.js.map +1 -0
- package/dist/controllers/action-metadata.controller.d.ts +1 -1
- package/dist/controllers/action-metadata.controller.js +1 -1
- package/dist/controllers/agent-event.controller.d.ts +1 -1
- package/dist/controllers/agent-event.controller.js +1 -1
- package/dist/controllers/agent-session.controller.d.ts +1 -1
- package/dist/controllers/agent-session.controller.js +1 -1
- package/dist/controllers/authentication.controller.d.ts +1 -1
- package/dist/controllers/authentication.controller.d.ts.map +1 -1
- package/dist/controllers/authentication.controller.js +4 -3
- package/dist/controllers/authentication.controller.js.map +1 -1
- package/dist/controllers/chatter-message.controller.d.ts +5 -0
- package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
- package/dist/controllers/chatter-message.controller.js +14 -0
- package/dist/controllers/chatter-message.controller.js.map +1 -1
- package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -1
- package/dist/controllers/dashboard-user-layout.controller.js +1 -1
- package/dist/controllers/email-template.controller.d.ts +1 -1
- package/dist/controllers/email-template.controller.js +1 -1
- package/dist/controllers/export-template.controller.d.ts +1 -1
- package/dist/controllers/export-template.controller.d.ts.map +1 -1
- package/dist/controllers/export-template.controller.js +6 -4
- package/dist/controllers/export-template.controller.js.map +1 -1
- package/dist/controllers/export-transaction.controller.d.ts +1 -1
- package/dist/controllers/export-transaction.controller.js +1 -1
- package/dist/controllers/field-metadata.controller.d.ts +2 -2
- package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -1
- package/dist/controllers/import-transaction-error-log.controller.js +1 -1
- package/dist/controllers/import-transaction.controller.d.ts +1 -1
- package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
- package/dist/controllers/import-transaction.controller.js +7 -7
- package/dist/controllers/import-transaction.controller.js.map +1 -1
- package/dist/controllers/list-of-values.controller.d.ts +1 -1
- package/dist/controllers/list-of-values.controller.js +1 -1
- package/dist/controllers/locale.controller.d.ts +1 -1
- package/dist/controllers/locale.controller.js +1 -1
- package/dist/controllers/mcp-audit-log.controller.d.ts +1 -1
- package/dist/controllers/mcp-audit-log.controller.js +1 -1
- package/dist/controllers/media.controller.d.ts +2 -2
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +13 -8
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/controllers/menu-item-metadata.controller.d.ts +1 -1
- package/dist/controllers/menu-item-metadata.controller.js +1 -1
- package/dist/controllers/model-sequence.controller.d.ts +1 -1
- package/dist/controllers/model-sequence.controller.js +1 -1
- package/dist/controllers/module-package.controller.d.ts.map +1 -1
- package/dist/controllers/module-package.controller.js +2 -3
- package/dist/controllers/module-package.controller.js.map +1 -1
- package/dist/controllers/mpin-authentication.controller.d.ts +44 -0
- package/dist/controllers/mpin-authentication.controller.d.ts.map +1 -0
- package/dist/controllers/mpin-authentication.controller.js +102 -0
- package/dist/controllers/mpin-authentication.controller.js.map +1 -0
- package/dist/controllers/mq-message-queue.controller.d.ts +1 -1
- package/dist/controllers/mq-message-queue.controller.js +1 -1
- package/dist/controllers/mq-message.controller.d.ts +1 -1
- package/dist/controllers/mq-message.controller.js +1 -1
- package/dist/controllers/permission-metadata.controller.d.ts +1 -1
- package/dist/controllers/permission-metadata.controller.js +1 -1
- package/dist/controllers/role-metadata.controller.d.ts +1 -1
- package/dist/controllers/role-metadata.controller.js +1 -1
- package/dist/controllers/saved-filters.controller.d.ts +1 -1
- package/dist/controllers/saved-filters.controller.js +1 -1
- package/dist/controllers/scheduled-job.controller.d.ts +1 -1
- package/dist/controllers/scheduled-job.controller.js +1 -1
- package/dist/controllers/security-rule.controller.d.ts +1 -1
- package/dist/controllers/security-rule.controller.js +1 -1
- package/dist/controllers/sms-template.controller.d.ts +1 -1
- package/dist/controllers/sms-template.controller.js +1 -1
- package/dist/controllers/user-activity-history.controller.d.ts +1 -1
- package/dist/controllers/user-activity-history.controller.js +1 -1
- package/dist/controllers/user-view-metadata.controller.d.ts +1 -1
- package/dist/controllers/user-view-metadata.controller.js +1 -1
- package/dist/controllers/user.controller.d.ts +2 -2
- package/dist/controllers/user.controller.js +2 -2
- package/dist/controllers/view-metadata.controller.d.ts +2 -2
- package/dist/controllers/view-metadata.controller.js +1 -1
- package/dist/controllers/workflow-definition.controller.d.ts +1 -1
- package/dist/controllers/workflow-definition.controller.js +1 -1
- package/dist/controllers/workflow-execution-artifact.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution-artifact.controller.js +1 -1
- package/dist/controllers/workflow-execution-log.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution-log.controller.js +1 -1
- package/dist/controllers/workflow-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-execution.controller.js +1 -1
- package/dist/controllers/workflow-secret.controller.d.ts +1 -1
- package/dist/controllers/workflow-secret.controller.js +1 -1
- package/dist/controllers/workflow-step-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-step-execution.controller.js +1 -1
- package/dist/controllers/workflow-trigger-execution.controller.d.ts +1 -1
- package/dist/controllers/workflow-trigger-execution.controller.js +1 -1
- package/dist/dtos/basic-filters.dto.d.ts +0 -1
- package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
- package/dist/dtos/basic-filters.dto.js +1 -6
- package/dist/dtos/basic-filters.dto.js.map +1 -1
- package/dist/dtos/change-mpin.dto.d.ts +6 -0
- package/dist/dtos/change-mpin.dto.d.ts.map +1 -0
- package/dist/dtos/change-mpin.dto.js +39 -0
- package/dist/dtos/change-mpin.dto.js.map +1 -0
- package/dist/dtos/create-field-metadata.dto.d.ts +2 -6
- package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-field-metadata.dto.js +4 -10
- package/dist/dtos/create-field-metadata.dto.js.map +1 -1
- package/dist/dtos/create-model-sequence.dto.d.ts +1 -1
- package/dist/dtos/create-model-sequence.dto.d.ts.map +1 -1
- package/dist/dtos/create-model-sequence.dto.js +1 -1
- package/dist/dtos/create-model-sequence.dto.js.map +1 -1
- package/dist/dtos/mpin-login.dto.d.ts +5 -0
- package/dist/dtos/mpin-login.dto.d.ts.map +1 -0
- package/dist/dtos/mpin-login.dto.js +33 -0
- package/dist/dtos/mpin-login.dto.js.map +1 -0
- package/dist/dtos/setup-mpin.dto.d.ts +7 -0
- package/dist/dtos/setup-mpin.dto.d.ts.map +1 -0
- package/dist/dtos/setup-mpin.dto.js +47 -0
- package/dist/dtos/setup-mpin.dto.js.map +1 -0
- package/dist/entities/common.entity.d.ts +4 -0
- package/dist/entities/common.entity.d.ts.map +1 -1
- package/dist/entities/common.entity.js +25 -1
- package/dist/entities/common.entity.js.map +1 -1
- package/dist/entities/dashboard-user-layout.entity.js +2 -2
- package/dist/entities/dashboard-user-layout.entity.js.map +1 -1
- package/dist/entities/saved-filters.entity.js +3 -3
- package/dist/entities/saved-filters.entity.js.map +1 -1
- package/dist/entities/user-device-credential.entity.d.ts +18 -0
- package/dist/entities/user-device-credential.entity.d.ts.map +1 -0
- package/dist/entities/user-device-credential.entity.js +91 -0
- package/dist/entities/user-device-credential.entity.js.map +1 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +36 -0
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entities/view-metadata.entity.js.map +1 -1
- package/dist/entities/workflow-execution-artifact.entity.d.ts.map +1 -1
- package/dist/entities/workflow-execution-artifact.entity.js +4 -3
- package/dist/entities/workflow-execution-artifact.entity.js.map +1 -1
- package/dist/entities/workflow-execution-log.entity.d.ts.map +1 -1
- package/dist/entities/workflow-execution-log.entity.js +4 -3
- package/dist/entities/workflow-execution-log.entity.js.map +1 -1
- package/dist/entities/workflow-execution.entity.d.ts.map +1 -1
- package/dist/entities/workflow-execution.entity.js +3 -2
- package/dist/entities/workflow-execution.entity.js.map +1 -1
- package/dist/entities/workflow-secret.entity.d.ts.map +1 -1
- package/dist/entities/workflow-secret.entity.js +3 -2
- package/dist/entities/workflow-secret.entity.js.map +1 -1
- package/dist/entities/workflow-step-execution.entity.d.ts.map +1 -1
- package/dist/entities/workflow-step-execution.entity.js +3 -2
- package/dist/entities/workflow-step-execution.entity.js.map +1 -1
- package/dist/entities/workflow-trigger-execution.entity.d.ts.map +1 -1
- package/dist/entities/workflow-trigger-execution.entity.js +7 -6
- package/dist/entities/workflow-trigger-execution.entity.js.map +1 -1
- package/dist/factories/mail.factory.d.ts.map +1 -1
- package/dist/factories/mail.factory.js +4 -0
- package/dist/factories/mail.factory.js.map +1 -1
- package/dist/filters/http-exception.filter.d.ts.map +1 -1
- package/dist/filters/http-exception.filter.js +5 -1
- package/dist/filters/http-exception.filter.js.map +1 -1
- package/dist/helpers/bootstrap.helper.d.ts +5 -2
- package/dist/helpers/bootstrap.helper.d.ts.map +1 -1
- package/dist/helpers/bootstrap.helper.js +7 -3
- package/dist/helpers/bootstrap.helper.js.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +1 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +18 -11
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/helpers/file-download.helper.d.ts +9 -0
- package/dist/helpers/file-download.helper.d.ts.map +1 -0
- package/dist/helpers/file-download.helper.js +19 -0
- package/dist/helpers/file-download.helper.js.map +1 -0
- package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
- package/dist/helpers/model-metadata-helper.service.js +30 -1
- package/dist/helpers/model-metadata-helper.service.js.map +1 -1
- package/dist/helpers/security.helper.d.ts +5 -1
- package/dist/helpers/security.helper.d.ts.map +1 -1
- package/dist/helpers/security.helper.js +15 -4
- package/dist/helpers/security.helper.js.map +1 -1
- package/dist/helpers/solid-core-error-codes-provider.service.d.ts.map +1 -1
- package/dist/helpers/solid-core-error-codes-provider.service.js +45 -0
- package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -1
- package/dist/helpers/solid-microservice-adapter.service.d.ts.map +1 -1
- package/dist/helpers/solid-microservice-adapter.service.js +1 -1
- package/dist/helpers/solid-microservice-adapter.service.js.map +1 -1
- package/dist/helpers/solid-registry.js +1 -1
- package/dist/helpers/solid-registry.js.map +1 -1
- package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
- package/dist/helpers/typeorm-db-helper.js +9 -0
- package/dist/helpers/typeorm-db-helper.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/active-user-data.interface.d.ts +1 -0
- package/dist/interfaces/active-user-data.interface.d.ts.map +1 -1
- package/dist/interfaces/active-user-data.interface.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/repository/user-device-credential.repository.d.ts +12 -0
- package/dist/repository/user-device-credential.repository.d.ts.map +1 -0
- package/dist/repository/user-device-credential.repository.js +34 -0
- package/dist/repository/user-device-credential.repository.js.map +1 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +51 -30
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/module-test-data.service.d.ts +3 -1
- package/dist/seeders/module-test-data.service.d.ts.map +1 -1
- package/dist/seeders/module-test-data.service.js +8 -2
- package/dist/seeders/module-test-data.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +290 -78
- package/dist/services/api-key.service.d.ts.map +1 -1
- package/dist/services/api-key.service.js +1 -1
- package/dist/services/api-key.service.js.map +1 -1
- package/dist/services/authentication.service.d.ts +9 -5
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +102 -23
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +15 -1
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +56 -4
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts +6 -4
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +32 -48
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts +13 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +93 -68
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/datasource-introspection.service.d.ts.map +1 -1
- package/dist/services/datasource-introspection.service.js.map +1 -1
- package/dist/services/draft-publish-helper.service.d.ts +53 -0
- package/dist/services/draft-publish-helper.service.d.ts.map +1 -0
- package/dist/services/draft-publish-helper.service.js +402 -0
- package/dist/services/draft-publish-helper.service.js.map +1 -0
- package/dist/services/field-metadata.service.d.ts +2 -2
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js +2 -1
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/internationalisation-helper.service.d.ts +19 -0
- package/dist/services/internationalisation-helper.service.d.ts.map +1 -0
- package/dist/services/internationalisation-helper.service.js +107 -0
- package/dist/services/internationalisation-helper.service.js.map +1 -0
- package/dist/services/locale.service.d.ts +1 -1
- package/dist/services/media-storage.utils.d.ts +1 -0
- package/dist/services/media-storage.utils.d.ts.map +1 -1
- package/dist/services/media-storage.utils.js +12 -1
- package/dist/services/media-storage.utils.js.map +1 -1
- package/dist/services/media.service.d.ts +3 -2
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +44 -29
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/metadata-validation.service.d.ts +7 -0
- package/dist/services/metadata-validation.service.d.ts.map +1 -0
- package/dist/services/metadata-validation.service.js +42 -0
- package/dist/services/metadata-validation.service.js.map +1 -0
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +2 -1
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +2 -1
- package/dist/services/module-metadata.service.js.map +1 -1
- package/dist/services/mpin.service.d.ts +67 -0
- package/dist/services/mpin.service.d.ts.map +1 -0
- package/dist/services/mpin.service.js +282 -0
- package/dist/services/mpin.service.js.map +1 -0
- package/dist/services/object.utils.d.ts +2 -0
- package/dist/services/object.utils.d.ts.map +1 -0
- package/dist/services/object.utils.js +11 -0
- package/dist/services/object.utils.js.map +1 -0
- package/dist/services/refresh-token-ids-storage.service.d.ts +25 -6
- package/dist/services/refresh-token-ids-storage.service.d.ts.map +1 -1
- package/dist/services/refresh-token-ids-storage.service.js +80 -42
- package/dist/services/refresh-token-ids-storage.service.js.map +1 -1
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +2 -1
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +228 -12
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +129 -6
- package/dist/services/settings/default-settings-provider.service.js.map +1 -1
- package/dist/services/user.service.d.ts +2 -2
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +9 -3
- package/dist/services/user.service.js.map +1 -1
- package/dist/services/view-metadata.service.d.ts +1 -2
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +3 -55
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist/services/workflow/nodes/execution-fail.node.d.ts +6 -0
- package/dist/services/workflow/nodes/execution-fail.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/execution-fail.node.js +81 -0
- package/dist/services/workflow/nodes/execution-fail.node.js.map +1 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts +2 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/for-each.node.js +114 -5
- package/dist/services/workflow/nodes/for-each.node.js.map +1 -1
- package/dist/services/workflow/nodes/if.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/if.node.js +7 -0
- package/dist/services/workflow/nodes/if.node.js.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.js +2 -0
- package/dist/services/workflow/nodes/log-write.node.js.map +1 -1
- package/dist/services/workflow/nodes/loop-until.node.d.ts +12 -0
- package/dist/services/workflow/nodes/loop-until.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/loop-until.node.js +281 -0
- package/dist/services/workflow/nodes/loop-until.node.js.map +1 -0
- package/dist/services/workflow/nodes/parallel.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/parallel.node.js +7 -0
- package/dist/services/workflow/nodes/parallel.node.js.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.js +7 -0
- package/dist/services/workflow/nodes/sequential.node.js.map +1 -1
- package/dist/services/workflow/nodes/switch.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/switch.node.js +7 -0
- package/dist/services/workflow/nodes/switch.node.js.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.js +5 -2
- package/dist/services/workflow/workflow-definition-validator.service.js.map +1 -1
- package/dist/services/workflow/workflow-expression.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-expression.service.js +5 -0
- package/dist/services/workflow/workflow-expression.service.js.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts +2 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.js +7 -0
- package/dist/services/workflow/workflow-node-registry.service.js.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.d.ts +8 -0
- package/dist/services/workflow/workflow-runtime.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.js +197 -32
- package/dist/services/workflow/workflow-runtime.service.js.map +1 -1
- package/dist/services/workflow-definition.service.d.ts +1 -1
- package/dist/solid-core.module.d.ts +1 -3
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +22 -40
- package/dist/solid-core.module.js.map +1 -1
- package/dist/testing/adapters/ui/playwright-adapter.d.ts +5 -0
- package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -1
- package/dist/testing/adapters/ui/playwright-adapter.js +17 -1
- package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -1
- package/dist/testing/adapters/ui/ui.types.d.ts +2 -0
- package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -1
- package/dist/testing/adapters/ui/ui.types.js.map +1 -1
- package/dist/testing/reporter/console-reporter.d.ts +3 -0
- package/dist/testing/reporter/console-reporter.d.ts.map +1 -1
- package/dist/testing/reporter/console-reporter.js +2 -0
- package/dist/testing/reporter/console-reporter.js.map +1 -1
- package/dist/testing/reporter/progress-reporter.d.ts +64 -0
- package/dist/testing/reporter/progress-reporter.d.ts.map +1 -0
- package/dist/testing/reporter/progress-reporter.js +224 -0
- package/dist/testing/reporter/progress-reporter.js.map +1 -0
- package/dist/testing/reporter/reporter.types.d.ts +3 -0
- package/dist/testing/reporter/reporter.types.d.ts.map +1 -1
- package/dist/testing/reporter/reporter.types.js.map +1 -1
- package/dist/testing/runner/run-from-metadata.d.ts.map +1 -1
- package/dist/testing/runner/run-from-metadata.js +1 -0
- package/dist/testing/runner/run-from-metadata.js.map +1 -1
- package/dist/testing/steps/ui/actions.step.d.ts.map +1 -1
- package/dist/testing/steps/ui/actions.step.js +6 -2
- package/dist/testing/steps/ui/actions.step.js.map +1 -1
- package/dist/testing/steps/ui/assertions.step.d.ts.map +1 -1
- package/dist/testing/steps/ui/assertions.step.js +11 -3
- package/dist/testing/steps/ui/assertions.step.js.map +1 -1
- package/dist/testing/steps/ui/form.step.d.ts.map +1 -1
- package/dist/testing/steps/ui/form.step.js +9 -3
- package/dist/testing/steps/ui/form.step.js.map +1 -1
- package/dist/testing/steps/ui/manual.step.js +1 -1
- package/dist/testing/steps/ui/manual.step.js.map +1 -1
- package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -1
- package/dist/testing/steps/ui/navigation.step.js +3 -1
- package/dist/testing/steps/ui/navigation.step.js.map +1 -1
- package/dist/theme/theme-registry.d.ts +14 -0
- package/dist/theme/theme-registry.d.ts.map +1 -0
- package/dist/theme/theme-registry.js +147 -0
- package/dist/theme/theme-registry.js.map +1 -0
- package/dist/types/workflow-dsl.types.d.ts +14 -0
- package/dist/types/workflow-dsl.types.d.ts.map +1 -1
- package/dist/types/workflow-dsl.types.js.map +1 -1
- package/package.json +2 -2
- package/postman/mpin.postman_collection.json +1045 -0
- package/src/commands/run-tests.command.ts +64 -4
- package/src/commands/seed.command.ts +19 -0
- package/src/config/cache.options.ts +9 -1
- package/src/constants/chatter-message.constants.ts +12 -0
- package/src/constants/draft-publish-fields.ts +5 -0
- package/src/constants/error-messages.ts +14 -0
- package/src/constants/media-file-types.ts +127 -0
- package/src/constants/success-messages.ts +5 -0
- package/src/constants/user.constants.ts +13 -0
- package/src/controllers/authentication.controller.ts +5 -2
- package/src/controllers/chatter-message.controller.ts +8 -0
- package/src/controllers/export-template.controller.ts +5 -3
- package/src/controllers/import-transaction.controller.ts +6 -6
- package/src/controllers/media.controller.ts +17 -6
- package/src/controllers/module-package.controller.ts +2 -3
- package/src/controllers/mpin-authentication.controller.ts +67 -0
- package/src/dtos/basic-filters.dto.ts +0 -4
- package/src/dtos/change-mpin.dto.ts +18 -0
- package/src/dtos/create-field-metadata.dto.ts +4 -9
- package/src/dtos/create-model-sequence.dto.ts +1 -1
- package/src/dtos/mpin-login.dto.ts +24 -0
- package/src/dtos/setup-mpin.dto.ts +51 -0
- package/src/entities/common.entity.ts +24 -0
- package/src/entities/dashboard-user-layout.entity.ts +2 -2
- package/src/entities/saved-filters.entity.ts +3 -3
- package/src/entities/user-device-credential.entity.ts +130 -0
- package/src/entities/user.entity.ts +53 -36
- package/src/entities/view-metadata.entity.ts +2 -2
- package/src/entities/workflow-execution-artifact.entity.ts +4 -3
- package/src/entities/workflow-execution-log.entity.ts +4 -3
- package/src/entities/workflow-execution.entity.ts +3 -2
- package/src/entities/workflow-secret.entity.ts +3 -2
- package/src/entities/workflow-step-execution.entity.ts +3 -2
- package/src/entities/workflow-trigger-execution.entity.ts +7 -6
- package/src/factories/mail.factory.ts +7 -1
- package/src/filters/http-exception.filter.ts +11 -1
- package/src/helpers/bootstrap.helper.ts +43 -6
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +26 -12
- package/src/helpers/file-download.helper.ts +45 -0
- package/src/helpers/model-metadata-helper.service.ts +32 -1
- package/src/helpers/security.helper.ts +35 -8
- package/src/helpers/solid-core-error-codes-provider.service.ts +53 -0
- package/src/helpers/solid-microservice-adapter.service.ts +6 -1
- package/src/helpers/solid-registry.ts +1 -1
- package/src/helpers/typeorm-db-helper.ts +12 -1
- package/src/index.ts +10 -0
- package/src/interfaces/active-user-data.interface.ts +9 -0
- package/src/interfaces.ts +1 -0
- package/src/repository/user-device-credential.repository.ts +17 -0
- package/src/seeders/module-metadata-seeder.service.ts +61 -39
- package/src/seeders/module-test-data.service.ts +6 -0
- package/src/seeders/seed-data/solid-core-metadata.json +290 -78
- package/src/services/api-key.service.ts +13 -1
- package/src/services/authentication.service.ts +203 -41
- package/src/services/chatter-message.service.ts +124 -5
- package/src/services/crud-helper.service.ts +35 -50
- package/src/services/crud.service.ts +131 -105
- package/src/services/datasource-introspection.service.ts +5 -0
- package/src/services/draft-publish-helper.service.ts +581 -0
- package/src/services/field-metadata.service.ts +3 -2
- package/src/services/internationalisation-helper.service.ts +148 -0
- package/src/services/media-storage.utils.ts +26 -1
- package/src/services/media.service.ts +67 -36
- package/src/services/metadata-validation.service.ts +39 -0
- package/src/services/model-metadata.service.ts +4 -1
- package/src/services/module-metadata.service.ts +3 -1
- package/src/services/mpin.service.ts +447 -0
- package/src/services/object.utils.ts +10 -0
- package/src/services/refresh-token-ids-storage.service.ts +229 -90
- package/src/services/setting.service.ts +3 -1
- package/src/services/settings/default-settings-provider.service.ts +140 -6
- package/src/services/user.service.ts +18 -3
- package/src/services/view-metadata.service.ts +5 -145
- package/src/services/workflow/nodes/execution-fail.node.ts +82 -0
- package/src/services/workflow/nodes/for-each.node.ts +140 -6
- package/src/services/workflow/nodes/if.node.ts +7 -0
- package/src/services/workflow/nodes/log-write.node.ts +2 -0
- package/src/services/workflow/nodes/loop-until.node.ts +343 -0
- package/src/services/workflow/nodes/parallel.node.ts +7 -0
- package/src/services/workflow/nodes/sequential.node.ts +7 -0
- package/src/services/workflow/nodes/switch.node.ts +7 -0
- package/src/services/workflow/workflow-definition-validator.service.ts +5 -2
- package/src/services/workflow/workflow-expression.service.ts +5 -0
- package/src/services/workflow/workflow-node-registry.service.ts +11 -0
- package/src/services/workflow/workflow-runtime.service.ts +274 -39
- package/src/solid-core.module.ts +33 -15
- package/src/testing/README.md +75 -3
- package/src/testing/adapters/ui/playwright-adapter.ts +25 -0
- package/src/testing/adapters/ui/ui.types.ts +2 -0
- package/src/testing/reporter/console-reporter.ts +4 -0
- package/src/testing/reporter/progress-reporter.ts +251 -0
- package/src/testing/reporter/reporter.types.ts +3 -0
- package/src/testing/runner/run-from-metadata.ts +1 -0
- package/src/testing/steps/ui/actions.step.ts +8 -4
- package/src/testing/steps/ui/assertions.step.ts +18 -5
- package/src/testing/steps/ui/form.step.ts +16 -6
- package/src/testing/steps/ui/manual.step.ts +1 -1
- package/src/testing/steps/ui/navigation.step.ts +4 -2
- package/src/theme/theme-registry.ts +181 -0
- package/src/types/workflow-dsl.types.ts +43 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CommonEntity } from 'src/entities/common.entity';
|
|
2
2
|
import { Entity, Column, Index } from 'typeorm';
|
|
3
|
+
import { getColumnType } from 'src/helpers/typeorm-db-helper';
|
|
3
4
|
|
|
4
5
|
@Entity('ss_workflow_secret')
|
|
5
6
|
export class WorkflowSecret extends CommonEntity {
|
|
@@ -25,9 +26,9 @@ export class WorkflowSecret extends CommonEntity {
|
|
|
25
26
|
@Column({ type: "varchar", default: "active" })
|
|
26
27
|
status: string = "active";
|
|
27
28
|
|
|
28
|
-
@Column({
|
|
29
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
29
30
|
lastRotatedAt: Date;
|
|
30
31
|
|
|
31
|
-
@Column({
|
|
32
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
32
33
|
lastAccessedAt: Date;
|
|
33
34
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CommonEntity } from 'src/entities/common.entity';
|
|
2
2
|
import { Entity, Column, Index, JoinColumn, ManyToOne } from 'typeorm';
|
|
3
3
|
import { WorkflowExecution } from './workflow-execution.entity'
|
|
4
|
+
import { getColumnType } from 'src/helpers/typeorm-db-helper';
|
|
4
5
|
|
|
5
6
|
@Entity('ss_workflow_step_execution')
|
|
6
7
|
export class WorkflowStepExecution extends CommonEntity {
|
|
@@ -55,11 +56,11 @@ export class WorkflowStepExecution extends CommonEntity {
|
|
|
55
56
|
sequenceNumber: number;
|
|
56
57
|
|
|
57
58
|
@Index()
|
|
58
|
-
@Column({
|
|
59
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
59
60
|
startedAt: Date;
|
|
60
61
|
|
|
61
62
|
@Index()
|
|
62
|
-
@Column({
|
|
63
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
63
64
|
finishedAt: Date;
|
|
64
65
|
|
|
65
66
|
@Column({ type: "bigint", nullable: true })
|
|
@@ -2,6 +2,7 @@ import { CommonEntity } from 'src/entities/common.entity';
|
|
|
2
2
|
import { Entity, Column, Index, JoinColumn, ManyToOne } from 'typeorm';
|
|
3
3
|
import { WorkflowDefinition } from './workflow-definition.entity';
|
|
4
4
|
import { WorkflowExecution } from './workflow-execution.entity'
|
|
5
|
+
import { getColumnType } from 'src/helpers/typeorm-db-helper';
|
|
5
6
|
|
|
6
7
|
@Entity('ss_workflow_trigger_execution')
|
|
7
8
|
export class WorkflowTriggerExecution extends CommonEntity {
|
|
@@ -10,12 +11,12 @@ export class WorkflowTriggerExecution extends CommonEntity {
|
|
|
10
11
|
triggerExecutionKey: string;
|
|
11
12
|
|
|
12
13
|
@Index()
|
|
13
|
-
@ManyToOne(() => WorkflowDefinition, {
|
|
14
|
+
@ManyToOne(() => WorkflowDefinition, { nullable: false })
|
|
14
15
|
@JoinColumn()
|
|
15
16
|
workflowDefinition: WorkflowDefinition;
|
|
16
17
|
|
|
17
18
|
@Index()
|
|
18
|
-
@ManyToOne(() => WorkflowExecution, {
|
|
19
|
+
@ManyToOne(() => WorkflowExecution, { nullable: true })
|
|
19
20
|
@JoinColumn()
|
|
20
21
|
workflowExecution: WorkflowExecution;
|
|
21
22
|
|
|
@@ -35,19 +36,19 @@ export class WorkflowTriggerExecution extends CommonEntity {
|
|
|
35
36
|
status: string = "received";
|
|
36
37
|
|
|
37
38
|
@Index()
|
|
38
|
-
@Column({
|
|
39
|
+
@Column({ nullable: true, default: false })
|
|
39
40
|
matched: boolean = false;
|
|
40
41
|
|
|
41
42
|
@Index()
|
|
42
|
-
@Column({
|
|
43
|
+
@Column({ ...getColumnType('datetime') })
|
|
43
44
|
firedAt: Date;
|
|
44
45
|
|
|
45
46
|
@Index()
|
|
46
|
-
@Column({
|
|
47
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
47
48
|
startedAt: Date;
|
|
48
49
|
|
|
49
50
|
@Index()
|
|
50
|
-
@Column({
|
|
51
|
+
@Column({ nullable: true, ...getColumnType('datetime') })
|
|
51
52
|
finishedAt: Date;
|
|
52
53
|
|
|
53
54
|
@Column({ type: "bigint", nullable: true })
|
|
@@ -30,8 +30,14 @@ export class MailFactory {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const mailServiceProvider = mailProviders.find(provider => provider.name === mailServiceName);
|
|
33
|
+
if (!mailServiceProvider?.instance) {
|
|
34
|
+
const registeredProviders = mailProviders.map((provider) => provider?.name).filter(Boolean).join(", ");
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Mail provider "${mailServiceName}" is not registered. Registered providers: ${registeredProviders || "none"}`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
return mailServiceProvider.instance as IMail;
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
}
|
|
43
|
+
}
|
|
@@ -30,12 +30,22 @@ export class HttpExceptionFilter implements ExceptionFilter {
|
|
|
30
30
|
const isHttp = exception instanceof HttpException;
|
|
31
31
|
const explicitStatus = isHttp ? exception.getStatus() : undefined;
|
|
32
32
|
|
|
33
|
+
// Errors from http-errors-style libraries (e.g. body-parser's PayloadTooLargeError)
|
|
34
|
+
// are plain Errors carrying their own status. Honour it rather than collapsing to 500.
|
|
35
|
+
const rawStatus = exception?.status ?? exception?.statusCode;
|
|
36
|
+
const derivedStatus =
|
|
37
|
+
typeof rawStatus === 'number' && rawStatus >= 400 && rawStatus < 600
|
|
38
|
+
? rawStatus
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
33
41
|
// Canonical code + static message
|
|
34
42
|
const code: ErrorCode = this.errorMapper.mapException(exception);
|
|
35
43
|
const defaultStatus = this.errorMapper.getHttpStatus(code);
|
|
36
44
|
const message = code === 'solidx-unknown-error' ? `${exception?.message}` : this.errorMapper.getMessage(code);
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
// derivedStatus must precede defaultStatus: getHttpStatus() returns a hard 500
|
|
47
|
+
// for unmatched codes, so it is never undefined and would always win otherwise.
|
|
48
|
+
const status = explicitStatus ?? derivedStatus ?? defaultStatus ?? 500;
|
|
39
49
|
|
|
40
50
|
// Logging
|
|
41
51
|
this.logger.error(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common';
|
|
2
2
|
import { NestFactory, Reflector } from '@nestjs/core';
|
|
3
|
+
import { NestExpressApplication } from '@nestjs/platform-express';
|
|
3
4
|
import { WsAdapter } from '@nestjs/platform-ws';
|
|
4
5
|
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
5
6
|
import { NextFunction, Request, Response } from 'express';
|
|
@@ -12,7 +13,12 @@ import { CommandFactory } from 'nest-commander';
|
|
|
12
13
|
import { createWinstonLoggerConfig } from '../winston.logger';
|
|
13
14
|
import { WrapResponseInterceptor } from '../interceptors/wrap-response.interceptor';
|
|
14
15
|
import { buildDefaultCorsOptions } from './cors.helper';
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
buildDefaultSecurityHeaderOptions,
|
|
18
|
+
buildPermissionsPolicyHeader,
|
|
19
|
+
PermissionsPolicyConfig,
|
|
20
|
+
SolidSecurityOptions,
|
|
21
|
+
} from './security.helper';
|
|
16
22
|
import { parseBooleanEnv } from './environment.helper';
|
|
17
23
|
|
|
18
24
|
// ---- Shared process handlers ----
|
|
@@ -50,8 +56,20 @@ export interface SolidBootstrapOptions {
|
|
|
50
56
|
swagger?: SolidSwaggerOptions | false;
|
|
51
57
|
/** Permissions-Policy header overrides (merged with defaults). */
|
|
52
58
|
permissionsPolicyOverrides?: Partial<PermissionsPolicyConfig>;
|
|
59
|
+
/** Security header overrides, including iframe frame-ancestor allowlists. */
|
|
60
|
+
security?: SolidSecurityOptions;
|
|
53
61
|
/** Show full NestJS init logs during bootstrap (route mapping, module deps, pollers). Defaults to false. */
|
|
54
62
|
verboseBootstrap?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Max request body size for JSON and urlencoded payloads, as a `bytes`-compatible
|
|
65
|
+
* string (e.g. '10mb', '512kb'). Defaults to '10mb'.
|
|
66
|
+
*
|
|
67
|
+
* Does NOT apply to multipart/form-data uploads: body-parser matches on Content-Type,
|
|
68
|
+
* so multipart requests skip these parsers entirely and are handled by Multer. Raise
|
|
69
|
+
* this only for large structured JSON (e.g. /bulk arrays), bearing in mind the parsed
|
|
70
|
+
* object graph can retain several times the raw byte size.
|
|
71
|
+
*/
|
|
72
|
+
bodyLimit?: string;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
/**
|
|
@@ -64,19 +82,30 @@ export interface SolidBootstrapOptions {
|
|
|
64
82
|
* // main.ts
|
|
65
83
|
* bootstrapSolidApp(() => AppModule.forRoot(), {
|
|
66
84
|
* swagger: { title: 'My API', description: 'My API description' },
|
|
85
|
+
* security: { frameAncestors: ["'self'", 'https://portal.example.com'] },
|
|
67
86
|
* });
|
|
68
87
|
*/
|
|
69
88
|
export async function bootstrapSolidApp(
|
|
70
89
|
appModuleFactory: () => Promise<any>,
|
|
71
90
|
options: SolidBootstrapOptions = {},
|
|
72
|
-
): Promise<
|
|
91
|
+
): Promise<NestExpressApplication> {
|
|
73
92
|
registerGlobalProcessHandlers();
|
|
74
93
|
|
|
75
|
-
const {
|
|
94
|
+
const {
|
|
95
|
+
globalPrefix = 'api',
|
|
96
|
+
swagger = {},
|
|
97
|
+
permissionsPolicyOverrides = {},
|
|
98
|
+
security = {},
|
|
99
|
+
verboseBootstrap = false,
|
|
100
|
+
bodyLimit = '10mb',
|
|
101
|
+
} = options;
|
|
76
102
|
|
|
77
103
|
const startTime = Date.now();
|
|
78
104
|
const appModule = await appModuleFactory();
|
|
79
|
-
const app = await NestFactory.create(appModule, {
|
|
105
|
+
const app = await NestFactory.create<NestExpressApplication>(appModule, {
|
|
106
|
+
// Nest's default parsers are registered during init() with a 100kb limit, ahead of
|
|
107
|
+
// any module middleware. Disable them so the parsers below own the limit outright.
|
|
108
|
+
bodyParser: false,
|
|
80
109
|
logger: WinstonModule.createLogger({ ...createWinstonLoggerConfig(), level: verboseBootstrap ? 'debug' : 'error' }),
|
|
81
110
|
});
|
|
82
111
|
|
|
@@ -87,7 +116,7 @@ export async function bootstrapSolidApp(
|
|
|
87
116
|
app
|
|
88
117
|
.get(WINSTON_MODULE_NEST_PROVIDER)
|
|
89
118
|
.log('API server disabled via API_ENABLED=false. Skipping HTTP listen.', 'Bootstrap');
|
|
90
|
-
return;
|
|
119
|
+
return app;
|
|
91
120
|
}
|
|
92
121
|
|
|
93
122
|
// Health check at root path
|
|
@@ -95,7 +124,7 @@ export async function bootstrapSolidApp(
|
|
|
95
124
|
server.get('/', (_req, res) => res.status(200).send('SOLID OK'));
|
|
96
125
|
|
|
97
126
|
// Security headers
|
|
98
|
-
app.use(helmet(buildDefaultSecurityHeaderOptions()));
|
|
127
|
+
app.use(helmet(buildDefaultSecurityHeaderOptions(security)));
|
|
99
128
|
|
|
100
129
|
// Nest's Swagger UI HTML injects inline styles; keep CSP strict elsewhere.
|
|
101
130
|
const isSwaggerPath = (path: string) =>
|
|
@@ -136,6 +165,12 @@ export async function bootstrapSolidApp(
|
|
|
136
165
|
next();
|
|
137
166
|
});
|
|
138
167
|
|
|
168
|
+
// Body parsers — replaces Nest's default 100kb parsers (disabled via bodyParser: false).
|
|
169
|
+
// Registered here so the middleware order Nest applied by default is preserved:
|
|
170
|
+
// helmet -> CSP -> Permissions-Policy -> qs -> body parsers -> routes.
|
|
171
|
+
app.useBodyParser('json', { limit: bodyLimit });
|
|
172
|
+
app.useBodyParser('urlencoded', { limit: bodyLimit, extended: true });
|
|
173
|
+
|
|
139
174
|
// Global ValidationPipe
|
|
140
175
|
app.useGlobalPipes(
|
|
141
176
|
new ValidationPipe({
|
|
@@ -195,6 +230,8 @@ export async function bootstrapSolidApp(
|
|
|
195
230
|
|
|
196
231
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
197
232
|
process.stdout.write(`\x1b[32mServer started on port ${port} in ${elapsed}s\x1b[0m\n`);
|
|
233
|
+
|
|
234
|
+
return app;
|
|
198
235
|
}
|
|
199
236
|
|
|
200
237
|
// ---- CLI bootstrap ----
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FieldCrudManager, ValidationError } from "src/interfaces";
|
|
2
|
-
import {
|
|
2
|
+
import { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from "src/constants/media-file-types";
|
|
3
3
|
|
|
4
4
|
export enum SolidMediaType {
|
|
5
5
|
mediaSingle = 'mediaSingle',
|
|
@@ -79,16 +79,15 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
79
79
|
constructor(private readonly options: MediaFieldOptions) {
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
private resolveMediaType(
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
private resolveMediaType(file: Express.Multer.File): MediaType | null {
|
|
83
|
+
// Belt-and-braces: dangerous files are already rejected outright by
|
|
84
|
+
// validateDangerousFiles, but never let one resolve to a usable category.
|
|
85
|
+
if (isDangerousMediaFile(file)) {
|
|
85
86
|
return null;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
89
|
+
const ext = getLowercaseFileExtension(getUploadedFileName(file));
|
|
90
|
+
const mt = (file.mimetype || '').toLowerCase().trim();
|
|
92
91
|
if (mt && MIME_TO_MEDIA_TYPE[mt]) {
|
|
93
92
|
return MIME_TO_MEDIA_TYPE[mt];
|
|
94
93
|
}
|
|
@@ -113,16 +112,31 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
115
|
+
// Runs for every media field type and regardless of the admin-configured mediaTypes
|
|
116
|
+
// allowlist - a dangerous upload is never acceptable, so this must not sit behind
|
|
117
|
+
// the optional type checks below.
|
|
118
|
+
const errors = this.validateDangerousFiles(fieldFiles);
|
|
119
|
+
|
|
116
120
|
switch (this.options.type) {
|
|
117
121
|
case SolidMediaType.mediaSingle:
|
|
118
|
-
return this.validateMediaSingle(fieldFiles);
|
|
122
|
+
return [...errors, ...this.validateMediaSingle(fieldFiles)];
|
|
119
123
|
case SolidMediaType.mediaMultiple:
|
|
120
|
-
return this.validateMediaMultiple(fieldFiles);
|
|
124
|
+
return [...errors, ...this.validateMediaMultiple(fieldFiles)];
|
|
121
125
|
default:
|
|
122
|
-
return
|
|
126
|
+
return errors;
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
131
|
+
return fieldFiles
|
|
132
|
+
.filter(fieldFile => isDangerousMediaFile(fieldFile))
|
|
133
|
+
.map(fieldFile => ({
|
|
134
|
+
field: this.options.fieldName,
|
|
135
|
+
error: `${this.options.fieldName} file type not allowed. ` +
|
|
136
|
+
`${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
|
|
126
140
|
private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {
|
|
127
141
|
const errors: ValidationError[] = [];
|
|
128
142
|
if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
|
|
@@ -157,7 +171,7 @@ export class MediaFieldCrudManager implements FieldCrudManager {
|
|
|
157
171
|
for (let i = 0; i < fieldFiles.length; i++) {
|
|
158
172
|
const fieldFile = fieldFiles[i];
|
|
159
173
|
|
|
160
|
-
const resolvedType = this.resolveMediaType(fieldFile
|
|
174
|
+
const resolvedType = this.resolveMediaType(fieldFile);
|
|
161
175
|
if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {
|
|
162
176
|
errors.push({
|
|
163
177
|
field: this.options.fieldName,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Response } from "express";
|
|
2
|
+
|
|
3
|
+
export interface FileDownloadHeaderOptions {
|
|
4
|
+
fileName: string;
|
|
5
|
+
mimeType: string;
|
|
6
|
+
/** Defaults to 'attachment'; only pass 'inline' for types known safe to render. */
|
|
7
|
+
disposition?: "inline" | "attachment";
|
|
8
|
+
/** Opt in for assets loaded cross-origin by the UI (e.g. media served to :3000). */
|
|
9
|
+
crossOriginResourcePolicy?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Builds an RFC 6266 Content-Disposition value. The file name is attacker-controlled (it comes
|
|
14
|
+
* from the uploaded originalFileName), so it can't be interpolated raw: a quote would close the
|
|
15
|
+
* quoted-string early and let the rest of the name forge further header parameters. The ASCII
|
|
16
|
+
* fallback is stripped to a safe subset and the real name is carried in the RFC 5987
|
|
17
|
+
* `filename*` parameter, which is also what preserves non-ASCII names correctly.
|
|
18
|
+
*/
|
|
19
|
+
function buildContentDisposition(disposition: "inline" | "attachment", fileName: string): string {
|
|
20
|
+
const name = (fileName || "file").replace(/[\r\n]/g, "");
|
|
21
|
+
const asciiFallback = name.replace(/[^\x20-\x7E]/g, "_").replace(/["\\]/g, "_") || "file";
|
|
22
|
+
|
|
23
|
+
return `${disposition}; filename="${asciiFallback}"; filename*=UTF-8''${encodeURIComponent(name)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Single place that stamps the response headers for every streamed file download, so the
|
|
28
|
+
* security headers can't be applied to one endpoint and forgotten on the next.
|
|
29
|
+
*/
|
|
30
|
+
export function setFileDownloadHeaders(res: Response, options: FileDownloadHeaderOptions): void {
|
|
31
|
+
const disposition = options.disposition ?? "attachment";
|
|
32
|
+
|
|
33
|
+
res.setHeader("Content-Disposition", buildContentDisposition(disposition, options.fileName));
|
|
34
|
+
res.setHeader("Content-Type", options.mimeType);
|
|
35
|
+
res.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Type");
|
|
36
|
+
|
|
37
|
+
// Prevent the browser from ever content-sniffing a served file into something more
|
|
38
|
+
// dangerous than its declared Content-Type (e.g. rendering a mislabeled upload as HTML
|
|
39
|
+
// and executing embedded script).
|
|
40
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
41
|
+
|
|
42
|
+
if (options.crossOriginResourcePolicy) {
|
|
43
|
+
res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
|
|
4
4
|
import { _ } from "lodash";
|
|
5
|
+
import { DRAFT_PUBLISH_VERSIONING_FIELD_NAMES } from "src/constants/draft-publish-fields";
|
|
5
6
|
import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity-with-existing-id.entity";
|
|
6
7
|
import { LegacyTableType } from "src/enums/legacy-table-type.enum";
|
|
7
8
|
import { ModelMetadataRepository } from "src/repository/model-metadata.repository";
|
|
@@ -87,6 +88,32 @@ export class ModelMetadataHelperService {
|
|
|
87
88
|
isSystem: true,
|
|
88
89
|
enableAuditTracking:true
|
|
89
90
|
},
|
|
91
|
+
{
|
|
92
|
+
name: "isPublished",
|
|
93
|
+
displayName: "Is Published",
|
|
94
|
+
type: "boolean",
|
|
95
|
+
isSystem: true,
|
|
96
|
+
enableAuditTracking: true
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "isLatest",
|
|
100
|
+
displayName: "Is Latest",
|
|
101
|
+
type: "boolean",
|
|
102
|
+
isSystem: true,
|
|
103
|
+
enableAuditTracking: true
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "initialEntityVersionId",
|
|
107
|
+
displayName: "Initial Entity Version Id",
|
|
108
|
+
type: "int",
|
|
109
|
+
isSystem: true,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "publishedTracker",
|
|
113
|
+
displayName: "Published Tracker",
|
|
114
|
+
type: "shortText",
|
|
115
|
+
isSystem: true,
|
|
116
|
+
},
|
|
90
117
|
{
|
|
91
118
|
name: "localeName",
|
|
92
119
|
displayName: "Locale",
|
|
@@ -117,7 +144,11 @@ export class ModelMetadataHelperService {
|
|
|
117
144
|
}
|
|
118
145
|
|
|
119
146
|
private getSystemFieldsMetadataMappingForLegacyTable(withId: boolean=true) {
|
|
120
|
-
|
|
147
|
+
// Legacy tables don't have the draft/publish versioning columns, so exclude
|
|
148
|
+
// them from the legacy system fields metadata mapping.
|
|
149
|
+
const legacyExcludedFieldNames: readonly string[] = DRAFT_PUBLISH_VERSIONING_FIELD_NAMES;
|
|
150
|
+
const systemFieldsMetadata = this.getSystemFieldsMetadataMapping()
|
|
151
|
+
.filter(field => !legacyExcludedFieldNames.includes(field.name));
|
|
121
152
|
if (!withId) {
|
|
122
153
|
// Remove the id field metadata
|
|
123
154
|
const index = systemFieldsMetadata.findIndex(field => field.name === 'id');
|
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { HelmetOptions } from "helmet";
|
|
2
2
|
import { Environment } from "src/decorators/disallow-in-production.decorator";
|
|
3
3
|
|
|
4
|
+
export interface SolidSecurityOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Origins that may embed this application in an iframe.
|
|
7
|
+
* Defaults to the local HTTP/HTTPS loopback origins on any port.
|
|
8
|
+
*/
|
|
9
|
+
frameAncestors?: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_FRAME_ANCESTORS = [
|
|
13
|
+
"'self'",
|
|
14
|
+
"http://localhost:*",
|
|
15
|
+
"https://localhost:*",
|
|
16
|
+
"http://127.0.0.1:*",
|
|
17
|
+
"https://127.0.0.1:*",
|
|
18
|
+
"http://[::1]:*",
|
|
19
|
+
"https://[::1]:*",
|
|
20
|
+
];
|
|
21
|
+
|
|
4
22
|
/**
|
|
5
23
|
* Default security headers for SolidX apps.
|
|
6
24
|
* - HSTS only in prod over HTTPS
|
|
7
|
-
* - CSP with frame-ancestors
|
|
8
|
-
* - X-Frame-Options
|
|
25
|
+
* - CSP with configurable frame-ancestors
|
|
26
|
+
* - X-Frame-Options disabled when cross-origin frame ancestors are allowed
|
|
9
27
|
* - No X-XSS-Protection (deprecated)
|
|
10
28
|
*/
|
|
11
|
-
export function buildDefaultSecurityHeaderOptions(
|
|
29
|
+
export function buildDefaultSecurityHeaderOptions(
|
|
30
|
+
options: SolidSecurityOptions = {},
|
|
31
|
+
): Readonly<HelmetOptions> {
|
|
12
32
|
const isProd = process.env.ENV === Environment.Production;
|
|
33
|
+
const frameAncestors = options.frameAncestors ?? DEFAULT_FRAME_ANCESTORS;
|
|
34
|
+
const allowsCrossOriginFrames = frameAncestors.some(
|
|
35
|
+
(source) => source !== "'self'" && source !== "'none'",
|
|
36
|
+
);
|
|
13
37
|
|
|
14
38
|
return {
|
|
15
39
|
// Modern CSP. Add more directives as your app needs (script-src, connect-src, etc.)
|
|
@@ -23,7 +47,7 @@ export function buildDefaultSecurityHeaderOptions(): Readonly<HelmetOptions> {
|
|
|
23
47
|
// "form-action": ["'self'"],
|
|
24
48
|
|
|
25
49
|
// clickjacking defense (modern)
|
|
26
|
-
"frame-ancestors":
|
|
50
|
+
"frame-ancestors": frameAncestors,
|
|
27
51
|
"style-src": ["'self'"],
|
|
28
52
|
// add/adjust as needed for your app:
|
|
29
53
|
// "script-src": ["'self'"], // add hashes/nonces/CSPRO if needed
|
|
@@ -34,9 +58,12 @@ export function buildDefaultSecurityHeaderOptions(): Readonly<HelmetOptions> {
|
|
|
34
58
|
},
|
|
35
59
|
},
|
|
36
60
|
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
61
|
+
// Legacy clickjacking defense for configurations that do not allow
|
|
62
|
+
// cross-origin parents (kept for older UAs).
|
|
63
|
+
// X-Frame-Options cannot express an allowlist. It must be omitted when
|
|
64
|
+
// CSP allows a parent on another origin, otherwise older browsers may
|
|
65
|
+
// still block the iframe despite the CSP configuration.
|
|
66
|
+
frameguard: allowsCrossOriginFrames ? false : { action: "deny" },
|
|
40
67
|
|
|
41
68
|
// Referrer/cross-origin policies
|
|
42
69
|
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
|
|
@@ -115,4 +142,4 @@ export function setDefaultCacheControl() {
|
|
|
115
142
|
// res.setHeader("Permissions-Policy", buildPermissionsPolicyHeader());
|
|
116
143
|
// next();
|
|
117
144
|
// });
|
|
118
|
-
// app.use(setDefaultCacheControl());
|
|
145
|
+
// app.use(setDefaultCacheControl());
|
|
@@ -32,6 +32,59 @@ export class SolidCoreErrorCodesProvider implements IErrorCodeProvider {
|
|
|
32
32
|
httpStatus: 401,
|
|
33
33
|
},
|
|
34
34
|
},
|
|
35
|
+
// MPIN rules sit above the generic session rules so that an MPIN
|
|
36
|
+
// failure is never reported as a session problem. The three codes
|
|
37
|
+
// drive three different client behaviours: retry, wait, and
|
|
38
|
+
// discard-the-handle.
|
|
39
|
+
{
|
|
40
|
+
code: 'solidx-mpin-locked',
|
|
41
|
+
priority: 120,
|
|
42
|
+
match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_LOCKED.toLowerCase()),
|
|
43
|
+
meta: {
|
|
44
|
+
message: ERROR_MESSAGES.MPIN_LOCKED,
|
|
45
|
+
httpStatus: 401,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
code: 'solidx-mpin-revoked',
|
|
50
|
+
priority: 120,
|
|
51
|
+
match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_REVOKED.toLowerCase()),
|
|
52
|
+
meta: {
|
|
53
|
+
message: ERROR_MESSAGES.MPIN_REVOKED,
|
|
54
|
+
httpStatus: 401,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
code: 'solidx-mpin-invalid',
|
|
59
|
+
priority: 120,
|
|
60
|
+
match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_INVALID.toLowerCase()),
|
|
61
|
+
meta: {
|
|
62
|
+
message: ERROR_MESSAGES.MPIN_INVALID,
|
|
63
|
+
httpStatus: 401,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
// Setup-time rejections. Distinct codes so the client can say
|
|
67
|
+
// "choose a less predictable PIN" rather than parsing a message.
|
|
68
|
+
// Safe to distinguish: both occur only on bearer-authenticated
|
|
69
|
+
// routes, so neither discloses anything.
|
|
70
|
+
{
|
|
71
|
+
code: 'solidx-mpin-too-predictable',
|
|
72
|
+
priority: 120,
|
|
73
|
+
match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_TOO_PREDICTABLE.toLowerCase()),
|
|
74
|
+
meta: {
|
|
75
|
+
message: ERROR_MESSAGES.MPIN_TOO_PREDICTABLE,
|
|
76
|
+
httpStatus: 400,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
code: 'solidx-mpin-format-invalid',
|
|
81
|
+
priority: 120,
|
|
82
|
+
match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_FORMAT_INVALID.toLowerCase()),
|
|
83
|
+
meta: {
|
|
84
|
+
message: ERROR_MESSAGES.MPIN_FORMAT_INVALID,
|
|
85
|
+
httpStatus: 400,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
35
88
|
{
|
|
36
89
|
code: 'solidx-mcp-server-unavailable',
|
|
37
90
|
priority: 100,
|
|
@@ -79,7 +79,12 @@ export class SolidMicroserviceAdapter {
|
|
|
79
79
|
const responseData = response.data as SolidxIamAuthResponse;
|
|
80
80
|
const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);
|
|
81
81
|
if (ttlSeconds && ttlSeconds > 0) {
|
|
82
|
-
|
|
82
|
+
// cache-manager v5 expects milliseconds. This previously passed seconds,
|
|
83
|
+
// which the old Redis store discarded outright - so the entry simply
|
|
84
|
+
// never expired. Now that TTLs are honoured, passing seconds unconverted
|
|
85
|
+
// would expire the cached token ~1000x too early and re-authenticate
|
|
86
|
+
// against IAM on nearly every call.
|
|
87
|
+
await this.cacheManager.set(cacheKey, responseData, ttlSeconds * 1000);
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
return responseData;
|
|
@@ -366,7 +366,7 @@ export class SolidRegistry {
|
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
getCommonEntityKeys(): (keyof CommonEntity | 'createdBy' | 'updatedBy')[] {
|
|
369
|
-
return ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdBy', 'updatedBy', 'deletedTracker', 'localeName', 'defaultEntityLocaleId', 'publishedAt'];
|
|
369
|
+
return ['id', 'createdAt', 'updatedAt', 'deletedAt', 'createdBy', 'updatedBy', 'deletedTracker', 'localeName', 'defaultEntityLocaleId', 'publishedAt', 'isPublished', 'isLatest', 'initialEntityVersionId', 'publishedTracker'];
|
|
370
370
|
// return Reflect.getMetadataKeys(CommonEntity.prototype) as (keyof CommonEntity)[];
|
|
371
371
|
}
|
|
372
372
|
|
|
@@ -40,6 +40,14 @@ const DECIMAL_MAP: Record<DatasourceType, ColumnOptions> = {
|
|
|
40
40
|
[DatasourceType.oracle]: { type: "float" },
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
const DATE_TIME_MAP: Record<DatasourceType, ColumnOptions> = {
|
|
44
|
+
[DatasourceType.postgres]: { type: "timestamp" },
|
|
45
|
+
[DatasourceType.mssql]: { type: "datetime2" },
|
|
46
|
+
[DatasourceType.mysql]: { type: "datetime" },
|
|
47
|
+
[DatasourceType.mariadb]: { type: "datetime" },
|
|
48
|
+
[DatasourceType.oracle]: { type: "timestamp" },
|
|
49
|
+
};
|
|
50
|
+
|
|
43
51
|
const solidCoreDbType: DatasourceType =
|
|
44
52
|
Object.values(DatasourceType).includes(process.env.SOLID_CORE_DB_TYPE as DatasourceType)
|
|
45
53
|
? (process.env.SOLID_CORE_DB_TYPE as DatasourceType)
|
|
@@ -72,7 +80,10 @@ export function getColumnType(solidType: string): ColumnOptions {
|
|
|
72
80
|
case "decimal":
|
|
73
81
|
return DECIMAL_MAP[solidCoreDbType];
|
|
74
82
|
|
|
83
|
+
case "datetime":
|
|
84
|
+
return DATE_TIME_MAP[solidCoreDbType];
|
|
85
|
+
|
|
75
86
|
default:
|
|
76
87
|
return {};
|
|
77
88
|
}
|
|
78
|
-
}
|
|
89
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -160,6 +160,12 @@ export * from './entities/role-metadata.entity'
|
|
|
160
160
|
export * from './entities/sms-template.entity'
|
|
161
161
|
export * from './entities/user.entity'
|
|
162
162
|
export * from './entities/user-api-key.entity'
|
|
163
|
+
export * from './entities/user-device-credential.entity'
|
|
164
|
+
export * from './repository/user-device-credential.repository'
|
|
165
|
+
export * from './services/mpin.service'
|
|
166
|
+
export * from './dtos/setup-mpin.dto'
|
|
167
|
+
export * from './dtos/change-mpin.dto'
|
|
168
|
+
export * from './dtos/mpin-login.dto'
|
|
163
169
|
export * from './entities/view-metadata.entity'
|
|
164
170
|
export * from './entities/setting.entity'
|
|
165
171
|
export * from './entities/saved-filters.entity'
|
|
@@ -225,6 +231,7 @@ export * from './helpers/environment.helper'
|
|
|
225
231
|
export * from './helpers/cache.helper'
|
|
226
232
|
export * from './helpers/cors.helper'
|
|
227
233
|
export * from './helpers/security.helper'
|
|
234
|
+
export * from './helpers/file-download.helper'
|
|
228
235
|
export * from './helpers/model-metadata-helper.service'
|
|
229
236
|
export * from './helpers/image-encoding.helper'
|
|
230
237
|
export * from './helpers/solid-microservice-adapter.service'
|
|
@@ -248,10 +255,12 @@ export * from './services/workflow/workflow-expression.service'
|
|
|
248
255
|
export * from './services/workflow/workflow-invocation.service'
|
|
249
256
|
export * from './services/workflow/workflow-node-registry.service'
|
|
250
257
|
export * from './services/workflow/workflow-runtime.service'
|
|
258
|
+
export * from './services/workflow/nodes/execution-fail.node'
|
|
251
259
|
export * from './services/workflow/nodes/for-each.node'
|
|
252
260
|
export * from './services/workflow/nodes/http-request.node'
|
|
253
261
|
export * from './services/workflow/nodes/if.node'
|
|
254
262
|
export * from './services/workflow/nodes/log-write.node'
|
|
263
|
+
export * from './services/workflow/nodes/loop-until.node'
|
|
255
264
|
export * from './services/workflow/nodes/parallel.node'
|
|
256
265
|
export * from './services/workflow/nodes/sequential.node'
|
|
257
266
|
export * from './services/workflow/nodes/solidx-crud.nodes'
|
|
@@ -335,6 +344,7 @@ export * from './services/action-metadata.service'
|
|
|
335
344
|
export * from './services/authentication.service'
|
|
336
345
|
export * from './services/bcrypt.service'
|
|
337
346
|
export * from './services/computed-fields/uuid-external-id-computed-field-provider.service'
|
|
347
|
+
export * from './services/draft-publish-helper.service'
|
|
338
348
|
export * from './services/crud-helper.service'
|
|
339
349
|
export * from './services/crud.service'
|
|
340
350
|
export * from './services/email-template.service'
|