@shopify/cli-kit 3.0.25 → 3.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/assets/auth-error.html +2 -4
- package/assets/empty-url.html +2 -4
- package/assets/missing-code.html +2 -4
- package/assets/missing-state.html +2 -4
- package/assets/style.css +5 -8
- package/assets/success.html +1 -1
- package/dist/abort.d.ts +1 -0
- package/dist/abort.js +2 -0
- package/dist/abort.js.map +1 -0
- package/dist/analytics.d.ts +11 -0
- package/dist/analytics.js +96 -0
- package/dist/analytics.js.map +1 -0
- package/dist/api/admin.d.ts +3 -0
- package/dist/api/admin.js +80 -0
- package/dist/api/admin.js.map +1 -0
- package/dist/api/common.d.ts +11 -0
- package/dist/api/common.js +40 -0
- package/dist/api/common.js.map +1 -0
- package/dist/api/graphql/all_app_extension_registrations.d.ts +14 -0
- package/dist/api/graphql/all_app_extension_registrations.js +14 -0
- package/dist/api/graphql/all_app_extension_registrations.js.map +1 -0
- package/dist/api/graphql/all_orgs.d.ts +12 -0
- package/dist/api/graphql/all_orgs.js +14 -0
- package/dist/api/graphql/all_orgs.js.map +1 -0
- package/dist/api/graphql/all_stores_by_org.d.ts +18 -0
- package/dist/api/graphql/all_stores_by_org.js +21 -0
- package/dist/api/graphql/all_stores_by_org.js.map +1 -0
- package/dist/api/graphql/convert_dev_to_test_store.d.ts +16 -0
- package/dist/api/graphql/convert_dev_to_test_store.js +13 -0
- package/dist/api/graphql/convert_dev_to_test_store.js.map +1 -0
- package/dist/api/graphql/create_app.d.ts +28 -0
- package/dist/api/graphql/create_app.js +32 -0
- package/dist/api/graphql/create_app.js.map +1 -0
- package/dist/api/graphql/create_deployment.d.ts +33 -0
- package/dist/api/graphql/create_deployment.js +25 -0
- package/dist/api/graphql/create_deployment.js.map +1 -0
- package/dist/api/graphql/extension_create.d.ts +30 -0
- package/dist/api/graphql/extension_create.js +26 -0
- package/dist/api/graphql/extension_create.js.map +1 -0
- package/dist/api/graphql/extension_specifications.d.ts +18 -0
- package/dist/api/graphql/extension_specifications.js +18 -0
- package/dist/api/graphql/extension_specifications.js.map +1 -0
- package/dist/api/graphql/find_app.d.ts +13 -0
- package/dist/api/graphql/find_app.js +16 -0
- package/dist/api/graphql/find_app.js.map +1 -0
- package/dist/api/graphql/find_org.d.ts +23 -0
- package/dist/api/graphql/find_org.js +26 -0
- package/dist/api/graphql/find_org.js.map +1 -0
- package/dist/api/graphql/find_org_basic.d.ts +11 -0
- package/dist/api/graphql/find_org_basic.js +14 -0
- package/dist/api/graphql/find_org_basic.js.map +1 -0
- package/dist/api/graphql/functions/app_function_set.d.ts +43 -0
- package/dist/api/graphql/functions/app_function_set.js +52 -0
- package/dist/api/graphql/functions/app_function_set.js.map +1 -0
- package/dist/api/graphql/functions/compile_module.d.ts +15 -0
- package/dist/api/graphql/functions/compile_module.js +13 -0
- package/dist/api/graphql/functions/compile_module.js.map +1 -0
- package/dist/api/graphql/functions/function_service_proxy.d.ts +4 -0
- package/dist/api/graphql/functions/function_service_proxy.js +7 -0
- package/dist/api/graphql/functions/function_service_proxy.js.map +1 -0
- package/dist/api/graphql/functions/get_app_functions.d.ts +1 -0
- package/dist/api/graphql/functions/get_app_functions.js +10 -0
- package/dist/api/graphql/functions/get_app_functions.js.map +1 -0
- package/dist/api/graphql/functions/module_compilation_status.d.ts +15 -0
- package/dist/api/graphql/functions/module_compilation_status.js +13 -0
- package/dist/api/graphql/functions/module_compilation_status.js.map +1 -0
- package/dist/api/graphql/functions/module_upload_url_generate.d.ts +18 -0
- package/dist/api/graphql/functions/module_upload_url_generate.js +17 -0
- package/dist/api/graphql/functions/module_upload_url_generate.js.map +1 -0
- package/dist/api/graphql/generate_signed_upload_url.d.ts +15 -0
- package/dist/api/graphql/generate_signed_upload_url.js +15 -0
- package/dist/api/graphql/generate_signed_upload_url.js.map +1 -0
- package/dist/api/graphql/get_variant_id.d.ts +17 -0
- package/dist/api/graphql/get_variant_id.js +20 -0
- package/dist/api/graphql/get_variant_id.js.map +1 -0
- package/dist/api/graphql/index.d.ts +21 -0
- package/dist/api/graphql/index.js +22 -0
- package/dist/api/graphql/index.js.map +1 -0
- package/dist/api/graphql/update_draft.d.ts +33 -0
- package/dist/api/graphql/update_draft.js +24 -0
- package/dist/api/graphql/update_draft.js.map +1 -0
- package/dist/api/graphql/update_urls.d.ts +14 -0
- package/dist/api/graphql/update_urls.js +12 -0
- package/dist/api/graphql/update_urls.js.map +1 -0
- package/dist/api/identity.d.ts +1 -0
- package/dist/api/identity.js +29 -0
- package/dist/api/identity.js.map +1 -0
- package/dist/api/partners.d.ts +25 -0
- package/dist/api/partners.js +100 -0
- package/dist/api/partners.js.map +1 -0
- package/dist/api.d.ts +5 -0
- package/dist/api.js +6 -0
- package/dist/api.js.map +1 -0
- package/dist/checksum.d.ts +15 -0
- package/dist/checksum.js +27 -0
- package/dist/checksum.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors.d.ts +1 -0
- package/dist/colors.js +8 -0
- package/dist/colors.js.map +1 -0
- package/dist/constants.d.ts +43 -0
- package/dist/constants.js +63 -0
- package/dist/constants.js.map +1 -0
- package/dist/dependency.d.ts +128 -0
- package/dist/dependency.js +302 -0
- package/dist/dependency.js.map +1 -0
- package/dist/dot-env.d.ts +28 -0
- package/dist/dot-env.js +31 -0
- package/dist/dot-env.js.map +1 -0
- package/dist/environment/fqdn.d.ts +23 -0
- package/dist/environment/fqdn.js +61 -0
- package/dist/environment/fqdn.js.map +1 -0
- package/dist/environment/local.d.ts +48 -0
- package/dist/environment/local.js +82 -0
- package/dist/environment/local.js.map +1 -0
- package/dist/environment/service.d.ts +17 -0
- package/dist/environment/service.js +41 -0
- package/dist/environment/service.js.map +1 -0
- package/dist/environment/spin.d.ts +47 -0
- package/dist/environment/spin.js +83 -0
- package/dist/environment/spin.js.map +1 -0
- package/dist/environment/utilities.d.ts +6 -0
- package/dist/environment/utilities.js +12 -0
- package/dist/environment/utilities.js.map +1 -0
- package/dist/environment.d.ts +5 -0
- package/dist/environment.js +6 -0
- package/dist/environment.js.map +1 -0
- package/dist/error.d.ts +44 -0
- package/dist/error.js +91 -0
- package/dist/error.js.map +1 -0
- package/dist/file.d.ts +67 -0
- package/dist/file.js +165 -0
- package/dist/file.js.map +1 -0
- package/dist/git.d.ts +15 -0
- package/dist/git.js +48 -0
- package/dist/git.js.map +1 -0
- package/dist/github.d.ts +33 -0
- package/dist/github.js +56 -0
- package/dist/github.js.map +1 -0
- package/dist/haiku.d.ts +1 -0
- package/dist/haiku.js +8 -0
- package/dist/haiku.js.map +1 -0
- package/dist/http/fetch.d.ts +16 -0
- package/dist/http/fetch.js +18 -0
- package/dist/http/fetch.js.map +1 -0
- package/dist/http/formdata.d.ts +3 -0
- package/dist/http/formdata.js +6 -0
- package/dist/http/formdata.js.map +1 -0
- package/dist/http.d.ts +2 -0
- package/dist/http.js +3 -0
- package/dist/http.js.map +1 -0
- package/dist/id.d.ts +6 -0
- package/dist/id.js +18 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +37 -2179
- package/dist/index.js +38 -3264
- package/dist/index.js.map +1 -1
- package/dist/network/api.d.ts +2 -0
- package/dist/network/api.js +2 -0
- package/dist/network/api.js.map +1 -0
- package/dist/network/service.d.ts +16 -0
- package/dist/network/service.js +12 -0
- package/dist/network/service.js.map +1 -0
- package/dist/{archiver.d.ts → node/archiver.d.ts} +1 -4
- package/dist/node/archiver.js +22 -42
- package/dist/node/archiver.js.map +1 -1
- package/dist/node/cli.d.ts +18 -0
- package/dist/node/cli.js +91 -0
- package/dist/node/cli.js.map +1 -0
- package/dist/npm.d.ts +27 -0
- package/dist/npm.js +20 -0
- package/dist/npm.js.map +1 -0
- package/dist/os.d.ts +10 -0
- package/dist/os.js +70 -0
- package/dist/os.js.map +1 -0
- package/dist/output.d.ts +142 -0
- package/dist/output.js +505 -0
- package/dist/output.js.map +1 -0
- package/dist/path.d.ts +22 -0
- package/dist/path.js +43 -0
- package/dist/path.js.map +1 -0
- package/dist/plugins.d.ts +9 -0
- package/dist/plugins.js +12 -0
- package/dist/plugins.js.map +1 -0
- package/dist/port.d.ts +5 -0
- package/dist/port.js +13 -0
- package/dist/port.js.map +1 -0
- package/dist/ruby.d.ts +21 -0
- package/dist/ruby.js +192 -0
- package/dist/ruby.js.map +1 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.js +2 -0
- package/dist/schema.js.map +1 -0
- package/dist/secure-store.d.ts +19 -0
- package/dist/secure-store.js +63 -0
- package/dist/secure-store.js.map +1 -0
- package/dist/semver.d.ts +3 -0
- package/dist/semver.js +6 -0
- package/dist/semver.js.map +1 -0
- package/dist/session/authorize.d.ts +7 -0
- package/dist/session/authorize.js +40 -0
- package/dist/session/authorize.js.map +1 -0
- package/dist/session/exchange.d.ts +42 -0
- package/dist/session/exchange.js +144 -0
- package/dist/session/exchange.js.map +1 -0
- package/dist/session/identity.d.ts +3 -0
- package/dist/session/identity.js +58 -0
- package/dist/session/identity.js.map +1 -0
- package/dist/session/post-auth.d.ts +13 -0
- package/dist/session/post-auth.js +56 -0
- package/dist/session/post-auth.js.map +1 -0
- package/dist/session/redirect-listener.d.ts +34 -0
- package/dist/session/redirect-listener.js +97 -0
- package/dist/session/redirect-listener.js.map +1 -0
- package/dist/session/schema.d.ts +174 -0
- package/dist/session/schema.js +59 -0
- package/dist/session/schema.js.map +1 -0
- package/dist/session/scopes.d.ts +16 -0
- package/dist/session/scopes.js +53 -0
- package/dist/session/scopes.js.map +1 -0
- package/dist/session/store.d.ts +24 -0
- package/dist/session/store.js +88 -0
- package/dist/session/store.js.map +1 -0
- package/dist/session/token.d.ts +40 -0
- package/dist/session/token.js +22 -0
- package/dist/session/token.js.map +1 -0
- package/dist/session/validate.d.ts +17 -0
- package/dist/session/validate.js +75 -0
- package/dist/session/validate.js.map +1 -0
- package/dist/session.d.ts +88 -0
- package/dist/session.js +251 -0
- package/dist/session.js.map +1 -0
- package/dist/store/schema.d.ts +3 -0
- package/dist/store/schema.js +27 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store.d.ts +32 -0
- package/dist/store.js +102 -0
- package/dist/store.js.map +1 -0
- package/dist/string.d.ts +22 -0
- package/dist/string.js +38 -0
- package/dist/string.js.map +1 -0
- package/dist/system.d.ts +53 -0
- package/dist/system.js +109 -0
- package/dist/system.js.map +1 -0
- package/dist/template.d.ts +11 -0
- package/dist/template.js +50 -0
- package/dist/template.js.map +1 -0
- package/dist/testing/output.d.ts +9 -0
- package/dist/testing/output.js +15 -0
- package/dist/testing/output.js.map +1 -0
- package/dist/testing/store.d.ts +7 -0
- package/dist/testing/store.js +26 -0
- package/dist/testing/store.js.map +1 -0
- package/dist/toml.d.ts +3 -0
- package/dist/toml.js +8 -0
- package/dist/toml.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/ui/autocomplete.d.ts +7 -0
- package/dist/ui/autocomplete.js +43 -0
- package/dist/ui/autocomplete.js.map +1 -0
- package/dist/ui/input.d.ts +7 -0
- package/dist/ui/input.js +48 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/select.d.ts +6 -0
- package/dist/ui/select.js +30 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui.d.ts +36 -0
- package/dist/ui.js +124 -0
- package/dist/ui.js.map +1 -0
- package/dist/version.d.ts +19 -0
- package/dist/version.js +34 -0
- package/dist/version.js.map +1 -0
- package/dist/vscode.d.ts +8 -0
- package/dist/vscode.js +36 -0
- package/dist/vscode.js.map +1 -0
- package/dist/yaml.d.ts +2 -0
- package/dist/yaml.js +8 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +14 -7
- package/dist/archiver.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/local-d0094ffe.js +0 -1344
- package/dist/local-d0094ffe.js.map +0 -1
package/dist/session.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { applicationId } from './session/identity.js';
|
|
2
|
+
import { Abort, Bug } from './error.js';
|
|
3
|
+
import { validateSession } from './session/validate.js';
|
|
4
|
+
import { allDefaultScopes, apiScopes } from './session/scopes.js';
|
|
5
|
+
import { identity as identityFqdn } from './environment/fqdn.js';
|
|
6
|
+
import { open } from './system.js';
|
|
7
|
+
import { exchangeAccessForApplicationTokens, exchangeCodeForAccessToken, exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError, } from './session/exchange.js';
|
|
8
|
+
import { content, token, debug } from './output.js';
|
|
9
|
+
import { keypress } from './ui.js';
|
|
10
|
+
import { authorize } from './session/authorize.js';
|
|
11
|
+
import * as secureStore from './session/store.js';
|
|
12
|
+
import constants from './constants.js';
|
|
13
|
+
import { normalizeStoreName } from './string.js';
|
|
14
|
+
import * as output from './output.js';
|
|
15
|
+
import { partners } from './api.js';
|
|
16
|
+
import { gql } from 'graphql-request';
|
|
17
|
+
const NoSessionError = new Bug('No session found after ensuring authenticated');
|
|
18
|
+
const MissingPartnerTokenError = new Bug('No partners token found after ensuring authenticated');
|
|
19
|
+
const MissingAdminTokenError = new Bug('No admin token found after ensuring authenticated');
|
|
20
|
+
const MissingStorefrontTokenError = new Bug('No storefront token found after ensuring authenticated');
|
|
21
|
+
export const PartnerOrganizationNotFoundError = () => {
|
|
22
|
+
return new Abort(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
|
|
23
|
+
};
|
|
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 {string[]} Optional array of extra scopes to authenticate with.
|
|
29
|
+
* @returns {Promise<string>} 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 {string[]} Optional array of extra scopes to authenticate with.
|
|
48
|
+
* @returns {Promise<string>} The access token for the Storefront API.
|
|
49
|
+
*/
|
|
50
|
+
export async function ensureAuthenticatedStorefront(scopes = []) {
|
|
51
|
+
debug(content `Ensuring that the user is authenticated with the Storefront API with the following scopes:
|
|
52
|
+
${token.json(scopes)}
|
|
53
|
+
`);
|
|
54
|
+
const tokens = await ensureAuthenticated({ storefrontRendererApi: { scopes } });
|
|
55
|
+
if (!tokens.storefront) {
|
|
56
|
+
throw MissingStorefrontTokenError;
|
|
57
|
+
}
|
|
58
|
+
return tokens.storefront;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Ensure that we have a valid Admin session for the given store.
|
|
62
|
+
* @param store {string} Store fqdn to request auth for
|
|
63
|
+
* @param scopes {string[]} Optional array of extra scopes to authenticate with.
|
|
64
|
+
* @returns {Promise<string>} The access token for the Admin API
|
|
65
|
+
*/
|
|
66
|
+
export async function ensureAuthenticatedAdmin(store, scopes = []) {
|
|
67
|
+
debug(content `Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${token.raw(store)}:
|
|
68
|
+
${token.json(scopes)}
|
|
69
|
+
`);
|
|
70
|
+
const tokens = await ensureAuthenticated({ adminApi: { scopes, storeFqdn: store } });
|
|
71
|
+
if (!tokens.admin) {
|
|
72
|
+
throw MissingAdminTokenError;
|
|
73
|
+
}
|
|
74
|
+
return tokens.admin;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
|
|
78
|
+
* @param applications {OAuthApplications} An object containing the applications we need to be authenticated with.
|
|
79
|
+
* @returns {OAuthSession} An instance with the access tokens organized by application.
|
|
80
|
+
*/
|
|
81
|
+
export async function ensureAuthenticated(applications, env = process.env) {
|
|
82
|
+
const fqdn = await identityFqdn();
|
|
83
|
+
if (applications.adminApi?.storeFqdn) {
|
|
84
|
+
applications.adminApi.storeFqdn = normalizeStoreName(applications.adminApi.storeFqdn);
|
|
85
|
+
}
|
|
86
|
+
const currentSession = (await secureStore.fetch()) || {};
|
|
87
|
+
const fqdnSession = currentSession[fqdn];
|
|
88
|
+
const scopes = getFlattenScopes(applications);
|
|
89
|
+
debug(content `Validating existing session against the scopes:
|
|
90
|
+
${token.json(scopes)}
|
|
91
|
+
For applications:
|
|
92
|
+
${token.json(applications)}
|
|
93
|
+
`);
|
|
94
|
+
const validationResult = await validateSession(scopes, applications, fqdnSession);
|
|
95
|
+
let newSession = {};
|
|
96
|
+
if (validationResult === 'needs_full_auth') {
|
|
97
|
+
debug(content `Initiating the full authentication flow...`);
|
|
98
|
+
newSession = await executeCompleteFlow(applications, fqdn);
|
|
99
|
+
}
|
|
100
|
+
else if (validationResult === 'needs_refresh') {
|
|
101
|
+
debug(content `The current session is valid but needs refresh. Refreshing...`);
|
|
102
|
+
try {
|
|
103
|
+
newSession = await refreshTokens(fqdnSession.identity, applications, fqdn);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof InvalidGrantError) {
|
|
107
|
+
newSession = await executeCompleteFlow(applications, fqdn);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const completeSession = { ...currentSession, ...newSession };
|
|
115
|
+
await secureStore.store(completeSession);
|
|
116
|
+
const tokens = await tokensFor(applications, completeSession, fqdn);
|
|
117
|
+
// Overwrite partners token if using a custom CLI Token
|
|
118
|
+
const envToken = env[constants.environmentVariables.partnersToken];
|
|
119
|
+
if (envToken && applications.partnersApi) {
|
|
120
|
+
tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken;
|
|
121
|
+
}
|
|
122
|
+
if (!envToken && tokens.partners) {
|
|
123
|
+
await ensureUserHasPartnerAccount(tokens.partners);
|
|
124
|
+
}
|
|
125
|
+
return tokens;
|
|
126
|
+
}
|
|
127
|
+
export async function hasPartnerAccount(partnersToken) {
|
|
128
|
+
try {
|
|
129
|
+
await partners.request(gql `
|
|
130
|
+
{
|
|
131
|
+
organizations(first: 1) {
|
|
132
|
+
nodes {
|
|
133
|
+
id
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
`, partnersToken);
|
|
138
|
+
return true;
|
|
139
|
+
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof partners.RequestClientError && error.statusCode === 404) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* If the user creates an account from the Identity website, the created
|
|
152
|
+
* account won't get a Partner organization created. We need to detect that
|
|
153
|
+
* and take the user to create a partner organization.
|
|
154
|
+
* @param partnersToken {string} Partners token
|
|
155
|
+
*/
|
|
156
|
+
export async function ensureUserHasPartnerAccount(partnersToken) {
|
|
157
|
+
debug(content `Verifying that the user has a Partner organization`);
|
|
158
|
+
if (!(await hasPartnerAccount(partnersToken))) {
|
|
159
|
+
output.info(`\nA Shopify Partners organization is needed to proceed.`);
|
|
160
|
+
output.info(`👉 Press any key to create one`);
|
|
161
|
+
await keypress();
|
|
162
|
+
open(`https://partners.shopify.com/signup`);
|
|
163
|
+
output.info(output.content `👉 Press any key when you have ${output.token.cyan('created the organization')}`);
|
|
164
|
+
output.warn(output.content `Make sure you've confirmed your Shopify and the Partner organization from the email`);
|
|
165
|
+
await keypress();
|
|
166
|
+
if (!(await hasPartnerAccount(partnersToken))) {
|
|
167
|
+
throw PartnerOrganizationNotFoundError();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function executeCompleteFlow(applications, identityFqdn) {
|
|
172
|
+
const scopes = getFlattenScopes(applications);
|
|
173
|
+
const exchangeScopes = getExchangeScopes(applications);
|
|
174
|
+
const store = applications.adminApi?.storeFqdn;
|
|
175
|
+
// Authorize user via browser
|
|
176
|
+
debug(content `Authorizing through Identity's website...`);
|
|
177
|
+
const code = await authorize(scopes);
|
|
178
|
+
// Exchange code for identity token
|
|
179
|
+
debug(content `Authorization code received. Exchanging it for a CLI token...`);
|
|
180
|
+
const identityToken = await exchangeCodeForAccessToken(code);
|
|
181
|
+
// Exchange identity token for application tokens
|
|
182
|
+
debug(content `CLI token received. Exchanging it for application tokens...`);
|
|
183
|
+
const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store);
|
|
184
|
+
const session = {
|
|
185
|
+
[identityFqdn]: {
|
|
186
|
+
identity: identityToken,
|
|
187
|
+
applications: result,
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
output.completed('Logged in.');
|
|
191
|
+
return session;
|
|
192
|
+
}
|
|
193
|
+
async function refreshTokens(token, applications, fqdn) {
|
|
194
|
+
// Refresh Identity Token
|
|
195
|
+
const identityToken = await refreshAccessToken(token);
|
|
196
|
+
// Exchange new identity token for application tokens
|
|
197
|
+
const exchangeScopes = getExchangeScopes(applications);
|
|
198
|
+
const applicationTokens = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, applications.adminApi?.storeFqdn);
|
|
199
|
+
return {
|
|
200
|
+
[fqdn]: {
|
|
201
|
+
identity: identityToken,
|
|
202
|
+
applications: applicationTokens,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async function tokensFor(applications, session, fqdn) {
|
|
207
|
+
const fqdnSession = session[fqdn];
|
|
208
|
+
if (!fqdnSession) {
|
|
209
|
+
throw NoSessionError;
|
|
210
|
+
}
|
|
211
|
+
const tokens = {};
|
|
212
|
+
if (applications.adminApi) {
|
|
213
|
+
const appId = applicationId('admin');
|
|
214
|
+
const realAppId = `${applications.adminApi.storeFqdn}-${appId}`;
|
|
215
|
+
const token = fqdnSession.applications[realAppId]?.accessToken;
|
|
216
|
+
if (token) {
|
|
217
|
+
tokens.admin = { token, storeFqdn: applications.adminApi.storeFqdn };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (applications.partnersApi) {
|
|
221
|
+
const appId = applicationId('partners');
|
|
222
|
+
tokens.partners = fqdnSession.applications[appId]?.accessToken;
|
|
223
|
+
}
|
|
224
|
+
if (applications.storefrontRendererApi) {
|
|
225
|
+
const appId = applicationId('storefront-renderer');
|
|
226
|
+
tokens.storefront = fqdnSession.applications[appId]?.accessToken;
|
|
227
|
+
}
|
|
228
|
+
return tokens;
|
|
229
|
+
}
|
|
230
|
+
// Scope Helpers
|
|
231
|
+
function getFlattenScopes(apps) {
|
|
232
|
+
const admin = apps.adminApi?.scopes || [];
|
|
233
|
+
const partner = apps.partnersApi?.scopes || [];
|
|
234
|
+
const storefront = apps.storefrontRendererApi?.scopes || [];
|
|
235
|
+
const requestedScopes = [...admin, ...partner, ...storefront];
|
|
236
|
+
return allDefaultScopes(requestedScopes);
|
|
237
|
+
}
|
|
238
|
+
function getExchangeScopes(apps) {
|
|
239
|
+
const adminScope = apps.adminApi?.scopes || [];
|
|
240
|
+
const partnerScope = apps.partnersApi?.scopes || [];
|
|
241
|
+
const storefrontScopes = apps.storefrontRendererApi?.scopes || [];
|
|
242
|
+
return {
|
|
243
|
+
admin: apiScopes('admin', adminScope),
|
|
244
|
+
partners: apiScopes('partners', partnerScope),
|
|
245
|
+
storefront: apiScopes('storefront-renderer', storefrontScopes),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
export function logout() {
|
|
249
|
+
return secureStore.remove();
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAC,KAAK,EAAE,GAAG,EAAC,MAAM,YAAY,CAAA;AACrC,OAAO,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAC,gBAAgB,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAAC,QAAQ,IAAI,YAAY,EAAC,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAC,IAAI,EAAC,MAAM,aAAa,CAAA;AAChC,OAAO,EACL,kCAAkC,EAClC,0BAA0B,EAC1B,0BAA0B,EAE1B,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AACjD,OAAO,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAA;AAEhC,OAAO,EAAC,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAEhD,OAAO,KAAK,WAAW,MAAM,oBAAoB,CAAA;AACjD,OAAO,SAAS,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAC,kBAAkB,EAAC,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAAC,QAAQ,EAAC,MAAM,UAAU,CAAA;AACjC,OAAO,EAAC,GAAG,EAAC,MAAM,iBAAiB,CAAA;AAEnC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,+CAA+C,CAAC,CAAA;AAC/E,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC,sDAAsD,CAAC,CAAA;AAChG,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,mDAAmD,CAAC,CAAA;AAC3F,MAAM,2BAA2B,GAAG,IAAI,GAAG,CAAC,wDAAwD,CAAC,CAAA;AAwDrG,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,EAAE;IACnD,OAAO,IAAI,KAAK,CACd,kDAAkD,EAClD,gEAAgE,CACjE,CAAA;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,SAAmB,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IACxF,KAAK,CAAC,OAAO,CAAA;EACb,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;CACnB,CAAC,CAAA;IACA,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;IAClE,IAAI,QAAQ,EAAE;QACZ,OAAO,CAAC,MAAM,0BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;KAChE;IACD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAC,WAAW,EAAE,EAAC,MAAM,EAAC,EAAC,CAAC,CAAA;IACjE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QACpB,MAAM,wBAAwB,CAAA;KAC/B;IACD,OAAO,MAAM,CAAC,QAAQ,CAAA;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,SAAmB,EAAE;IACvE,KAAK,CAAC,OAAO,CAAA;EACb,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;CACnB,CAAC,CAAA;IACA,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAC,qBAAqB,EAAE,EAAC,MAAM,EAAC,EAAC,CAAC,CAAA;IAC3E,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;QACtB,MAAM,2BAA2B,CAAA;KAClC;IACD,OAAO,MAAM,CAAC,UAAU,CAAA;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAa,EAAE,SAAmB,EAAE;IACjF,KAAK,CAAC,OAAO,CAAA,sGAAsG,KAAK,CAAC,GAAG,CAC1H,KAAK,CACN;EACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;CACnB,CAAC,CAAA;IACA,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,EAAC,QAAQ,EAAE,EAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAC,EAAC,CAAC,CAAA;IAChF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;QACjB,MAAM,sBAAsB,CAAA;KAC7B;IACD,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,YAA+B,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IAC1F,MAAM,IAAI,GAAG,MAAM,YAAY,EAAE,CAAA;IAEjC,IAAI,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE;QACpC,YAAY,CAAC,QAAQ,CAAC,SAAS,GAAG,kBAAkB,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;KACtF;IAED,MAAM,cAAc,GAAG,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;IACxD,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAE7C,KAAK,CAAC,OAAO,CAAA;EACb,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;;EAElB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;CACzB,CAAC,CAAA;IACA,MAAM,gBAAgB,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,CAAA;IAEjF,IAAI,UAAU,GAAG,EAAE,CAAA;IAEnB,IAAI,gBAAgB,KAAK,iBAAiB,EAAE;QAC1C,KAAK,CAAC,OAAO,CAAA,4CAA4C,CAAC,CAAA;QAC1D,UAAU,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;KAC3D;SAAM,IAAI,gBAAgB,KAAK,eAAe,EAAE;QAC/C,KAAK,CAAC,OAAO,CAAA,+DAA+D,CAAC,CAAA;QAC7E,IAAI;YACF,UAAU,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;SAC3E;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,YAAY,iBAAiB,EAAE;gBACtC,UAAU,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;aAC3D;iBAAM;gBACL,MAAM,KAAK,CAAA;aACZ;SACF;KACF;IAED,MAAM,eAAe,GAAY,EAAC,GAAG,cAAc,EAAE,GAAG,UAAU,EAAC,CAAA;IACnE,MAAM,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,CAAC,CAAA;IAEnE,uDAAuD;IACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAA;IAClE,IAAI,QAAQ,IAAI,YAAY,CAAC,WAAW,EAAE;QACxC,MAAM,CAAC,QAAQ,GAAG,CAAC,MAAM,0BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;KAC3E;IACD,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;QAChC,MAAM,2BAA2B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;KACnD;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,aAAqB;IAC3D,IAAI;QACF,MAAM,QAAQ,CAAC,OAAO,CACpB,GAAG,CAAA;;;;;;;;OAQF,EACD,aAAa,CACd,CAAA;QACD,OAAO,IAAI,CAAA;QACX,qDAAqD;KACtD;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,KAAK,YAAY,QAAQ,CAAC,kBAAkB,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG,EAAE;YAC5E,OAAO,KAAK,CAAA;SACb;aAAM;YACL,OAAO,IAAI,CAAA;SACZ;KACF;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,aAAqB;IACrE,KAAK,CAAC,OAAO,CAAA,oDAAoD,CAAC,CAAA;IAClE,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE;QAC7C,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAA;QACtE,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;QAC7C,MAAM,QAAQ,EAAE,CAAA;QAChB,IAAI,CAAC,qCAAqC,CAAC,CAAA;QAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,kCAAkC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAA;QAC5G,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAA,qFAAqF,CAAC,CAAA;QAChH,MAAM,QAAQ,EAAE,CAAA;QAChB,IAAI,CAAC,CAAC,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC,EAAE;YAC7C,MAAM,gCAAgC,EAAE,CAAA;SACzC;KACF;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,YAA+B,EAAE,YAAoB;IACtF,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;IAC7C,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAA;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAA;IAE9C,6BAA6B;IAC7B,KAAK,CAAC,OAAO,CAAA,2CAA2C,CAAC,CAAA;IACzD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;IAEpC,mCAAmC;IACnC,KAAK,CAAC,OAAO,CAAA,+DAA+D,CAAC,CAAA;IAC7E,MAAM,aAAa,GAAG,MAAM,0BAA0B,CAAC,IAAI,CAAC,CAAA;IAE5D,iDAAiD;IACjD,KAAK,CAAC,OAAO,CAAA,6DAA6D,CAAC,CAAA;IAC3E,MAAM,MAAM,GAAG,MAAM,kCAAkC,CAAC,aAAa,EAAE,cAAc,EAAE,KAAK,CAAC,CAAA;IAE7F,MAAM,OAAO,GAAY;QACvB,CAAC,YAAY,CAAC,EAAE;YACd,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,MAAM;SACrB;KACF,CAAA;IAED,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;IAE9B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,KAAoB,EAAE,YAA+B,EAAE,IAAY;IAC9F,yBAAyB;IACzB,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAErD,qDAAqD;IACrD,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAA;IACtD,MAAM,iBAAiB,GAAG,MAAM,kCAAkC,CAChE,aAAa,EACb,cAAc,EACd,YAAY,CAAC,QAAQ,EAAE,SAAS,CACjC,CAAA;IAED,OAAO;QACL,CAAC,IAAI,CAAC,EAAE;YACN,QAAQ,EAAE,aAAa;YACvB,YAAY,EAAE,iBAAiB;SAChC;KACF,CAAA;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,YAA+B,EAAE,OAAgB,EAAE,IAAY;IACtF,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,cAAc,CAAA;KACrB;IACD,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,YAAY,CAAC,QAAQ,EAAE;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,CAAA;QAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,WAAW,CAAA;QAC9D,IAAI,KAAK,EAAE;YACT,MAAM,CAAC,KAAK,GAAG,EAAC,KAAK,EAAE,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAC,CAAA;SACnE;KACF;IAED,IAAI,YAAY,CAAC,WAAW,EAAE;QAC5B,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;QACvC,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAC/D;IAED,IAAI,YAAY,CAAC,qBAAqB,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAA;QAClD,MAAM,CAAC,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KACjE;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,gBAAgB;AAChB,SAAS,gBAAgB,CAAC,IAAuB;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAA;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,IAAI,EAAE,CAAA;IAC3D,MAAM,eAAe,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,CAAA;IAC7D,OAAO,gBAAgB,CAAC,eAAe,CAAC,CAAA;AAC1C,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAuB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAA;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,CAAA;IACnD,MAAM,gBAAgB,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,IAAI,EAAE,CAAA;IACjE,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC;QACrC,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC;QAC7C,UAAU,EAAE,SAAS,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;KAC/D,CAAA;AACH,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,OAAO,WAAW,CAAC,MAAM,EAAE,CAAA;AAC7B,CAAC","sourcesContent":["import {applicationId} from './session/identity.js'\nimport {Abort, Bug} from './error.js'\nimport {validateSession} from './session/validate.js'\nimport {allDefaultScopes, apiScopes} from './session/scopes.js'\nimport {identity as identityFqdn} from './environment/fqdn.js'\nimport {open} from './system.js'\nimport {\n exchangeAccessForApplicationTokens,\n exchangeCodeForAccessToken,\n exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n} from './session/exchange.js'\n\nimport {content, token, debug} from './output.js'\nimport {keypress} from './ui.js'\n\nimport {authorize} from './session/authorize.js'\nimport {IdentityToken, Session} from './session/schema.js'\nimport * as secureStore from './session/store.js'\nimport constants from './constants.js'\nimport {normalizeStoreName} from './string.js'\nimport * as output from './output.js'\nimport {partners} from './api.js'\nimport {gql} from 'graphql-request'\n\nconst NoSessionError = new Bug('No session found after ensuring authenticated')\nconst MissingPartnerTokenError = new Bug('No partners token found after ensuring authenticated')\nconst MissingAdminTokenError = new Bug('No admin token found after ensuring authenticated')\nconst MissingStorefrontTokenError = new Bug('No storefront token found after ensuring authenticated')\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 */\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 AdminSession {\n token: string\n storeFqdn: string\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n}\nexport const PartnerOrganizationNotFoundError = () => {\n return 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 * Ensure that we have a valid session to access the Partners API.\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token\n * If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored\n * @param scopes {string[]} Optional array of extra scopes to authenticate with.\n * @returns {Promise<string>} The access token for the Partners API.\n */\nexport async function ensureAuthenticatedPartners(scopes: string[] = [], env = process.env): Promise<string> {\n debug(content`Ensuring that the user is authenticated with the Partners API with the following scopes:\n${token.json(scopes)}\n`)\n const envToken = env[constants.environmentVariables.partnersToken]\n if (envToken) {\n return (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n const tokens = await ensureAuthenticated({partnersApi: {scopes}})\n if (!tokens.partners) {\n throw MissingPartnerTokenError\n }\n return tokens.partners\n}\n\n/**\n * Ensure that we have a valid session to access the Storefront API.\n * @param scopes {string[]} Optional array of extra scopes to authenticate with.\n * @returns {Promise<string>} The access token for the Storefront API.\n */\nexport async function ensureAuthenticatedStorefront(scopes: string[] = []): Promise<string> {\n debug(content`Ensuring that the user is authenticated with the Storefront API with the following scopes:\n${token.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({storefrontRendererApi: {scopes}})\n if (!tokens.storefront) {\n throw MissingStorefrontTokenError\n }\n return tokens.storefront\n}\n\n/**\n * Ensure that we have a valid Admin session for the given store.\n * @param store {string} Store fqdn to request auth for\n * @param scopes {string[]} Optional array of extra scopes to authenticate with.\n * @returns {Promise<string>} The access token for the Admin API\n */\nexport async function ensureAuthenticatedAdmin(store: string, scopes: string[] = []): Promise<AdminSession> {\n debug(content`Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${token.raw(\n store,\n )}:\n${token.json(scopes)}\n`)\n const tokens = await ensureAuthenticated({adminApi: {scopes, storeFqdn: store}})\n if (!tokens.admin) {\n throw MissingAdminTokenError\n }\n return tokens.admin\n}\n\n/**\n * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.\n * @param applications {OAuthApplications} An object containing the applications we need to be authenticated with.\n * @returns {OAuthSession} An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(applications: OAuthApplications, env = process.env): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n if (applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizeStoreName(applications.adminApi.storeFqdn)\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') {\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 {\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\nexport async function hasPartnerAccount(partnersToken: string): Promise<boolean> {\n try {\n await partners.request(\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 partners.RequestClientError && error.statusCode === 404) {\n return false\n } else {\n return true\n }\n }\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 * @param partnersToken {string} Partners token\n */\nexport async 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 open(`https://partners.shopify.com/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 PartnerOrganizationNotFoundError()\n }\n }\n}\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\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 const identityToken = await exchangeCodeForAccessToken(code)\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\nasync function refreshTokens(token: IdentityToken, applications: OAuthApplications, fqdn: string): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(token)\n\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\nasync function tokensFor(applications: OAuthApplications, session: Session, fqdn: string): Promise<OAuthSession> {\n const fqdnSession = session[fqdn]\n if (!fqdnSession) {\n throw NoSessionError\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\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\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\nexport function logout() {\n return secureStore.remove()\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const schema = {
|
|
2
|
+
appInfo: {
|
|
3
|
+
type: 'array',
|
|
4
|
+
items: {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
appId: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
},
|
|
10
|
+
title: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
},
|
|
13
|
+
orgId: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
},
|
|
16
|
+
storeFqdn: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
},
|
|
19
|
+
directory: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export default schema;
|
|
27
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE;QACP,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;iBACf;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;iBACf;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;iBACf;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;iBACf;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ;iBACf;aACF;SACF;KACF;CACF,CAAA;AAED,eAAe,MAAM,CAAA","sourcesContent":["import type {Schema} from 'conf'\n\nconst schema: Schema<unknown> = {\n appInfo: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n appId: {\n type: 'string',\n },\n title: {\n type: 'string',\n },\n orgId: {\n type: 'string',\n },\n storeFqdn: {\n type: 'string',\n },\n directory: {\n type: 'string',\n },\n },\n },\n },\n}\n\nexport default schema\n"]}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
export interface CachedAppInfo {
|
|
3
|
+
directory: string;
|
|
4
|
+
appId: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
orgId?: string;
|
|
7
|
+
storeFqdn?: string;
|
|
8
|
+
}
|
|
9
|
+
interface ConfSchema {
|
|
10
|
+
appInfo: CachedAppInfo[];
|
|
11
|
+
themeStore: string;
|
|
12
|
+
session: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function cliKitStore(): CLIKitStore;
|
|
15
|
+
export declare function initializeCliKitStore(): Promise<void>;
|
|
16
|
+
export declare class CLIKitStore extends Conf<ConfSchema> {
|
|
17
|
+
getAppInfo(directory: string): CachedAppInfo | undefined;
|
|
18
|
+
setAppInfo(options: {
|
|
19
|
+
directory: string;
|
|
20
|
+
appId: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
storeFqdn?: string;
|
|
23
|
+
orgId?: string;
|
|
24
|
+
}): void;
|
|
25
|
+
clearAppInfo(directory: string): void;
|
|
26
|
+
getTheme(): string | undefined;
|
|
27
|
+
setTheme(store: string): void;
|
|
28
|
+
getSession(): string | undefined;
|
|
29
|
+
setSession(store: string): void;
|
|
30
|
+
removeSession(): void;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { content, token, debug } from './output.js';
|
|
2
|
+
import constants from './constants.js';
|
|
3
|
+
import { Abort } from './error.js';
|
|
4
|
+
import Conf from 'conf';
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const migrations = {};
|
|
8
|
+
const schema = {
|
|
9
|
+
appInfo: {
|
|
10
|
+
type: 'array',
|
|
11
|
+
items: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
appId: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
},
|
|
17
|
+
orgId: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
},
|
|
20
|
+
storeFqdn: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
let _instance;
|
|
28
|
+
export function cliKitStore() {
|
|
29
|
+
if (!_instance) {
|
|
30
|
+
throw new Abort("The CLIKitStore instance hasn't been initialized");
|
|
31
|
+
}
|
|
32
|
+
return _instance;
|
|
33
|
+
}
|
|
34
|
+
export async function initializeCliKitStore() {
|
|
35
|
+
if (!_instance) {
|
|
36
|
+
// eslint-disable-next-line require-atomic-updates
|
|
37
|
+
_instance = new CLIKitStore({
|
|
38
|
+
schema,
|
|
39
|
+
migrations,
|
|
40
|
+
projectName: 'shopify-cli-kit',
|
|
41
|
+
projectVersion: await constants.versions.cliKit(),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export class CLIKitStore extends Conf {
|
|
46
|
+
getAppInfo(directory) {
|
|
47
|
+
debug(content `Reading cached app information for directory ${token.path(directory)}...`);
|
|
48
|
+
const apps = this.get('appInfo') ?? [];
|
|
49
|
+
return apps.find((app) => app.directory === directory);
|
|
50
|
+
}
|
|
51
|
+
setAppInfo(options) {
|
|
52
|
+
debug(content `Storing app information for directory ${token.path(options.directory)}:
|
|
53
|
+
${token.json(options)}
|
|
54
|
+
`);
|
|
55
|
+
const apps = this.get('appInfo') ?? [];
|
|
56
|
+
const index = apps.findIndex((saved) => saved.directory === options.directory);
|
|
57
|
+
if (index === -1) {
|
|
58
|
+
apps.push(options);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const app = apps[index];
|
|
62
|
+
apps[index] = {
|
|
63
|
+
appId: options.appId,
|
|
64
|
+
directory: options.directory,
|
|
65
|
+
title: options.title ?? app.title,
|
|
66
|
+
storeFqdn: options.storeFqdn ?? app.storeFqdn,
|
|
67
|
+
orgId: options.orgId ?? app.orgId,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
this.set('appInfo', apps);
|
|
71
|
+
}
|
|
72
|
+
clearAppInfo(directory) {
|
|
73
|
+
debug(content `Clearning app information for directory ${token.path(directory)}...`);
|
|
74
|
+
const apps = this.get('appInfo') ?? [];
|
|
75
|
+
const index = apps.findIndex((saved) => saved.directory === directory);
|
|
76
|
+
if (index !== -1) {
|
|
77
|
+
apps.splice(index, 1);
|
|
78
|
+
}
|
|
79
|
+
this.set('appInfo', apps);
|
|
80
|
+
}
|
|
81
|
+
getTheme() {
|
|
82
|
+
debug(content `Getting theme store...`);
|
|
83
|
+
return this.get('themeStore');
|
|
84
|
+
}
|
|
85
|
+
setTheme(store) {
|
|
86
|
+
debug(content `Setting theme store...`);
|
|
87
|
+
this.set('themeStore', store);
|
|
88
|
+
}
|
|
89
|
+
getSession() {
|
|
90
|
+
debug(content `Getting session store...`);
|
|
91
|
+
return this.get('sessionStore');
|
|
92
|
+
}
|
|
93
|
+
setSession(store) {
|
|
94
|
+
debug(content `Setting session store...`);
|
|
95
|
+
this.set('sessionStore', store);
|
|
96
|
+
}
|
|
97
|
+
removeSession() {
|
|
98
|
+
debug(content `Removing session store...`);
|
|
99
|
+
this.set('sessionStore', '');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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","sourcesContent":["import {content, token, debug} from './output.js'\nimport constants from './constants.js'\nimport {Abort} from './error.js'\nimport Conf, {Schema} from 'conf'\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n\nconst migrations = {}\n\nexport interface CachedAppInfo {\n directory: string\n appId: string\n title?: string\n orgId?: string\n storeFqdn?: string\n}\n\ninterface ConfSchema {\n appInfo: CachedAppInfo[]\n themeStore: string\n session: string\n}\n\nconst schema = {\n appInfo: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n appId: {\n type: 'string',\n },\n orgId: {\n type: 'string',\n },\n storeFqdn: {\n type: 'string',\n },\n },\n },\n },\n} as unknown as Schema<ConfSchema>\n\nlet _instance: CLIKitStore | undefined\n\nexport function cliKitStore() {\n if (!_instance) {\n throw new Abort(\"The CLIKitStore instance hasn't been initialized\")\n }\n return _instance\n}\n\nexport async function initializeCliKitStore() {\n if (!_instance) {\n // eslint-disable-next-line require-atomic-updates\n _instance = new CLIKitStore({\n schema,\n migrations,\n projectName: 'shopify-cli-kit',\n projectVersion: await constants.versions.cliKit(),\n })\n }\n}\n\nexport class CLIKitStore extends Conf<ConfSchema> {\n getAppInfo(directory: string): CachedAppInfo | undefined {\n debug(content`Reading cached app information for directory ${token.path(directory)}...`)\n const apps = this.get('appInfo') ?? []\n return apps.find((app: CachedAppInfo) => app.directory === directory)\n }\n\n setAppInfo(options: {directory: string; appId: string; title?: string; storeFqdn?: string; orgId?: string}): void {\n debug(content`Storing app information for directory ${token.path(options.directory)}:\n${token.json(options)}\n`)\n const apps = this.get('appInfo') ?? []\n const index = apps.findIndex((saved: CachedAppInfo) => saved.directory === options.directory)\n if (index === -1) {\n apps.push(options)\n } else {\n const app: CachedAppInfo = apps[index]\n apps[index] = {\n appId: options.appId,\n directory: options.directory,\n title: options.title ?? app.title,\n storeFqdn: options.storeFqdn ?? app.storeFqdn,\n orgId: options.orgId ?? app.orgId,\n }\n }\n this.set('appInfo', apps)\n }\n\n clearAppInfo(directory: string): void {\n debug(content`Clearning app information for directory ${token.path(directory)}...`)\n const apps = this.get('appInfo') ?? []\n const index = apps.findIndex((saved: CachedAppInfo) => saved.directory === directory)\n if (index !== -1) {\n apps.splice(index, 1)\n }\n this.set('appInfo', apps)\n }\n\n getTheme(): string | undefined {\n debug(content`Getting theme store...`)\n return this.get('themeStore')\n }\n\n setTheme(store: string): void {\n debug(content`Setting theme store...`)\n this.set('themeStore', store)\n }\n\n getSession(): string | undefined {\n debug(content`Getting session store...`)\n return this.get('sessionStore')\n }\n\n setSession(store: string): void {\n debug(content`Setting session store...`)\n this.set('sessionStore', store)\n }\n\n removeSession(): void {\n debug(content`Removing session store...`)\n this.set('sessionStore', '')\n }\n}\n"]}
|
package/dist/string.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { camelCase as camelize } from 'change-case';
|
|
2
|
+
export { paramCase as hyphenize } from 'change-case';
|
|
3
|
+
export { snakeCase as underscore } from 'change-case';
|
|
4
|
+
export { constantCase as constantize } from 'change-case';
|
|
5
|
+
/** Returns a random string */
|
|
6
|
+
export declare function randomHex(size: number): string;
|
|
7
|
+
export declare function generateRandomChallengePair(): {
|
|
8
|
+
codeVerifier: string;
|
|
9
|
+
codeChallenge: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Given a string, it returns it with the first letter capitalized.
|
|
13
|
+
* @param string {string} String whose first letter will be caplitalized.
|
|
14
|
+
* @returns The given string with its first letter capitalized.
|
|
15
|
+
*/
|
|
16
|
+
export declare function capitalize(string: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Given a store, returns a valid store fqdn removing protocol and adding .myshopify.com domain
|
|
19
|
+
* @param store Original store name provided by the user
|
|
20
|
+
* @returns a valid store fqdn
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeStoreName(store: string): string;
|
package/dist/string.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
export { camelCase as camelize } from 'change-case';
|
|
3
|
+
export { paramCase as hyphenize } from 'change-case';
|
|
4
|
+
export { snakeCase as underscore } from 'change-case';
|
|
5
|
+
export { constantCase as constantize } from 'change-case';
|
|
6
|
+
/** Returns a random string */
|
|
7
|
+
export function randomHex(size) {
|
|
8
|
+
return crypto.randomBytes(size).toString('hex');
|
|
9
|
+
}
|
|
10
|
+
export function generateRandomChallengePair() {
|
|
11
|
+
const codeVerifier = base64URLEncode(crypto.randomBytes(32));
|
|
12
|
+
const codeChallenge = base64URLEncode(sha256(codeVerifier));
|
|
13
|
+
return { codeVerifier, codeChallenge };
|
|
14
|
+
}
|
|
15
|
+
function base64URLEncode(str) {
|
|
16
|
+
return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/[=]/g, '');
|
|
17
|
+
}
|
|
18
|
+
function sha256(str) {
|
|
19
|
+
return crypto.createHash('sha256').update(str).digest();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Given a string, it returns it with the first letter capitalized.
|
|
23
|
+
* @param string {string} String whose first letter will be caplitalized.
|
|
24
|
+
* @returns The given string with its first letter capitalized.
|
|
25
|
+
*/
|
|
26
|
+
export function capitalize(string) {
|
|
27
|
+
return string.substring(0, 1).toUpperCase() + string.substring(1);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Given a store, returns a valid store fqdn removing protocol and adding .myshopify.com domain
|
|
31
|
+
* @param store Original store name provided by the user
|
|
32
|
+
* @returns a valid store fqdn
|
|
33
|
+
*/
|
|
34
|
+
export function normalizeStoreName(store) {
|
|
35
|
+
const storeFqdn = store.replace(/^https?:\/\//, '').replace(/\/$/, '');
|
|
36
|
+
return storeFqdn.includes('.myshopify.com') ? storeFqdn : `${storeFqdn}.myshopify.com`;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string.js","sourceRoot":"","sources":["../src/string.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,OAAO,EAAC,SAAS,IAAI,QAAQ,EAAC,MAAM,aAAa,CAAA;AACjD,OAAO,EAAC,SAAS,IAAI,SAAS,EAAC,MAAM,aAAa,CAAA;AAClD,OAAO,EAAC,SAAS,IAAI,UAAU,EAAC,MAAM,aAAa,CAAA;AACnD,OAAO,EAAC,YAAY,IAAI,WAAW,EAAC,MAAM,aAAa,CAAA;AAEvD,8BAA8B;AAC9B,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5D,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;IAC3D,OAAO,EAAC,YAAY,EAAE,aAAa,EAAC,CAAA;AACtC,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAC3F,CAAC;AAED,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACtE,OAAO,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,gBAAgB,CAAA;AACxF,CAAC","sourcesContent":["import crypto from 'crypto'\n\nexport {camelCase as camelize} from 'change-case'\nexport {paramCase as hyphenize} from 'change-case'\nexport {snakeCase as underscore} from 'change-case'\nexport {constantCase as constantize} from 'change-case'\n\n/** Returns a random string */\nexport function randomHex(size: number): string {\n return crypto.randomBytes(size).toString('hex')\n}\n\nexport function generateRandomChallengePair() {\n const codeVerifier = base64URLEncode(crypto.randomBytes(32))\n const codeChallenge = base64URLEncode(sha256(codeVerifier))\n return {codeVerifier, codeChallenge}\n}\n\nfunction base64URLEncode(str: Buffer) {\n return str.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/[=]/g, '')\n}\n\nfunction sha256(str: string) {\n return crypto.createHash('sha256').update(str).digest()\n}\n\n/**\n * Given a string, it returns it with the first letter capitalized.\n * @param string {string} String whose first letter will be caplitalized.\n * @returns The given string with its first letter capitalized.\n */\nexport function capitalize(string: string) {\n return string.substring(0, 1).toUpperCase() + string.substring(1)\n}\n\n/**\n * Given a store, returns a valid store fqdn removing protocol and adding .myshopify.com domain\n * @param store Original store name provided by the user\n * @returns a valid store fqdn\n */\nexport function normalizeStoreName(store: string) {\n const storeFqdn = store.replace(/^https?:\\/\\//, '').replace(/\\/$/, '')\n return storeFqdn.includes('.myshopify.com') ? storeFqdn : `${storeFqdn}.myshopify.com`\n}\n"]}
|
package/dist/system.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { AbortSignal } from 'abort-controller';
|
|
3
|
+
import type { Writable, Readable } from 'node:stream';
|
|
4
|
+
export interface ExecOptions {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
env?: {
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
stdout?: Writable | 'inherit';
|
|
10
|
+
stderr?: Writable;
|
|
11
|
+
stdio?: Readable | 'inherit';
|
|
12
|
+
stdin?: string;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
export declare type WritableExecOptions = Omit<ExecOptions, 'stdout'> & {
|
|
16
|
+
stdout?: Writable;
|
|
17
|
+
};
|
|
18
|
+
export declare const open: (url: string) => Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Runs a command asynchronously, aggregates the stdout data, and returns it.
|
|
21
|
+
* @param command {string} Command to be executed.
|
|
22
|
+
* @param args {string[]} Arguments to pass to the command.
|
|
23
|
+
* @returns A promise that resolves with the aggregatted stdout of the command.
|
|
24
|
+
*/
|
|
25
|
+
export declare const captureOutput: (command: string, args: string[], options?: ExecOptions) => Promise<string>;
|
|
26
|
+
export declare const exec: (command: string, args: string[], options?: ExecOptions) => Promise<void>;
|
|
27
|
+
interface ConcurrentExecCommand {
|
|
28
|
+
prefix: string;
|
|
29
|
+
executable: string;
|
|
30
|
+
args: string[];
|
|
31
|
+
cwd: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Runs commands concurrently and combines the standard output and error data
|
|
35
|
+
* into a single stream that differenciates the sources using a colored prefix:
|
|
36
|
+
*
|
|
37
|
+
* Example:
|
|
38
|
+
* [my-extension] Log coming from my-extension
|
|
39
|
+
* [my-script] Log coming from my script
|
|
40
|
+
*
|
|
41
|
+
* If one of the processes fails, it aborts the running ones and exits with that error.
|
|
42
|
+
* @param commands {ConcurrentExecCommand[]} Commands to execute.
|
|
43
|
+
*/
|
|
44
|
+
export declare const concurrentExec: (commands: ConcurrentExecCommand[]) => Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Displays a large file using the terminal pager set by the user, or a
|
|
47
|
+
* reasonable default for the user's OS:
|
|
48
|
+
*
|
|
49
|
+
* @param filename string The path to the file to be displayed.
|
|
50
|
+
*/
|
|
51
|
+
export declare function page(filename: string): Promise<void>;
|
|
52
|
+
export declare function sleep(seconds: number): Promise<unknown>;
|
|
53
|
+
export {};
|