@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
package/src/solid-core.module.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "multer";
|
|
2
|
-
import { Global,
|
|
3
|
-
import * as express from "express";
|
|
2
|
+
import { Global, Module } from "@nestjs/common";
|
|
4
3
|
import { ConfigModule, ConfigService } from "@nestjs/config";
|
|
5
4
|
import {
|
|
6
5
|
APP_FILTER,
|
|
@@ -98,6 +97,7 @@ import { GoogleAuthenticationController } from "./controllers/google-authenticat
|
|
|
98
97
|
import { MenuItemMetadataController } from "./controllers/menu-item-metadata.controller";
|
|
99
98
|
import { MqMessageQueueController } from "./controllers/mq-message-queue.controller";
|
|
100
99
|
import { MqMessageController } from "./controllers/mq-message.controller";
|
|
100
|
+
import { MpinAuthenticationController } from "./controllers/mpin-authentication.controller";
|
|
101
101
|
import { OTPAuthenticationController } from "./controllers/otp-authentication.controller";
|
|
102
102
|
import { ServiceController } from "./controllers/service.controller";
|
|
103
103
|
import { SmsTemplateController } from "./controllers/sms-template.controller";
|
|
@@ -167,6 +167,7 @@ import { TwilioSmsQueueSubscriberRedis } from "./jobs/redis/twilio-sms-subscribe
|
|
|
167
167
|
import { UserRegistrationListener } from "./listeners/user-registration.listener";
|
|
168
168
|
import { GoogleOauthStrategy } from "./passport-strategies/google-oauth.strategy";
|
|
169
169
|
import { ApiKeyService } from "./services/api-key.service";
|
|
170
|
+
import { MpinService } from "./services/mpin.service";
|
|
170
171
|
import { ActiveSessionStorageService } from "./services/active-session-storage.service";
|
|
171
172
|
import { AuthenticationService } from "./services/authentication.service";
|
|
172
173
|
import { MetadataValidationService } from "./services/metadata-validation.service";
|
|
@@ -247,6 +248,7 @@ import { Setting } from './entities/setting.entity';
|
|
|
247
248
|
import { UserActivityHistory } from './entities/user-activity-history.entity';
|
|
248
249
|
import { UserViewMetadata } from './entities/user-view-metadata.entity';
|
|
249
250
|
import { UserApiKey } from './entities/user-api-key.entity';
|
|
251
|
+
import { UserDeviceCredential } from './entities/user-device-credential.entity';
|
|
250
252
|
import { User } from './entities/user.entity';
|
|
251
253
|
import { HttpExceptionFilter } from './filters/http-exception.filter';
|
|
252
254
|
import { ModelMetadataHelperService } from './helpers/model-metadata-helper.service';
|
|
@@ -319,6 +321,7 @@ import { SmsTemplateRepository } from './repository/sms-template.repository';
|
|
|
319
321
|
import { UserActivityHistoryRepository } from './repository/user-activity-history.repository';
|
|
320
322
|
import { UserViewMetadataRepository } from './repository/user-view-metadata.repository';
|
|
321
323
|
import { UserApiKeyRepository } from './repository/user-api-key.repository';
|
|
324
|
+
import { UserDeviceCredentialRepository } from './repository/user-device-credential.repository';
|
|
322
325
|
import { UserRepository } from './repository/user.repository';
|
|
323
326
|
import { ViewMetadataRepository } from './repository/view-metadata.repository';
|
|
324
327
|
import { PermissionMetadataSeederService } from './seeders/permission-metadata-seeder.service';
|
|
@@ -501,6 +504,7 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
501
504
|
SmsTemplate,
|
|
502
505
|
User,
|
|
503
506
|
UserApiKey,
|
|
507
|
+
UserDeviceCredential,
|
|
504
508
|
UserActivityHistory,
|
|
505
509
|
UserViewMetadata,
|
|
506
510
|
ViewMetadata,
|
|
@@ -553,6 +557,19 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
553
557
|
imports: [ConfigModule],
|
|
554
558
|
useFactory: async (configService: ConfigService) => ({
|
|
555
559
|
dest: process.env.AB_MEDIA_UPLOAD_DIR ?? "media-uploads",
|
|
560
|
+
// A global floor under whatever per-field mediaMaxSizeKb restrictions apply, not a
|
|
561
|
+
// replacement for them - some upload paths (e.g. chatter attachments) had no size cap
|
|
562
|
+
// enforced anywhere before this. Must stay >= the largest legitimate per-field limit
|
|
563
|
+
// already configured (chatter's messageAttachments is 102400 KB / 100MB), since Multer
|
|
564
|
+
// enforces this before any of our own field-level checks ever run. Mirrored (read-only,
|
|
565
|
+
// for visibility only - see comment there for why) as the "maxMediaFileSizeMb" setting
|
|
566
|
+
// in default-settings-provider.service.ts; keep both parsing expressions in sync.
|
|
567
|
+
limits: {
|
|
568
|
+
fileSize: (() => {
|
|
569
|
+
const parsedMb = Number(process.env.AB_MEDIA_MAX_FILE_SIZE_MB);
|
|
570
|
+
return (Number.isFinite(parsedMb) && parsedMb > 0 ? parsedMb : 100) * 1024 * 1024;
|
|
571
|
+
})(),
|
|
572
|
+
},
|
|
556
573
|
}),
|
|
557
574
|
inject: [ConfigService],
|
|
558
575
|
}),
|
|
@@ -596,6 +613,7 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
596
613
|
GupshupWebhookController,
|
|
597
614
|
MetaCloudWhatsappWebhookController,
|
|
598
615
|
OTPAuthenticationController,
|
|
616
|
+
MpinAuthenticationController,
|
|
599
617
|
PermissionMetadataController,
|
|
600
618
|
RoleMetadataController,
|
|
601
619
|
SavedFiltersController,
|
|
@@ -761,6 +779,7 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
761
779
|
ApiKeyGuard,
|
|
762
780
|
MediaSignedUrlGuard,
|
|
763
781
|
ApiKeyService,
|
|
782
|
+
MpinService,
|
|
764
783
|
ActiveSessionStorageService,
|
|
765
784
|
AuthenticationService,
|
|
766
785
|
GoogleAuthenticationController,
|
|
@@ -830,6 +849,7 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
830
849
|
PermissionMetadataSeederService,
|
|
831
850
|
UserService,
|
|
832
851
|
UserApiKeyRepository,
|
|
852
|
+
UserDeviceCredentialRepository,
|
|
833
853
|
UserRepository,
|
|
834
854
|
SettingService,
|
|
835
855
|
ConcatComputedFieldProvider,
|
|
@@ -1050,13 +1070,7 @@ import { SwitchNode } from './services/workflow/nodes/switch.node';
|
|
|
1050
1070
|
WorkflowExpressionService,
|
|
1051
1071
|
],
|
|
1052
1072
|
})
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
express.json({ limit: "10mb" }),
|
|
1058
|
-
express.urlencoded({ limit: "10mb", extended: true }),
|
|
1059
|
-
)
|
|
1060
|
-
.forRoutes("*");
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1073
|
+
// Body-size limits live in bootstrapSolidApp (see SolidBootstrapOptions.bodyLimit).
|
|
1074
|
+
// They cannot be applied here: module middleware is registered in registerRouter(),
|
|
1075
|
+
// which runs after Nest's own parser middleware, so anything set here never takes effect.
|
|
1076
|
+
export class SolidCoreModule {}
|
package/src/testing/README.md
CHANGED
|
@@ -104,6 +104,15 @@ Or set the installation-wide default under **Settings → Testing Settings** in
|
|
|
104
104
|
(`uiTestDefaultTimeoutMs` / `uiTestNavigationTimeoutMs`). Those rows are created by `solid seed`;
|
|
105
105
|
until then the built-in `30000` applies. Flags and env vars still win, so CI keeps per-run control.
|
|
106
106
|
|
|
107
|
+
The seeded value of those two settings can be provisioned from the environment with
|
|
108
|
+
`COMMON_UI_TEST_DEFAULT_TIMEOUT_MS` and `COMMON_UI_TEST_NAVIGATION_TIMEOUT_MS` (the latter falls
|
|
109
|
+
back to the former). Seeding is insert-only, so these apply on first seed only — afterwards the
|
|
110
|
+
stored value wins and the setting must be changed in the admin UI. Values that are missing,
|
|
111
|
+
non-numeric, or not positive fall back to `30000`.
|
|
112
|
+
|
|
113
|
+
Note these are distinct from the run-time `UI_TIMEOUT_MS` / `UI_NAVIGATION_TIMEOUT_MS` vars,
|
|
114
|
+
which override the setting on a per-run basis and are read every run.
|
|
115
|
+
|
|
107
116
|
Or bump only the one slow step, leaving the rest of the suite strict:
|
|
108
117
|
```json
|
|
109
118
|
{
|
|
@@ -470,10 +479,11 @@ Common `test run` flags (all pass through solidctl unchanged):
|
|
|
470
479
|
- `--ui-navigation-timeout-ms <number>` — default wait for `ui.goto`
|
|
471
480
|
- `--timeout-ms <number>` / `--retries <number>` — scenario-level guard and retry count
|
|
472
481
|
- `--scenario-ids <ids>` / `--include-tags <tags>` / `--skip-scenario-ids <ids>`
|
|
482
|
+
- `--no-progress` — disable the interactive test progress footer
|
|
473
483
|
|
|
474
484
|
## Add A New Step (SOP)
|
|
475
485
|
1. Create a new `*.step.ts` in the right domain folder.
|
|
476
486
|
2. Implement a `registerXSteps(registry)` function and `registry.register("op.name", handler)`.
|
|
477
487
|
3. Validate required `step.with` fields and throw clear errors.
|
|
478
488
|
4. Use adapters via `ctx.api` / `ctx.ui` and update `ctx.last` when helpful.
|
|
479
|
-
5. Export and register it from the domain `index.ts`.
|
|
489
|
+
5. Export and register it from the domain `index.ts`.
|
|
@@ -150,6 +150,10 @@ export class ConsoleReporter implements Reporter {
|
|
|
150
150
|
private passedScenarios = 0;
|
|
151
151
|
private failedScenarios = 0;
|
|
152
152
|
|
|
153
|
+
onRunStart(_args: { total: number }): void {
|
|
154
|
+
// Progress-aware reporters use this hook; the plain console reporter has no setup.
|
|
155
|
+
}
|
|
156
|
+
|
|
153
157
|
onScenarioStart(scenario: { id: string; name?: string }): void {
|
|
154
158
|
const label = scenario.name ? `${scenario.id} (${scenario.name})` : scenario.id;
|
|
155
159
|
console.log(`\n▶ Scenario: ${label}`);
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as readline from "readline";
|
|
2
|
+
import type { StepPhase } from "../contracts/runtime-context.types";
|
|
3
|
+
import type { OpStep, ScenarioSpec } from "../contracts/testing-metadata.types";
|
|
4
|
+
import type { SolidTestSpecResult } from "../contracts/test-spec.types";
|
|
5
|
+
import type { Reporter } from "./reporter.types";
|
|
6
|
+
|
|
7
|
+
const ANSI_BOLD = "\u001b[1m";
|
|
8
|
+
const ANSI_BOLD_OFF = "\u001b[22m";
|
|
9
|
+
const ANSI_DIM = "\u001b[2m";
|
|
10
|
+
const ANSI_GREEN = "\u001b[32m";
|
|
11
|
+
const ANSI_COLOR_OFF = "\u001b[39m";
|
|
12
|
+
const ANSI_RED = "\u001b[31m";
|
|
13
|
+
const ANSI_INVERSE = "\u001b[7m";
|
|
14
|
+
const ANSI_INVERSE_OFF = "\u001b[27m";
|
|
15
|
+
|
|
16
|
+
export class ProgressReporter implements Reporter {
|
|
17
|
+
private startedAt = Date.now();
|
|
18
|
+
private total = 0;
|
|
19
|
+
private completed = 0;
|
|
20
|
+
private passed = 0;
|
|
21
|
+
private failed = 0;
|
|
22
|
+
private timer?: NodeJS.Timeout;
|
|
23
|
+
private rendered = false;
|
|
24
|
+
|
|
25
|
+
constructor(private readonly delegate: Reporter) {}
|
|
26
|
+
|
|
27
|
+
onRunStart(args: { total: number }): void {
|
|
28
|
+
this.total = args.total;
|
|
29
|
+
this.startedAt = Date.now();
|
|
30
|
+
this.completed = 0;
|
|
31
|
+
this.passed = 0;
|
|
32
|
+
this.failed = 0;
|
|
33
|
+
this.delegate.onRunStart?.(args);
|
|
34
|
+
this.startTimer();
|
|
35
|
+
this.renderFooter();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onScenarioStart(scenario: ScenarioSpec): void {
|
|
39
|
+
this.withFooterPaused(() => this.delegate.onScenarioStart(scenario));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onScenarioEnd(
|
|
43
|
+
scenario: ScenarioSpec,
|
|
44
|
+
result: { ok: boolean; error?: unknown; durationMs: number },
|
|
45
|
+
): void {
|
|
46
|
+
this.completed += 1;
|
|
47
|
+
if (result.ok) {
|
|
48
|
+
this.passed += 1;
|
|
49
|
+
} else {
|
|
50
|
+
this.failed += 1;
|
|
51
|
+
}
|
|
52
|
+
this.withFooterPaused(() => this.delegate.onScenarioEnd(scenario, result));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onStepStart(args: {
|
|
56
|
+
scenarioId: string;
|
|
57
|
+
phase: StepPhase;
|
|
58
|
+
step: OpStep;
|
|
59
|
+
}): void {
|
|
60
|
+
this.withFooterPaused(() => this.delegate.onStepStart(args));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onStepEnd(args: {
|
|
64
|
+
scenarioId: string;
|
|
65
|
+
phase: StepPhase;
|
|
66
|
+
step: OpStep;
|
|
67
|
+
ok: boolean;
|
|
68
|
+
error?: unknown;
|
|
69
|
+
durationMs: number;
|
|
70
|
+
}): void {
|
|
71
|
+
this.withFooterPaused(() => this.delegate.onStepEnd(args));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onSpecResult(args: {
|
|
75
|
+
scenarioId: string;
|
|
76
|
+
specId: string;
|
|
77
|
+
stepName?: string;
|
|
78
|
+
result: SolidTestSpecResult;
|
|
79
|
+
}): void {
|
|
80
|
+
this.withFooterPaused(() => this.delegate.onSpecResult?.(args));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
attach(args: {
|
|
84
|
+
scenarioId: string;
|
|
85
|
+
name: string;
|
|
86
|
+
contentType: string;
|
|
87
|
+
data: Buffer | string;
|
|
88
|
+
}): void {
|
|
89
|
+
this.withFooterPaused(() => this.delegate.attach?.(args));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
onRunEnd(args: {
|
|
93
|
+
ok: boolean;
|
|
94
|
+
total: number;
|
|
95
|
+
passed: number;
|
|
96
|
+
failed: number;
|
|
97
|
+
durationMs: number;
|
|
98
|
+
}): void {
|
|
99
|
+
this.completed = args.passed + args.failed;
|
|
100
|
+
this.passed = args.passed;
|
|
101
|
+
this.failed = args.failed;
|
|
102
|
+
this.total = args.total;
|
|
103
|
+
this.stopTimer();
|
|
104
|
+
this.withFooterPaused(() => this.delegate.onRunEnd?.(args), false);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private startTimer(): void {
|
|
108
|
+
this.stopTimer();
|
|
109
|
+
if (!this.isInteractive()) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.timer = setInterval(() => this.renderFooter(), 1_000);
|
|
113
|
+
this.timer.unref?.();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private stopTimer(): void {
|
|
117
|
+
if (!this.timer) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
clearInterval(this.timer);
|
|
121
|
+
this.timer = undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private withFooterPaused(callback: () => void, renderAfter = true): void {
|
|
125
|
+
this.clearFooter();
|
|
126
|
+
callback();
|
|
127
|
+
if (renderAfter) {
|
|
128
|
+
this.renderFooter();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private renderFooter(): void {
|
|
133
|
+
if (!this.isInteractive()) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
138
|
+
const elapsed = formatElapsed(Date.now() - this.startedAt);
|
|
139
|
+
const progressText = `${this.completed}/${this.total}`;
|
|
140
|
+
const resultText = `${ANSI_GREEN}${this.passed} passed${ANSI_COLOR_OFF}${ANSI_DIM} | ${ANSI_BOLD_OFF}${this.failed ? ANSI_RED : ANSI_DIM}${this.failed} failed${this.failed ? ANSI_COLOR_OFF : ANSI_BOLD_OFF}`;
|
|
141
|
+
const footer = [
|
|
142
|
+
`${ANSI_BOLD}Tests${ANSI_BOLD_OFF}: ${this.renderProgressBar(terminalWidth)} ${progressText}`,
|
|
143
|
+
`${ANSI_BOLD}Elapsed${ANSI_BOLD_OFF}: ${elapsed}`,
|
|
144
|
+
resultText,
|
|
145
|
+
].join(`${ANSI_DIM} | ${ANSI_BOLD_OFF}`);
|
|
146
|
+
|
|
147
|
+
readline.clearLine(process.stdout, 0);
|
|
148
|
+
readline.cursorTo(process.stdout, 0);
|
|
149
|
+
process.stdout.write(truncateAnsiText(`${ANSI_INVERSE} ${footer} ${ANSI_INVERSE_OFF}`, terminalWidth));
|
|
150
|
+
this.rendered = true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private clearFooter(): void {
|
|
154
|
+
if (!this.rendered || !this.isInteractive()) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
readline.clearLine(process.stdout, 0);
|
|
158
|
+
readline.cursorTo(process.stdout, 0);
|
|
159
|
+
this.rendered = false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private renderProgressBar(terminalWidth: number): string {
|
|
163
|
+
const width = terminalWidth >= 120 ? 30 : terminalWidth >= 90 ? 22 : 14;
|
|
164
|
+
const ratio = this.total > 0 ? Math.min(1, this.completed / this.total) : 0;
|
|
165
|
+
const filled = Math.round(width * ratio);
|
|
166
|
+
const empty = Math.max(0, width - filled);
|
|
167
|
+
return `[${ANSI_GREEN}${"=".repeat(filled)}${ANSI_COLOR_OFF}${" ".repeat(empty)}]`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private isInteractive(): boolean {
|
|
171
|
+
return Boolean(process.stdout.isTTY || process.env.SOLIDCTL_TEST_PROGRESS === "1");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function formatElapsed(durationMs: number): string {
|
|
176
|
+
const totalSeconds = Math.max(0, Math.floor(durationMs / 1000));
|
|
177
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
178
|
+
const seconds = totalSeconds % 60;
|
|
179
|
+
if (minutes < 60) {
|
|
180
|
+
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
181
|
+
}
|
|
182
|
+
const hours = Math.floor(minutes / 60);
|
|
183
|
+
const remainingMinutes = minutes % 60;
|
|
184
|
+
return `${hours}:${remainingMinutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function truncateAnsiText(text: string, maxWidth: number): string {
|
|
188
|
+
if (maxWidth <= 0) {
|
|
189
|
+
return "";
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let visibleWidth = 0;
|
|
193
|
+
let index = 0;
|
|
194
|
+
let output = "";
|
|
195
|
+
let hasEscape = false;
|
|
196
|
+
|
|
197
|
+
while (index < text.length) {
|
|
198
|
+
if (text[index] === "\u001b") {
|
|
199
|
+
const match = /\u001b\[[0-9;]*m/.exec(text.slice(index));
|
|
200
|
+
if (!match) {
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
output += match[0];
|
|
204
|
+
hasEscape = true;
|
|
205
|
+
index += match[0].length;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (visibleWidth >= maxWidth) {
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
output += text[index];
|
|
214
|
+
visibleWidth += 1;
|
|
215
|
+
index += 1;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (index < text.length && maxWidth >= 1) {
|
|
219
|
+
output = trimAnsiText(output, maxWidth - 1) + "…";
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (hasEscape && !output.endsWith(ANSI_INVERSE_OFF)) {
|
|
223
|
+
output += ANSI_INVERSE_OFF;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return output;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function trimAnsiText(text: string, maxWidth: number): string {
|
|
230
|
+
let visibleWidth = 0;
|
|
231
|
+
let index = 0;
|
|
232
|
+
let output = "";
|
|
233
|
+
|
|
234
|
+
while (index < text.length && visibleWidth < maxWidth) {
|
|
235
|
+
if (text[index] === "\u001b") {
|
|
236
|
+
const match = /\u001b\[[0-9;]*m/.exec(text.slice(index));
|
|
237
|
+
if (!match) {
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
output += match[0];
|
|
241
|
+
index += match[0].length;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
output += text[index];
|
|
246
|
+
visibleWidth += 1;
|
|
247
|
+
index += 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return output;
|
|
251
|
+
}
|
|
@@ -3,6 +3,9 @@ import type { OpStep, ScenarioSpec } from "../contracts/testing-metadata.types";
|
|
|
3
3
|
import type { SolidTestSpecResult } from "../contracts/test-spec.types";
|
|
4
4
|
|
|
5
5
|
export interface Reporter {
|
|
6
|
+
onRunStart?(args: {
|
|
7
|
+
total: number;
|
|
8
|
+
}): void;
|
|
6
9
|
onScenarioStart(scenario: ScenarioSpec): void;
|
|
7
10
|
onScenarioEnd(
|
|
8
11
|
scenario: ScenarioSpec,
|
|
@@ -67,6 +67,7 @@ export async function runFromMetadata(opts: RunnerOptions): Promise<void> {
|
|
|
67
67
|
|
|
68
68
|
const resources = new SimpleResourceStore();
|
|
69
69
|
const reporter = opts.reporter ?? new ConsoleReporter();
|
|
70
|
+
reporter.onRunStart?.({ total: scenarios.length });
|
|
70
71
|
const api = new ApiAdapter(opts.api);
|
|
71
72
|
const { PlaywrightAdapter } = await import("../adapters/ui/playwright-adapter");
|
|
72
73
|
const ui = new PlaywrightAdapter(opts.ui);
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Backend theme registry.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - discover theme folders from the filesystem
|
|
9
|
+
* - classify each theme as light/dark from its key
|
|
10
|
+
* - expose default and grouped theme helpers for backend settings
|
|
11
|
+
*
|
|
12
|
+
* Shared pure parsing helpers are intentionally mirrored in solid-core-ui,
|
|
13
|
+
* but all filesystem discovery stays here.
|
|
14
|
+
*/
|
|
15
|
+
export type ThemeMode = "light" | "dark";
|
|
16
|
+
|
|
17
|
+
export type AppThemeDefinition = {
|
|
18
|
+
key: string;
|
|
19
|
+
label: string;
|
|
20
|
+
mode: ThemeMode;
|
|
21
|
+
default?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const DEFAULT_THEME_KEYS: Record<ThemeMode, string> = {
|
|
25
|
+
light: "solid-light-purple",
|
|
26
|
+
dark: "solid-dark-purple",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const THEME_MODE_TOKENS: Record<ThemeMode, string> = {
|
|
30
|
+
light: "-light-",
|
|
31
|
+
dark: "-dark-",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const THEME_MODE_SUFFIXES: Record<ThemeMode, string> = {
|
|
35
|
+
light: "-light",
|
|
36
|
+
dark: "-dark",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function normalizeThemeKey(value?: string | null): string | null {
|
|
40
|
+
const normalized = value?.trim().toLowerCase();
|
|
41
|
+
return normalized || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function matchesThemeMode(value: string, mode: ThemeMode): boolean {
|
|
45
|
+
return (
|
|
46
|
+
value.includes(THEME_MODE_TOKENS[mode])
|
|
47
|
+
|| value.endsWith(THEME_MODE_SUFFIXES[mode])
|
|
48
|
+
|| value === mode
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function titleCase(value: string): string {
|
|
53
|
+
return value
|
|
54
|
+
.split(/[-_\s]+/)
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.map((token) => {
|
|
57
|
+
if (token.toLowerCase() === "solid") return "SolidX";
|
|
58
|
+
return token.charAt(0).toUpperCase() + token.slice(1);
|
|
59
|
+
})
|
|
60
|
+
.join(" ");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getThemeModeFromThemeKey(value?: string | null): ThemeMode | null {
|
|
64
|
+
const normalized = normalizeThemeKey(value);
|
|
65
|
+
if (!normalized) return null;
|
|
66
|
+
|
|
67
|
+
if (matchesThemeMode(normalized, "light")) return "light";
|
|
68
|
+
if (matchesThemeMode(normalized, "dark")) return "dark";
|
|
69
|
+
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createThemeDefinition(key: string, defaultTheme = false): AppThemeDefinition {
|
|
74
|
+
const mode = getThemeModeFromThemeKey(key);
|
|
75
|
+
if (!mode) {
|
|
76
|
+
throw new Error(`Invalid theme key: ${key}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
key,
|
|
81
|
+
label: titleCase(key),
|
|
82
|
+
mode,
|
|
83
|
+
default: defaultTheme,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function createDefaultTheme(mode: ThemeMode): AppThemeDefinition {
|
|
88
|
+
return createThemeDefinition(DEFAULT_THEME_KEYS[mode], true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function groupThemesByMode(themes: AppThemeDefinition[], mode: ThemeMode): AppThemeDefinition[] {
|
|
92
|
+
return themes.filter((theme) => theme.mode === mode);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function pickDefaultThemeKey(themes: AppThemeDefinition[], mode: ThemeMode): string {
|
|
96
|
+
const themesForMode = groupThemesByMode(themes, mode);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
themesForMode.find((theme) => theme.default)?.key
|
|
100
|
+
?? themesForMode[0]?.key
|
|
101
|
+
?? DEFAULT_THEME_KEYS[mode]
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveThemeDirectory(): string | null {
|
|
106
|
+
const themeDirectory = path.resolve(process.cwd(), "..", "solid-ui", "public", "themes");
|
|
107
|
+
try {
|
|
108
|
+
if (fs.existsSync(themeDirectory) && fs.statSync(themeDirectory).isDirectory()) {
|
|
109
|
+
return path.resolve(themeDirectory);
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isThemeDirectory(themeDirectory: string, entryName: string): boolean {
|
|
119
|
+
return fs.existsSync(path.join(themeDirectory, entryName, "theme.css"));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function readThemesFromPath(): AppThemeDefinition[] {
|
|
123
|
+
const themeDirectory = resolveThemeDirectory();
|
|
124
|
+
if (!themeDirectory) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const directoryEntries = fs.readdirSync(themeDirectory, { withFileTypes: true });
|
|
130
|
+
|
|
131
|
+
return directoryEntries
|
|
132
|
+
.filter((entry) => entry.isDirectory())
|
|
133
|
+
.map((entry) => entry.name.trim())
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.filter((entryName) => isThemeDirectory(themeDirectory, entryName))
|
|
136
|
+
.flatMap((entryName) => {
|
|
137
|
+
const mode = getThemeModeFromThemeKey(entryName);
|
|
138
|
+
if (!mode) return [];
|
|
139
|
+
|
|
140
|
+
return [createThemeDefinition(entryName, entryName === DEFAULT_THEME_KEYS[mode])];
|
|
141
|
+
})
|
|
142
|
+
.sort((left, right) => left.label.localeCompare(right.label));
|
|
143
|
+
} catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getThemes(): AppThemeDefinition[] {
|
|
149
|
+
const discoveredThemes = readThemesFromPath();
|
|
150
|
+
|
|
151
|
+
if (discoveredThemes.length) {
|
|
152
|
+
return discoveredThemes;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return [createDefaultTheme("light"), createDefaultTheme("dark")];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function getCoreThemes(): AppThemeDefinition[] {
|
|
159
|
+
return getThemes();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function getRegisteredThemes(): AppThemeDefinition[] {
|
|
163
|
+
return getThemes();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function getThemesByMode(mode: ThemeMode): AppThemeDefinition[] {
|
|
167
|
+
return groupThemesByMode(getRegisteredThemes(), mode);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function getDefaultThemeKey(mode: ThemeMode = "light"): string {
|
|
171
|
+
return pickDefaultThemeKey(getRegisteredThemes(), mode);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function isRegisteredThemeKey(value?: string | null, mode?: ThemeMode): value is string {
|
|
175
|
+
if (!value) return false;
|
|
176
|
+
|
|
177
|
+
return getRegisteredThemes().some((theme) => {
|
|
178
|
+
if (theme.key !== value) return false;
|
|
179
|
+
return mode ? theme.mode === mode : true;
|
|
180
|
+
});
|
|
181
|
+
}
|
package/CLAUDE.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# This is the SolidX API project.
|
|
2
|
-
This is included as a dependency in consuming projects.
|
|
3
|
-
|
|
4
|
-
# SolidX UI
|
|
5
|
-
# The corresponding UI project is at the below path:
|
|
6
|
-
/Users/oswald/projects/Solid_Starters/solid-core-ui
|
|
7
|
-
|
|
8
|
-
# SolidX Docs
|
|
9
|
-
# The documentation project is at the below path:
|
|
10
|
-
/Users/oswald/projects/solidxai-docs
|
|
11
|
-
|
|
12
|
-
# SolidX Agent
|
|
13
|
-
# The agent project which has the skills for helping users configure, build and use SolidX is at the below path:
|
|
14
|
-
/Users/oswald/projects/Solid_Starters/agent
|
|
15
|
-
|
|
16
|
-
# SolidX Control Plane Commands
|
|
17
|
-
# The control plane commands for managing SolidX instances are in the below path:
|
|
18
|
-
/Users/oswald/projects/Solid_Starters/solidctl
|
|
19
|
-
|
|
20
|
-
# Testing reference project
|
|
21
|
-
# This is the reference library management project that is used for testing and development of SolidX features. It is located at the below path:
|
|
22
|
-
/Users/oswald/projects/Solid_Starters/solid-library-management
|
|
23
|
-
|
|
24
|
-
# Code Builder project
|
|
25
|
-
# This is the project that contains the code builder which generates code based on user input and templates. It is located at the below path:
|
|
26
|
-
/Users/oswald/projects/Solid_Starters/solid-code-builder
|