@solidxai/core 0.1.13-beta.8 → 0.1.13
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 +8568 -0
- package/README.md +19 -0
- package/dist/commands/run-tests.command.d.ts +2 -0
- package/dist/commands/run-tests.command.d.ts.map +1 -1
- package/dist/commands/run-tests.command.js +20 -3
- package/dist/commands/run-tests.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/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 +3 -0
- package/dist/constants/media-file-types.d.ts.map +1 -1
- package/dist/constants/media-file-types.js +47 -8
- 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/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/field-metadata.controller.d.ts +2 -2
- 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/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 +3 -6
- package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-field-metadata.dto.js +15 -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 -4
- package/dist/entities/common.entity.d.ts.map +1 -1
- package/dist/entities/common.entity.js +1 -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/field-metadata.entity.d.ts +1 -0
- package/dist/entities/field-metadata.entity.d.ts.map +1 -1
- package/dist/entities/field-metadata.entity.js +5 -1
- package/dist/entities/field-metadata.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.js +2 -2
- 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 +6 -5
- package/dist/entities/workflow-trigger-execution.entity.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 +6 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +54 -27
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/helpers/file-download.helper.d.ts.map +1 -1
- package/dist/helpers/file-download.helper.js +6 -1
- package/dist/helpers/file-download.helper.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/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 +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -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/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 +7 -3
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +168 -2
- 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 +5 -4
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +50 -19
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +5 -1
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +48 -13
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/crud-helper.service.d.ts +1 -2
- package/dist/services/crud-helper.service.d.ts.map +1 -1
- package/dist/services/crud-helper.service.js +2 -16
- package/dist/services/crud-helper.service.js.map +1 -1
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +2 -1
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/draft-publish-helper.service.d.ts +1 -0
- package/dist/services/draft-publish-helper.service.d.ts.map +1 -1
- package/dist/services/draft-publish-helper.service.js +38 -4
- package/dist/services/draft-publish-helper.service.js.map +1 -1
- 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 +4 -1
- package/dist/services/field-metadata.service.js.map +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.map +1 -1
- package/dist/services/media.service.js +1 -0
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/module-metadata.service.d.ts.map +1 -1
- package/dist/services/module-metadata.service.js +9 -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/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 +6 -1
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/settings/default-settings-provider.service.d.ts +206 -10
- package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
- package/dist/services/settings/default-settings-provider.service.js +120 -5
- package/dist/services/settings/default-settings-provider.service.js.map +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 +14 -39
- package/dist/solid-core.module.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/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/package.json +2 -2
- package/src/commands/run-tests.command.ts +17 -3
- package/src/config/cache.options.ts +9 -1
- package/src/constants/error-messages.ts +14 -0
- package/src/constants/media-file-types.ts +87 -9
- package/src/constants/success-messages.ts +5 -0
- package/src/controllers/authentication.controller.ts +5 -2
- package/src/controllers/mpin-authentication.controller.ts +67 -0
- package/src/dtos/change-mpin.dto.ts +18 -0
- package/src/dtos/create-field-metadata.dto.ts +17 -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 +8 -4
- package/src/entities/dashboard-user-layout.entity.ts +2 -2
- package/src/entities/field-metadata.entity.ts +3 -0
- package/src/entities/user-device-credential.entity.ts +130 -0
- package/src/entities/user.entity.ts +2 -2
- 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 +6 -5
- 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 +73 -34
- package/src/helpers/file-download.helper.ts +15 -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/typeorm-db-helper.ts +12 -1
- package/src/index.ts +6 -0
- package/src/interfaces/active-user-data.interface.ts +9 -0
- package/src/repository/user-device-credential.repository.ts +17 -0
- package/src/seeders/module-metadata-seeder.service.ts +11 -3
- package/src/seeders/seed-data/solid-core-metadata.json +168 -2
- package/src/services/api-key.service.ts +13 -1
- package/src/services/authentication.service.ts +127 -36
- package/src/services/chatter-message.service.ts +78 -15
- package/src/services/crud-helper.service.ts +19 -16
- package/src/services/crud.service.ts +3 -1
- package/src/services/draft-publish-helper.service.ts +56 -4
- package/src/services/field-metadata.service.ts +5 -2
- package/src/services/media-storage.utils.ts +26 -1
- package/src/services/media.service.ts +1 -0
- package/src/services/module-metadata.service.ts +10 -1
- package/src/services/mpin.service.ts +447 -0
- package/src/services/refresh-token-ids-storage.service.ts +229 -90
- package/src/services/setting.service.ts +8 -1
- package/src/services/settings/default-settings-provider.service.ts +131 -5
- package/src/solid-core.module.ts +26 -12
- package/src/testing/README.md +11 -1
- 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/theme/theme-registry.ts +181 -0
- package/CLAUDE.md +0 -26
|
@@ -61,34 +61,31 @@ class MediaFieldCrudManager {
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
const ext = (0, media_file_types_1.getLowercaseFileExtension)((0, media_file_types_1.getUploadedFileName)(file));
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
64
|
+
const extType = ext ? media_file_types_1.EXT_TO_MEDIA_TYPE[ext] : undefined;
|
|
65
|
+
if (!extType) {
|
|
66
|
+
return null;
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return 'video';
|
|
74
|
-
if (ext && media_file_types_1.EXT_TO_MEDIA_TYPE[ext]) {
|
|
75
|
-
return media_file_types_1.EXT_TO_MEDIA_TYPE[ext];
|
|
68
|
+
const mt = (file.mimetype || '').toLowerCase().trim();
|
|
69
|
+
const mimeType = MIME_TO_MEDIA_TYPE[mt]
|
|
70
|
+
?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);
|
|
71
|
+
if (mimeType && mimeType !== extType) {
|
|
72
|
+
return null;
|
|
76
73
|
}
|
|
77
|
-
return
|
|
74
|
+
return extType;
|
|
78
75
|
}
|
|
79
76
|
validate(dto, files) {
|
|
80
77
|
const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);
|
|
81
78
|
return this.applyValidations(fieldFiles);
|
|
82
79
|
}
|
|
83
80
|
applyValidations(fieldFiles) {
|
|
84
|
-
const
|
|
81
|
+
const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);
|
|
85
82
|
switch (this.options.type) {
|
|
86
83
|
case SolidMediaType.mediaSingle:
|
|
87
|
-
return [...
|
|
84
|
+
return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];
|
|
88
85
|
case SolidMediaType.mediaMultiple:
|
|
89
|
-
return [...
|
|
86
|
+
return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];
|
|
90
87
|
default:
|
|
91
|
-
return
|
|
88
|
+
return dangerousFileErrors;
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
91
|
validateDangerousFiles(fieldFiles) {
|
|
@@ -100,7 +97,15 @@ class MediaFieldCrudManager {
|
|
|
100
97
|
`${(0, media_file_types_1.getUploadedFileName)(fieldFile) || 'File'} is a potentially dangerous file type.`
|
|
101
98
|
}));
|
|
102
99
|
}
|
|
103
|
-
|
|
100
|
+
validateCommon(fieldFiles) {
|
|
101
|
+
return [
|
|
102
|
+
...this.validateRequired(fieldFiles),
|
|
103
|
+
...this.validateSize(fieldFiles),
|
|
104
|
+
...this.validateTypes(fieldFiles),
|
|
105
|
+
...this.validateAllowedExtensions(fieldFiles),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
validateRequired(fieldFiles) {
|
|
104
109
|
const errors = [];
|
|
105
110
|
if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {
|
|
106
111
|
errors.push({
|
|
@@ -108,12 +113,10 @@ class MediaFieldCrudManager {
|
|
|
108
113
|
error: `${this.options.fieldName} is required`
|
|
109
114
|
});
|
|
110
115
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
116
|
-
}
|
|
116
|
+
return errors;
|
|
117
|
+
}
|
|
118
|
+
validateSize(fieldFiles) {
|
|
119
|
+
const errors = [];
|
|
117
120
|
if (this.options.mediaMaxSizeKb) {
|
|
118
121
|
for (let i = 0; i < fieldFiles.length; i++) {
|
|
119
122
|
const fieldFile = fieldFiles[i];
|
|
@@ -126,6 +129,10 @@ class MediaFieldCrudManager {
|
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
132
|
+
return errors;
|
|
133
|
+
}
|
|
134
|
+
validateTypes(fieldFiles) {
|
|
135
|
+
const errors = [];
|
|
129
136
|
if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {
|
|
130
137
|
const allowedFileTypes = this.options.mediaTypes;
|
|
131
138
|
for (let i = 0; i < fieldFiles.length; i++) {
|
|
@@ -143,16 +150,36 @@ class MediaFieldCrudManager {
|
|
|
143
150
|
}
|
|
144
151
|
return errors;
|
|
145
152
|
}
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
if (!
|
|
153
|
+
validateAllowedExtensions(fieldFiles) {
|
|
154
|
+
const allowed = this.options.mediaAllowedExtensions;
|
|
155
|
+
if (!allowed || allowed.length === 0) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\./, '')));
|
|
159
|
+
return fieldFiles
|
|
160
|
+
.filter(fieldFile => {
|
|
161
|
+
const ext = (0, media_file_types_1.getLowercaseFileExtension)((0, media_file_types_1.getUploadedFileName)(fieldFile));
|
|
162
|
+
return !ext || !normalizedAllowed.has(ext);
|
|
163
|
+
})
|
|
164
|
+
.map(fieldFile => ({
|
|
165
|
+
field: this.options.fieldName,
|
|
166
|
+
error: `${this.options.fieldName} file type not allowed. ` +
|
|
167
|
+
`Allowed extensions: ${[...normalizedAllowed].join(', ')}.`
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
validateMediaSingle(fieldFiles) {
|
|
171
|
+
const errors = this.validateCommon(fieldFiles);
|
|
172
|
+
if (fieldFiles.length > 1) {
|
|
149
173
|
errors.push({
|
|
150
174
|
field: this.options.fieldName,
|
|
151
|
-
error: `${this.options.fieldName}
|
|
175
|
+
error: `${this.options.fieldName} must be a single file`
|
|
152
176
|
});
|
|
153
177
|
}
|
|
154
178
|
return errors;
|
|
155
179
|
}
|
|
180
|
+
validateMediaMultiple(fieldFiles) {
|
|
181
|
+
return this.validateCommon(fieldFiles);
|
|
182
|
+
}
|
|
156
183
|
transformForCreate(dto) {
|
|
157
184
|
return dto;
|
|
158
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from \"src/constants/media-file-types\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n};\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const mt = (file.mimetype || '').toLowerCase().trim();\n if (mt && MIME_TO_MEDIA_TYPE[mt]) {\n return MIME_TO_MEDIA_TYPE[mt];\n }\n\n // Some libs may send \"image/*\" etc. Treat broad families safely.\n if (mt.startsWith('image/')) return 'image';\n if (mt.startsWith('audio/')) return 'audio';\n if (mt.startsWith('video/')) return 'video';\n\n // Fallback to extension if provided (also covers generic/unrecognized\n // mimetypes such as application/octet-stream).\n if (ext && EXT_TO_MEDIA_TYPE[ext]) {\n return EXT_TO_MEDIA_TYPE[ext];\n }\n\n return null;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n // Runs for every media field type and regardless of the admin-configured mediaTypes\n // allowlist - a dangerous upload is never acceptable, so this must not sit behind\n // the optional type checks below.\n const errors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...errors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...errors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return errors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n // validate size\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n // validate type\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile);\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MediaFieldCrudManager.js","sourceRoot":"","sources":["../../../src/helpers/field-crud-managers/MediaFieldCrudManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldCrudManager, ValidationError } from \"src/interfaces\";\nimport { EXT_TO_MEDIA_TYPE, getLowercaseFileExtension, getUploadedFileName, isDangerousMediaFile, MediaCategory } from \"src/constants/media-file-types\";\n\nexport enum SolidMediaType {\n mediaSingle = 'mediaSingle',\n mediaMultiple = 'mediaMultiple'\n}\n\nexport interface MediaFieldOptions {\n type: SolidMediaType;\n required: boolean | undefined | null;\n fieldName: string | undefined | null;\n mediaMaxSizeKb: number | undefined | null;\n mediaTypes: string[];\n mediaAllowedExtensions?: string[] | null;\n isUpdate: boolean | undefined | null;\n}\n\ntype MediaType = MediaCategory;\n\nconst MIME_TO_MEDIA_TYPE: Record<string, MediaType> = {\n // Images\n 'image/png': 'image',\n 'image/jpeg': 'image',\n 'image/jpg': 'image',\n 'image/webp': 'image',\n 'image/gif': 'image',\n 'image/bmp': 'image',\n 'image/tiff': 'image',\n 'image/heic': 'image',\n 'image/heif': 'image',\n\n // Audio\n 'audio/mpeg': 'audio', // mp3\n 'audio/mp3': 'audio',\n 'audio/wav': 'audio',\n 'audio/x-wav': 'audio',\n 'audio/webm': 'audio',\n 'audio/ogg': 'audio',\n 'audio/aac': 'audio',\n 'audio/mp4': 'audio', // m4a often shows as audio/mp4\n 'audio/x-m4a': 'audio',\n 'audio/flac': 'audio',\n\n // Video\n 'video/mp4': 'video',\n 'video/mpeg': 'video',\n 'video/webm': 'video',\n 'video/ogg': 'video',\n 'video/quicktime': 'video', // mov\n 'video/x-msvideo': 'video', // avi\n 'video/x-matroska': 'video',// mkv\n 'video/3gpp': 'video',\n 'video/3gpp2': 'video',\n\n // Documents / files (treat as \"file\")\n 'application/pdf': 'pdf',\n 'text/plain': 'file',\n 'text/markdown': 'file',\n 'application/json': 'file',\n 'text/csv': 'file',\n\n // Office\n 'application/msword': 'file', // doc\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'file', // docx\n 'application/vnd.ms-excel': 'file', // xls\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'file', // xlsx\n 'application/vnd.ms-powerpoint': 'file', // ppt\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'file', // pptx,\n\n // Archives (optional)\n 'application/zip': 'file',\n 'application/x-zip-compressed': 'file',\n 'application/x-rar-compressed': 'file',\n 'application/x-7z-compressed': 'file',\n};\n\nexport class MediaFieldCrudManager implements FieldCrudManager {\n\n constructor(private readonly options: MediaFieldOptions) {\n }\n\n private resolveMediaType(file: Express.Multer.File): MediaType | null {\n // Belt-and-braces: dangerous files are already rejected outright by\n // validateDangerousFiles, but never let one resolve to a usable category.\n if (isDangerousMediaFile(file)) {\n return null;\n }\n\n // Extension is authoritative: a declared mimetype is fully attacker-controlled and\n // proved insufficient on its own (a .msi uploaded as image/png previously resolved to\n // 'image', since the mimetype match short-circuited before the extension was ever\n // checked). The extension must independently resolve to a known-safe category before\n // anything is accepted - not merely \"not on the denylist\".\n const ext = getLowercaseFileExtension(getUploadedFileName(file));\n const extType = ext ? EXT_TO_MEDIA_TYPE[ext] : undefined;\n if (!extType) {\n return null;\n }\n\n // The mimetype may only confirm or veto what the extension already established, never\n // grant a category on its own. A mimetype that doesn't resolve to anything (e.g.\n // application/octet-stream) has no opinion and is treated as agreeing.\n const mt = (file.mimetype || '').toLowerCase().trim();\n const mimeType = MIME_TO_MEDIA_TYPE[mt]\n ?? (mt.startsWith('image/') ? 'image' : mt.startsWith('audio/') ? 'audio' : mt.startsWith('video/') ? 'video' : undefined);\n if (mimeType && mimeType !== extType) {\n return null;\n }\n\n return extType;\n }\n\n validate(dto: any, files: Array<Express.Multer.File>): ValidationError[] {\n const fieldFiles = files.filter(file => file.fieldname === this.options.fieldName);\n return this.applyValidations(fieldFiles);\n }\n\n private applyValidations(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n // A dangerous upload is never acceptable, regardless of admin config, so this is the\n // only check that sits outside validateCommon() and can't be skipped either way below.\n const dangerousFileErrors = this.validateDangerousFiles(fieldFiles);\n\n switch (this.options.type) {\n case SolidMediaType.mediaSingle:\n return [...dangerousFileErrors, ...this.validateMediaSingle(fieldFiles)];\n case SolidMediaType.mediaMultiple:\n return [...dangerousFileErrors, ...this.validateMediaMultiple(fieldFiles)];\n default:\n return dangerousFileErrors;\n }\n }\n\n private validateDangerousFiles(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return fieldFiles\n .filter(fieldFile => isDangerousMediaFile(fieldFile))\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `${getUploadedFileName(fieldFile) || 'File'} is a potentially dangerous file type.`\n }));\n }\n\n // Every optional, admin-configured, per-field check - no-ops when its setting is unset -\n // shared between mediaSingle and mediaMultiple so neither can drift out of sync with it.\n private validateCommon(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return [\n ...this.validateRequired(fieldFiles),\n ...this.validateSize(fieldFiles),\n ...this.validateTypes(fieldFiles),\n ...this.validateAllowedExtensions(fieldFiles),\n ];\n }\n\n private validateRequired(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (!this.options.isUpdate && this.options.required && fieldFiles.length === 0) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} is required`\n });\n }\n return errors;\n }\n\n private validateSize(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (this.options.mediaMaxSizeKb) {\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n const fieldFileSizeInBytes = Math.ceil(fieldFile.size / 1024);\n if (fieldFileSizeInBytes > this.options.mediaMaxSizeKb) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} with size ${fieldFileSizeInBytes} KB exceeds max size limit of ${this.options.mediaMaxSizeKb} KB`\n });\n }\n }\n }\n return errors;\n }\n\n private validateTypes(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors: ValidationError[] = [];\n if (this.options.mediaTypes && this.options.mediaTypes.length > 0) {\n const allowedFileTypes = this.options.mediaTypes as MediaType[];\n\n for (let i = 0; i < fieldFiles.length; i++) {\n const fieldFile = fieldFiles[i];\n\n const resolvedType = this.resolveMediaType(fieldFile);\n if (!resolvedType || !allowedFileTypes.includes(resolvedType)) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed: ${allowedFileTypes.join(', ')}. ` +\n `Received mimetype: ${fieldFile.mimetype}${resolvedType ? ` (mapped to ${resolvedType})` : ''}`\n });\n }\n }\n }\n return errors;\n }\n\n private validateAllowedExtensions(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const allowed = this.options.mediaAllowedExtensions;\n if (!allowed || allowed.length === 0) {\n return [];\n }\n\n const normalizedAllowed = new Set(allowed.map(ext => ext.toLowerCase().replace(/^\\./, '')));\n return fieldFiles\n .filter(fieldFile => {\n const ext = getLowercaseFileExtension(getUploadedFileName(fieldFile));\n return !ext || !normalizedAllowed.has(ext);\n })\n .map(fieldFile => ({\n field: this.options.fieldName,\n error: `${this.options.fieldName} file type not allowed. ` +\n `Allowed extensions: ${[...normalizedAllowed].join(', ')}.`\n }));\n }\n\n private validateMediaSingle(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n const errors = this.validateCommon(fieldFiles);\n if (fieldFiles.length > 1) {\n errors.push({\n field: this.options.fieldName,\n error: `${this.options.fieldName} must be a single file`\n });\n }\n return errors;\n }\n\n private validateMediaMultiple(fieldFiles: Array<Express.Multer.File>): ValidationError[] {\n return this.validateCommon(fieldFiles);\n }\n\n transformForCreate(dto: any): any {\n return dto;\n }\n\n // Validation to be applied\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-download.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/file-download.helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IAEjB,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IAEtC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;
|
|
1
|
+
{"version":3,"file":"file-download.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/file-download.helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IAEjB,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IAEtC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAoBD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI,CAe9F"}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.setFileDownloadHeaders = setFileDownloadHeaders;
|
|
4
|
+
function buildContentDisposition(disposition, fileName) {
|
|
5
|
+
const name = (fileName || "file").replace(/[\r\n]/g, "");
|
|
6
|
+
const asciiFallback = name.replace(/[^\x20-\x7E]/g, "_").replace(/["\\]/g, "_") || "file";
|
|
7
|
+
return `${disposition}; filename="${asciiFallback}"; filename*=UTF-8''${encodeURIComponent(name)}`;
|
|
8
|
+
}
|
|
4
9
|
function setFileDownloadHeaders(res, options) {
|
|
5
10
|
const disposition = options.disposition ?? "attachment";
|
|
6
|
-
res.setHeader("Content-Disposition",
|
|
11
|
+
res.setHeader("Content-Disposition", buildContentDisposition(disposition, options.fileName));
|
|
7
12
|
res.setHeader("Content-Type", options.mimeType);
|
|
8
13
|
res.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Type");
|
|
9
14
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-download.helper.js","sourceRoot":"","sources":["../../src/helpers/file-download.helper.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"file-download.helper.js","sourceRoot":"","sources":["../../src/helpers/file-download.helper.ts"],"names":[],"mappings":";;AA6BA,wDAeC;AA1BD,SAAS,uBAAuB,CAAC,WAAoC,EAAE,QAAgB;IACrF,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACzD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC;IAE1F,OAAO,GAAG,WAAW,eAAe,aAAa,uBAAuB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACrG,CAAC;AAMD,SAAgB,sBAAsB,CAAC,GAAa,EAAE,OAAkC;IACtF,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,YAAY,CAAC;IAExD,GAAG,CAAC,SAAS,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7F,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,GAAG,CAAC,SAAS,CAAC,+BAA+B,EAAE,mCAAmC,CAAC,CAAC;IAKpF,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IAEnD,IAAI,OAAO,CAAC,yBAAyB,EAAE,CAAC;QACtC,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;IAChE,CAAC;AACH,CAAC","sourcesContent":["import type { Response } from \"express\";\n\nexport interface FileDownloadHeaderOptions {\n fileName: string;\n mimeType: string;\n /** Defaults to 'attachment'; only pass 'inline' for types known safe to render. */\n disposition?: \"inline\" | \"attachment\";\n /** Opt in for assets loaded cross-origin by the UI (e.g. media served to :3000). */\n crossOriginResourcePolicy?: boolean;\n}\n\n/**\n * Builds an RFC 6266 Content-Disposition value. The file name is attacker-controlled (it comes\n * from the uploaded originalFileName), so it can't be interpolated raw: a quote would close the\n * quoted-string early and let the rest of the name forge further header parameters. The ASCII\n * fallback is stripped to a safe subset and the real name is carried in the RFC 5987\n * `filename*` parameter, which is also what preserves non-ASCII names correctly.\n */\nfunction buildContentDisposition(disposition: \"inline\" | \"attachment\", fileName: string): string {\n const name = (fileName || \"file\").replace(/[\\r\\n]/g, \"\");\n const asciiFallback = name.replace(/[^\\x20-\\x7E]/g, \"_\").replace(/[\"\\\\]/g, \"_\") || \"file\";\n\n return `${disposition}; filename=\"${asciiFallback}\"; filename*=UTF-8''${encodeURIComponent(name)}`;\n}\n\n/**\n * Single place that stamps the response headers for every streamed file download, so the\n * security headers can't be applied to one endpoint and forgotten on the next.\n */\nexport function setFileDownloadHeaders(res: Response, options: FileDownloadHeaderOptions): void {\n const disposition = options.disposition ?? \"attachment\";\n\n res.setHeader(\"Content-Disposition\", buildContentDisposition(disposition, options.fileName));\n res.setHeader(\"Content-Type\", options.mimeType);\n res.setHeader(\"Access-Control-Expose-Headers\", \"Content-Disposition, Content-Type\");\n\n // Prevent the browser from ever content-sniffing a served file into something more\n // dangerous than its declared Content-Type (e.g. rendering a mislabeled upload as HTML\n // and executing embedded script).\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\n\n if (options.crossOriginResourcePolicy) {\n res.setHeader(\"Cross-Origin-Resource-Policy\", \"cross-origin\");\n }\n}\n"]}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { HelmetOptions } from "helmet";
|
|
2
|
-
export
|
|
2
|
+
export interface SolidSecurityOptions {
|
|
3
|
+
frameAncestors?: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare const DEFAULT_FRAME_ANCESTORS: string[];
|
|
6
|
+
export declare function buildDefaultSecurityHeaderOptions(options?: SolidSecurityOptions): Readonly<HelmetOptions>;
|
|
3
7
|
type Source = "self" | "none" | string;
|
|
4
8
|
type DirectiveConfig = "self" | "none" | Source[];
|
|
5
9
|
export type PermissionsPolicyConfig = Record<string, DirectiveConfig>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/security.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"security.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/security.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAGvC,MAAM,WAAW,oBAAoB;IAKnC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,uBAAuB,UAQnC,CAAC;AASF,wBAAgB,iCAAiC,CAC/C,OAAO,GAAE,oBAAyB,GACjC,QAAQ,CAAC,aAAa,CAAC,CA+CzB;AAID,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AACvC,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAClD,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEtE,eAAO,MAAM,0BAA0B,EAAE,uBAaxC,CAAC;AAEF,wBAAgB,4BAA4B,CAC1C,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,MAAM,CAKR;AAeD,eAAO,MAAM,qBAAqB,iFAC8C,CAAC;AAEjF,wBAAgB,sBAAsB,KAElC,MAAM,OAAO,SAAS,EAAE,OAAO,EAC/B,MAAM,OAAO,SAAS,EAAE,QAAQ,EAChC,MAAM,OAAO,SAAS,EAAE,YAAY,UAKvC"}
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_CACHE_CONTROL = exports.DEFAULT_PERMISSIONS_POLICY = void 0;
|
|
3
|
+
exports.DEFAULT_CACHE_CONTROL = exports.DEFAULT_PERMISSIONS_POLICY = exports.DEFAULT_FRAME_ANCESTORS = void 0;
|
|
4
4
|
exports.buildDefaultSecurityHeaderOptions = buildDefaultSecurityHeaderOptions;
|
|
5
5
|
exports.buildPermissionsPolicyHeader = buildPermissionsPolicyHeader;
|
|
6
6
|
exports.setDefaultCacheControl = setDefaultCacheControl;
|
|
7
7
|
const disallow_in_production_decorator_1 = require("../decorators/disallow-in-production.decorator");
|
|
8
|
-
|
|
8
|
+
exports.DEFAULT_FRAME_ANCESTORS = [
|
|
9
|
+
"'self'",
|
|
10
|
+
"http://localhost:*",
|
|
11
|
+
"https://localhost:*",
|
|
12
|
+
"http://127.0.0.1:*",
|
|
13
|
+
"https://127.0.0.1:*",
|
|
14
|
+
"http://[::1]:*",
|
|
15
|
+
"https://[::1]:*",
|
|
16
|
+
];
|
|
17
|
+
function buildDefaultSecurityHeaderOptions(options = {}) {
|
|
9
18
|
const isProd = process.env.ENV === disallow_in_production_decorator_1.Environment.Production;
|
|
19
|
+
const frameAncestors = options.frameAncestors ?? exports.DEFAULT_FRAME_ANCESTORS;
|
|
20
|
+
const allowsCrossOriginFrames = frameAncestors.some((source) => source !== "'self'" && source !== "'none'");
|
|
10
21
|
return {
|
|
11
22
|
contentSecurityPolicy: {
|
|
12
23
|
useDefaults: true,
|
|
13
24
|
directives: {
|
|
14
|
-
"frame-ancestors":
|
|
25
|
+
"frame-ancestors": frameAncestors,
|
|
15
26
|
"style-src": ["'self'"],
|
|
16
27
|
},
|
|
17
28
|
},
|
|
18
|
-
frameguard: { action: "deny" },
|
|
29
|
+
frameguard: allowsCrossOriginFrames ? false : { action: "deny" },
|
|
19
30
|
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
|
|
20
31
|
crossOriginEmbedderPolicy: false,
|
|
21
32
|
crossOriginResourcePolicy: { policy: "same-site" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.helper.js","sourceRoot":"","sources":["../../src/helpers/security.helper.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"security.helper.js","sourceRoot":"","sources":["../../src/helpers/security.helper.ts"],"names":[],"mappings":"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","sourcesContent":["import { HelmetOptions } from \"helmet\";\nimport { Environment } from \"src/decorators/disallow-in-production.decorator\";\n\nexport interface SolidSecurityOptions {\n /**\n * Origins that may embed this application in an iframe.\n * Defaults to the local HTTP/HTTPS loopback origins on any port.\n */\n frameAncestors?: string[];\n}\n\nexport const DEFAULT_FRAME_ANCESTORS = [\n \"'self'\",\n \"http://localhost:*\",\n \"https://localhost:*\",\n \"http://127.0.0.1:*\",\n \"https://127.0.0.1:*\",\n \"http://[::1]:*\",\n \"https://[::1]:*\",\n];\n\n/**\n * Default security headers for SolidX apps.\n * - HSTS only in prod over HTTPS\n * - CSP with configurable frame-ancestors\n * - X-Frame-Options disabled when cross-origin frame ancestors are allowed\n * - No X-XSS-Protection (deprecated)\n */\nexport function buildDefaultSecurityHeaderOptions(\n options: SolidSecurityOptions = {},\n): Readonly<HelmetOptions> {\n const isProd = process.env.ENV === Environment.Production;\n const frameAncestors = options.frameAncestors ?? DEFAULT_FRAME_ANCESTORS;\n const allowsCrossOriginFrames = frameAncestors.some(\n (source) => source !== \"'self'\" && source !== \"'none'\",\n );\n\n return {\n // Modern CSP. Add more directives as your app needs (script-src, connect-src, etc.)\n contentSecurityPolicy: {\n useDefaults: true,\n directives: {\n // sensible secure defaults\n // \"default-src\": [\"'self'\"],\n // \"base-uri\": [\"'self'\"],\n // \"object-src\": [\"'none'\"],\n // \"form-action\": [\"'self'\"],\n\n // clickjacking defense (modern)\n \"frame-ancestors\": frameAncestors,\n \"style-src\": [\"'self'\"],\n // add/adjust as needed for your app:\n // \"script-src\": [\"'self'\"], // add hashes/nonces/CSPRO if needed\n // \"style-src\": [\"'self'\", \"'unsafe-inline'\"],\n // \"img-src\": [\"'self'\", \"data:\"],\n // \"connect-src\": [\"'self'\", \"https://api.example.com\"],\n // \"frame-src\": [\"'none'\"], // iframes you intentionally allow\n },\n },\n\n // Legacy clickjacking defense for configurations that do not allow\n // cross-origin parents (kept for older UAs).\n // X-Frame-Options cannot express an allowlist. It must be omitted when\n // CSP allows a parent on another origin, otherwise older browsers may\n // still block the iframe despite the CSP configuration.\n frameguard: allowsCrossOriginFrames ? false : { action: \"deny\" },\n\n // Referrer/cross-origin policies\n referrerPolicy: { policy: \"strict-origin-when-cross-origin\" },\n crossOriginEmbedderPolicy: false,\n crossOriginResourcePolicy: { policy: \"same-site\" },\n\n // HSTS only when you’re on HTTPS in production\n hsts: isProd\n ? { maxAge: 31536000, includeSubDomains: true, preload: true }\n : false,\n };\n}\n\n/* ---------------- Permissions-Policy (formerly Feature-Policy) ---------------- */\n\ntype Source = \"self\" | \"none\" | string;\ntype DirectiveConfig = \"self\" | \"none\" | Source[];\nexport type PermissionsPolicyConfig = Record<string, DirectiveConfig>;\n\nexport const DEFAULT_PERMISSIONS_POLICY: PermissionsPolicyConfig = {\n camera: \"none\",\n microphone: \"none\",\n geolocation: \"none\",\n fullscreen: \"self\",\n payment: \"none\",\n accelerometer: \"none\",\n autoplay: \"none\",\n \"clipboard-read\": \"none\",\n \"clipboard-write\": \"none\",\n gyroscope: \"none\",\n magnetometer: \"none\",\n usb: \"none\",\n};\n\nexport function buildPermissionsPolicyHeader(\n overrides: Partial<PermissionsPolicyConfig> = {}\n): string {\n const merged: PermissionsPolicyConfig = { ...DEFAULT_PERMISSIONS_POLICY, ...overrides };\n return Object.entries(merged)\n .map(([feature, value]) => `${feature}=${serializeValue(value)}`)\n .join(\", \");\n}\n\nfunction serializeValue(v: DirectiveConfig): string {\n if (v === \"none\") return \"()\";\n if (v === \"self\") return \"(self)\";\n const parts = v.map((src) => (src === \"self\" ? \"self\" : src)).join(\" \");\n return `(${parts})`;\n}\n\n/* ---------------- Cache-Control helpers ---------------- */\n\n/**\n * Default: no-store for HTML/API responses unless you have a reason to cache.\n * Attach as a global middleware or on selected routes.\n */\nexport const DEFAULT_CACHE_CONTROL =\n \"no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0\";\n\nexport function setDefaultCacheControl() {\n return function cacheControlMiddleware(\n _req: import(\"express\").Request,\n _res: import(\"express\").Response,\n next: import(\"express\").NextFunction\n ) {\n _res.setHeader(\"Cache-Control\", DEFAULT_CACHE_CONTROL);\n next();\n };\n}\n\n/* ---------------- Example Express wiring ---------------- */\n// import express from \"express\";\n// const app = express();\n// app.use(helmet(buildDefaultSecurityHeaderOptions()));\n// app.use((req, res, next) => {\n// res.setHeader(\"Permissions-Policy\", buildPermissionsPolicyHeader());\n// next();\n// });\n// app.use(setDefaultCacheControl());\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-core-error-codes-provider.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-core-error-codes-provider.service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG1E,qBAEa,2BAA4B,YAAW,kBAAkB;IAClE,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,aAAa,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"solid-core-error-codes-provider.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-core-error-codes-provider.service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG1E,qBAEa,2BAA4B,YAAW,kBAAkB;IAClE,IAAI,IAAI,MAAM;IAId,KAAK,IAAI,aAAa,CAAC,SAAS,CAAC;IA6HjC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;CAI/C"}
|
|
@@ -34,6 +34,51 @@ let SolidCoreErrorCodesProvider = class SolidCoreErrorCodesProvider {
|
|
|
34
34
|
httpStatus: 401,
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
code: 'solidx-mpin-locked',
|
|
39
|
+
priority: 120,
|
|
40
|
+
match: (txt) => txt.includes(error_messages_1.ERROR_MESSAGES.MPIN_LOCKED.toLowerCase()),
|
|
41
|
+
meta: {
|
|
42
|
+
message: error_messages_1.ERROR_MESSAGES.MPIN_LOCKED,
|
|
43
|
+
httpStatus: 401,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
code: 'solidx-mpin-revoked',
|
|
48
|
+
priority: 120,
|
|
49
|
+
match: (txt) => txt.includes(error_messages_1.ERROR_MESSAGES.MPIN_REVOKED.toLowerCase()),
|
|
50
|
+
meta: {
|
|
51
|
+
message: error_messages_1.ERROR_MESSAGES.MPIN_REVOKED,
|
|
52
|
+
httpStatus: 401,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
code: 'solidx-mpin-invalid',
|
|
57
|
+
priority: 120,
|
|
58
|
+
match: (txt) => txt.includes(error_messages_1.ERROR_MESSAGES.MPIN_INVALID.toLowerCase()),
|
|
59
|
+
meta: {
|
|
60
|
+
message: error_messages_1.ERROR_MESSAGES.MPIN_INVALID,
|
|
61
|
+
httpStatus: 401,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
code: 'solidx-mpin-too-predictable',
|
|
66
|
+
priority: 120,
|
|
67
|
+
match: (txt) => txt.includes(error_messages_1.ERROR_MESSAGES.MPIN_TOO_PREDICTABLE.toLowerCase()),
|
|
68
|
+
meta: {
|
|
69
|
+
message: error_messages_1.ERROR_MESSAGES.MPIN_TOO_PREDICTABLE,
|
|
70
|
+
httpStatus: 400,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
code: 'solidx-mpin-format-invalid',
|
|
75
|
+
priority: 120,
|
|
76
|
+
match: (txt) => txt.includes(error_messages_1.ERROR_MESSAGES.MPIN_FORMAT_INVALID.toLowerCase()),
|
|
77
|
+
meta: {
|
|
78
|
+
message: error_messages_1.ERROR_MESSAGES.MPIN_FORMAT_INVALID,
|
|
79
|
+
httpStatus: 400,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
37
82
|
{
|
|
38
83
|
code: 'solidx-mcp-server-unavailable',
|
|
39
84
|
priority: 100,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-core-error-codes-provider.service.js","sourceRoot":"","sources":["../../src/helpers/solid-core-error-codes-provider.service.ts"],"names":[],"mappings":";;;;;;;;;AACA,2CAA4C;AAC5C,gEAA8D;AAC9D,iGAAkF;AAM3E,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACpC,IAAI;QACA,OAAO,4BAA4B,CAAC;IACxC,CAAC;IAED,KAAK;QACD,OAAO;YACH;gBACI,IAAI,EAAE,wBAAwB;gBAC9B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;gBAC1E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,eAAe;oBACvC,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,wBAAwB;gBAC9B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;gBAC1E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,eAAe;oBACvC,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,+BAA+B;gBACrC,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CACX,GAAG,CAAC,QAAQ,CAAC,gCAAgC,CAAC;oBAC9C,GAAG,CAAC,QAAQ,CAAC,mDAAmD,CAAC;gBACrE,IAAI,EAAE;oBACF,OAAO,EAAE,mEAAmE;oBAC5E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,2BAA2B;gBACjC,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,2BAA2B,CAAC;gBACnF,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,kBAAkB;oBAC1C,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,yBAAyB;gBAC/B,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC;gBAClF,IAAI,EAAE;oBACF,OAAO,EAAE,qEAAqE;oBAC9E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,6BAA6B;gBACnC,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBACpD,IAAI,EAAE;oBACF,OAAO,EACH,wEAAwE;oBAC5E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,CAAC,CAAC;gBACZ,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI;gBACrB,IAAI,EAAE;oBACF,OAAO,EAAE,+BAA+B;oBACxC,UAAU,EAAE,GAAG;iBAClB;aACJ;SACJ,CAAC;IACN,CAAC;IAGD,OAAO,CAAC,IAAY;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACvD,OAAO,IAAI,EAAE,IAAI,CAAC;IACtB,CAAC;CACJ,CAAA;
|
|
1
|
+
{"version":3,"file":"solid-core-error-codes-provider.service.js","sourceRoot":"","sources":["../../src/helpers/solid-core-error-codes-provider.service.ts"],"names":[],"mappings":";;;;;;;;;AACA,2CAA4C;AAC5C,gEAA8D;AAC9D,iGAAkF;AAM3E,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACpC,IAAI;QACA,OAAO,4BAA4B,CAAC;IACxC,CAAC;IAED,KAAK;QACD,OAAO;YACH;gBACI,IAAI,EAAE,wBAAwB;gBAC9B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;gBAC1E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,eAAe;oBACvC,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,wBAAwB;gBAC9B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;gBAC1E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,eAAe;oBACvC,UAAU,EAAE,GAAG;iBAClB;aACJ;YAKD;gBACI,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;gBACtE,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,WAAW;oBACnC,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,qBAAqB;gBAC3B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;gBACvE,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,YAAY;oBACpC,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,qBAAqB;gBAC3B,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;gBACvE,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,YAAY;oBACpC,UAAU,EAAE,GAAG;iBAClB;aACJ;YAKD;gBACI,IAAI,EAAE,6BAA6B;gBACnC,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,oBAAoB,CAAC,WAAW,EAAE,CAAC;gBAC/E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,oBAAoB;oBAC5C,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,4BAA4B;gBAClC,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,+BAAc,CAAC,mBAAmB,CAAC,WAAW,EAAE,CAAC;gBAC9E,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,mBAAmB;oBAC3C,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,+BAA+B;gBACrC,QAAQ,EAAE,GAAG;gBACb,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CACX,GAAG,CAAC,QAAQ,CAAC,gCAAgC,CAAC;oBAC9C,GAAG,CAAC,QAAQ,CAAC,mDAAmD,CAAC;gBACrE,IAAI,EAAE;oBACF,OAAO,EAAE,mEAAmE;oBAC5E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,2BAA2B;gBACjC,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,2BAA2B,CAAC;gBACnF,IAAI,EAAE;oBACF,OAAO,EAAE,+BAAc,CAAC,kBAAkB;oBAC1C,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,yBAAyB;gBAC/B,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC;gBAClF,IAAI,EAAE;oBACF,OAAO,EAAE,qEAAqE;oBAC9E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,6BAA6B;gBACnC,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC;gBACpD,IAAI,EAAE;oBACF,OAAO,EACH,wEAAwE;oBAC5E,UAAU,EAAE,GAAG;iBAClB;aACJ;YACD;gBACI,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,CAAC,CAAC;gBACZ,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI;gBACrB,IAAI,EAAE;oBACF,OAAO,EAAE,+BAA+B;oBACxC,UAAU,EAAE,GAAG;iBAClB;aACJ;SACJ,CAAC;IACN,CAAC;IAGD,OAAO,CAAC,IAAY;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACvD,OAAO,IAAI,EAAE,IAAI,CAAC;IACtB,CAAC;CACJ,CAAA;AAtIY,kEAA2B;sCAA3B,2BAA2B;IAFvC,IAAA,kDAAiB,GAAE;IACnB,IAAA,mBAAU,GAAE;GACA,2BAA2B,CAsIvC","sourcesContent":["// src/common/errors/providers/solidcore-error-code.provider.ts\nimport { Injectable } from '@nestjs/common';\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { ErrorCodeProvider } from 'src/decorators/error-codes-provider.decorator';\nimport { ErrorMeta, ErrorRule, IErrorCodeProvider } from 'src/interfaces';\n\n\n@ErrorCodeProvider()\n@Injectable()\nexport class SolidCoreErrorCodesProvider implements IErrorCodeProvider {\n name(): string {\n return 'SolidCoreErrorCodeProvider';\n }\n\n rules(): ReadonlyArray<ErrorRule> {\n return [\n {\n code: 'solidx-session-invalid',\n priority: 110,\n match: (txt) => txt.includes(ERROR_MESSAGES.SESSION_INVALID.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.SESSION_INVALID,\n httpStatus: 401,\n },\n },\n {\n code: 'solidx-session-expired',\n priority: 110,\n match: (txt) => txt.includes(ERROR_MESSAGES.SESSION_EXPIRED.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.SESSION_EXPIRED,\n httpStatus: 401,\n },\n },\n // MPIN rules sit above the generic session rules so that an MPIN\n // failure is never reported as a session problem. The three codes\n // drive three different client behaviours: retry, wait, and\n // discard-the-handle.\n {\n code: 'solidx-mpin-locked',\n priority: 120,\n match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_LOCKED.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.MPIN_LOCKED,\n httpStatus: 401,\n },\n },\n {\n code: 'solidx-mpin-revoked',\n priority: 120,\n match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_REVOKED.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.MPIN_REVOKED,\n httpStatus: 401,\n },\n },\n {\n code: 'solidx-mpin-invalid',\n priority: 120,\n match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_INVALID.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.MPIN_INVALID,\n httpStatus: 401,\n },\n },\n // Setup-time rejections. Distinct codes so the client can say\n // \"choose a less predictable PIN\" rather than parsing a message.\n // Safe to distinguish: both occur only on bearer-authenticated\n // routes, so neither discloses anything.\n {\n code: 'solidx-mpin-too-predictable',\n priority: 120,\n match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_TOO_PREDICTABLE.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.MPIN_TOO_PREDICTABLE,\n httpStatus: 400,\n },\n },\n {\n code: 'solidx-mpin-format-invalid',\n priority: 120,\n match: (txt) => txt.includes(ERROR_MESSAGES.MPIN_FORMAT_INVALID.toLowerCase()),\n meta: {\n message: ERROR_MESSAGES.MPIN_FORMAT_INVALID,\n httpStatus: 400,\n },\n },\n {\n code: 'solidx-mcp-server-unavailable',\n priority: 100,\n match: (txt) =>\n txt.includes('all connection attempts failed') &&\n txt.includes('unhandled errors in a taskgroup (1 sub-exception)'),\n meta: {\n message: 'SolidX MCP server is unreachable. Please verify the MCP endpoint.',\n httpStatus: 503,\n },\n },\n {\n code: 'solidx-resource-not-found',\n priority: 95,\n match: (txt) => txt.includes('enoent') && txt.includes('no such file or directory'),\n meta: {\n message: ERROR_MESSAGES.RESOURCE_NOT_FOUND,\n httpStatus: 404,\n },\n },\n {\n code: 'solidx-db-duplicate-key',\n priority: 90,\n match: (txt) => txt.includes('unique constraint') || txt.includes('duplicate key'),\n meta: {\n message: 'Duplicate key violation. A record with these values already exists.',\n httpStatus: 409,\n },\n },\n {\n code: 'solidx-db-foreign-key-error',\n priority: 90,\n match: (txt) => txt.includes('violates foreign key'),\n meta: {\n message:\n 'Foreign key constraint prevents this operation due to related records.',\n httpStatus: 409,\n },\n },\n {\n code: 'solidx-unknown-error',\n priority: -1, // last resort\n match: (_txt) => true, // fallback catch-all\n meta: {\n message: 'An unexpected error occurred.',\n httpStatus: 500,\n },\n },\n ];\n }\n\n // Optional explicit meta resolution (if you want)\n resolve(code: string): ErrorMeta | undefined {\n const rule = this.rules().find((r) => r.code === code);\n return rule?.meta;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-microservice-adapter.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED,qBACa,wBAAwB;IAIA,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHhE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,OAAO,CAAC,CAAS;gBAE2B,YAAY,EAAE,KAAK;IAEvE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"solid-microservice-adapter.service.d.ts","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAED,qBACa,wBAAwB;IAIA,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHhE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6C;IACpE,OAAO,CAAC,OAAO,CAAC,CAAS;gBAE2B,YAAY,EAAE,KAAK;IAEvE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK3B,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA+CvG,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,iBAAiB;CAK1B"}
|
|
@@ -61,7 +61,7 @@ let SolidMicroserviceAdapter = SolidMicroserviceAdapter_1 = class SolidMicroserv
|
|
|
61
61
|
const responseData = response.data;
|
|
62
62
|
const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);
|
|
63
63
|
if (ttlSeconds && ttlSeconds > 0) {
|
|
64
|
-
await this.cacheManager.set(cacheKey, responseData, ttlSeconds);
|
|
64
|
+
await this.cacheManager.set(cacheKey, responseData, ttlSeconds * 1000);
|
|
65
65
|
}
|
|
66
66
|
return responseData;
|
|
67
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-microservice-adapter.service.js","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,yDAAsD;AACtD,2CAAmE;AACnE,kDAA0B;AAgCnB,IAAM,wBAAwB,gCAA9B,MAAM,wBAAwB;IAInC,YAAmC,YAAoC;QAAnB,iBAAY,GAAZ,YAAY,CAAO;QAHtD,WAAM,GAAG,IAAI,eAAM,CAAC,0BAAwB,CAAC,IAAI,CAAC,CAAC;IAGM,CAAC;IAE3E,UAAU,CAAC,OAAe;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAwB;QACpE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,cAAc,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAsC,CAAC;QACpG,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;YACxD,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;QAEzD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,OAAO,GAAyB,EAAE,QAAQ,EAAE,CAAC;QACnD,IAAI,KAAK;YAAE,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACjC,IAAI,QAAQ;YAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAE1C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,IAAI,CAAC,OAAO,uBAAuB,CAAC,CAAC;QAE3F,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,uBAAuB,EAAE,OAAO,EAAE;YACjF,OAAO,EAAE,KAAK;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,QAAQ,CAAC,IAA6B,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAC1E,IAAI,UAAU,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"solid-microservice-adapter.service.js","sourceRoot":"","sources":["../../src/helpers/solid-microservice-adapter.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { CACHE_MANAGER } from '@nestjs/cache-manager';\nimport { Inject, Injectable, Logger, Scope } from '@nestjs/common';\nimport axios from 'axios';\nimport { Cache } from 'cache-manager';\n\nexport interface SolidxIamAuthRequest {\n email?: string;\n username?: string;\n password: string;\n}\n\nexport interface SolidxIamUser {\n email: string;\n mobile: string;\n username: string;\n forcePasswordChange: boolean;\n id: number;\n roles: string[];\n}\n\nexport interface SolidxIamAuthData {\n user: SolidxIamUser;\n accessToken: string;\n refreshToken: string;\n}\n\nexport interface SolidxIamAuthResponse {\n statusCode: number;\n message: string[];\n error: string;\n data: SolidxIamAuthData;\n}\n\n@Injectable({ scope: Scope.TRANSIENT })\nexport class SolidMicroserviceAdapter {\n private readonly logger = new Logger(SolidMicroserviceAdapter.name);\n private baseUrl?: string;\n\n constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {}\n\n setBaseUrl(baseUrl: string): this {\n this.baseUrl = baseUrl;\n return this;\n }\n\n async authenticate({ email, username, password }: SolidxIamAuthRequest): Promise<SolidxIamAuthResponse> {\n if (!password) {\n throw new Error('password is required for IAM authentication');\n }\n if (!email && !username) {\n throw new Error('email or username is required for IAM authentication');\n }\n\n const cacheKey = this.getAuthCacheKey(email, username);\n const cachedResponse = (await this.cacheManager.get(cacheKey)) as SolidxIamAuthResponse | undefined;\n if (cachedResponse) {\n this.logger.debug(`IAM auth cache hit for ${cacheKey}`);\n return cachedResponse;\n }\n this.logger.debug(`IAM auth cache miss for ${cacheKey}`);\n\n if (!this.baseUrl) {\n throw new Error('baseUrl must be set before IAM authentication');\n }\n\n const payload: SolidxIamAuthRequest = { password };\n if (email) payload.email = email;\n if (username) payload.username = username;\n\n this.logger.debug(`Requesting IAM access token from ${this.baseUrl}/api/iam/authenticate`);\n\n const response = await axios.post(`${this.baseUrl}/api/iam/authenticate`, payload, {\n timeout: 10000,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n const responseData = response.data as SolidxIamAuthResponse;\n const ttlSeconds = this.getJwtTtlSeconds(responseData?.data?.accessToken);\n if (ttlSeconds && ttlSeconds > 0) {\n // cache-manager v5 expects milliseconds. This previously passed seconds,\n // which the old Redis store discarded outright - so the entry simply\n // never expired. Now that TTLs are honoured, passing seconds unconverted\n // would expire the cached token ~1000x too early and re-authenticate\n // against IAM on nearly every call.\n await this.cacheManager.set(cacheKey, responseData, ttlSeconds * 1000);\n }\n\n return responseData;\n }\n\n private getAuthCacheKey(email?: string, username?: string): string {\n return `iam-auth:${email ?? ''}:${username ?? ''}`;\n }\n\n private getJwtTtlSeconds(accessToken?: string): number | undefined {\n if (!accessToken) return undefined;\n const parts = accessToken.split('.');\n if (parts.length < 2) return undefined;\n try {\n const payloadJson = Buffer.from(this.base64UrlToBase64(parts[1]), 'base64').toString('utf-8');\n const payload = JSON.parse(payloadJson) as { exp?: number };\n if (!payload?.exp || typeof payload.exp !== 'number') return undefined;\n const nowSeconds = Math.floor(Date.now() / 1000);\n const ttl = payload.exp - nowSeconds - 10;\n return ttl > 0 ? ttl : undefined;\n } catch {\n return undefined;\n }\n }\n\n private base64UrlToBase64(value: string): string {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const padLength = (4 - (normalized.length % 4)) % 4;\n return normalized + '='.repeat(padLength);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typeorm-db-helper.d.ts","sourceRoot":"","sources":["../../src/helpers/typeorm-db-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"typeorm-db-helper.d.ts","sourceRoot":"","sources":["../../src/helpers/typeorm-db-helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA0DxC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAUvE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAkB9D"}
|
|
@@ -36,6 +36,13 @@ const DECIMAL_MAP = {
|
|
|
36
36
|
[create_model_metadata_dto_1.DatasourceType.mariadb]: { type: "float" },
|
|
37
37
|
[create_model_metadata_dto_1.DatasourceType.oracle]: { type: "float" },
|
|
38
38
|
};
|
|
39
|
+
const DATE_TIME_MAP = {
|
|
40
|
+
[create_model_metadata_dto_1.DatasourceType.postgres]: { type: "timestamp" },
|
|
41
|
+
[create_model_metadata_dto_1.DatasourceType.mssql]: { type: "datetime2" },
|
|
42
|
+
[create_model_metadata_dto_1.DatasourceType.mysql]: { type: "datetime" },
|
|
43
|
+
[create_model_metadata_dto_1.DatasourceType.mariadb]: { type: "datetime" },
|
|
44
|
+
[create_model_metadata_dto_1.DatasourceType.oracle]: { type: "timestamp" },
|
|
45
|
+
};
|
|
39
46
|
const solidCoreDbType = Object.values(create_model_metadata_dto_1.DatasourceType).includes(process.env.SOLID_CORE_DB_TYPE)
|
|
40
47
|
? process.env.SOLID_CORE_DB_TYPE
|
|
41
48
|
: create_model_metadata_dto_1.DatasourceType.postgres;
|
|
@@ -59,6 +66,8 @@ function getColumnType(solidType) {
|
|
|
59
66
|
return SIMPLE_JSON_LARGE_TEXT_MAP[solidCoreDbType];
|
|
60
67
|
case "decimal":
|
|
61
68
|
return DECIMAL_MAP[solidCoreDbType];
|
|
69
|
+
case "datetime":
|
|
70
|
+
return DATE_TIME_MAP[solidCoreDbType];
|
|
62
71
|
default:
|
|
63
72
|
return {};
|
|
64
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typeorm-db-helper.js","sourceRoot":"","sources":["../../src/helpers/typeorm-db-helper.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"typeorm-db-helper.js","sourceRoot":"","sources":["../../src/helpers/typeorm-db-helper.ts"],"names":[],"mappings":"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","sourcesContent":["import { ColumnOptions } from \"typeorm\";\nimport { DatasourceType } from \"src/dtos/create-model-metadata.dto\";\n\nconst LONG_TEXT_MAP: Record<DatasourceType, ColumnOptions> = {\n [DatasourceType.postgres]: { type: \"text\" },\n [DatasourceType.mssql]: { type: \"nvarchar\", length: \"max\" },\n [DatasourceType.mysql]: { type: \"longtext\" },\n [DatasourceType.mariadb]: { type: \"longtext\" },\n [DatasourceType.oracle]: { type: \"clob\" },\n};\n\n// For simple-json columns that may contain large payloads: on MySQL/MariaDB the default\n// TEXT backing store is limited to 64 KB, so we override the type to longtext and supply\n// an explicit JSON transformer so TypeORM still serialises/deserialises correctly.\nconst SIMPLE_JSON_LARGE_TEXT_MAP: Record<DatasourceType, ColumnOptions> = {\n [DatasourceType.postgres]: {},\n [DatasourceType.mssql]: {},\n [DatasourceType.mysql]: {\n type: \"longtext\",\n transformer: {\n to: (value: any) => (value !== undefined && value !== null ? JSON.stringify(value) : value),\n from: (value: any) => (value !== null && value !== undefined ? JSON.parse(value) : value),\n },\n },\n [DatasourceType.mariadb]: {\n type: \"longtext\",\n transformer: {\n to: (value: any) => (value !== undefined && value !== null ? JSON.stringify(value) : value),\n from: (value: any) => (value !== null && value !== undefined ? JSON.parse(value) : value),\n },\n },\n [DatasourceType.oracle]: { type: \"clob\" },\n};\n\nconst DECIMAL_MAP: Record<DatasourceType, ColumnOptions> = {\n [DatasourceType.postgres]: { type: \"float4\" },\n [DatasourceType.mssql]: { type: \"float\" },\n [DatasourceType.mysql]: { type: \"float\" },\n [DatasourceType.mariadb]: { type: \"float\" },\n [DatasourceType.oracle]: { type: \"float\" },\n};\n\nconst DATE_TIME_MAP: Record<DatasourceType, ColumnOptions> = {\n [DatasourceType.postgres]: { type: \"timestamp\" },\n [DatasourceType.mssql]: { type: \"datetime2\" },\n [DatasourceType.mysql]: { type: \"datetime\" },\n [DatasourceType.mariadb]: { type: \"datetime\" },\n [DatasourceType.oracle]: { type: \"timestamp\" },\n};\n\nconst solidCoreDbType: DatasourceType =\n Object.values(DatasourceType).includes(process.env.SOLID_CORE_DB_TYPE as DatasourceType)\n ? (process.env.SOLID_CORE_DB_TYPE as DatasourceType)\n : DatasourceType.postgres;\n\n// Must use ANSI CAST() syntax — not Postgres-specific `::text` — because TypeORM's\n// replacePropertyNamesForTheWholeQuery regex treats ':' as part of the property name,\n// so `alias.col::text` is parsed as property `col::text` (no match → no column substitution).\nexport function buildCastToText(driver: string, colExpr: string): string {\n switch (driver) {\n case DatasourceType.mssql:\n return `CAST(${colExpr} AS NVARCHAR(MAX))`;\n case DatasourceType.mysql:\n case DatasourceType.mariadb:\n return `CAST(${colExpr} AS CHAR)`;\n default:\n return `CAST(${colExpr} AS TEXT)`;\n }\n}\n\nexport function getColumnType(solidType: string): ColumnOptions {\n switch (solidType) {\n case \"longText\":\n case \"richText\":\n return LONG_TEXT_MAP[solidCoreDbType];\n\n case \"simpleJsonLargeText\":\n return SIMPLE_JSON_LARGE_TEXT_MAP[solidCoreDbType];\n\n case \"decimal\":\n return DECIMAL_MAP[solidCoreDbType];\n\n case \"datetime\":\n return DATE_TIME_MAP[solidCoreDbType];\n\n default:\n return {};\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -156,6 +156,12 @@ export * from './entities/role-metadata.entity';
|
|
|
156
156
|
export * from './entities/sms-template.entity';
|
|
157
157
|
export * from './entities/user.entity';
|
|
158
158
|
export * from './entities/user-api-key.entity';
|
|
159
|
+
export * from './entities/user-device-credential.entity';
|
|
160
|
+
export * from './repository/user-device-credential.repository';
|
|
161
|
+
export * from './services/mpin.service';
|
|
162
|
+
export * from './dtos/setup-mpin.dto';
|
|
163
|
+
export * from './dtos/change-mpin.dto';
|
|
164
|
+
export * from './dtos/mpin-login.dto';
|
|
159
165
|
export * from './entities/view-metadata.entity';
|
|
160
166
|
export * from './entities/setting.entity';
|
|
161
167
|
export * from './entities/saved-filters.entity';
|