@shoper/cli 0.1.0-3 → 0.1.0-31
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/bin/run.js +0 -1
- package/build/cli/auth/api/cli_auth_api.js +16 -0
- package/build/cli/auth/cli_auth_constants.js +6 -0
- package/build/cli/auth/cli_auth_errors_factory.js +10 -0
- package/build/cli/auth/cli_auth_initializer.js +19 -0
- package/build/cli/auth/cli_auth_utils.js +22 -0
- package/build/cli/auth/model/cli_credentials.js +10 -0
- package/build/cli/auth/service/cli_auth_service.js +34 -0
- package/build/cli/auth/tokens/api/cli_auth_tokens_api.js +43 -0
- package/build/cli/auth/tokens/cli_auth_tokens_constants.js +6 -0
- package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +10 -0
- package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +35 -0
- package/build/cli/auth/tokens/cli_auth_tokens_utils.js +26 -0
- package/build/cli/auth/tokens/service/cli_auth_tokens_service.js +86 -0
- package/build/cli/auth/tokens/service/cli_auth_tokens_service_constants.js +2 -0
- package/build/cli/class/base_cli_command.js +3 -0
- package/build/cli/class/errors/app/app_error.js +17 -0
- package/build/cli/class/errors/app/app_error_constants.js +7 -0
- package/build/cli/class/errors/file_system_errors_factory.js +26 -0
- package/build/cli/class/errors/http/http_errors_constants.js +1 -0
- package/build/cli/class/errors/http/http_errors_factory.js +22 -0
- package/build/cli/cli_constants.js +2 -0
- package/build/cli/commands/auth/cli_auth_add_token_command.js +35 -0
- package/build/cli/commands/auth/cli_auth_commands_constants.js +3 -0
- package/build/cli/commands/auth/cli_auth_commands_utils.js +46 -0
- package/build/cli/commands/auth/cli_auth_list_tokens_command.js +30 -0
- package/build/cli/commands/auth/cli_auth_remove_token_command.js +63 -0
- package/build/cli/commands/auth/cli_auth_switch_token_command.js +46 -0
- package/build/cli/commands/auth/ui/invalid_token_index_error.js +11 -0
- package/build/cli/commands/auth/ui/missing_credentials_error.js +9 -0
- package/build/cli/commands/auth/ui/missing_token_index_error.js +19 -0
- package/build/cli/commands/cli_ui_dump_command.js +11 -0
- package/build/cli/commands/cli_update_command.js +34 -0
- package/build/cli/commands/commands_constants.js +7 -2
- package/build/cli/commands/files_diff_command.js +174 -0
- package/build/cli/commands/utils/prompt_for_token_utils.js +25 -0
- package/build/cli/core/cli_setup.js +30 -7
- package/build/cli/features/caches/json_cache/json_cache.js +50 -0
- package/build/cli/features/caches/memory_cache.js +6 -0
- package/build/cli/features/data_directory/api/cli_data_directory_api.js +16 -0
- package/build/cli/features/data_directory/cli_data_directory_constants.js +3 -0
- package/build/cli/features/data_directory/cli_data_directory_initializer.js +17 -0
- package/build/cli/features/data_directory/cli_data_directory_utils.js +17 -0
- package/build/cli/features/data_directory/service/cli_data_directory_service.js +15 -0
- package/build/cli/features/execution_context/execution_context_constants.js +1 -2
- package/build/cli/features/execution_context/execution_context_service.js +11 -31
- package/build/cli/features/http_requester/http_client.js +32 -1
- package/build/cli/features/version/api/cli_version_api.js +16 -0
- package/build/cli/features/version/cli_version_constants.js +2 -0
- package/build/cli/features/version/cli_version_initializer.js +17 -0
- package/build/cli/features/version/service/cli_version_service.js +26 -0
- package/build/cli/hooks/authorization/ensure_authorization_hook.js +12 -7
- package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -5
- package/build/cli/hooks/ensure_cli_initialized_hook.js +12 -0
- package/build/index.js +56 -4
- package/build/theme/class/checksums/theme_checksums.js +174 -0
- package/build/theme/class/checksums/theme_checksums_error_factory.js +10 -0
- package/build/theme/class/checksums/theme_checksums_utils.js +17 -0
- package/build/theme/class/fetch_resources/fetch_resources.js +127 -0
- package/build/theme/class/fetch_resources/fetch_resources_constants.js +2 -0
- package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +11 -0
- package/build/theme/class/fetch_resources/fetch_resources_utils.js +35 -0
- package/build/theme/commands/delete/theme_delete_command.js +111 -0
- package/build/theme/commands/delete/ui/theme_deleted_successfully.js +15 -0
- package/build/theme/commands/delete/ui/theme_deletion_warning.js +10 -0
- package/build/theme/commands/info/theme_info_command.js +94 -0
- package/build/theme/commands/info/theme_info_command_utils.js +39 -0
- package/build/theme/commands/init/theme_init_command.js +97 -0
- package/build/theme/commands/init/ui/theme_created_success.js +15 -0
- package/build/theme/commands/list/theme_list_command.js +25 -0
- package/build/theme/commands/list/theme_list_command_utils.js +27 -0
- package/build/theme/commands/pull/theme_pull_command.js +192 -0
- package/build/theme/commands/pull/ui/theme_pull_id_mismatch_error.js +7 -0
- package/build/theme/commands/pull/ui/theme_pull_unpublished_changes_warning.js +10 -0
- package/build/theme/commands/pull/ui/theme_pulled_success.js +5 -0
- package/build/theme/commands/push/theme_push_command.js +134 -0
- package/build/theme/commands/push/ui/theme_push_skip_into.js +7 -0
- package/build/theme/commands/push/ui/theme_pushed_success.js +5 -0
- package/build/theme/commands/push/ui/theme_unpermitted_actions_error.js +12 -0
- package/build/theme/commands/theme_commands_constants.js +10 -0
- package/build/theme/commands/theme_show_changes_command.js +61 -0
- package/build/theme/commands/theme_verify_command.js +44 -0
- package/build/theme/commands/ui/invalid_theme_id.js +11 -0
- package/build/theme/commands/ui/missing_theme_files.js +15 -0
- package/build/theme/commands/ui/missing_theme_id_error.js +13 -0
- package/build/theme/commands/ui/ouside_of_theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_directory_context_error.js +7 -0
- package/build/theme/commands/ui/theme_work_url_mismatch.js +17 -0
- package/build/theme/commands/ui/unpermitted_command_error.js +18 -0
- package/build/theme/features/theme/actions/api/theme_actions_api.js +22 -0
- package/build/theme/features/theme/actions/service/theme_actions_service.js +104 -0
- package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +3 -0
- package/build/theme/features/theme/actions/theme_actions_constants.js +17 -0
- package/build/theme/features/theme/actions/theme_actions_initializer.js +27 -0
- package/build/theme/features/theme/actions/theme_actions_utils.js +11 -0
- package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
- package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
- package/build/theme/features/theme/delete/service/theme_delete_service.js +31 -0
- package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
- package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
- package/build/theme/features/theme/fetch/api/theme_fetch_api.js +16 -0
- package/build/theme/features/theme/fetch/http/theme_fetch_http_api.js +18 -0
- package/build/theme/features/theme/fetch/service/theme_fetch_service.js +132 -0
- package/build/theme/features/theme/fetch/theme_fetch_constants.js +7 -0
- package/build/theme/features/theme/fetch/theme_fetch_initializer.js +23 -0
- package/build/theme/features/theme/info/theme_info_utils.js +9 -0
- package/build/theme/features/theme/init/api/theme_init_api.js +13 -0
- package/build/theme/features/theme/init/http/theme_init_http_api.js +18 -0
- package/build/theme/features/theme/init/service/theme_init_service.js +33 -0
- package/build/theme/features/theme/init/theme_init_constants.js +2 -0
- package/build/theme/features/theme/init/theme_init_initializer.js +22 -0
- package/build/theme/features/theme/merge/api/theme_merge_api.js +16 -0
- package/build/theme/features/theme/merge/service/theme_merge_service.js +42 -0
- package/build/theme/features/theme/merge/theme_merge_constants.js +9 -0
- package/build/theme/features/theme/merge/theme_merge_initializer.js +18 -0
- package/build/theme/features/theme/push/api/theme_push_api.js +13 -0
- package/build/theme/features/theme/push/http_api/theme_push_http_api.js +21 -0
- package/build/theme/features/theme/push/service/theme_push_service.js +205 -0
- package/build/theme/features/theme/push/service/theme_push_service_constants.js +1 -0
- package/build/theme/features/theme/push/theme_push_constants.js +6 -0
- package/build/theme/features/theme/push/theme_push_errors_factory.js +44 -0
- package/build/theme/features/theme/push/theme_push_initializer.js +24 -0
- package/build/theme/features/theme/push/theme_push_utils.js +25 -0
- package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +17 -0
- package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +7 -0
- package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +3 -0
- package/build/theme/features/theme/skinstore/theme_publish_constants.js +2 -0
- package/build/theme/features/theme/skinstore/theme_publish_utils.js +7 -0
- package/build/theme/features/theme/theme_constants.js +6 -0
- package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +34 -0
- package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +32 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_constants.js +1 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +15 -0
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +39 -0
- package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js +69 -0
- package/build/theme/features/theme/utils/theme_images_utils.js +30 -0
- package/build/theme/features/themes/list/api/themes_list_api.js +16 -0
- package/build/theme/features/themes/{http/shoper_themes_http_api.js → list/http/themes_list_http_api.js} +3 -2
- package/build/theme/features/themes/{model/theme_metadata.js → list/model/theme_list_metadata.js} +3 -1
- package/build/theme/features/themes/list/services/themes_list_service.js +43 -0
- package/build/theme/features/themes/list/themes_list_constants.js +2 -0
- package/build/theme/features/themes/list/themes_list_initializer.js +20 -0
- package/build/theme/hooks/ensure_theme_meta_data_untouched_hook.js +17 -0
- package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +7 -0
- package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_hook.js +18 -0
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +46 -0
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +7 -0
- package/build/theme/index.js +17 -4
- package/build/theme/utils/directory_validator/directory_validator_constants.js +9 -0
- package/build/theme/utils/directory_validator/directory_validator_utils.js +167 -0
- package/build/ui/box.js +2 -0
- package/build/ui/color_constants.js +30 -0
- package/build/ui/command.js +6 -0
- package/build/ui/file_name.js +6 -0
- package/build/ui/flag.js +6 -0
- package/build/ui/form/controls_mappers.js +39 -0
- package/build/ui/form/form.js +5 -0
- package/build/ui/form/form_constants.js +13 -0
- package/build/ui/icons/error_icon.js +7 -0
- package/build/ui/icons/info_icon.js +7 -0
- package/build/ui/icons/success_icon.js +7 -0
- package/build/ui/icons/warning_icon.js +7 -0
- package/build/ui/link.js +8 -0
- package/build/ui/list/list.js +10 -0
- package/build/ui/list/list_constants.js +4 -0
- package/build/ui/list/list_item.js +11 -0
- package/build/ui/message_box/error.js +4 -0
- package/build/ui/message_box/info.js +4 -0
- package/build/ui/message_box/message_box.js +11 -0
- package/build/ui/message_box/message_box_constants.js +24 -0
- package/build/ui/message_box/success.js +4 -0
- package/build/ui/message_box/warning.js +4 -0
- package/build/ui/prompts/prompt_confirmation.js +11 -0
- package/build/ui/prompts/prompt_input.js +10 -0
- package/build/ui/table/t_cell.js +7 -0
- package/build/ui/table/t_header.js +9 -0
- package/build/ui/table/t_row.js +5 -0
- package/build/ui/table/table.js +18 -0
- package/build/ui/text.js +2 -0
- package/build/ui/tip.js +9 -0
- package/build/ui/ui_dump/ui_component_box.js +9 -0
- package/build/ui/ui_dump/ui_dump.js +53 -0
- package/build/ui/ui_dump/ui_dump_constants.js +21 -0
- package/build/ui/ui_utils.js +11 -0
- package/build/ui/validation_errors/validation_error_content.js +19 -0
- package/build/ui/validation_errors/validation_errors.js +21 -0
- package/build/ui/validation_errors/validation_errors_utils.js +17 -0
- package/build/utils/checksums/checksums_utils.js +78 -0
- package/build/utils/checksums/checksums_utils_constants.js +1 -0
- package/build/utils/date_utils.js +3 -0
- package/build/utils/download_file/download_file_errors_factory.js +9 -0
- package/build/utils/download_file/download_file_utils.js +48 -0
- package/build/utils/fs/errors/stream_read_error.js +11 -0
- package/build/utils/fs/errors/stream_write_error.js +11 -0
- package/build/utils/fs/fs_utils.js +166 -0
- package/build/utils/http_utils.js +10 -0
- package/build/utils/path_utils.js +53 -0
- package/build/utils/platform_utils.js +3 -0
- package/build/utils/stream_transforms/json_indent_transform.js +21 -0
- package/build/utils/url_utils.js +9 -0
- package/build/utils/zip/create_zip_utils.js +80 -0
- package/build/utils/zip/errors/create_zip_error.js +11 -0
- package/build/utils/zip/errors/open_zip_error.js +11 -0
- package/build/utils/zip/extract_zip_utils.js +104 -0
- package/oclif.config.js +35 -0
- package/package.json +48 -11
- package/build/cli/commands/init_command.js +0 -19
- package/build/cli/features/cli_project/api/cli_project_api.js +0 -16
- package/build/cli/features/cli_project/cli_project_constants.js +0 -3
- package/build/cli/features/cli_project/cli_project_directory_utils.js +0 -34
- package/build/cli/features/cli_project/cli_project_initializer.js +0 -20
- package/build/cli/features/cli_project/cli_project_service.js +0 -15
- package/build/cli/hooks/ensure_initalized_project_hook.js +0 -1
- package/build/cli/hooks/migration/migration_hook.js +0 -4
- package/build/theme/commands/list_command.js +0 -12
- package/build/theme/commands/pull_command.js +0 -24
- package/build/theme/features/theme/directory/theme_directories_utils.js +0 -10
- package/build/theme/features/theme/directory/theme_directory_utils.js +0 -29
- package/build/theme/features/theme/pull/api/shoper_theme_pull_api.js +0 -9
- package/build/theme/features/theme/pull/http/shoper_theme_pull_http_api.js +0 -14
- package/build/theme/features/theme/pull/service/shoper_theme_pull_service.js +0 -68
- package/build/theme/features/theme/pull/shoper_theme_pull_initializer.js +0 -22
- package/build/theme/features/themes/api/shoper_themes_api.js +0 -14
- package/build/theme/features/themes/services/shoper_themes_service.js +0 -15
- package/build/theme/features/themes/shoper_themes_constants.js +0 -2
- package/build/theme/features/themes/shoper_themes_initalizer.js +0 -20
- package/build/utils/fs.js +0 -44
- package/build/utils/path.js +0 -13
package/bin/run.js
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FeatureApi } from '@dreamcommerce/star_core';
|
|
2
|
+
import { CLI_AUTH_API_NAME } from '../cli_auth_constants.js';
|
|
3
|
+
export class CliAuthApi extends FeatureApi {
|
|
4
|
+
moduleName = CLI_AUTH_API_NAME;
|
|
5
|
+
#cliAuthService;
|
|
6
|
+
constructor(cliAuthService) {
|
|
7
|
+
super();
|
|
8
|
+
this.#cliAuthService = cliAuthService;
|
|
9
|
+
}
|
|
10
|
+
getCredentials() {
|
|
11
|
+
return this.#cliAuthService.getCredentials();
|
|
12
|
+
}
|
|
13
|
+
hasCredentialsExpired() {
|
|
14
|
+
return this.#cliAuthService.hasCredentialsExpired();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AppError } from '../class/errors/app/app_error.js';
|
|
2
|
+
export class CliAuthErrorsFactory {
|
|
3
|
+
static createCredentialNotFoundError() {
|
|
4
|
+
return new AppError({
|
|
5
|
+
code: 'cli_auth.credential_not_found',
|
|
6
|
+
message: 'Credential not found',
|
|
7
|
+
level: 'error'
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FEATURE_CORES_TYPES, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
|
+
import { CliAuthService } from './service/cli_auth_service.js';
|
|
3
|
+
import { CliAuthApi } from './api/cli_auth_api.js';
|
|
4
|
+
import { CLI_AUTH_TOKENS_API_NAME } from './tokens/cli_auth_tokens_constants.js';
|
|
5
|
+
import { CLI_AUTH_FEATURE_NAME } from './cli_auth_constants.js';
|
|
6
|
+
export class CliAuthInitializer extends SyncFeatureInitializer {
|
|
7
|
+
static featureName = CLI_AUTH_FEATURE_NAME;
|
|
8
|
+
init() {
|
|
9
|
+
const cliAuthTokensApi = this.getApiSync(CLI_AUTH_TOKENS_API_NAME);
|
|
10
|
+
return {
|
|
11
|
+
cores: [
|
|
12
|
+
{
|
|
13
|
+
type: FEATURE_CORES_TYPES.api,
|
|
14
|
+
instance: new CliAuthApi(new CliAuthService(cliAuthTokensApi))
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CLI_AUTH_SCOPES } from './cli_auth_constants.js';
|
|
2
|
+
export class CliAuthUtils {
|
|
3
|
+
static checkCredentials(credentialsApi, command) {
|
|
4
|
+
const credentials = credentialsApi.getCredentials();
|
|
5
|
+
if (!credentials)
|
|
6
|
+
return false;
|
|
7
|
+
if (credentialsApi.hasCredentialsExpired()) {
|
|
8
|
+
console.log('Credentials are expired, please reauthorize');
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return CliAuthUtils.ensureScopeAccessRights(credentials.scopes, command.id);
|
|
12
|
+
}
|
|
13
|
+
// We assume for now that scopes names are same as topics names
|
|
14
|
+
static ensureScopeAccessRights(tokenScopes, commandId) {
|
|
15
|
+
if (!CliAuthUtils.isScopedCommand(Object.values(CLI_AUTH_SCOPES), commandId))
|
|
16
|
+
return true;
|
|
17
|
+
return CliAuthUtils.isScopedCommand(tokenScopes, commandId);
|
|
18
|
+
}
|
|
19
|
+
static isScopedCommand(scopes, commandId) {
|
|
20
|
+
return scopes.some((scope) => commandId.includes(scope));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CliCredentials } from '../model/cli_credentials.js';
|
|
2
|
+
import { CliAuthErrorsFactory } from '../cli_auth_errors_factory.js';
|
|
3
|
+
export class CliAuthService {
|
|
4
|
+
#cliAuthTokensApi;
|
|
5
|
+
#credentials = null;
|
|
6
|
+
constructor(cliAuthTokensApi) {
|
|
7
|
+
this.#cliAuthTokensApi = cliAuthTokensApi;
|
|
8
|
+
this._setCredentials();
|
|
9
|
+
}
|
|
10
|
+
_setCredentials() {
|
|
11
|
+
const defaultTokenPayload = this.#cliAuthTokensApi.getDefaultTokenPayload();
|
|
12
|
+
if (!defaultTokenPayload)
|
|
13
|
+
return;
|
|
14
|
+
this.#credentials = new CliCredentials({
|
|
15
|
+
shopUrl: defaultTokenPayload.iss,
|
|
16
|
+
scopes: defaultTokenPayload.scope.split(';'),
|
|
17
|
+
expires: defaultTokenPayload.exp
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
getCredentials() {
|
|
21
|
+
if (this.#credentials)
|
|
22
|
+
return this.#credentials;
|
|
23
|
+
this._setCredentials();
|
|
24
|
+
return this.#credentials;
|
|
25
|
+
}
|
|
26
|
+
hasCredentialsExpired() {
|
|
27
|
+
if (!this.#credentials)
|
|
28
|
+
throw CliAuthErrorsFactory.createCredentialNotFoundError();
|
|
29
|
+
const defaultTokenIndex = this.#cliAuthTokensApi.getDefaultTokenIndex();
|
|
30
|
+
if (!defaultTokenIndex)
|
|
31
|
+
return true;
|
|
32
|
+
return this.#cliAuthTokensApi.hasTokenExpired(defaultTokenIndex);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CLI_AUTH_TOKENS_API_NAME } from '../cli_auth_tokens_constants.js';
|
|
2
|
+
import { FeatureApi } from '@dreamcommerce/star_core';
|
|
3
|
+
export class CliAuthTokensApi extends FeatureApi {
|
|
4
|
+
moduleName = CLI_AUTH_TOKENS_API_NAME;
|
|
5
|
+
#service;
|
|
6
|
+
constructor(service) {
|
|
7
|
+
super();
|
|
8
|
+
this.#service = service;
|
|
9
|
+
}
|
|
10
|
+
addToken(token) {
|
|
11
|
+
this.#service.addToken(token);
|
|
12
|
+
}
|
|
13
|
+
removeToken(index) {
|
|
14
|
+
this.#service.removeToken(index);
|
|
15
|
+
}
|
|
16
|
+
setDefaultToken(index) {
|
|
17
|
+
this.#service.setDefaultToken(index);
|
|
18
|
+
}
|
|
19
|
+
getTokenPayload(index) {
|
|
20
|
+
return this.#service.getTokenPayload(index);
|
|
21
|
+
}
|
|
22
|
+
hasToken(index) {
|
|
23
|
+
return this.#service.hasToken(index);
|
|
24
|
+
}
|
|
25
|
+
getAllTokensPayloads() {
|
|
26
|
+
return this.#service.getAllTokensPayloads();
|
|
27
|
+
}
|
|
28
|
+
getDefaultTokenIndex() {
|
|
29
|
+
return this.#service.getDefaultTokenIndex();
|
|
30
|
+
}
|
|
31
|
+
getDefaultToken() {
|
|
32
|
+
return this.#service.getDefaultToken();
|
|
33
|
+
}
|
|
34
|
+
getDefaultTokenPayload() {
|
|
35
|
+
return this.#service.getDefaultTokenPayload();
|
|
36
|
+
}
|
|
37
|
+
hasTokenExpired(index) {
|
|
38
|
+
return this.#service.hasTokenExpired(index);
|
|
39
|
+
}
|
|
40
|
+
getTokensCount() {
|
|
41
|
+
return this.#service.getTokensCount();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AppError } from '../../class/errors/app/app_error.js';
|
|
2
|
+
export class CliAuthTokensErrorsFactory {
|
|
3
|
+
static createTokenNotFoundError(index) {
|
|
4
|
+
return new AppError({
|
|
5
|
+
code: 'cli_auth_tokens.token_not_found',
|
|
6
|
+
message: `Token with index "${index}" not found`,
|
|
7
|
+
level: 'error'
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FEATURE_CORES_TYPES, SyncFeatureInitializer } from '@dreamcommerce/star_core';
|
|
2
|
+
import { CliAuthTokensApi } from './api/cli_auth_tokens_api.js';
|
|
3
|
+
import { CLiAuthTokensService } from './service/cli_auth_tokens_service.js';
|
|
4
|
+
import { CLI_AUTH_TOKENS_FEATURE_NAME, CLI_AUTH_TOKENS_FILE_NAME } from './cli_auth_tokens_constants.js';
|
|
5
|
+
import { CLI_DATA_DIRECTORY_API_NAME } from '../../features/data_directory/cli_data_directory_constants.js';
|
|
6
|
+
import { JsonCache } from '../../features/caches/json_cache/json_cache.js';
|
|
7
|
+
// schema
|
|
8
|
+
// {
|
|
9
|
+
// default: string;
|
|
10
|
+
// tokens: {
|
|
11
|
+
// [key: string]: {
|
|
12
|
+
// type: string;
|
|
13
|
+
// token: string;
|
|
14
|
+
// expires: string;
|
|
15
|
+
// }
|
|
16
|
+
// }
|
|
17
|
+
export class CliAuthTokensInitializer extends SyncFeatureInitializer {
|
|
18
|
+
static featureName = CLI_AUTH_TOKENS_FEATURE_NAME;
|
|
19
|
+
init() {
|
|
20
|
+
const cliDataDirectoryApi = this.getApiSync(CLI_DATA_DIRECTORY_API_NAME);
|
|
21
|
+
const tokensStore = new JsonCache({
|
|
22
|
+
path: cliDataDirectoryApi.getDataDirectoryFullPath(),
|
|
23
|
+
configFileMode: 0o600,
|
|
24
|
+
name: CLI_AUTH_TOKENS_FILE_NAME
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
cores: [
|
|
28
|
+
{
|
|
29
|
+
type: FEATURE_CORES_TYPES.api,
|
|
30
|
+
instance: new CliAuthTokensApi(new CLiAuthTokensService(tokensStore))
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
export class CLiAuthTokensUtils {
|
|
3
|
+
static getTokenPayload(token) {
|
|
4
|
+
try {
|
|
5
|
+
return jwt.decode(token);
|
|
6
|
+
}
|
|
7
|
+
catch (err) {
|
|
8
|
+
console.error('Error decoding token:', err);
|
|
9
|
+
throw new Error('Invalid token');
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
static getTokenName(token) {
|
|
13
|
+
const payload = this.getTokenPayload(token);
|
|
14
|
+
const tokenName = payload?.name;
|
|
15
|
+
if (!tokenName) {
|
|
16
|
+
throw new Error('Token name not found in payload');
|
|
17
|
+
}
|
|
18
|
+
return tokenName;
|
|
19
|
+
}
|
|
20
|
+
static hasTokenExpired(token) {
|
|
21
|
+
const tokenPayload = CLiAuthTokensUtils.getTokenPayload(token);
|
|
22
|
+
if (!tokenPayload)
|
|
23
|
+
return true;
|
|
24
|
+
return tokenPayload.exp - Math.floor(Date.now() / 1000) < 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CLI_AUTH_TOKENS_TYPES } from '../cli_auth_tokens_constants.js';
|
|
2
|
+
import { CLiAuthTokensUtils } from '../cli_auth_tokens_utils.js';
|
|
3
|
+
import { CLI_AUTH_DEFAULT_TOKEN_NAME, CLI_AUTH_TOKENS_KEY } from './cli_auth_tokens_service_constants.js';
|
|
4
|
+
import { CliAuthTokensErrorsFactory } from '../cli_auth_tokens_errors_factory.js';
|
|
5
|
+
export class CLiAuthTokensService {
|
|
6
|
+
#tokensStore;
|
|
7
|
+
constructor(tokensStore) {
|
|
8
|
+
this.#tokensStore = tokensStore;
|
|
9
|
+
}
|
|
10
|
+
addToken(token) {
|
|
11
|
+
const tokeItem = {
|
|
12
|
+
token,
|
|
13
|
+
type: CLI_AUTH_TOKENS_TYPES.jwt
|
|
14
|
+
};
|
|
15
|
+
const tokens = this._getTokenItems() ?? [];
|
|
16
|
+
tokens.push(tokeItem);
|
|
17
|
+
this._setTokens(tokens);
|
|
18
|
+
}
|
|
19
|
+
hasToken(index) {
|
|
20
|
+
return index <= this.getTokensCount();
|
|
21
|
+
}
|
|
22
|
+
removeToken(index) {
|
|
23
|
+
if (!this.hasToken(index))
|
|
24
|
+
return;
|
|
25
|
+
const tokens = this._getTokenItems();
|
|
26
|
+
const newTokens = tokens.filter((_, currIndex) => currIndex !== index - 1);
|
|
27
|
+
this._setTokens(newTokens);
|
|
28
|
+
}
|
|
29
|
+
getDefaultTokenPayload() {
|
|
30
|
+
const defaultTokenIndex = this.getDefaultTokenIndex();
|
|
31
|
+
if (!defaultTokenIndex)
|
|
32
|
+
return null;
|
|
33
|
+
return this.getTokenPayload(defaultTokenIndex);
|
|
34
|
+
}
|
|
35
|
+
getDefaultTokenIndex() {
|
|
36
|
+
return this.#tokensStore.get(CLI_AUTH_DEFAULT_TOKEN_NAME);
|
|
37
|
+
}
|
|
38
|
+
getTokenPayload(index) {
|
|
39
|
+
const tokenItem = this._getTokenItem(index - 1);
|
|
40
|
+
if (!tokenItem)
|
|
41
|
+
return null;
|
|
42
|
+
return CLiAuthTokensUtils.getTokenPayload(tokenItem.token);
|
|
43
|
+
}
|
|
44
|
+
hasTokenExpired(index) {
|
|
45
|
+
const tokenItem = this._getTokenItem(index - 1);
|
|
46
|
+
if (!tokenItem)
|
|
47
|
+
return true;
|
|
48
|
+
return CLiAuthTokensUtils.hasTokenExpired(tokenItem.token);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Index starts from 1
|
|
52
|
+
*/
|
|
53
|
+
setDefaultToken(index) {
|
|
54
|
+
const tokens = this._getTokenItems();
|
|
55
|
+
if (tokens.length < index)
|
|
56
|
+
throw CliAuthTokensErrorsFactory.createTokenNotFoundError(index);
|
|
57
|
+
this.#tokensStore.set(CLI_AUTH_DEFAULT_TOKEN_NAME, index);
|
|
58
|
+
}
|
|
59
|
+
_getTokenItems() {
|
|
60
|
+
return this.#tokensStore.get(CLI_AUTH_TOKENS_KEY) ?? [];
|
|
61
|
+
}
|
|
62
|
+
_getTokenItem(index) {
|
|
63
|
+
const tokens = this._getTokenItems();
|
|
64
|
+
return tokens[index] ?? null;
|
|
65
|
+
}
|
|
66
|
+
_setTokens(tokens) {
|
|
67
|
+
this.#tokensStore.set(CLI_AUTH_TOKENS_KEY, tokens);
|
|
68
|
+
}
|
|
69
|
+
getTokensCount() {
|
|
70
|
+
const tokens = this._getTokenItems();
|
|
71
|
+
return tokens.length;
|
|
72
|
+
}
|
|
73
|
+
getDefaultToken() {
|
|
74
|
+
const defaultTokenIndex = this.getDefaultTokenIndex();
|
|
75
|
+
if (!defaultTokenIndex)
|
|
76
|
+
return null;
|
|
77
|
+
const tokenItem = this._getTokenItem(defaultTokenIndex - 1);
|
|
78
|
+
if (!tokenItem)
|
|
79
|
+
return null;
|
|
80
|
+
return tokenItem.token;
|
|
81
|
+
}
|
|
82
|
+
getAllTokensPayloads() {
|
|
83
|
+
const tokens = this._getTokenItems();
|
|
84
|
+
return tokens.map((tokenItem) => CLiAuthTokensUtils.getTokenPayload(tokenItem.token));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { APP_ERRORS_LEVELS } from './app_error_constants.js';
|
|
2
|
+
//TODO errory do zaprojektownia
|
|
3
|
+
export class AppError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
level;
|
|
6
|
+
tags;
|
|
7
|
+
details;
|
|
8
|
+
stack;
|
|
9
|
+
constructor({ code, details, message, level = APP_ERRORS_LEVELS.error, tags, stack }) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.details = details;
|
|
13
|
+
this.level = level;
|
|
14
|
+
this.tags = tags;
|
|
15
|
+
this.stack = stack;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AppError } from './app/app_error.js';
|
|
2
|
+
export class FileSystemErrorsFactory {
|
|
3
|
+
static createDiskFullError() {
|
|
4
|
+
return new AppError({
|
|
5
|
+
code: 'file_system.disk_full',
|
|
6
|
+
message: 'Disk is full',
|
|
7
|
+
level: 'error'
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
static createErrorMovingFile(source, destination, err) {
|
|
11
|
+
return new AppError({
|
|
12
|
+
code: 'file_system.error_moving_file',
|
|
13
|
+
message: `Failed to move file from ${source} to ${destination}`,
|
|
14
|
+
level: 'error',
|
|
15
|
+
stack: err.stack
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
static createErrorCopyingFile(source, destination, err) {
|
|
19
|
+
return new AppError({
|
|
20
|
+
code: 'file_system.error_copying_file',
|
|
21
|
+
message: `Failed to copy file from ${source} to ${destination}`,
|
|
22
|
+
level: 'error',
|
|
23
|
+
stack: err.stack
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HTTP_NOT_FOUND_ERROR_CODE = 'not_found';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AppError } from '../app/app_error.js';
|
|
2
|
+
import { HTTP_NOT_FOUND_ERROR_CODE } from './http_errors_constants.js';
|
|
3
|
+
export class HttpErrorsFactory {
|
|
4
|
+
static createUnauthorizedError() {
|
|
5
|
+
return new AppError({
|
|
6
|
+
message: 'Unauthorized',
|
|
7
|
+
code: 'unauthorized'
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
static createForbiddenError() {
|
|
11
|
+
return new AppError({
|
|
12
|
+
message: 'Forbidden',
|
|
13
|
+
code: 'forbidden'
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
static createNotFoundError() {
|
|
17
|
+
return new AppError({
|
|
18
|
+
message: 'Not found',
|
|
19
|
+
code: HTTP_NOT_FOUND_ERROR_CODE
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseCliCommand } from '../../class/base_cli_command.js';
|
|
2
|
+
import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
|
|
3
|
+
import { promptInput } from '../../../ui/prompts/prompt_input.js';
|
|
4
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
5
|
+
import { Success } from '../../../ui/message_box/success.js';
|
|
6
|
+
import { Text } from '../../../ui/text.js';
|
|
7
|
+
import { Box } from '../../../ui/box.js';
|
|
8
|
+
import { Command } from '../../../ui/command.js';
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
11
|
+
export class CliAuthAddTokenCommand extends BaseCliCommand {
|
|
12
|
+
static summary = 'Adds a new authentication token and saves it locally.';
|
|
13
|
+
static description = 'The added token will be set as your default authentication token.\n\nUse this when you’ve generated a token in your store panel and want to authenticate your CLI commands.';
|
|
14
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
15
|
+
async run() {
|
|
16
|
+
const cliAuthTokensApi = this.getApi(CLI_AUTH_TOKENS_API_NAME);
|
|
17
|
+
try {
|
|
18
|
+
const { input: token } = await promptInput('Please paste your CLI token:');
|
|
19
|
+
cliAuthTokensApi.addToken(token);
|
|
20
|
+
cliAuthTokensApi.setDefaultToken(cliAuthTokensApi.getTokensCount());
|
|
21
|
+
renderOnce(React.createElement(Success, null,
|
|
22
|
+
React.createElement(Text, null, "Token saved locally and set as your default. You can now authenticate using this token."),
|
|
23
|
+
React.createElement(Box, null,
|
|
24
|
+
React.createElement(Text, null,
|
|
25
|
+
"Run ",
|
|
26
|
+
React.createElement(Command, null, "shoper auth list-tokens"),
|
|
27
|
+
" to view your saved tokens."))));
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
renderOnce(React.createElement(Error, { header: "Error: Failed to add token: " },
|
|
31
|
+
React.createElement(Box, null,
|
|
32
|
+
React.createElement(Text, null, err.toString()))));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Text } from '../../../ui/text.js';
|
|
2
|
+
import { TOKEN_SCOPE_TO_DESCRIPTION } from './cli_auth_commands_constants.js';
|
|
3
|
+
import { CSS_BACKGROUND_COLORS, CSS_TEXT_COLORS } from '../../../ui/color_constants.js';
|
|
4
|
+
import { DateUtils } from '@dreamcommerce/utilities';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export class CliAuthCommandsUtils {
|
|
7
|
+
static mapToTableData(data, defaultIndex, tokensApi) {
|
|
8
|
+
return {
|
|
9
|
+
headers: [
|
|
10
|
+
{
|
|
11
|
+
content: 'Index',
|
|
12
|
+
width: 10
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
content: 'Token Name',
|
|
16
|
+
width: 40
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
content: 'Store',
|
|
20
|
+
width: 40
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
content: 'Access Scope',
|
|
24
|
+
width: 20
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
content: 'Valid until',
|
|
28
|
+
width: 20
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
rows: data.map((tokenData, index) => {
|
|
32
|
+
const tokenIndex = index + 1;
|
|
33
|
+
const isDefault = defaultIndex !== null && tokenIndex === defaultIndex;
|
|
34
|
+
const tokenName = isDefault ? React.createElement(Text, { bold: true }, `${tokenData.name} (Default)`) : tokenData.name;
|
|
35
|
+
const hasExpired = tokensApi.hasTokenExpired(tokenIndex);
|
|
36
|
+
return [
|
|
37
|
+
React.createElement(Text, { bold: isDefault }, tokenIndex),
|
|
38
|
+
tokenName,
|
|
39
|
+
React.createElement(Text, { bold: isDefault }, tokenData.iss),
|
|
40
|
+
TOKEN_SCOPE_TO_DESCRIPTION[tokenData.scope],
|
|
41
|
+
React.createElement(Text, { color: hasExpired ? CSS_TEXT_COLORS.invert : undefined, backgroundColor: hasExpired ? CSS_BACKGROUND_COLORS.danger : undefined }, DateUtils.toLocaleDate(new Date(tokenData.exp * 1000), 'pl-PL'))
|
|
42
|
+
];
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseCliCommand } from '../../class/base_cli_command.js';
|
|
2
|
+
import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { CliAuthCommandsUtils } from './cli_auth_commands_utils.js';
|
|
5
|
+
import { Table } from '../../../ui/table/table.js';
|
|
6
|
+
import { render } from '../../../ui/ui_utils.js';
|
|
7
|
+
import { Box } from '../../../ui/box.js';
|
|
8
|
+
import { Tip } from '../../../ui/tip.js';
|
|
9
|
+
import { Command } from '../../../ui/command.js';
|
|
10
|
+
import { Text } from '../../../ui/text.js';
|
|
11
|
+
import { Info } from '../../../ui/message_box/info.js';
|
|
12
|
+
export class CliAuthListTokensCommand extends BaseCliCommand {
|
|
13
|
+
static summary = 'Displays a list of all authentication tokens stored locally.';
|
|
14
|
+
static description = 'For each token, you’ll see its name, index, assigned store URL, access scope and expiration date.\n\nUse this to review your tokens and check which one is set as the default.';
|
|
15
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
16
|
+
async run() {
|
|
17
|
+
const tokensApi = this.getApi(CLI_AUTH_TOKENS_API_NAME);
|
|
18
|
+
const tokensPayloads = tokensApi.getAllTokensPayloads();
|
|
19
|
+
if (!tokensPayloads.length) {
|
|
20
|
+
await render(React.createElement(Info, null,
|
|
21
|
+
React.createElement(Box, null,
|
|
22
|
+
React.createElement(Text, null, "No tokens found")),
|
|
23
|
+
React.createElement(Tip, null,
|
|
24
|
+
"Generate one using ",
|
|
25
|
+
React.createElement(Command, null, "shoper auth add-token"))));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await render(React.createElement(Table, { data: CliAuthCommandsUtils.mapToTableData(tokensPayloads, tokensApi.getDefaultTokenIndex(), tokensApi) }));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BaseCliCommand } from '../../class/base_cli_command.js';
|
|
2
|
+
import { Args } from '@oclif/core';
|
|
3
|
+
import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
|
|
4
|
+
import { renderOnce } from '../../../ui/ui_utils.js';
|
|
5
|
+
import { MissingTokenIndexError } from './ui/missing_token_index_error.js';
|
|
6
|
+
import { InvalidTokenIndexError } from './ui/invalid_token_index_error.js';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { Text } from '../../../ui/text.js';
|
|
9
|
+
import { Command } from '../../../ui/command.js';
|
|
10
|
+
import { Box } from '../../../ui/box.js';
|
|
11
|
+
import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
|
|
12
|
+
import { Info } from '../../../ui/message_box/info.js';
|
|
13
|
+
import { Success } from '../../../ui/message_box/success.js';
|
|
14
|
+
import { Warning } from '../../../ui/message_box/warning.js';
|
|
15
|
+
import { Error } from '../../../ui/message_box/error.js';
|
|
16
|
+
export class CliAuthRemoveTokenCommand extends BaseCliCommand {
|
|
17
|
+
static summary = 'Removes a locally saved authentication token.';
|
|
18
|
+
static description = 'Use this to clean up tokens you no longer need.';
|
|
19
|
+
static examples = [
|
|
20
|
+
{
|
|
21
|
+
description: 'Remove token with index 2',
|
|
22
|
+
command: '<%= config.bin %> <%= command.id %> 2'
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
static args = {
|
|
26
|
+
index: Args.integer({
|
|
27
|
+
description: 'Index of the token to remove',
|
|
28
|
+
required: false
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const cliAuthTokensApi = this.getApi(CLI_AUTH_TOKENS_API_NAME);
|
|
33
|
+
const data = await this.parse(CliAuthRemoveTokenCommand);
|
|
34
|
+
const { args } = data;
|
|
35
|
+
const { index } = args;
|
|
36
|
+
if (!index || !cliAuthTokensApi.hasToken(index)) {
|
|
37
|
+
renderOnce(React.createElement(MissingTokenIndexError, { command: React.createElement(Command, null, "shoper auth remove-token [TOKEN_INDEX]") }));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const token = cliAuthTokensApi.getTokenPayload(index);
|
|
41
|
+
if (!token) {
|
|
42
|
+
renderOnce(React.createElement(InvalidTokenIndexError, null));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
renderOnce(React.createElement(Warning, { header: `Warning: This will permanently delete the token "${token.name}" assigned to "${token.iss}". This action cannot be undone.` }));
|
|
47
|
+
const { proceed } = await promptConfirmation('Proceed?');
|
|
48
|
+
if (proceed) {
|
|
49
|
+
cliAuthTokensApi.removeToken(index);
|
|
50
|
+
cliAuthTokensApi.setDefaultToken(cliAuthTokensApi.getTokensCount());
|
|
51
|
+
renderOnce(React.createElement(Success, { header: `Success: Token "${token.name}" has been removed.` }));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
renderOnce(React.createElement(Info, null,
|
|
55
|
+
React.createElement(Text, null, "Token removal was cancelled.")));
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
renderOnce(React.createElement(Error, { header: "Error: Failed to remove token: " },
|
|
59
|
+
React.createElement(Box, null,
|
|
60
|
+
React.createElement(Text, null, err.toString()))));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|