@shopify/cli-kit 3.43.0 → 3.44.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/assets/cli-ruby/Gemfile +6 -3
- package/assets/cli-ruby/lib/project_types/extension/commands/serve.rb +10 -0
- package/assets/cli-ruby/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +1 -1
- package/assets/cli-ruby/lib/project_types/theme/cli.rb +1 -0
- package/assets/cli-ruby/lib/project_types/theme/commands/common/root_helper.rb +3 -2
- package/assets/cli-ruby/lib/project_types/theme/commands/console.rb +15 -0
- package/assets/cli-ruby/lib/project_types/theme/commands/push.rb +1 -0
- package/assets/cli-ruby/lib/project_types/theme/messages/messages.rb +4 -2
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/hot_reload/script_injector.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/hot_reload.rb +9 -2
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/proxy.rb +13 -12
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server.rb +2 -2
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +7 -4
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/host_theme.rb +19 -14
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/api.rb +107 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/auth_dev_server.rb +80 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/auth_middleware.rb +73 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/resources/success.html +79 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/resources/template.liquid +15 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/repl.rb +145 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/syncer/standard_reporter.rb +2 -2
- package/assets/cli-ruby/lib/shopify_cli/theme/syncer.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/theme.rb +6 -6
- package/dist/private/node/analytics.d.ts +2 -2
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/graphql.js +9 -16
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api/headers.js +8 -5
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/api.d.ts +9 -0
- package/dist/private/node/api.js +19 -0
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/colors.js.map +1 -0
- package/dist/private/node/conf-store.d.ts +24 -5
- package/dist/private/node/conf-store.js +21 -3
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/constants.d.ts +2 -0
- package/dist/private/node/constants.js +2 -0
- package/dist/private/node/constants.js.map +1 -1
- package/dist/private/node/content-tokens.js +1 -1
- package/dist/private/node/content-tokens.js.map +1 -1
- package/dist/private/node/semver.js.map +1 -0
- package/dist/private/node/session/identity-token-validation.d.ts +1 -1
- package/dist/private/node/session/identity-token-validation.js +45 -20
- package/dist/private/node/session/identity-token-validation.js.map +1 -1
- package/dist/private/node/session/store.js +3 -46
- package/dist/private/node/session/store.js.map +1 -1
- package/dist/private/node/session.js +13 -10
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/themes/generate-theme-name.js.map +1 -0
- package/dist/private/node/themes/replace-invalid-characters.js.map +1 -0
- package/dist/private/node/themes/themes-api/headers.js.map +1 -0
- package/dist/private/node/themes/themes-api/retry.js.map +1 -0
- package/dist/private/node/themes/themes-api/throttler.js.map +1 -0
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +0 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js +0 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/public/common/string.d.ts +16 -4
- package/dist/public/common/string.js +25 -4
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/ts/deep-required.d.ts +0 -1
- package/dist/public/common/ts/deep-required.js.map +1 -1
- package/dist/public/common/ts/pick-by-prefix.d.ts +0 -1
- package/dist/public/common/ts/pick-by-prefix.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/base-command.d.ts +8 -5
- package/dist/public/node/base-command.js +1 -1
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.d.ts +1 -1
- package/dist/public/node/cli.js +0 -1
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/spin.d.ts +14 -0
- package/dist/public/node/context/spin.js +19 -0
- package/dist/public/node/context/spin.js.map +1 -1
- package/dist/public/node/environment.d.ts +12 -0
- package/dist/public/node/environment.js +14 -0
- package/dist/public/node/environment.js.map +1 -0
- package/dist/public/node/fs.d.ts +8 -12
- package/dist/public/node/fs.js +11 -35
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/http.js +5 -10
- package/dist/public/node/http.js.map +1 -1
- package/dist/public/node/local-storage.d.ts +37 -0
- package/dist/public/node/local-storage.js +44 -0
- package/dist/public/node/local-storage.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/output.d.ts +0 -1
- package/dist/public/node/output.js +1 -2
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/path.d.ts +58 -2
- package/dist/public/node/path.js +75 -3
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/ruby.d.ts +2 -1
- package/dist/public/node/ruby.js +52 -17
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/themes/conf.d.ts +12 -0
- package/dist/public/node/themes/conf.js +24 -0
- package/dist/public/node/themes/conf.js.map +1 -0
- package/dist/public/node/themes/theme-manager.js +1 -1
- package/dist/public/node/themes/theme-manager.js.map +1 -1
- package/dist/public/node/themes/themes-api.js +3 -3
- package/dist/public/node/themes/themes-api.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/dist/private/node/secure-store.d.ts +0 -19
- package/dist/private/node/secure-store.js +0 -63
- package/dist/private/node/secure-store.js.map +0 -1
- package/dist/public/node/colors.js.map +0 -1
- package/dist/public/node/conf.d.ts +0 -2
- package/dist/public/node/conf.js +0 -3
- package/dist/public/node/conf.js.map +0 -1
- package/dist/public/node/semver.js.map +0 -1
- package/dist/public/node/themes/generate-theme-name.js.map +0 -1
- package/dist/public/node/themes/replace-invalid-characters.js.map +0 -1
- package/dist/public/node/themes/themes-api/headers.js.map +0 -1
- package/dist/public/node/themes/themes-api/retry.js.map +0 -1
- package/dist/public/node/themes/themes-api/throttler.js.map +0 -1
- package/dist/store/schema.d.ts +0 -3
- package/dist/store/schema.js +0 -27
- package/dist/store/schema.js.map +0 -1
- /package/dist/{public → private}/node/colors.d.ts +0 -0
- /package/dist/{public → private}/node/colors.js +0 -0
- /package/dist/{public → private}/node/semver.d.ts +0 -0
- /package/dist/{public → private}/node/semver.js +0 -0
- /package/dist/{public → private}/node/themes/generate-theme-name.d.ts +0 -0
- /package/dist/{public → private}/node/themes/generate-theme-name.js +0 -0
- /package/dist/{public → private}/node/themes/replace-invalid-characters.d.ts +0 -0
- /package/dist/{public → private}/node/themes/replace-invalid-characters.js +0 -0
- /package/dist/{public → private}/node/themes/themes-api/headers.d.ts +0 -0
- /package/dist/{public → private}/node/themes/themes-api/headers.js +0 -0
- /package/dist/{public → private}/node/themes/themes-api/retry.d.ts +0 -0
- /package/dist/{public → private}/node/themes/themes-api/retry.js +0 -0
- /package/dist/{public → private}/node/themes/themes-api/throttler.d.ts +0 -0
- /package/dist/{public → private}/node/themes/themes-api/throttler.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-tokens.js","sourceRoot":"","sources":["../../../src/private/node/content-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"content-tokens.js","sourceRoot":"","sources":["../../../src/private/node/content-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import colors from './colors.js'\nimport {OutputMessage, stringifyMessage} from '../../public/node/output.js'\nimport {relativizePath} from '../../public/node/path.js'\nimport terminalLink from 'terminal-link'\nimport cjs from 'color-json'\nimport type {Change} from 'diff'\n\nexport abstract class ContentToken<T> {\n value: T\n\n constructor(value: T) {\n this.value = value\n }\n\n abstract output(): string | string[]\n}\n\nexport class RawContentToken extends ContentToken<string> {\n output(): string {\n return this.value\n }\n}\n\nexport class LinkContentToken extends ContentToken<OutputMessage> {\n link: string\n\n constructor(value: OutputMessage, link: string) {\n super(value)\n this.link = link\n }\n\n output() {\n const text = colors.green(stringifyMessage(this.value))\n const url = this.link ?? ''\n return terminalLink(text, url, {fallback: () => `${text} ( ${url} )`})\n }\n}\n\nexport class CommandContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.bold(colors.yellow(stringifyMessage(this.value)))\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class JsonContentToken extends ContentToken<any> {\n output(): string {\n try {\n return cjs(stringifyMessage(this.value) ?? {})\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (_) {\n return JSON.stringify(stringifyMessage(this.value) ?? {}, null, 2)\n }\n }\n}\n\nexport class LinesDiffContentToken extends ContentToken<Change[]> {\n output(): string[] {\n return this.value\n .map((part) => {\n if (part.added) {\n return part.value\n .split(/\\n/)\n .filter((line) => line !== '')\n .map((line) => {\n return colors.green(`+ ${line}\\n`)\n })\n } else if (part.removed) {\n return part.value\n .split(/\\n/)\n .filter((line) => line !== '')\n .map((line) => {\n return colors.magenta(`- ${line}\\n`)\n })\n } else {\n return part.value\n }\n })\n .flat()\n }\n}\n\nexport class ColorContentToken extends ContentToken<OutputMessage> {\n color: (text: string) => string\n\n constructor(value: OutputMessage, color: (text: string) => string) {\n super(value)\n this.color = color\n }\n\n output(): string {\n return this.color(stringifyMessage(this.value))\n }\n}\n\nexport class ErrorContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.bold.redBright(stringifyMessage(this.value))\n }\n}\n\nexport class PathContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return relativizePath(stringifyMessage(this.value))\n }\n}\n\nexport class HeadingContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.bold.underline(stringifyMessage(this.value))\n }\n}\n\nexport class SubHeadingContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.underline(stringifyMessage(this.value))\n }\n}\n\nexport class ItalicContentToken extends ContentToken<OutputMessage> {\n output(): string {\n return colors.italic(stringifyMessage(this.value))\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semver.js","sourceRoot":"","sources":["../../../src/private/node/semver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AAEpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAM,EAAC,MAAM,EAAE,MAAM,EAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;AAE1C,OAAO,EAAC,MAAM,IAAI,OAAO,EAAC,CAAA;AAC1B,OAAO,EAAC,MAAM,IAAI,mBAAmB,EAAC,CAAA","sourcesContent":["import {createRequire} from 'module'\n\nconst require = createRequire(import.meta.url)\nconst {coerce, SemVer} = require('semver')\n\nexport {SemVer as Version}\nexport {coerce as coerceSemverVersion}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function validateIdentityToken(token: string): Promise<
|
|
1
|
+
export declare function validateIdentityToken(token: string): Promise<boolean>;
|
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
import { identityFqdn } from '../../../public/node/context/fqdn.js';
|
|
2
2
|
import { outputDebug } from '../../../public/node/output.js';
|
|
3
3
|
import { shopifyFetch } from '../../../public/node/http.js';
|
|
4
|
+
import { cacheRetrieveOrRepopulate } from '../conf-store.js';
|
|
5
|
+
import { err, ok } from '../../../public/node/result.js';
|
|
6
|
+
import { AbortError } from '../../../public/node/error.js';
|
|
4
7
|
export async function validateIdentityToken(token) {
|
|
5
8
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
return withIntrospectionURL(async (introspectionURL) => {
|
|
10
|
+
const options = {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
13
|
+
body: JSON.stringify({ token }),
|
|
14
|
+
};
|
|
15
|
+
outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`);
|
|
16
|
+
const response = await shopifyFetch(introspectionURL, options);
|
|
17
|
+
if (response.ok && response.headers.get('content-type')?.includes('json')) {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
const json = await response.json();
|
|
20
|
+
outputDebug(`The identity token is valid: ${json.valid}`);
|
|
21
|
+
return ok(json.valid);
|
|
22
|
+
}
|
|
23
|
+
else if (response.status === 404 || response.status > 500) {
|
|
24
|
+
// If the status is 404 or 5xx, most likely the introspection endpoint
|
|
25
|
+
// has changed. We should invalidate the cache and try again.
|
|
26
|
+
return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const text = await response.text();
|
|
30
|
+
outputDebug(`The Introspection request failed with:
|
|
23
31
|
- status: ${response.status}
|
|
24
32
|
- www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}
|
|
25
33
|
- body: ${JSON.stringify(text)}`);
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
return ok(false);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
28
37
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
29
38
|
}
|
|
30
39
|
catch (error) {
|
|
@@ -32,7 +41,23 @@ export async function validateIdentityToken(token) {
|
|
|
32
41
|
return false;
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
|
-
async function
|
|
44
|
+
async function withIntrospectionURL(fn) {
|
|
45
|
+
const week = 7 * 24 * 60 * 60 * 1000;
|
|
46
|
+
const cacheKey = `identity-introspection-url-${await identityFqdn()}`;
|
|
47
|
+
let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week);
|
|
48
|
+
let result = await fn(introspectionURL);
|
|
49
|
+
if (result.isErr()) {
|
|
50
|
+
introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0);
|
|
51
|
+
result = await fn(introspectionURL);
|
|
52
|
+
}
|
|
53
|
+
if (result.isErr()) {
|
|
54
|
+
throw result.error;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return result.value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function getIntrospectionURL() {
|
|
36
61
|
const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`);
|
|
37
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
63
|
const json = await response.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,sCAAsC,CAAA;AACjE,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAC,YAAY,EAAC,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"identity-token-validation.js","sourceRoot":"","sources":["../../../../src/private/node/session/identity-token-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {outputDebug} from '../../../public/node/output.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {cacheRetrieveOrRepopulate, IntrospectionUrlKey} from '../conf-store.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError} from '../../../public/node/error.js'\n\nexport async function validateIdentityToken(token: string): Promise<boolean> {\n try {\n return withIntrospectionURL<boolean>(async (introspectionURL: string) => {\n const options = {\n method: 'POST',\n headers: {Authorization: `Bearer ${token}`, 'Content-Type': 'application/json'},\n body: JSON.stringify({token}),\n }\n outputDebug(`Sending Identity Introspection request to URL: ${introspectionURL}`)\n\n const response = await shopifyFetch(introspectionURL, options)\n\n if (response.ok && response.headers.get('content-type')?.includes('json')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n outputDebug(`The identity token is valid: ${json.valid}`)\n return ok(json.valid)\n } else if (response.status === 404 || response.status > 500) {\n // If the status is 404 or 5xx, most likely the introspection endpoint\n // has changed. We should invalidate the cache and try again.\n return err(new AbortError(`The introspection endpoint returned a ${response.status}: ${introspectionURL}`))\n } else {\n const text = await response.text()\n outputDebug(`The Introspection request failed with:\n - status: ${response.status}\n - www-authenticate header: ${JSON.stringify(response.headers.get('www-authenticate'))}\n - body: ${JSON.stringify(text)}`)\n return ok(false)\n }\n })\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(`The identity token is invalid: ${error}`)\n return false\n }\n}\n\nasync function withIntrospectionURL<T>(fn: (introspectionUrl: string) => Promise<Result<T, AbortError>>): Promise<T> {\n const week = 7 * 24 * 60 * 60 * 1000\n const cacheKey: IntrospectionUrlKey = `identity-introspection-url-${await identityFqdn()}`\n let introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, week)\n let result: Result<T, AbortError> = await fn(introspectionURL)\n if (result.isErr()) {\n introspectionURL = await cacheRetrieveOrRepopulate(cacheKey, getIntrospectionURL, 0)\n result = await fn(introspectionURL)\n }\n if (result.isErr()) {\n throw result.error\n } else {\n return result.value\n }\n}\n\nasync function getIntrospectionURL(): Promise<string> {\n const response = await shopifyFetch(`https://${await identityFqdn()}/.well-known/openid-configuration.json`)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const json: any = await response.json()\n return json.introspection_endpoint\n}\n"]}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { SessionSchema } from './schema.js';
|
|
2
2
|
import { getSession, removeSession, setSession } from '../conf-store.js';
|
|
3
|
-
import { keychainConstants } from '../constants.js';
|
|
4
|
-
import { platformAndArch } from '../../../public/node/os.js';
|
|
5
|
-
import { secureStoreSave, secureStoreFetch, secureStoreRemove } from '../secure-store.js';
|
|
6
|
-
import { outputContent, outputDebug } from '../../../public/node/output.js';
|
|
7
3
|
/**
|
|
8
4
|
* The identifier of the session in the secure store.
|
|
9
5
|
*/
|
|
@@ -15,12 +11,7 @@ export const identifier = 'session';
|
|
|
15
11
|
*/
|
|
16
12
|
export async function store(session) {
|
|
17
13
|
const jsonSession = JSON.stringify(session);
|
|
18
|
-
|
|
19
|
-
await secureStoreSave(identifier, jsonSession);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
setSession(jsonSession);
|
|
23
|
-
}
|
|
14
|
+
setSession(jsonSession);
|
|
24
15
|
}
|
|
25
16
|
/**
|
|
26
17
|
* Fetches the session from the secure store and returns it.
|
|
@@ -31,13 +22,7 @@ export async function store(session) {
|
|
|
31
22
|
* @returns Returns a promise that resolves with the session if it exists and is valid.
|
|
32
23
|
*/
|
|
33
24
|
export async function fetch() {
|
|
34
|
-
|
|
35
|
-
if (await secureStoreAvailable()) {
|
|
36
|
-
content = await secureStoreFetch(identifier);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
content = getSession();
|
|
40
|
-
}
|
|
25
|
+
const content = getSession();
|
|
41
26
|
if (!content) {
|
|
42
27
|
return undefined;
|
|
43
28
|
}
|
|
@@ -55,34 +40,6 @@ export async function fetch() {
|
|
|
55
40
|
* Removes a session from the system.
|
|
56
41
|
*/
|
|
57
42
|
export async function remove() {
|
|
58
|
-
|
|
59
|
-
await secureStoreRemove(identifier);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
removeSession();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Returns true if the secure store is available on the system.
|
|
67
|
-
* Keytar it's not supported on some Linux environments or Windows.
|
|
68
|
-
* More details: https://github.com/Shopify/shopify-cli-planning/issues/261
|
|
69
|
-
* @returns a boolean indicating if the secure store is available.
|
|
70
|
-
*/
|
|
71
|
-
async function secureStoreAvailable() {
|
|
72
|
-
try {
|
|
73
|
-
if (platformAndArch().platform === 'windows') {
|
|
74
|
-
outputDebug(outputContent `Secure store not supported on Windows`);
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
const keytar = await import('keytar');
|
|
78
|
-
await keytar.default.findCredentials(keychainConstants.service);
|
|
79
|
-
outputDebug(outputContent `Secure store is available`);
|
|
80
|
-
return true;
|
|
81
|
-
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
82
|
-
}
|
|
83
|
-
catch (_error) {
|
|
84
|
-
outputDebug(outputContent `Failed to load secure store`);
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
43
|
+
removeSession();
|
|
87
44
|
}
|
|
88
45
|
//# sourceMappingURL=store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/private/node/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/private/node/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAGtE;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAA;AAEnC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAAgB;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3C,UAAU,CAAC,WAAW,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAE5B,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,SAAS,CAAA;KACjB;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,WAAW,CAAC,CAAA;IACrE,IAAI,aAAa,CAAC,OAAO,EAAE;QACzB,OAAO,aAAa,CAAC,IAAI,CAAA;KAC1B;SAAM;QACL,MAAM,MAAM,EAAE,CAAA;QACd,OAAO,SAAS,CAAA;KACjB;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,aAAa,EAAE,CAAA;AACjB,CAAC","sourcesContent":["import {SessionSchema} from './schema.js'\nimport {getSession, removeSession, setSession} from '../conf-store.js'\nimport type {Session} from './schema.js'\n\n/**\n * The identifier of the session in the secure store.\n */\nexport const identifier = 'session'\n\n/**\n * Serializes the session as a JSON and stores it securely in the system.\n * If the secure store is not available, the session is stored in the local config.\n * @param session - the session to store.\n */\nexport async function store(session: Session) {\n const jsonSession = JSON.stringify(session)\n setSession(jsonSession)\n}\n\n/**\n * Fetches the session from the secure store and returns it.\n * If the secure store is not available, the session is fetched from the local config.\n * If the format of the session is invalid, the method will discard it.\n * In the future might add some logic for supporting migrating the schema\n * of already-persisted sessions.\n * @returns Returns a promise that resolves with the session if it exists and is valid.\n */\nexport async function fetch(): Promise<Session | undefined> {\n const content = getSession()\n\n if (!content) {\n return undefined\n }\n const contentJson = JSON.parse(content)\n const parsedSession = await SessionSchema.safeParseAsync(contentJson)\n if (parsedSession.success) {\n return parsedSession.data\n } else {\n await remove()\n return undefined\n }\n}\n\n/**\n * Removes a session from the system.\n */\nexport async function remove() {\n removeSession()\n}\n"]}
|
|
@@ -66,7 +66,9 @@ ${outputToken.json(applications)}
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
const completeSession = { ...currentSession, ...newSession };
|
|
69
|
-
|
|
69
|
+
// Save the new session info if it has changed
|
|
70
|
+
if (Object.keys(newSession).length > 0)
|
|
71
|
+
await secureStore.store(completeSession);
|
|
70
72
|
const tokens = await tokensFor(applications, completeSession, fqdn);
|
|
71
73
|
// Overwrite partners token if using a custom CLI Token
|
|
72
74
|
const envToken = env[environmentVariables.partnersToken];
|
|
@@ -143,6 +145,15 @@ async function ensureUserHasPartnerAccount(partnersToken) {
|
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
}
|
|
148
|
+
const getFirstOrganization = gql `
|
|
149
|
+
{
|
|
150
|
+
organizations(first: 1) {
|
|
151
|
+
nodes {
|
|
152
|
+
id
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
`;
|
|
146
157
|
/**
|
|
147
158
|
* Validate if the current token is valid for partners API.
|
|
148
159
|
*
|
|
@@ -151,15 +162,7 @@ async function ensureUserHasPartnerAccount(partnersToken) {
|
|
|
151
162
|
*/
|
|
152
163
|
async function hasPartnerAccount(partnersToken) {
|
|
153
164
|
try {
|
|
154
|
-
await partnersRequest(
|
|
155
|
-
{
|
|
156
|
-
organizations(first: 1) {
|
|
157
|
-
nodes {
|
|
158
|
-
id
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
`, partnersToken);
|
|
165
|
+
await partnersRequest(getFirstOrganization, partnersToken);
|
|
163
166
|
return true;
|
|
164
167
|
// eslint-disable-next-line no-catch-all/no-catch-all
|
|
165
168
|
}
|
|
@@ -1 +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'\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 {environmentVariables} from './constants.js'\nimport {outputContent, outputToken, outputDebug} from '../../public/node/output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/context/local.js'\nimport {AbortError, BugError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {keypress} from '../../public/node/ui.js'\nimport {gql} from 'graphql-request'\nimport {AdminSession} from '@shopify/cli-kit/node/session'\nimport {outputCompleted, outputInfo, outputWarn} from '@shopify/cli-kit/node/output'\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 outputDebug(outputContent`Validating existing session against the scopes:\n${outputToken.json(scopes)}\nFor applications:\n${outputToken.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n outputDebug(outputContent`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[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 outputDebug(outputContent`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 outputDebug(outputContent`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n outputDebug(outputContent`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n outputDebug(outputContent`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n outputDebug(outputContent`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n outputDebug(outputContent`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 outputCompleted('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 outputDebug(outputContent`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n outputInfo(`\\nA Shopify Partners organization is needed to proceed.`)\n outputInfo(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n outputInfo(outputContent`👉 Press any key when you have ${outputToken.cyan('created the organization')}`)\n outputWarn(outputContent`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 AbortError(\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 BugError('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"]}
|
|
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'\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 {environmentVariables} from './constants.js'\nimport {outputContent, outputToken, outputDebug} from '../../public/node/output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/context/local.js'\nimport {AbortError, BugError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {keypress} from '../../public/node/ui.js'\nimport {gql} from 'graphql-request'\nimport {AdminSession} from '@shopify/cli-kit/node/session'\nimport {outputCompleted, outputInfo, outputWarn} from '@shopify/cli-kit/node/output'\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 outputDebug(outputContent`Validating existing session against the scopes:\n${outputToken.json(scopes)}\nFor applications:\n${outputToken.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n outputDebug(outputContent`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 // Save the new session info if it has changed\n if (Object.keys(newSession).length > 0) 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[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 outputDebug(outputContent`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 outputDebug(outputContent`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n outputDebug(outputContent`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n outputDebug(outputContent`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n outputDebug(outputContent`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n outputDebug(outputContent`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 outputCompleted('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 outputDebug(outputContent`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n outputInfo(`\\nA Shopify Partners organization is needed to proceed.`)\n outputInfo(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n outputInfo(outputContent`👉 Press any key when you have ${outputToken.cyan('created the organization')}`)\n outputWarn(outputContent`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 AbortError(\n `Couldn't find your Shopify Partners organization`,\n `Have you confirmed your accounts from the emails you received?`,\n )\n }\n }\n}\n\nconst getFirstOrganization = gql`\n {\n organizations(first: 1) {\n nodes {\n id\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(getFirstOrganization, partnersToken)\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 BugError('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 @@
|
|
|
1
|
+
{"version":3,"file":"generate-theme-name.js","sourceRoot":"","sources":["../../../../src/private/node/themes/generate-theme-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,wBAAwB,EAAC,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAC,WAAW,EAAC,MAAM,QAAQ,CAAA;AAClC,OAAO,EAAC,QAAQ,EAAC,MAAM,IAAI,CAAA;AAE3B,MAAM,cAAc,GAAG,EAAE,CAAA;AAEzB,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,qBAAqB,GAAG,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAA;IACvD,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,MAAM,IAAI,GAAG,GAAG,OAAO,KAAK,CAAA;IAC5B,MAAM,sBAAsB,GAAG,cAAc,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IACzE,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,IAAI,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAC,EAAE,sBAAsB,CAAC,EAAE,CAAC,CAAA;IACpH,OAAO,GAAG,OAAO,KAAK,UAAU,GAAG,CAAA;AACrC,CAAC","sourcesContent":["import {replaceInvalidCharacters} from './replace-invalid-characters.js'\nimport {randomBytes} from 'crypto'\nimport {hostname} from 'os'\n\nconst API_NAME_LIMIT = 50\n\nexport function generateThemeName(context: string): string {\n const hostNameWithoutDomain = hostname().split('.')[0]!\n const hash = randomBytes(3).toString('hex')\n\n const name = `${context} ()`\n const hostNameCharacterLimit = API_NAME_LIMIT - name.length - hash.length\n const identifier = replaceInvalidCharacters(`${hash}-${hostNameWithoutDomain.substring(0, hostNameCharacterLimit)}`)\n return `${context} (${identifier})`\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replace-invalid-characters.js","sourceRoot":"","sources":["../../../../src/private/node/themes/replace-invalid-characters.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,wBAAwB,CAAC,UAAkB;IACzD,MAAM,cAAc,GAAG,GAAG,CAAA;IAC1B,MAAM,qBAAqB,GAAG,GAAG,CAAA;IACjC,OAAO,UAAU,CAAC,OAAO,CACvB,IAAI,MAAM,CAAC,kCAAkC,EAAE,GAAG,cAAc,GAAG,qBAAqB,EAAE,CAAC,EAC3F,GAAG,CACJ,CAAA;AACH,CAAC","sourcesContent":["export function replaceInvalidCharacters(identifier: string) {\n const findAllMatches = 'g'\n const enablesUnicodeSupport = 'u'\n return identifier.replace(\n new RegExp(/[^\\p{Letter}\\p{Number}\\p{Mark}-]/, `${findAllMatches}${enablesUnicodeSupport}`),\n '-',\n )\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.js","sourceRoot":"","sources":["../../../../../src/private/node/themes/themes-api/headers.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAA;AAE1D,MAAM,UAAU,UAAU,CAAC,QAAsB;IAC/C,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;IACrD,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;IAE7C,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,CAAC,CAAA;KACT;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAsB;IACjD,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,EAAE,+BAA+B,CAAC,CAAA;IAEtE,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,YAAY;SAC/B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;SAC9B,MAAM,CAAC,OAAO,CAAC,CAAA;IAElB,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE;QACnB,OAAM;KACP;IAED,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACtB,CAAC;AAED,SAAS,MAAM,CAAC,QAAsB,EAAE,IAAY;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAA;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE5B,IAAI,MAAM,EAAE,MAAM,KAAK,CAAC,EAAE;QACxB,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;KACvB;IAED,OAAO,EAAE,CAAA;AACX,CAAC","sourcesContent":["import {RestResponse} from '@shopify/cli-kit/node/api/admin'\nimport {tryParseInt} from '@shopify/cli-kit/common/string'\n\nexport function retryAfter(response: RestResponse): number {\n const retryAfterStr = header(response, 'retry-after')\n const retryAfter = tryParseInt(retryAfterStr)\n\n if (!retryAfter) {\n return 0\n }\n\n return retryAfter\n}\n\nexport function apiCallLimit(response: RestResponse): [number, number] | undefined {\n const apiCallLimit = header(response, 'x-shopify-shop-api-call-limit')\n\n const [used, limit] = apiCallLimit\n .split('/')\n .map((num) => tryParseInt(num))\n .filter(Boolean)\n\n if (!used || !limit) {\n return\n }\n\n return [used, limit]\n}\n\nfunction header(response: RestResponse, name: string): string {\n const headers = response.headers\n const header = headers[name]\n\n if (header?.length === 1) {\n return header[0] ?? ''\n }\n\n return ''\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../../../src/private/node/themes/themes-api/retry.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,KAAK,CAAI,SAAkB,EAAE,UAAkB;IACnE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QACzC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,UAAU,CAAC,CAAA;IACpD,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["export async function retry<T>(operation: () => T, retryDelay: number) {\n return new Promise<T>((resolve, _reject) => {\n setTimeout(() => resolve(operation()), retryDelay)\n })\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttler.js","sourceRoot":"","sources":["../../../../../src/private/node/themes/themes-api/throttler.ts"],"names":[],"mappings":"AAAA,MAAM,+BAA+B,GAAG,CAAC,CAAA;AACzC,MAAM,oBAAoB,GAAG,CAAC,CAAA;AAE9B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,OAAgB;IAChD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QACzC,MAAM,cAAc,GAAG,GAAG,EAAE;YAC1B,eAAe,EAAE,CAAC,cAAc,IAAI,CAAC,CAAA;YACrC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;QACpB,CAAC,CAAA;QAED;;;;;;;WAOG;QACH,MAAM,gBAAgB,GAAG,GAAG,EAAE;YAC5B,IAAI,CAAC,kBAAkB,EAAE,EAAE;gBACzB,iBAAiB,CAAC,cAAc,CAAC,CAAA;gBACjC,OAAM;aACP;YAED,UAAU,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,CAAA;QAC3D,CAAC,CAAA;QAED;;;;;;WAMG;QACH,MAAM,iBAAiB,GAAG,CAAC,OAAmB,EAAE,EAAE;YAChD,IAAI,CAAC,kBAAkB,EAAE,EAAE;gBACzB,OAAO,EAAE,CAAA;gBACT,OAAM;aACP;YAED,UAAU,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,CAAA;QAC7D,CAAC,CAAA;QAED;;WAEG;QACH,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;IACrC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACd,eAAe,EAAE,CAAC,cAAc,IAAI,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,SAAuC;IACxE,IAAI,CAAC,SAAS,EAAE;QACd,OAAM;KACP;IAED,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,SAAS,CAAA;IAE/B,iBAAiB,EAAE,CAAC,YAAY,GAAG,EAAC,IAAI,EAAE,KAAK,EAAC,CAAA;AAClD,CAAC;AAED,SAAS,kBAAkB;IACzB,OAAO,eAAe,EAAE,CAAC,cAAc,GAAG,+BAA+B,CAAA;AAC3E,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,iBAAiB,EAAE,CAAC,YAAY,CAAA;IACtD,OAAO,IAAI,IAAI,KAAK,GAAG,oBAAoB,CAAA;AAC7C,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,eAAe,EAAE,CAAC,iBAAiB,CAAA;AAC5C,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe;IACtB,OAAO,CACL,gBAAgB;QAChB,CAAC,gBAAgB,GAAG;YAClB,cAAc,EAAE,CAAC;YACjB,iBAAiB,EAAE;gBACjB,YAAY,EAAE,EAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAC;aACnC;SACF,CAAC,CACH,CAAA;AACH,CAAC;AAED,IAAI,gBAUH,CAAA","sourcesContent":["const MAX_NUMBER_OF_PARALLEL_REQUESTS = 5\nconst MARGIN_TO_RATE_LIMIT = 5\n\nexport async function throttle<T>(request: () => T) {\n return new Promise<T>((resolve, _reject) => {\n const performRequest = () => {\n throttlingState().requestCounter += 1\n resolve(request())\n }\n\n /**\n * Performs the {@link performRequest} taking into account the\n * limit of parallel requests only when the API limit has not\n * been reached.\n *\n * Otherwise, performs the request to get the updated API limit\n * headers, so throttler parameters get updates.\n */\n const throttleByHeader = () => {\n if (!isReachingApiLimit()) {\n throttleByCounter(performRequest)\n return\n }\n\n setTimeout(() => throttleByCounter(performRequest), 4000)\n }\n\n /**\n * Performs the {@link command} only when the the limit\n * of parallel request has not been reached.\n *\n * Otherwise, defers the execution to the {@link throttleByHeader},\n * still respecting the limit of parallel requests.\n */\n const throttleByCounter = (command: () => void) => {\n if (!hasTooManyRequests()) {\n command()\n return\n }\n\n setTimeout(() => throttleByCounter(throttleByHeader), 1000)\n }\n\n /**\n * Start throttling by counter to get the API limit headers.\n */\n throttleByCounter(throttleByHeader)\n }).finally(() => {\n throttlingState().requestCounter -= 1\n })\n}\n\nexport function updateApiCallLimit(callLimit: [number, number] | undefined) {\n if (!callLimit) {\n return\n }\n\n const [used, limit] = callLimit\n\n latestRequestInfo().apiCallLimit = {used, limit}\n}\n\nfunction hasTooManyRequests() {\n return throttlingState().requestCounter > MAX_NUMBER_OF_PARALLEL_REQUESTS\n}\n\nfunction isReachingApiLimit() {\n const {used, limit} = latestRequestInfo().apiCallLimit\n return used >= limit - MARGIN_TO_RATE_LIMIT\n}\n\nfunction latestRequestInfo() {\n return throttlingState().latestRequestInfo\n}\n\n/**\n * Even considering the Stateless modules convention,\n * tracking information about the latest request is\n * critical to optimize the request throttler efficiently.\n *\n * Thus, in this case, this module deliberately avoids\n * IO cost and uses the `_throttlingState` instance for\n * that purpose.\n */\nfunction throttlingState() {\n return (\n _throttlingState ??\n (_throttlingState = {\n requestCounter: 0,\n latestRequestInfo: {\n apiCallLimit: {used: 0, limit: 40},\n },\n })\n )\n}\n\nlet _throttlingState: {\n /**\n * Number of parallel requests */\n requestCounter: number\n\n /**\n * Latest request information */\n latestRequestInfo: {\n apiCallLimit: {used: number; limit: number}\n }\n}\n"]}
|
|
@@ -39,7 +39,6 @@ export interface ConcurrentOutputProps {
|
|
|
39
39
|
* 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js
|
|
40
40
|
* 2022-10-10 13:11:03 | frontend |
|
|
41
41
|
* 2022-10-10 13:11:03 | frontend |
|
|
42
|
-
* 2022-10-10 13:11:03 | backend | [nodemon] 2.0.19
|
|
43
42
|
* 2022-10-10 13:11:03 | backend |
|
|
44
43
|
* 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`
|
|
45
44
|
* 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/
|
|
@@ -30,7 +30,6 @@ import { Writable } from 'stream';
|
|
|
30
30
|
* 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js
|
|
31
31
|
* 2022-10-10 13:11:03 | frontend |
|
|
32
32
|
* 2022-10-10 13:11:03 | frontend |
|
|
33
|
-
* 2022-10-10 13:11:03 | backend | [nodemon] 2.0.19
|
|
34
33
|
* 2022-10-10 13:11:03 | backend |
|
|
35
34
|
* 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`
|
|
36
35
|
* 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAA;AAE1D,OAAO,kBAAkB,MAAM,mCAAmC,CAAA;AAElE,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,EAAoB,WAAW,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACrE,OAAO,EAAC,GAAG,EAAO,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAC,MAAM,KAAK,CAAA;AACpD,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,QAAQ,CAAA;AAoB/B
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TextWithBackground} from './TextWithBackground.js'\nimport {OutputProcess} from '../../../../public/node/output.js'\nimport useAsyncAndUnmount from '../hooks/use-async-and-unmount.js'\nimport {AbortController} from '../../../../public/node/abort.js'\nimport {handleCtrlC} from '../../ui.js'\nimport React, {FunctionComponent, useCallback, useState} from 'react'\nimport {Box, Key, Static, Text, useInput} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport treeKill from 'tree-kill'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n abortController: AbortController\n showTimestamps?: boolean\n onInput?: (input: string, key: Key, exit: () => void) => void\n footer?: {\n title: string\n subTitle?: string\n }\n}\ninterface Chunk {\n color: string\n prefix: string\n lines: string[]\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n abortController,\n showTimestamps = true,\n onInput,\n footer,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const concurrentColors = ['yellow', 'cyan', 'magenta', 'green', 'blue']\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n\n function lineColor(index: number) {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n }\n\n const writableStream = (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('ascii').replace(/(\\n)$/, '')).split(/\\n/)\n\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix: process.prefix,\n lines,\n },\n ])\n\n next()\n },\n })\n }\n\n const runProcesses = () => {\n return Promise.all(\n processes.map(async (process, index) => {\n const stdout = writableStream(process, index)\n const stderr = writableStream(process, index)\n\n await process.action(stdout, stderr, abortController.signal)\n }),\n )\n }\n\n if (onInput) {\n useInput(\n useCallback(\n (input, key) => {\n handleCtrlC(input, key)\n onInput(input, key, () => treeKill(process.pid, 'SIGINT'))\n },\n [onInput],\n ),\n )\n }\n\n useAsyncAndUnmount(runProcesses, {onRejected: () => abortController.abort()})\n\n return (\n <>\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n {showTimestamps ? (\n <Box>\n <Box marginRight={1}>\n <Text color={chunk.color}>\n {new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '')}\n </Text>\n </Box>\n\n <Text bold color={chunk.color}>\n |\n </Text>\n </Box>\n ) : null}\n\n <Box width={prefixColumnSize} marginX={1}>\n <Text color={chunk.color}>{chunk.prefix}</Text>\n </Box>\n\n <Text bold color={chunk.color}>\n |\n </Text>\n\n <Box flexGrow={1} paddingLeft={1}>\n <Text color={chunk.color}>{line}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n {footer ? (\n <Box marginY={1} flexDirection=\"column\">\n <Box flexGrow={1}>\n <TextWithBackground text={footer.title} inverse paddingX={2} paddingY={1} />\n </Box>\n {footer.subTitle ? (\n <Box marginTop={1} flexGrow={1}>\n <Text>{footer.subTitle}</Text>\n </Box>\n ) : null}\n </Box>\n ) : null}\n </>\n )\n}\n\nexport {ConcurrentOutput}\n"]}
|
|
@@ -55,17 +55,29 @@ export declare function slugify(str: string): string;
|
|
|
55
55
|
export declare function escapeRegExp(str: string): string;
|
|
56
56
|
/**
|
|
57
57
|
* Transform a string to camelCase.
|
|
58
|
+
*
|
|
59
|
+
* @param input - String to escape.
|
|
60
|
+
* @returns The escaped string.
|
|
58
61
|
*/
|
|
59
|
-
export
|
|
62
|
+
export declare function camelize(input: string): string;
|
|
60
63
|
/**
|
|
61
64
|
* Transform a string to param-case.
|
|
65
|
+
*
|
|
66
|
+
* @param input - String to transform.
|
|
67
|
+
* @returns The transformed string.
|
|
62
68
|
*/
|
|
63
|
-
export
|
|
69
|
+
export declare function hyphenate(input: string): string;
|
|
64
70
|
/**
|
|
65
71
|
* Transform a string to snake_case.
|
|
72
|
+
*
|
|
73
|
+
* @param input - String to transform.
|
|
74
|
+
* @returns The transformed string.
|
|
66
75
|
*/
|
|
67
|
-
export
|
|
76
|
+
export declare function underscore(input: string): string;
|
|
68
77
|
/**
|
|
69
78
|
* Transform a string to CONSTANT_CASE.
|
|
79
|
+
*
|
|
80
|
+
* @param input - String to transform.
|
|
81
|
+
* @returns The transformed string.
|
|
70
82
|
*/
|
|
71
|
-
export
|
|
83
|
+
export declare function constantize(input: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { takeRandomFromArray } from './array.js';
|
|
2
2
|
import { unstyled } from '../../public/node/output.js';
|
|
3
|
+
import { camelCase, constantCase, paramCase, snakeCase } from 'change-case';
|
|
3
4
|
const SAFE_RANDOM_BUSINESS_ADJECTIVES = [
|
|
4
5
|
'commercial',
|
|
5
6
|
'profitable',
|
|
@@ -205,18 +206,38 @@ export function escapeRegExp(str) {
|
|
|
205
206
|
}
|
|
206
207
|
/**
|
|
207
208
|
* Transform a string to camelCase.
|
|
209
|
+
*
|
|
210
|
+
* @param input - String to escape.
|
|
211
|
+
* @returns The escaped string.
|
|
208
212
|
*/
|
|
209
|
-
export
|
|
213
|
+
export function camelize(input) {
|
|
214
|
+
return camelCase(input);
|
|
215
|
+
}
|
|
210
216
|
/**
|
|
211
217
|
* Transform a string to param-case.
|
|
218
|
+
*
|
|
219
|
+
* @param input - String to transform.
|
|
220
|
+
* @returns The transformed string.
|
|
212
221
|
*/
|
|
213
|
-
export
|
|
222
|
+
export function hyphenate(input) {
|
|
223
|
+
return paramCase(input);
|
|
224
|
+
}
|
|
214
225
|
/**
|
|
215
226
|
* Transform a string to snake_case.
|
|
227
|
+
*
|
|
228
|
+
* @param input - String to transform.
|
|
229
|
+
* @returns The transformed string.
|
|
216
230
|
*/
|
|
217
|
-
export
|
|
231
|
+
export function underscore(input) {
|
|
232
|
+
return snakeCase(input);
|
|
233
|
+
}
|
|
218
234
|
/**
|
|
219
235
|
* Transform a string to CONSTANT_CASE.
|
|
236
|
+
*
|
|
237
|
+
* @param input - String to transform.
|
|
238
|
+
* @returns The transformed string.
|
|
220
239
|
*/
|
|
221
|
-
export
|
|
240
|
+
export function constantize(input) {
|
|
241
|
+
return constantCase(input);
|
|
242
|
+
}
|
|
222
243
|
//# sourceMappingURL=string.js.map
|