@shopify/cli-kit 3.32.1 → 3.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +2 -6
- package/dist/constants.js +0 -4
- package/dist/constants.js.map +1 -1
- package/dist/file.d.ts +1 -1
- package/dist/git.js +1 -1
- package/dist/git.js.map +1 -1
- package/dist/http.js +2 -2
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -5
- package/dist/index.js.map +1 -1
- package/dist/metadata.js +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/output.js +1 -1
- package/dist/output.js.map +1 -1
- package/dist/path.d.ts +1 -1
- package/dist/path.js +5 -3
- package/dist/path.js.map +1 -1
- package/dist/private/common/array.d.ts +1 -0
- package/dist/private/common/array.js +4 -0
- package/dist/private/common/array.js.map +1 -0
- package/dist/private/node/analytics.js +6 -9
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/graphql.js +1 -0
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api/headers.js +1 -1
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/api/rest.d.ts +6 -0
- package/dist/private/node/api/rest.js +27 -0
- package/dist/private/node/api/rest.js.map +1 -0
- package/dist/private/node/environment/service.d.ts +18 -0
- package/dist/private/node/environment/service.js +32 -0
- package/dist/private/node/environment/service.js.map +1 -0
- package/dist/{environment → private/node/environment}/spin-cache.d.ts +0 -0
- package/dist/{environment → private/node/environment}/spin-cache.js +0 -0
- package/dist/private/node/environment/spin-cache.js.map +1 -0
- package/dist/{environment → private/node/environment}/utilities.d.ts +0 -0
- package/dist/{environment → private/node/environment}/utilities.js +0 -0
- package/dist/private/node/environment/utilities.js.map +1 -0
- package/dist/{session → private/node/session}/authorize.d.ts +1 -5
- package/dist/{session → private/node/session}/authorize.js +9 -9
- package/dist/private/node/session/authorize.js.map +1 -0
- package/dist/{session → private/node/session}/device-authorization.d.ts +0 -0
- package/dist/{session → private/node/session}/device-authorization.js +7 -9
- package/dist/private/node/session/device-authorization.js.map +1 -0
- package/dist/{session → private/node/session}/exchange.d.ts +2 -2
- package/dist/{session → private/node/session}/exchange.js +5 -5
- package/dist/private/node/session/exchange.js.map +1 -0
- package/dist/{session → private/node/session}/identity-token-validation.d.ts +0 -0
- package/dist/{session → private/node/session}/identity-token-validation.js +4 -4
- package/dist/private/node/session/identity-token-validation.js.map +1 -0
- package/dist/{session → private/node/session}/identity.d.ts +1 -1
- package/dist/{session → private/node/session}/identity.js +2 -3
- package/dist/private/node/session/identity.js.map +1 -0
- package/dist/{session → private/node/session}/post-auth.d.ts +1 -1
- package/dist/{session → private/node/session}/post-auth.js +3 -3
- package/dist/private/node/session/post-auth.js.map +1 -0
- package/dist/{session → private/node/session}/redirect-listener.d.ts +0 -0
- package/dist/{session → private/node/session}/redirect-listener.js +2 -2
- package/dist/private/node/session/redirect-listener.js.map +1 -0
- package/dist/{session → private/node/session}/schema.d.ts +1 -1
- package/dist/{session → private/node/session}/schema.js +1 -1
- package/dist/private/node/session/schema.js.map +1 -0
- package/dist/{session → private/node/session}/scopes.d.ts +1 -1
- package/dist/{session → private/node/session}/scopes.js +2 -2
- package/dist/private/node/session/scopes.js.map +1 -0
- package/dist/{session → private/node/session}/store.d.ts +0 -0
- package/dist/{session → private/node/session}/store.js +5 -5
- package/dist/private/node/session/store.js.map +1 -0
- package/dist/{session → private/node/session}/validate.d.ts +0 -0
- package/dist/{session → private/node/session}/validate.js +5 -5
- package/dist/private/node/session/validate.js.map +1 -0
- package/dist/private/node/session.d.ts +56 -0
- package/dist/{session.js → private/node/session.js} +97 -133
- package/dist/private/node/session.js.map +1 -0
- package/dist/private/node/ui/components/Subdued.d.ts +9 -0
- package/dist/private/node/ui/components/Subdued.js +10 -0
- package/dist/private/node/ui/components/Subdued.js.map +1 -0
- package/dist/private/node/ui/components/Subdued.test.d.ts +1 -0
- package/dist/private/node/ui/components/Subdued.test.js +11 -0
- package/dist/private/node/ui/components/Subdued.test.js.map +1 -0
- package/dist/private/node/ui/components/TokenizedText.d.ts +4 -1
- package/dist/private/node/ui/components/TokenizedText.js +4 -0
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.test.js +4 -1
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/private/node/ui.js +1 -1
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/array.d.ts +4 -0
- package/dist/public/common/array.js +4 -0
- package/dist/public/common/array.js.map +1 -1
- package/dist/public/common/object.d.ts +3 -3
- package/dist/public/common/object.js +5 -7
- package/dist/public/common/object.js.map +1 -1
- package/dist/public/common/url.d.ts +2 -1
- package/dist/public/common/url.js +3 -2
- package/dist/public/common/url.js.map +1 -1
- package/dist/public/node/analytics.js +3 -3
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/api/admin.d.ts +31 -1
- package/dist/public/node/api/admin.js +28 -0
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/partners.js +7 -2
- package/dist/public/node/api/partners.js.map +1 -1
- package/dist/public/node/base-command.js +2 -2
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.d.ts +8 -0
- package/dist/public/node/cli.js +21 -4
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/environment/fqdn.d.ts +26 -0
- package/dist/{environment → public/node/environment}/fqdn.js +15 -31
- package/dist/public/node/environment/fqdn.js.map +1 -0
- package/dist/{environment → public/node/environment}/local.d.ts +62 -16
- package/dist/{environment → public/node/environment}/local.js +66 -24
- package/dist/public/node/environment/local.js.map +1 -0
- package/dist/public/node/environment/spin.d.ts +43 -0
- package/dist/{environment → public/node/environment}/spin.js +28 -35
- package/dist/public/node/environment/spin.js.map +1 -0
- package/dist/public/node/node-package-manager.js +1 -1
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/ruby.d.ts +1 -1
- package/dist/public/node/ruby.js +12 -13
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/session.d.ts +53 -0
- package/dist/public/node/session.js +95 -0
- package/dist/public/node/session.js.map +1 -0
- package/dist/public/node/system.d.ts +44 -0
- package/dist/{system.js → public/node/system.js} +34 -54
- package/dist/public/node/system.js.map +1 -0
- package/dist/public/node/tcp.js +1 -1
- package/dist/public/node/tcp.js.map +1 -1
- package/dist/public/node/ui.d.ts +1 -1
- package/dist/public/node/ui.js.map +1 -1
- package/dist/testing/ui.js +1 -1
- package/dist/testing/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui.js +1 -1
- package/dist/ui.js.map +1 -1
- package/package.json +9 -7
- package/dist/api/graphql/all_app_extension_registrations.d.ts +0 -20
- package/dist/api/graphql/all_app_extension_registrations.js +0 -20
- package/dist/api/graphql/all_app_extension_registrations.js.map +0 -1
- package/dist/api/graphql/all_dev_stores_by_org.d.ts +0 -18
- package/dist/api/graphql/all_dev_stores_by_org.js +0 -21
- package/dist/api/graphql/all_dev_stores_by_org.js.map +0 -1
- package/dist/api/graphql/all_orgs.d.ts +0 -12
- package/dist/api/graphql/all_orgs.js +0 -14
- package/dist/api/graphql/all_orgs.js.map +0 -1
- package/dist/api/graphql/convert_dev_to_test_store.d.ts +0 -16
- package/dist/api/graphql/convert_dev_to_test_store.js +0 -13
- package/dist/api/graphql/convert_dev_to_test_store.js.map +0 -1
- package/dist/api/graphql/create_app.d.ts +0 -29
- package/dist/api/graphql/create_app.js +0 -33
- package/dist/api/graphql/create_app.js.map +0 -1
- package/dist/api/graphql/create_deployment.d.ts +0 -33
- package/dist/api/graphql/create_deployment.js +0 -25
- package/dist/api/graphql/create_deployment.js.map +0 -1
- package/dist/api/graphql/extension_create.d.ts +0 -30
- package/dist/api/graphql/extension_create.js +0 -26
- package/dist/api/graphql/extension_create.js.map +0 -1
- package/dist/api/graphql/extension_specifications.d.ts +0 -27
- package/dist/api/graphql/extension_specifications.js +0 -22
- package/dist/api/graphql/extension_specifications.js.map +0 -1
- package/dist/api/graphql/find_app.d.ts +0 -14
- package/dist/api/graphql/find_app.js +0 -17
- package/dist/api/graphql/find_app.js.map +0 -1
- package/dist/api/graphql/find_org.d.ts +0 -18
- package/dist/api/graphql/find_org.js +0 -21
- package/dist/api/graphql/find_org.js.map +0 -1
- package/dist/api/graphql/find_org_basic.d.ts +0 -11
- package/dist/api/graphql/find_org_basic.js +0 -14
- package/dist/api/graphql/find_org_basic.js.map +0 -1
- package/dist/api/graphql/find_store_by_domain.d.ts +0 -21
- package/dist/api/graphql/find_store_by_domain.js +0 -24
- package/dist/api/graphql/find_store_by_domain.js.map +0 -1
- package/dist/api/graphql/functions/api_schema_definition.d.ts +0 -9
- package/dist/api/graphql/functions/api_schema_definition.js +0 -7
- package/dist/api/graphql/functions/api_schema_definition.js.map +0 -1
- package/dist/api/graphql/functions/app_function_set.d.ts +0 -30
- package/dist/api/graphql/functions/app_function_set.js +0 -38
- package/dist/api/graphql/functions/app_function_set.js.map +0 -1
- package/dist/api/graphql/functions/function_service_proxy.d.ts +0 -4
- package/dist/api/graphql/functions/function_service_proxy.js +0 -7
- package/dist/api/graphql/functions/function_service_proxy.js.map +0 -1
- package/dist/api/graphql/functions/upload_url_generate.d.ts +0 -12
- package/dist/api/graphql/functions/upload_url_generate.js +0 -11
- package/dist/api/graphql/functions/upload_url_generate.js.map +0 -1
- package/dist/api/graphql/generate_signed_upload_url.d.ts +0 -15
- package/dist/api/graphql/generate_signed_upload_url.js +0 -15
- package/dist/api/graphql/generate_signed_upload_url.js.map +0 -1
- package/dist/api/graphql/get_urls.d.ts +0 -10
- package/dist/api/graphql/get_urls.js +0 -10
- package/dist/api/graphql/get_urls.js.map +0 -1
- package/dist/api/graphql/get_variant_id.d.ts +0 -17
- package/dist/api/graphql/get_variant_id.js +0 -20
- package/dist/api/graphql/get_variant_id.js.map +0 -1
- package/dist/api/graphql/index.d.ts +0 -21
- package/dist/api/graphql/index.js +0 -22
- package/dist/api/graphql/index.js.map +0 -1
- package/dist/api/graphql/update_draft.d.ts +0 -33
- package/dist/api/graphql/update_draft.js +0 -24
- package/dist/api/graphql/update_draft.js.map +0 -1
- package/dist/api/graphql/update_urls.d.ts +0 -14
- package/dist/api/graphql/update_urls.js +0 -12
- package/dist/api/graphql/update_urls.js.map +0 -1
- package/dist/api.d.ts +0 -3
- package/dist/api.js +0 -4
- package/dist/api.js.map +0 -1
- package/dist/cli.d.ts +0 -8
- package/dist/cli.js +0 -18
- package/dist/cli.js.map +0 -1
- package/dist/environment/fqdn.d.ts +0 -29
- package/dist/environment/fqdn.js.map +0 -1
- package/dist/environment/local.js.map +0 -1
- package/dist/environment/service.d.ts +0 -4
- package/dist/environment/service.js +0 -19
- package/dist/environment/service.js.map +0 -1
- package/dist/environment/spin-cache.js.map +0 -1
- package/dist/environment/spin.d.ts +0 -50
- package/dist/environment/spin.js.map +0 -1
- package/dist/environment/utilities.js.map +0 -1
- package/dist/environment.d.ts +0 -7
- package/dist/environment.js +0 -8
- package/dist/environment.js.map +0 -1
- package/dist/network/service.d.ts +0 -14
- package/dist/network/service.js +0 -11
- package/dist/network/service.js.map +0 -1
- package/dist/public/node/checksum.d.ts +0 -20
- package/dist/public/node/checksum.js +0 -32
- package/dist/public/node/checksum.js.map +0 -1
- package/dist/session/authorize.js.map +0 -1
- package/dist/session/device-authorization.js.map +0 -1
- package/dist/session/exchange.js.map +0 -1
- package/dist/session/identity-token-validation.js.map +0 -1
- package/dist/session/identity.js.map +0 -1
- package/dist/session/post-auth.js.map +0 -1
- package/dist/session/redirect-listener.js.map +0 -1
- package/dist/session/schema.js.map +0 -1
- package/dist/session/scopes.js.map +0 -1
- package/dist/session/store.js.map +0 -1
- package/dist/session/token.d.ts +0 -40
- package/dist/session/token.js +0 -22
- package/dist/session/token.js.map +0 -1
- package/dist/session/validate.js.map +0 -1
- package/dist/session.d.ts +0 -96
- package/dist/session.js.map +0 -1
- package/dist/system.d.ts +0 -51
- package/dist/system.js.map +0 -1
|
@@ -1,107 +1,35 @@
|
|
|
1
1
|
import { applicationId } from './session/identity.js';
|
|
2
|
-
import { Abort, Bug } from './error.js';
|
|
3
2
|
import { validateSession } from './session/validate.js';
|
|
4
3
|
import { allDefaultScopes, apiScopes } from './session/scopes.js';
|
|
5
|
-
import { identity as identityFqdn, normalizeStoreName, partners as partnersFqdn } from './environment/fqdn.js';
|
|
6
|
-
import { open } from './system.js';
|
|
7
4
|
import { exchangeAccessForApplicationTokens, exchangeCodeForAccessToken, exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError, InvalidRequestError, } from './session/exchange.js';
|
|
8
|
-
import { content, token, debug } from './output.js';
|
|
9
|
-
import { keypress } from './ui.js';
|
|
10
5
|
import { authorize } from './session/authorize.js';
|
|
11
6
|
import * as secureStore from './session/store.js';
|
|
12
|
-
import constants from './constants.js';
|
|
13
|
-
import * as output from './output.js';
|
|
14
|
-
import { firstPartyDev, useDeviceAuth } from './environment/local.js';
|
|
15
7
|
import { pollForDeviceAuthorization, requestDeviceAuthorization } from './session/device-authorization.js';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
8
|
+
import { RequestClientError } from './api/headers.js';
|
|
9
|
+
import { content, token, debug } from '../../output.js';
|
|
10
|
+
import { keypress } from '../../ui.js';
|
|
11
|
+
import constants from '../../constants.js';
|
|
12
|
+
import * as output from '../../output.js';
|
|
13
|
+
import { firstPartyDev, useDeviceAuth } from '../../public/node/environment/local.js';
|
|
14
|
+
import { AbortError } from '../../public/node/error.js';
|
|
15
|
+
import { partnersRequest } from '../../public/node/api/partners.js';
|
|
16
|
+
import { normalizeStoreFqdn, partnersFqdn, identityFqdn } from '../../public/node/environment/fqdn.js';
|
|
17
|
+
import { openURL } from '../../public/node/system.js';
|
|
18
|
+
import { Abort, Bug } from '../../error.js';
|
|
19
19
|
import { gql } from 'graphql-request';
|
|
20
|
-
const NoSessionError = new Bug('No session found after ensuring authenticated');
|
|
21
|
-
const MissingPartnerTokenError = new Bug('No partners token found after ensuring authenticated');
|
|
22
|
-
const MissingAdminTokenError = new Bug('No admin token found after ensuring authenticated');
|
|
23
|
-
const MissingStorefrontTokenError = new Bug('No storefront token found after ensuring authenticated');
|
|
24
|
-
/**
|
|
25
|
-
* Ensure that we have a valid session to access the Partners API.
|
|
26
|
-
* If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token
|
|
27
|
-
* If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored
|
|
28
|
-
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
29
|
-
* @returns The access token for the Partners API.
|
|
30
|
-
*/
|
|
31
|
-
export async function ensureAuthenticatedPartners(scopes = [], env = process.env) {
|
|
32
|
-
debug(content `Ensuring that the user is authenticated with the Partners API with the following scopes:
|
|
33
|
-
${token.json(scopes)}
|
|
34
|
-
`);
|
|
35
|
-
const envToken = env[constants.environmentVariables.partnersToken];
|
|
36
|
-
if (envToken) {
|
|
37
|
-
return (await exchangeCustomPartnerToken(envToken)).accessToken;
|
|
38
|
-
}
|
|
39
|
-
const tokens = await ensureAuthenticated({ partnersApi: { scopes } });
|
|
40
|
-
if (!tokens.partners) {
|
|
41
|
-
throw MissingPartnerTokenError;
|
|
42
|
-
}
|
|
43
|
-
return tokens.partners;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Ensure that we have a valid session to access the Storefront API.
|
|
47
|
-
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
48
|
-
* @returns The access token for the Storefront API.
|
|
49
|
-
*/
|
|
50
|
-
export async function ensureAuthenticatedStorefront(scopes = [], password = undefined) {
|
|
51
|
-
if (password)
|
|
52
|
-
return password;
|
|
53
|
-
debug(content `Ensuring that the user is authenticated with the Storefront API with the following scopes:
|
|
54
|
-
${token.json(scopes)}
|
|
55
|
-
`);
|
|
56
|
-
const tokens = await ensureAuthenticated({ storefrontRendererApi: { scopes } });
|
|
57
|
-
if (!tokens.storefront) {
|
|
58
|
-
throw MissingStorefrontTokenError;
|
|
59
|
-
}
|
|
60
|
-
return tokens.storefront;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Ensure that we have a valid Admin session for the given store.
|
|
64
|
-
* @param store - Store fqdn to request auth for
|
|
65
|
-
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
66
|
-
* @returns The access token for the Admin API
|
|
67
|
-
*/
|
|
68
|
-
export async function ensureAuthenticatedAdmin(store, scopes = [], forceRefresh = false) {
|
|
69
|
-
debug(content `Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${token.raw(store)}:
|
|
70
|
-
${token.json(scopes)}
|
|
71
|
-
`);
|
|
72
|
-
const tokens = await ensureAuthenticated({ adminApi: { scopes, storeFqdn: store } }, process.env, forceRefresh);
|
|
73
|
-
if (!tokens.admin) {
|
|
74
|
-
throw MissingAdminTokenError;
|
|
75
|
-
}
|
|
76
|
-
return tokens.admin;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Ensure that we have a valid session to access the Theme API.
|
|
80
|
-
* If a password is provided, that token will be used against Theme Access API.
|
|
81
|
-
* Otherwise, it will ensure that the user is authenticated with the Admin API.
|
|
82
|
-
* @param store - Store fqdn to request auth for
|
|
83
|
-
* @param password - Password generated from Theme Access app
|
|
84
|
-
* @param scopes - Optional array of extra scopes to authenticate with.
|
|
85
|
-
* @returns The access token and store
|
|
86
|
-
*/
|
|
87
|
-
export async function ensureAuthenticatedThemes(store, password, scopes = [], forceRefresh = false) {
|
|
88
|
-
debug(content `Ensuring that the user is authenticated with the Theme API with the following scopes:
|
|
89
|
-
${token.json(scopes)}
|
|
90
|
-
`);
|
|
91
|
-
if (password)
|
|
92
|
-
return { token: password, storeFqdn: await normalizeStoreName(store) };
|
|
93
|
-
return ensureAuthenticatedAdmin(store, scopes, forceRefresh);
|
|
94
|
-
}
|
|
95
20
|
/**
|
|
96
21
|
* This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
|
|
22
|
+
*
|
|
97
23
|
* @param applications - An object containing the applications we need to be authenticated with.
|
|
24
|
+
* @param env - Optional environment variables to use.
|
|
25
|
+
* @param forceRefresh - Optional flag to force a refresh of the token.
|
|
98
26
|
* @returns An instance with the access tokens organized by application.
|
|
99
27
|
*/
|
|
100
28
|
export async function ensureAuthenticated(applications, env = process.env, forceRefresh = false) {
|
|
101
29
|
const fqdn = await identityFqdn();
|
|
102
30
|
const previousStoreFqdn = applications.adminApi?.storeFqdn;
|
|
103
31
|
if (previousStoreFqdn) {
|
|
104
|
-
const normalizedStoreName = await
|
|
32
|
+
const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn);
|
|
105
33
|
if (previousStoreFqdn === applications.adminApi?.storeFqdn) {
|
|
106
34
|
applications.adminApi.storeFqdn = normalizedStoreName;
|
|
107
35
|
}
|
|
@@ -151,50 +79,12 @@ ${token.json(applications)}
|
|
|
151
79
|
}
|
|
152
80
|
return tokens;
|
|
153
81
|
}
|
|
154
|
-
export async function hasPartnerAccount(partnersToken) {
|
|
155
|
-
try {
|
|
156
|
-
await partnersRequest(gql `
|
|
157
|
-
{
|
|
158
|
-
organizations(first: 1) {
|
|
159
|
-
nodes {
|
|
160
|
-
id
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
`, partnersToken);
|
|
165
|
-
return true;
|
|
166
|
-
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
if (error instanceof RequestClientError && error.statusCode === 404) {
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
82
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
* @param
|
|
83
|
+
* Execute the full authentication flow.
|
|
84
|
+
*
|
|
85
|
+
* @param applications - An object containing the applications we need to be authenticated with.
|
|
86
|
+
* @param identityFqdn - The identity FQDN.
|
|
182
87
|
*/
|
|
183
|
-
export async function ensureUserHasPartnerAccount(partnersToken) {
|
|
184
|
-
debug(content `Verifying that the user has a Partner organization`);
|
|
185
|
-
if (!(await hasPartnerAccount(partnersToken))) {
|
|
186
|
-
output.info(`\nA Shopify Partners organization is needed to proceed.`);
|
|
187
|
-
output.info(`👉 Press any key to create one`);
|
|
188
|
-
await keypress();
|
|
189
|
-
await open(`https://${await partnersFqdn()}/signup`);
|
|
190
|
-
output.info(output.content `👉 Press any key when you have ${output.token.cyan('created the organization')}`);
|
|
191
|
-
output.warn(output.content `Make sure you've confirmed your Shopify and the Partner organization from the email`);
|
|
192
|
-
await keypress();
|
|
193
|
-
if (!(await hasPartnerAccount(partnersToken))) {
|
|
194
|
-
throw new Abort(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
88
|
async function executeCompleteFlow(applications, identityFqdn) {
|
|
199
89
|
const scopes = getFlattenScopes(applications);
|
|
200
90
|
const exchangeScopes = getExchangeScopes(applications);
|
|
@@ -232,6 +122,64 @@ async function executeCompleteFlow(applications, identityFqdn) {
|
|
|
232
122
|
output.completed('Logged in.');
|
|
233
123
|
return session;
|
|
234
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* If the user creates an account from the Identity website, the created
|
|
127
|
+
* account won't get a Partner organization created. We need to detect that
|
|
128
|
+
* and take the user to create a partner organization.
|
|
129
|
+
*
|
|
130
|
+
* @param partnersToken - Partners token.
|
|
131
|
+
*/
|
|
132
|
+
async function ensureUserHasPartnerAccount(partnersToken) {
|
|
133
|
+
debug(content `Verifying that the user has a Partner organization`);
|
|
134
|
+
if (!(await hasPartnerAccount(partnersToken))) {
|
|
135
|
+
output.info(`\nA Shopify Partners organization is needed to proceed.`);
|
|
136
|
+
output.info(`👉 Press any key to create one`);
|
|
137
|
+
await keypress();
|
|
138
|
+
await openURL(`https://${await partnersFqdn()}/signup`);
|
|
139
|
+
output.info(output.content `👉 Press any key when you have ${output.token.cyan('created the organization')}`);
|
|
140
|
+
output.warn(output.content `Make sure you've confirmed your Shopify and the Partner organization from the email`);
|
|
141
|
+
await keypress();
|
|
142
|
+
if (!(await hasPartnerAccount(partnersToken))) {
|
|
143
|
+
throw new Abort(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate if the current token is valid for partners API.
|
|
149
|
+
*
|
|
150
|
+
* @param partnersToken - Partners token.
|
|
151
|
+
* @returns A promise that resolves to true if the token is valid for partners API.
|
|
152
|
+
*/
|
|
153
|
+
async function hasPartnerAccount(partnersToken) {
|
|
154
|
+
try {
|
|
155
|
+
await partnersRequest(gql `
|
|
156
|
+
{
|
|
157
|
+
organizations(first: 1) {
|
|
158
|
+
nodes {
|
|
159
|
+
id
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
`, partnersToken);
|
|
164
|
+
return true;
|
|
165
|
+
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (error instanceof RequestClientError && error.statusCode === 404) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Refresh the tokens for a given session.
|
|
178
|
+
*
|
|
179
|
+
* @param token - Identity token.
|
|
180
|
+
* @param applications - An object containing the applications we need to be authenticated with.
|
|
181
|
+
* @param fqdn - The identity FQDN.
|
|
182
|
+
*/
|
|
235
183
|
async function refreshTokens(token, applications, fqdn) {
|
|
236
184
|
// Refresh Identity Token
|
|
237
185
|
const identityToken = await refreshAccessToken(token);
|
|
@@ -245,10 +193,17 @@ async function refreshTokens(token, applications, fqdn) {
|
|
|
245
193
|
},
|
|
246
194
|
};
|
|
247
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Get the application tokens for a given session.
|
|
198
|
+
*
|
|
199
|
+
* @param applications - An object containing the applications we need the tokens for.
|
|
200
|
+
* @param session - The current session.
|
|
201
|
+
* @param fqdn - The identity FQDN.
|
|
202
|
+
*/
|
|
248
203
|
async function tokensFor(applications, session, fqdn) {
|
|
249
204
|
const fqdnSession = session[fqdn];
|
|
250
205
|
if (!fqdnSession) {
|
|
251
|
-
throw
|
|
206
|
+
throw new Bug('No session found after ensuring authenticated');
|
|
252
207
|
}
|
|
253
208
|
const tokens = {};
|
|
254
209
|
if (applications.adminApi) {
|
|
@@ -270,6 +225,12 @@ async function tokensFor(applications, session, fqdn) {
|
|
|
270
225
|
return tokens;
|
|
271
226
|
}
|
|
272
227
|
// Scope Helpers
|
|
228
|
+
/**
|
|
229
|
+
* Get a flattened array of scopes for the given applications.
|
|
230
|
+
*
|
|
231
|
+
* @param apps - An object containing the applications we need the scopes for.
|
|
232
|
+
* @returns A flattened array of scopes.
|
|
233
|
+
*/
|
|
273
234
|
function getFlattenScopes(apps) {
|
|
274
235
|
const admin = apps.adminApi?.scopes || [];
|
|
275
236
|
const partner = apps.partnersApi?.scopes || [];
|
|
@@ -277,6 +238,12 @@ function getFlattenScopes(apps) {
|
|
|
277
238
|
const requestedScopes = [...admin, ...partner, ...storefront];
|
|
278
239
|
return allDefaultScopes(requestedScopes);
|
|
279
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Get the scopes for the given applications.
|
|
243
|
+
*
|
|
244
|
+
* @param apps - An object containing the applications we need the scopes for.
|
|
245
|
+
* @returns An object containing the scopes for each application.
|
|
246
|
+
*/
|
|
280
247
|
function getExchangeScopes(apps) {
|
|
281
248
|
const adminScope = apps.adminApi?.scopes || [];
|
|
282
249
|
const partnerScope = apps.partnersApi?.scopes || [];
|
|
@@ -287,7 +254,4 @@ function getExchangeScopes(apps) {
|
|
|
287
254
|
storefront: apiScopes('storefront-renderer', storefrontScopes),
|
|
288
255
|
};
|
|
289
256
|
}
|
|
290
|
-
export function logout() {
|
|
291
|
-
return secureStore.remove();
|
|
292
|
-
}
|
|
293
257
|
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/private/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {applicationId} from './session/identity.js'\nimport {validateSession} from './session/validate.js'\nimport {allDefaultScopes, apiScopes} from './session/scopes.js'\nimport {\n exchangeAccessForApplicationTokens,\n exchangeCodeForAccessToken,\n exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\n\nimport {authorize} from './session/authorize.js'\nimport {IdentityToken, Session} from './session/schema.js'\nimport * as secureStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {RequestClientError} from './api/headers.js'\nimport {content, token, debug} from '../../output.js'\nimport {keypress} from '../../ui.js'\n\nimport constants from '../../constants.js'\nimport * as output from '../../output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/environment/local.js'\nimport {AbortError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/environment/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {Abort, Bug} from '../../error.js'\nimport {gql} from 'graphql-request'\n\nimport {AdminSession} from '@shopify/cli-kit/node/session'\n\n/**\n * A scope supported by the Shopify Admin API.\n */\ntype AdminAPIScope = 'graphql' | 'themes' | 'collaborator' | string\n\n/**\n * It represents the options to authenticate against the Shopify Admin API.\n */\n\ninterface AdminAPIOAuthOptions {\n /** Store to request permissions for. */\n storeFqdn: string\n /** List of scopes to request permissions for. */\n scopes: AdminAPIScope[]\n}\n\n/**\n * A scope supported by the Partners API.\n */\ntype PartnersAPIScope = 'cli' | string\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\ntype StorefrontRendererScope = 'devtools' | string\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\n/**\n * It represents the authentication requirements and\n * is the input necessary to trigger the authentication\n * flow.\n */\nexport interface OAuthApplications {\n adminApi?: AdminAPIOAuthOptions\n storefrontRendererApi?: StorefrontRendererAPIOAuthOptions\n partnersApi?: PartnersAPIOAuthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n}\n\n/**\n * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param env - Optional environment variables to use.\n * @param forceRefresh - Optional flag to force a refresh of the token.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n env = process.env,\n forceRefresh = false,\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const currentSession = (await secureStore.fetch()) || {}\n const fqdnSession = currentSession[fqdn]!\n const scopes = getFlattenScopes(applications)\n\n debug(content`Validating existing session against the scopes:\n${token.json(scopes)}\nFor applications:\n${token.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n debug(content`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n debug(content`The current session is valid but needs refresh. Refreshing...`)\n try {\n newSession = await refreshTokens(fqdnSession.identity, applications, fqdn)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (error instanceof InvalidRequestError) {\n await secureStore.remove()\n throw new AbortError('\\nError validating auth session', \"We've cleared the current session, please try again\")\n } else {\n throw error\n }\n }\n }\n\n const completeSession: Session = {...currentSession, ...newSession}\n await secureStore.store(completeSession)\n const tokens = await tokensFor(applications, completeSession, fqdn)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = env[constants.environmentVariables.partnersToken]\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n if (!envToken && tokens.partners) {\n await ensureUserHasPartnerAccount(tokens.partners)\n }\n\n return tokens\n}\n\n/**\n * Execute the full authentication flow.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param identityFqdn - The identity FQDN.\n */\nasync function executeCompleteFlow(applications: OAuthApplications, identityFqdn: string): Promise<Session> {\n const scopes = getFlattenScopes(applications)\n const exchangeScopes = getExchangeScopes(applications)\n const store = applications.adminApi?.storeFqdn\n if (firstPartyDev()) {\n debug(content`Authenticating as Shopify Employee...`)\n scopes.push('employee')\n }\n\n let identityToken: IdentityToken\n if (useDeviceAuth()) {\n // Request a device code to authorize without a browser redirect.\n debug(content`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n debug(content`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n debug(content`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n debug(content`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n debug(content`CLI token received. Exchanging it for application tokens...`)\n const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store)\n\n const session: Session = {\n [identityFqdn]: {\n identity: identityToken,\n applications: result,\n },\n }\n\n output.completed('Logged in.')\n\n return session\n}\n\n/**\n * If the user creates an account from the Identity website, the created\n * account won't get a Partner organization created. We need to detect that\n * and take the user to create a partner organization.\n *\n * @param partnersToken - Partners token.\n */\nasync function ensureUserHasPartnerAccount(partnersToken: string) {\n debug(content`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n output.info(`\\nA Shopify Partners organization is needed to proceed.`)\n output.info(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n output.info(output.content`👉 Press any key when you have ${output.token.cyan('created the organization')}`)\n output.warn(output.content`Make sure you've confirmed your Shopify and the Partner organization from the email`)\n await keypress()\n if (!(await hasPartnerAccount(partnersToken))) {\n throw new Abort(\n `Couldn't find your Shopify Partners organization`,\n `Have you confirmed your accounts from the emails you received?`,\n )\n }\n }\n}\n\n/**\n * Validate if the current token is valid for partners API.\n *\n * @param partnersToken - Partners token.\n * @returns A promise that resolves to true if the token is valid for partners API.\n */\nasync function hasPartnerAccount(partnersToken: string): Promise<boolean> {\n try {\n await partnersRequest(\n gql`\n {\n organizations(first: 1) {\n nodes {\n id\n }\n }\n }\n `,\n partnersToken,\n )\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n if (error instanceof RequestClientError && error.statusCode === 404) {\n return false\n } else {\n return true\n }\n }\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param token - Identity token.\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param fqdn - The identity FQDN.\n */\nasync function refreshTokens(token: IdentityToken, applications: OAuthApplications, fqdn: string): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(token)\n // Exchange new identity token for application tokens\n const exchangeScopes = getExchangeScopes(applications)\n const applicationTokens = await exchangeAccessForApplicationTokens(\n identityToken,\n exchangeScopes,\n applications.adminApi?.storeFqdn,\n )\n\n return {\n [fqdn]: {\n identity: identityToken,\n applications: applicationTokens,\n },\n }\n}\n\n/**\n * Get the application tokens for a given session.\n *\n * @param applications - An object containing the applications we need the tokens for.\n * @param session - The current session.\n * @param fqdn - The identity FQDN.\n */\nasync function tokensFor(applications: OAuthApplications, session: Session, fqdn: string): Promise<OAuthSession> {\n const fqdnSession = session[fqdn]\n if (!fqdnSession) {\n throw new Bug('No session found after ensuring authenticated')\n }\n const tokens: OAuthSession = {}\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = fqdnSession.applications[realAppId]?.accessToken\n if (token) {\n tokens.admin = {token, storeFqdn: applications.adminApi.storeFqdn}\n }\n }\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n tokens.partners = fqdnSession.applications[appId]?.accessToken\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n tokens.storefront = fqdnSession.applications[appId]?.accessToken\n }\n return tokens\n}\n\n// Scope Helpers\n/**\n * Get a flattened array of scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns A flattened array of scopes.\n */\nfunction getFlattenScopes(apps: OAuthApplications): string[] {\n const admin = apps.adminApi?.scopes || []\n const partner = apps.partnersApi?.scopes || []\n const storefront = apps.storefrontRendererApi?.scopes || []\n const requestedScopes = [...admin, ...partner, ...storefront]\n return allDefaultScopes(requestedScopes)\n}\n\n/**\n * Get the scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns An object containing the scopes for each application.\n */\nfunction getExchangeScopes(apps: OAuthApplications): ExchangeScopes {\n const adminScope = apps.adminApi?.scopes || []\n const partnerScope = apps.partnersApi?.scopes || []\n const storefrontScopes = apps.storefrontRendererApi?.scopes || []\n return {\n admin: apiScopes('admin', adminScope),\n partners: apiScopes('partners', partnerScope),\n storefront: apiScopes('storefront-renderer', storefrontScopes),\n }\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Text } from 'ink';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* `Subdued` displays some text with subdued colors
|
|
5
|
+
*/
|
|
6
|
+
const Subdued = ({ subdued }) => {
|
|
7
|
+
return React.createElement(Text, { dimColor: true }, subdued);
|
|
8
|
+
};
|
|
9
|
+
export { Subdued };
|
|
10
|
+
//# sourceMappingURL=Subdued.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Subdued.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Subdued.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB;;GAEG;AACH,MAAM,OAAO,GAAoB,CAAC,EAAC,OAAO,EAAiC,EAAe,EAAE;IAC1F,OAAO,oBAAC,IAAI,IAAC,QAAQ,UAAE,OAAO,CAAQ,CAAA;AACxC,CAAC,CAAA;AAED,OAAO,EAAC,OAAO,EAAC,CAAA","sourcesContent":["import {Text} from 'ink'\nimport React from 'react'\n\ninterface Props {\n subdued: string\n}\n\n/**\n * `Subdued` displays some text with subdued colors\n */\nconst Subdued: React.FC<Props> = ({subdued}: React.PropsWithChildren<Props>): JSX.Element => {\n return <Text dimColor>{subdued}</Text>\n}\n\nexport {Subdued}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Subdued } from './Subdued.js';
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { render } from 'ink-testing-library';
|
|
5
|
+
describe('Subdued', async () => {
|
|
6
|
+
test('renders correctly', async () => {
|
|
7
|
+
const { lastFrame } = render(React.createElement(Subdued, { subdued: "my-text" }));
|
|
8
|
+
expect(lastFrame()).toEqual('[2mmy-text[22m');
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=Subdued.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Subdued.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Subdued.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;IAC7B,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,OAAO,IAAC,OAAO,EAAC,SAAS,GAAG,CAAC,CAAA;QAEzD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {Subdued} from './Subdued.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('Subdued', async () => {\n test('renders correctly', async () => {\n const {lastFrame} = render(<Subdued subdued=\"my-text\" />)\n\n expect(lastFrame()).toEqual('\u001b[2mmy-text\u001b[22m')\n })\n})\n"]}
|
|
@@ -14,6 +14,9 @@ interface CharToken {
|
|
|
14
14
|
interface UserInputToken {
|
|
15
15
|
userInput: string;
|
|
16
16
|
}
|
|
17
|
+
interface SubduedToken {
|
|
18
|
+
subdued: string;
|
|
19
|
+
}
|
|
17
20
|
interface FilePathToken {
|
|
18
21
|
filePath: string;
|
|
19
22
|
}
|
|
@@ -23,7 +26,7 @@ interface ListToken {
|
|
|
23
26
|
ordered?: boolean;
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
|
-
declare type Token = string | CommandToken | LinkToken | CharToken | UserInputToken | FilePathToken | ListToken;
|
|
29
|
+
declare type Token = string | CommandToken | LinkToken | CharToken | UserInputToken | SubduedToken | FilePathToken | ListToken;
|
|
27
30
|
export declare type TokenItem = Token | Token[];
|
|
28
31
|
interface Props {
|
|
29
32
|
item: TokenItem;
|
|
@@ -3,6 +3,7 @@ import { Link } from './Link.js';
|
|
|
3
3
|
import { List } from './List.js';
|
|
4
4
|
import { UserInput } from './UserInput.js';
|
|
5
5
|
import { FilePath } from './FilePath.js';
|
|
6
|
+
import { Subdued } from './Subdued.js';
|
|
6
7
|
import { Box, Text } from 'ink';
|
|
7
8
|
import React from 'react';
|
|
8
9
|
function tokenToBlock(token) {
|
|
@@ -46,6 +47,9 @@ const TokenizedText = ({ item }) => {
|
|
|
46
47
|
else if ('userInput' in item) {
|
|
47
48
|
return React.createElement(UserInput, { userInput: item.userInput });
|
|
48
49
|
}
|
|
50
|
+
else if ('subdued' in item) {
|
|
51
|
+
return React.createElement(Subdued, { subdued: item.subdued });
|
|
52
|
+
}
|
|
49
53
|
else if ('filePath' in item) {
|
|
50
54
|
return React.createElement(FilePath, { filePath: item.filePath });
|
|
51
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenizedText.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AACtC,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"TokenizedText.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Command} from './Command.js'\nimport {Link} from './Link.js'\nimport {List} from './List.js'\nimport {UserInput} from './UserInput.js'\nimport {FilePath} from './FilePath.js'\nimport {Subdued} from './Subdued.js'\nimport {Box, Text} from 'ink'\nimport React from 'react'\n\ninterface CommandToken {\n command: string\n}\n\ninterface LinkToken {\n link: {\n label?: string\n url: string\n }\n}\n\ninterface CharToken {\n char: string\n}\n\ninterface UserInputToken {\n userInput: string\n}\n\ninterface SubduedToken {\n subdued: string\n}\n\ninterface FilePathToken {\n filePath: string\n}\n\ninterface ListToken {\n list: {\n items: TokenItem[]\n ordered?: boolean\n }\n}\n\ntype Token = string | CommandToken | LinkToken | CharToken | UserInputToken | SubduedToken | FilePathToken | ListToken\nexport type TokenItem = Token | Token[]\n\ntype DisplayType = 'block' | 'inline'\ninterface Block {\n display: DisplayType\n value: Token\n}\n\nfunction tokenToBlock(token: Token): Block {\n return {\n display: typeof token !== 'string' && 'list' in token ? 'block' : 'inline',\n value: token,\n }\n}\n\nfunction splitByDisplayType(acc: Block[][], item: Block) {\n if (item.display === 'block') {\n acc.push([item])\n } else {\n const last = acc[acc.length - 1]\n if (last && last[0]!.display === 'inline') {\n last.push(item)\n } else {\n acc.push([item])\n }\n }\n return acc\n}\n\ninterface Props {\n item: TokenItem\n}\n\n/**\n * `TokenizedText` renders a text string with tokens that can be either strings,\n * links, and commands.\n */\nconst TokenizedText: React.FC<Props> = ({item}) => {\n if (typeof item === 'string') {\n return <Text>{item}</Text>\n } else if ('command' in item) {\n return <Command command={item.command} />\n } else if ('link' in item) {\n return <Link {...item.link} />\n } else if ('char' in item) {\n return <Text>{item.char[0]}</Text>\n } else if ('userInput' in item) {\n return <UserInput userInput={item.userInput} />\n } else if ('subdued' in item) {\n return <Subdued subdued={item.subdued} />\n } else if ('filePath' in item) {\n return <FilePath filePath={item.filePath} />\n } else if ('list' in item) {\n return <List {...item.list} />\n } else {\n const groupedItems = item.map(tokenToBlock).reduce(splitByDisplayType, [])\n\n return (\n <Box flexDirection=\"column\">\n {groupedItems.map((items, groupIndex) => {\n if (items[0]!.display === 'inline') {\n return (\n <Text key={groupIndex}>\n {items.map((item, itemIndex) => (\n <Text key={itemIndex}>\n {itemIndex !== 0 && !(typeof item.value !== 'string' && 'char' in item.value) && <Text> </Text>}\n <TokenizedText item={item.value} />\n </Text>\n ))}\n </Text>\n )\n } else {\n return <List key={groupIndex} items={(items[0]!.value as ListToken).list.items} />\n }\n })}\n </Box>\n )\n }\n}\n\nexport {TokenizedText}\n"]}
|
|
@@ -22,6 +22,9 @@ describe('TokenizedText', async () => {
|
|
|
22
22
|
{
|
|
23
23
|
userInput: 'my-app',
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
subdued: '(my-text)',
|
|
27
|
+
},
|
|
25
28
|
{
|
|
26
29
|
list: {
|
|
27
30
|
items: ['Item 1', 'Item 2', 'Item 3'],
|
|
@@ -33,7 +36,7 @@ describe('TokenizedText', async () => {
|
|
|
33
36
|
];
|
|
34
37
|
const { lastFrame } = render(React.createElement(TokenizedText, { item: item }));
|
|
35
38
|
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
36
|
-
"Run \`cd verification-app\` Example ( https://example.com )! my-app
|
|
39
|
+
"Run \`cd verification-app\` Example ( https://example.com )! my-app (my-text)
|
|
37
40
|
• Item 1
|
|
38
41
|
• Item 2
|
|
39
42
|
• Item 3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenizedText.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;IACnC,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,IAAI,GAAG;YACX,KAAK;YACL;gBACE,OAAO,EAAE,qBAAqB;aAC/B;YACD;gBACE,IAAI,EAAE;oBACJ,GAAG,EAAE,qBAAqB;oBAC1B,KAAK,EAAE,SAAS;iBACjB;aACF;YACD;gBACE,IAAI,EAAE,GAAG;aACV;YACD;gBACE,SAAS,EAAE,QAAQ;aACpB;YACD;gBACE,IAAI,EAAE;oBACJ,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;iBACtC;aACF;YACD;gBACE,QAAQ,EAAE,uBAAuB;aAClC;SACF,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CAAC,CAAA;QAEzD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;KAMpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {TokenizedText} from './TokenizedText.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('TokenizedText', async () => {\n test('renders arrays of items separated by spaces', async () => {\n const item = [\n 'Run',\n {\n command: 'cd verification-app',\n },\n {\n link: {\n url: 'https://example.com',\n label: 'Example',\n },\n },\n {\n char: '!',\n },\n {\n userInput: 'my-app',\n },\n {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n {\n filePath: 'src/this/is/a/test.js',\n },\n ]\n\n const {lastFrame} = render(<TokenizedText item={item} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Run \\`cd verification-app\\` Example ( https://example.com )! my-app\n • Item 1\n • Item 2\n • Item 3\n \\\\\"src/this/is/a/test.js\\\\\"\"\n `)\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"TokenizedText.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;IACnC,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,IAAI,GAAG;YACX,KAAK;YACL;gBACE,OAAO,EAAE,qBAAqB;aAC/B;YACD;gBACE,IAAI,EAAE;oBACJ,GAAG,EAAE,qBAAqB;oBAC1B,KAAK,EAAE,SAAS;iBACjB;aACF;YACD;gBACE,IAAI,EAAE,GAAG;aACV;YACD;gBACE,SAAS,EAAE,QAAQ;aACpB;YACD;gBACE,OAAO,EAAE,WAAW;aACrB;YACD;gBACE,IAAI,EAAE;oBACJ,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;iBACtC;aACF;YACD;gBACE,QAAQ,EAAE,uBAAuB;aAClC;SACF,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CAAC,CAAA;QAEzD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;KAMpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {TokenizedText} from './TokenizedText.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('TokenizedText', async () => {\n test('renders arrays of items separated by spaces', async () => {\n const item = [\n 'Run',\n {\n command: 'cd verification-app',\n },\n {\n link: {\n url: 'https://example.com',\n label: 'Example',\n },\n },\n {\n char: '!',\n },\n {\n userInput: 'my-app',\n },\n {\n subdued: '(my-text)',\n },\n {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n {\n filePath: 'src/this/is/a/test.js',\n },\n ]\n\n const {lastFrame} = render(<TokenizedText item={item} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Run \\`cd verification-app\\` Example ( https://example.com )! my-app (my-text)\n • Item 1\n • Item 2\n • Item 3\n \\\\\"src/this/is/a/test.js\\\\\"\"\n `)\n })\n})\n"]}
|
package/dist/private/node/ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isUnitTest } from '../../environment/local.js';
|
|
2
1
|
import { collectLog, consoleLog, outputWhereAppropriate } from '../../output.js';
|
|
2
|
+
import { isUnitTest } from '../../public/node/environment/local.js';
|
|
3
3
|
import { render as inkRender } from 'ink';
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
export function renderOnce(element, logLevel = 'info', logger = consoleLog) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,UAAU,EAAoB,sBAAsB,EAAC,MAAM,iBAAiB,CAAA;AAChG,OAAO,EAAC,UAAU,EAAC,MAAM,wCAAwC,CAAA;AAEjE,OAAO,EAAM,MAAM,IAAI,SAAS,EAAgB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAA;AAEnC,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,WAAqB,MAAM,EAAE,SAAiB,UAAU;IACvG,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;IAE/C,IAAI,MAAM,EAAE;QACV,IAAI,UAAU,EAAE;YAAE,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAC9C,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;KACjD;IAED,OAAO,EAAE,CAAA;AACX,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAoB,EAAE,OAAuB;IAClE,MAAM,EAAC,aAAa,EAAC,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACnD,OAAO,aAAa,EAAE,CAAA;AACxB,CAAC;AAOD,MAAM,OAAO,YAAa,SAAQ,YAAY;IAI5C,YAAY,OAA0B;QACpC,KAAK,EAAE,CAAA;QAIT,UAAK,GAAG,CAAC,KAAa,EAAE,EAAE;YACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;QACzB,CAAC,CAAA;QAED,cAAS,GAAG,GAAG,EAAE;YACf,OAAO,IAAI,CAAC,UAAU,CAAA;QACxB,CAAC,CAAA;QATC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAChC,CAAC;CASF;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAY,EAAE;IAC9D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAC,CAAC,CAAA;IAClE,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAC,CAAC,CAAA;IAElE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,EAAE;QAClC,8DAA8D;QAC9D,MAAM,EAAE,MAAa;QACrB,8DAA8D;QAC9D,MAAM,EAAE,MAAa;QACrB,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE;QAC1B,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAA;AACH,CAAC,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,GAAQ;IACjD,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE;QAC7B,gEAAgE;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAChB;AACH,CAAC","sourcesContent":["import {collectLog, consoleLog, Logger, LogLevel, outputWhereAppropriate} from '../../output.js'\nimport {isUnitTest} from '../../public/node/environment/local.js'\nimport {ReactElement} from 'react'\nimport {Key, render as inkRender, RenderOptions} from 'ink'\nimport {EventEmitter} from 'events'\n\nexport function renderOnce(element: JSX.Element, logLevel: LogLevel = 'info', logger: Logger = consoleLog) {\n const {output, unmount} = renderString(element)\n\n if (output) {\n if (isUnitTest()) collectLog(logLevel, output)\n outputWhereAppropriate(logLevel, logger, output)\n }\n\n unmount()\n}\n\nexport function render(element: JSX.Element, options?: RenderOptions) {\n const {waitUntilExit} = inkRender(element, options)\n return waitUntilExit()\n}\n\ninterface Instance {\n output: string | undefined\n unmount: () => void\n}\n\nexport class OutputStream extends EventEmitter {\n columns: number\n private _lastFrame?: string\n\n constructor(options: {columns: number}) {\n super()\n this.columns = options.columns\n }\n\n write = (frame: string) => {\n this._lastFrame = frame\n }\n\n lastFrame = () => {\n return this._lastFrame\n }\n}\n\nexport const renderString = (element: ReactElement): Instance => {\n const stdout = new OutputStream({columns: process.stdout.columns})\n const stderr = new OutputStream({columns: process.stderr.columns})\n\n const instance = inkRender(element, {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stdout: stdout as any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n stderr: stderr as any,\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n output: stdout.lastFrame(),\n unmount: instance.unmount,\n }\n}\n\nexport function handleCtrlC(input: string, key: Key) {\n if (input === 'c' && key.ctrl) {\n // Exceptions thrown in hooks aren't caught by our errorHandler.\n process.exit(1)\n }\n}\n"]}
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import type { List, ValueIteratee } from 'lodash';
|
|
2
2
|
/**
|
|
3
3
|
* Takes a random value from an array.
|
|
4
|
+
*
|
|
4
5
|
* @param array - Array from which we'll select a random item.
|
|
5
6
|
* @returns A random element from the array.
|
|
6
7
|
*/
|
|
7
8
|
export declare function takeRandomFromArray<T>(array: T[]): T;
|
|
8
9
|
/**
|
|
9
10
|
* Returns a copy of the array deleting the elemements that are undefined.
|
|
11
|
+
*
|
|
10
12
|
* @param array - The array whose undefined will be deleted.
|
|
11
13
|
* @returns A copy of the array with the undefined elements deleted.
|
|
12
14
|
*/
|
|
13
15
|
export declare function getArrayRejectingUndefined<T>(array: (T | undefined)[]): T[];
|
|
14
16
|
/**
|
|
15
17
|
* Returns true if an array contains duplicates.
|
|
18
|
+
*
|
|
19
|
+
* @param array - The array to check against.
|
|
16
20
|
* @returns True if the array contains duplicates.
|
|
17
21
|
*/
|
|
18
22
|
export declare function getArrayContainsDuplicates<T>(array: T[]): boolean;
|
|
@@ -2,6 +2,7 @@ import { createRequire } from 'module';
|
|
|
2
2
|
const require = createRequire(import.meta.url);
|
|
3
3
|
/**
|
|
4
4
|
* Takes a random value from an array.
|
|
5
|
+
*
|
|
5
6
|
* @param array - Array from which we'll select a random item.
|
|
6
7
|
* @returns A random element from the array.
|
|
7
8
|
*/
|
|
@@ -10,6 +11,7 @@ export function takeRandomFromArray(array) {
|
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
12
13
|
* Returns a copy of the array deleting the elemements that are undefined.
|
|
14
|
+
*
|
|
13
15
|
* @param array - The array whose undefined will be deleted.
|
|
14
16
|
* @returns A copy of the array with the undefined elements deleted.
|
|
15
17
|
*/
|
|
@@ -18,6 +20,8 @@ export function getArrayRejectingUndefined(array) {
|
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Returns true if an array contains duplicates.
|
|
23
|
+
*
|
|
24
|
+
* @param array - The array to check against.
|
|
21
25
|
* @returns True if the array contains duplicates.
|
|
22
26
|
*/
|
|
23
27
|
export function getArrayContainsDuplicates(array) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array.js","sourceRoot":"","sources":["../../../src/public/common/array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AAGpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C
|
|
1
|
+
{"version":3,"file":"array.js","sourceRoot":"","sources":["../../../src/public/common/array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AAGpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAI,KAAU;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAE,CAAA;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAwB;IACpE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAmC,CAAA;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAI,KAAU;IACtD,OAAO,KAAK,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAA;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM,CAAI,KAAiC,EAAE,QAA0B;IACrF,MAAM,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC7C,OAAO,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAI,KAAiC,EAAE,GAAG,MAAiB;IACnF,MAAM,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACrD,OAAO,gBAAgB,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,CAAA;AAC3C,CAAC","sourcesContent":["import {createRequire} from 'module'\nimport type {List, ValueIteratee} from 'lodash'\n\nconst require = createRequire(import.meta.url)\n\n/**\n * Takes a random value from an array.\n *\n * @param array - Array from which we'll select a random item.\n * @returns A random element from the array.\n */\nexport function takeRandomFromArray<T>(array: T[]): T {\n return array[Math.floor(Math.random() * array.length)]!\n}\n\n/**\n * Returns a copy of the array deleting the elemements that are undefined.\n *\n * @param array - The array whose undefined will be deleted.\n * @returns A copy of the array with the undefined elements deleted.\n */\nexport function getArrayRejectingUndefined<T>(array: (T | undefined)[]): T[] {\n return array.filter((item) => item !== undefined) as Exclude<T, null | undefined>[]\n}\n\n/**\n * Returns true if an array contains duplicates.\n *\n * @param array - The array to check against.\n * @returns True if the array contains duplicates.\n */\nexport function getArrayContainsDuplicates<T>(array: T[]): boolean {\n return array.length !== new Set(array).size\n}\n\n/**\n * This method is like `_.uniq` except that it accepts `iteratee` which is\n * invoked for each element in `array` to generate the criterion by which\n * uniqueness is computed. The iteratee is invoked with one argument: (value).\n *\n * @param array - The array to inspect.\n * @param iteratee - The iteratee invoked per element.\n * @returns Returns the new duplicate free array.\n */\nexport function uniqBy<T>(array: List<T> | null | undefined, iteratee: ValueIteratee<T>): T[] {\n const lodashUniqBy = require('lodash/uniqBy')\n return lodashUniqBy(array, iteratee)\n}\n\n/**\n * Creates an array of `array` values not included in the other provided arrays using SameValueZero for\n * equality comparisons. The order and references of result values are determined by the first array.\n *\n * @param array - The array to inspect.\n * @param values - The arrays of values to exclude.\n * @returns Returns the new array of filtered values.\n */\nexport function difference<T>(array: List<T> | null | undefined, ...values: List<T>[]): T[] {\n const lodashDifference = require('lodash/difference')\n return lodashDifference(array, ...values)\n}\n"]}
|
|
@@ -13,7 +13,7 @@ export declare function deepMergeObjects<T1, T2>(lhs: Partial<T1>, rhs: Partial<
|
|
|
13
13
|
* Creates an object composed of the `object` properties `predicate` returns
|
|
14
14
|
* truthy for. The predicate is invoked with two arguments: (value, key).
|
|
15
15
|
*
|
|
16
|
-
* @param object-
|
|
16
|
+
* @param object - The source object.
|
|
17
17
|
* @param predicate - The function invoked per property.
|
|
18
18
|
* @returns Returns the new object.
|
|
19
19
|
*/
|
|
@@ -23,10 +23,10 @@ export declare function pickBy<T, S extends T>(object: Dictionary<T> | null | un
|
|
|
23
23
|
* enumerable property of object through iteratee. The iteratee function is
|
|
24
24
|
* invoked with three arguments: (value, key, object).
|
|
25
25
|
*
|
|
26
|
-
* @param
|
|
26
|
+
* @param source - The object to iterate over.
|
|
27
27
|
* @param callback - The function invoked per iteration.
|
|
28
28
|
* @returns Returns the new mapped object.
|
|
29
29
|
*/
|
|
30
|
-
export declare function mapValues<T extends object, TResult>(
|
|
30
|
+
export declare function mapValues<T extends object, TResult>(source: T | null | undefined, callback: ObjectIterator<T, TResult>): {
|
|
31
31
|
[P in keyof T]: TResult;
|
|
32
32
|
};
|