@shopify/cli-kit 3.91.1 → 3.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/private/node/analytics/bounded-collections.d.ts +1 -3
- package/dist/private/node/analytics/bounded-collections.js.map +1 -1
- package/dist/private/node/analytics/error-categorizer.js.map +1 -1
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/api/graphql.d.ts +1 -3
- package/dist/private/node/api/graphql.js.map +1 -1
- package/dist/private/node/api/headers.d.ts +2 -6
- package/dist/private/node/api/headers.js +0 -1
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/api/rest.d.ts +2 -6
- package/dist/private/node/api/rest.js.map +1 -1
- package/dist/private/node/api.js.map +1 -1
- package/dist/private/node/conf-store.d.ts +6 -6
- package/dist/private/node/conf-store.js +13 -6
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/private/node/session/device-authorization.js.map +1 -1
- package/dist/private/node/session/exchange.d.ts +1 -19
- package/dist/private/node/session/exchange.js +13 -30
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/session/schema.d.ts +62 -62
- package/dist/private/node/session/store.js +1 -1
- package/dist/private/node/session/store.js.map +1 -1
- package/dist/private/node/session/validate.d.ts +4 -5
- package/dist/private/node/session/validate.js +7 -35
- package/dist/private/node/session/validate.js.map +1 -1
- package/dist/private/node/session.js +18 -65
- package/dist/private/node/session.js.map +1 -1
- package/dist/private/node/testing/ui.d.ts +2 -1
- package/dist/private/node/testing/ui.js +22 -24
- package/dist/private/node/testing/ui.js.map +1 -1
- package/dist/private/node/themes/generate-theme-name.js +0 -1
- package/dist/private/node/themes/generate-theme-name.js.map +1 -1
- package/dist/private/node/ui/alert.js.map +1 -1
- package/dist/private/node/ui/components/Alert.test.js +2 -4
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +6 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.test.js +2 -3
- package/dist/private/node/ui/components/AutocompletePrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/Banner.js +0 -1
- package/dist/private/node/ui/components/Banner.js.map +1 -1
- package/dist/private/node/ui/components/Banner.test.js +2 -2
- package/dist/private/node/ui/components/Banner.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js +4 -2
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +9 -3
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
- package/dist/private/node/ui/components/DangerousConfirmationPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.js +0 -1
- package/dist/private/node/ui/components/FatalError.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.test.js.map +1 -1
- package/dist/private/node/ui/components/List.test.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.js.map +1 -1
- package/dist/private/node/ui/components/LoadingBar.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -3
- package/dist/private/node/ui/components/Prompts/InfoTable.js +0 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/InfoTable.test.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.js +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js +1 -1
- package/dist/private/node/ui/components/Prompts/PromptLayout.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.d.ts +4 -5
- package/dist/private/node/ui/components/SelectInput.js +5 -7
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.js +0 -1
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js +0 -1
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.js.map +1 -1
- package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
- package/dist/private/node/ui/components/Table/ScalarDict.d.ts +2 -4
- package/dist/private/node/ui/components/Table/ScalarDict.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.js +0 -1
- package/dist/private/node/ui/components/Table/Table.js.map +1 -1
- package/dist/private/node/ui/components/Table/Table.test.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.js +0 -2
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +2 -6
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.test.js +1 -1
- package/dist/private/node/ui/components/TextAnimation.test.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.js +19 -19
- package/dist/private/node/ui/components/TextInput.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.js +1 -1
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextPrompt.test.js +0 -1
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.js +1 -2
- package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/private/node/ui/contexts/LinksContext.d.ts +1 -3
- package/dist/private/node/ui/contexts/LinksContext.js.map +1 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js +9 -1
- package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
- package/dist/private/node/ui.js +8 -1
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/array.js +0 -1
- package/dist/public/common/array.js.map +1 -1
- package/dist/public/common/collection.d.ts +1 -3
- package/dist/public/common/collection.js.map +1 -1
- package/dist/public/common/string.js +1 -4
- package/dist/public/common/string.js.map +1 -1
- package/dist/public/common/ts/json-narrowing.d.ts +1 -3
- package/dist/public/common/ts/json-narrowing.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/analytics.js +1 -1
- package/dist/public/node/analytics.js.map +1 -1
- package/dist/public/node/api/admin.d.ts +2 -6
- package/dist/public/node/api/admin.js +1 -2
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/app-dev.d.ts +1 -1
- package/dist/public/node/api/app-dev.js +1 -1
- package/dist/public/node/api/app-dev.js.map +1 -1
- package/dist/public/node/api/app-management.d.ts +1 -3
- package/dist/public/node/api/app-management.js +1 -1
- package/dist/public/node/api/app-management.js.map +1 -1
- package/dist/public/node/api/business-platform.js.map +1 -1
- package/dist/public/node/api/functions.js +1 -1
- package/dist/public/node/api/functions.js.map +1 -1
- package/dist/public/node/api/graphql.d.ts +4 -12
- package/dist/public/node/api/graphql.js.map +1 -1
- package/dist/public/node/api/partners.js +1 -1
- package/dist/public/node/api/partners.js.map +1 -1
- package/dist/public/node/api/rest-api-throttler.js +0 -1
- package/dist/public/node/api/rest-api-throttler.js.map +1 -1
- package/dist/public/node/archiver.js +2 -2
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/base-command.js +0 -2
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.js.map +1 -1
- package/dist/public/node/context/local.js.map +1 -1
- package/dist/public/node/custom-oclif-loader.js +0 -1
- package/dist/public/node/custom-oclif-loader.js.map +1 -1
- package/dist/public/node/doctor/framework.d.ts +14 -9
- package/dist/public/node/doctor/framework.js +10 -3
- package/dist/public/node/doctor/framework.js.map +1 -1
- package/dist/public/node/doctor/reporter.d.ts +23 -0
- package/dist/public/node/doctor/reporter.js +33 -1
- package/dist/public/node/doctor/reporter.js.map +1 -1
- package/dist/public/node/dot-env.d.ts +2 -6
- package/dist/public/node/dot-env.js +1 -2
- package/dist/public/node/dot-env.js.map +1 -1
- package/dist/public/node/environments.d.ts +1 -3
- package/dist/public/node/environments.js.map +1 -1
- package/dist/public/node/error-handler.js +3 -3
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/error.d.ts +1 -1
- package/dist/public/node/error.js +2 -2
- package/dist/public/node/error.js.map +1 -1
- package/dist/public/node/framework.js +0 -1
- package/dist/public/node/framework.js.map +1 -1
- package/dist/public/node/fs.d.ts +1 -1
- package/dist/public/node/fs.js +1 -1
- package/dist/public/node/fs.js.map +1 -1
- package/dist/public/node/git.d.ts +1 -3
- package/dist/public/node/git.js +1 -3
- package/dist/public/node/git.js.map +1 -1
- package/dist/public/node/github.js +14 -8
- package/dist/public/node/github.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +2 -2
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/hooks/prerun.js +2 -2
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/http.js +2 -3
- package/dist/public/node/http.js.map +1 -1
- package/dist/public/node/json-schema.d.ts +1 -3
- package/dist/public/node/json-schema.js +0 -1
- package/dist/public/node/json-schema.js.map +1 -1
- package/dist/public/node/liquid.js +1 -1
- package/dist/public/node/liquid.js.map +1 -1
- package/dist/public/node/local-storage.d.ts +1 -3
- package/dist/public/node/local-storage.js.map +1 -1
- package/dist/public/node/metadata.d.ts +1 -3
- package/dist/public/node/metadata.js +0 -1
- package/dist/public/node/metadata.js.map +1 -1
- package/dist/public/node/mimes.d.ts +1 -3
- package/dist/public/node/mimes.js.map +1 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/multiple-installation-warning.d.ts +1 -3
- package/dist/public/node/multiple-installation-warning.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +9 -27
- 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/os.js +1 -1
- package/dist/public/node/os.js.map +1 -1
- package/dist/public/node/output.d.ts +1 -3
- package/dist/public/node/output.js +1 -2
- package/dist/public/node/output.js.map +1 -1
- package/dist/public/node/path.d.ts +13 -0
- package/dist/public/node/path.js +10 -1
- package/dist/public/node/path.js.map +1 -1
- package/dist/public/node/plugins/tunnel.d.ts +5 -11
- package/dist/public/node/plugins/tunnel.js.map +1 -1
- package/dist/public/node/plugins.d.ts +4 -12
- package/dist/public/node/plugins.js.map +1 -1
- package/dist/public/node/result.js +1 -1
- package/dist/public/node/result.js.map +1 -1
- package/dist/public/node/session.js +15 -7
- package/dist/public/node/session.js.map +1 -1
- package/dist/public/node/system.d.ts +1 -3
- package/dist/public/node/system.js +1 -1
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tcp.js +1 -1
- package/dist/public/node/tcp.js.map +1 -1
- package/dist/public/node/testing/output.js +1 -1
- package/dist/public/node/testing/output.js.map +1 -1
- package/dist/public/node/themes/api.js +2 -2
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/public/node/themes/conf.d.ts +1 -3
- package/dist/public/node/themes/conf.js.map +1 -1
- package/dist/public/node/tree-kill.js +0 -1
- package/dist/public/node/tree-kill.js.map +1 -1
- package/dist/public/node/ui.js +0 -12
- package/dist/public/node/ui.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2016.d.ts +8 -0
- package/dist/public/node/vendor/dev_server/dev-server-2016.js +10 -2
- package/dist/public/node/vendor/dev_server/dev-server-2016.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server-2024.d.ts +8 -0
- package/dist/public/node/vendor/dev_server/dev-server-2024.js +10 -2
- package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
- package/dist/public/node/vendor/dev_server/dev-server.js +1 -1
- package/dist/public/node/vendor/dev_server/dev-server.js.map +1 -1
- package/dist/public/node/vendor/dev_server/env.d.ts +3 -0
- package/dist/public/node/vendor/dev_server/env.js +3 -0
- package/dist/public/node/vendor/dev_server/env.js.map +1 -1
- package/dist/public/node/vendor/dev_server/network/host.d.ts +7 -0
- package/dist/public/node/vendor/dev_server/network/host.js +7 -1
- package/dist/public/node/vendor/dev_server/network/host.js.map +1 -1
- package/dist/public/node/vendor/dev_server/network/index.d.ts +7 -0
- package/dist/public/node/vendor/dev_server/network/index.js +7 -2
- package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.d.ts +1 -1
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js +2 -4
- package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.d.ts +7 -0
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js +9 -1
- package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.d.ts +12 -1
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js +11 -0
- package/dist/public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js.map +1 -1
- package/dist/public/node/vendor/otel-js/service/types.d.ts +6 -10
- package/dist/public/node/vendor/otel-js/service/types.js.map +1 -1
- package/dist/public/node/vendor/otel-js/utils/throttle.d.ts +10 -2
- package/dist/public/node/vendor/otel-js/utils/throttle.js +9 -0
- package/dist/public/node/vendor/otel-js/utils/throttle.js.map +1 -1
- package/dist/public/node/vendor/otel-js/utils/validators.d.ts +4 -0
- package/dist/public/node/vendor/otel-js/utils/validators.js +4 -0
- package/dist/public/node/vendor/otel-js/utils/validators.js.map +1 -1
- package/dist/public/node/version.js +1 -1
- package/dist/public/node/version.js.map +1 -1
- package/dist/public/node/vscode.js +1 -1
- package/dist/public/node/vscode.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
-
import { applicationId } from './identity.js';
|
|
3
1
|
import { validateCachedIdentityTokenStructure } from './schema.js';
|
|
4
2
|
import { sessionConstants } from '../constants.js';
|
|
5
3
|
import { firstPartyDev } from '../../../public/node/context/local.js';
|
|
@@ -14,53 +12,27 @@ function validateScopes(requestedScopes, identity) {
|
|
|
14
12
|
return requestedScopes.every((scope) => currentScopes.includes(scope));
|
|
15
13
|
}
|
|
16
14
|
/**
|
|
17
|
-
* Validate if the current session is valid or we need to refresh/re-authenticate
|
|
15
|
+
* Validate if the current session is valid or we need to refresh/re-authenticate.
|
|
16
|
+
* With PCAT, only the identity token needs validation - no per-application tokens.
|
|
18
17
|
* @param scopes - requested scopes to validate
|
|
19
|
-
* @param
|
|
20
|
-
* @param session - current session with identity and application tokens
|
|
18
|
+
* @param session - current session with identity token
|
|
21
19
|
* @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session
|
|
22
20
|
*/
|
|
23
|
-
export async function validateSession(scopes,
|
|
21
|
+
export async function validateSession(scopes, session) {
|
|
24
22
|
if (!session)
|
|
25
23
|
return 'needs_full_auth';
|
|
26
24
|
const scopesAreValid = validateScopes(scopes, session.identity);
|
|
27
25
|
if (!scopesAreValid)
|
|
28
26
|
return 'needs_full_auth';
|
|
29
|
-
let tokensAreExpired = isTokenExpired(session.identity);
|
|
30
|
-
if (applications.partnersApi) {
|
|
31
|
-
const appId = applicationId('partners');
|
|
32
|
-
const token = session.applications[appId];
|
|
33
|
-
tokensAreExpired = tokensAreExpired || isTokenExpired(token);
|
|
34
|
-
}
|
|
35
|
-
if (applications.appManagementApi) {
|
|
36
|
-
const appId = applicationId('app-management');
|
|
37
|
-
const token = session.applications[appId];
|
|
38
|
-
tokensAreExpired = tokensAreExpired || isTokenExpired(token);
|
|
39
|
-
}
|
|
40
|
-
if (applications.storefrontRendererApi) {
|
|
41
|
-
const appId = applicationId('storefront-renderer');
|
|
42
|
-
const token = session.applications[appId];
|
|
43
|
-
tokensAreExpired = tokensAreExpired || isTokenExpired(token);
|
|
44
|
-
}
|
|
45
|
-
if (applications.adminApi) {
|
|
46
|
-
const appId = applicationId('admin');
|
|
47
|
-
const realAppId = `${applications.adminApi.storeFqdn}-${appId}`;
|
|
48
|
-
const token = session.applications[realAppId];
|
|
49
|
-
tokensAreExpired = tokensAreExpired || isTokenExpired(token);
|
|
50
|
-
}
|
|
51
|
-
outputDebug(`- Token validation -> It's expired: ${tokensAreExpired}`);
|
|
52
27
|
if (!validateCachedIdentityTokenStructure(session.identity)) {
|
|
53
28
|
return 'needs_full_auth';
|
|
54
29
|
}
|
|
55
|
-
|
|
30
|
+
const expired = session.identity.expiresAt < expireThreshold();
|
|
31
|
+
outputDebug(`- Token validation -> It's expired: ${expired}`);
|
|
32
|
+
if (expired)
|
|
56
33
|
return 'needs_refresh';
|
|
57
34
|
return 'ok';
|
|
58
35
|
}
|
|
59
|
-
function isTokenExpired(token) {
|
|
60
|
-
if (!token)
|
|
61
|
-
return true;
|
|
62
|
-
return token.expiresAt < expireThreshold();
|
|
63
|
-
}
|
|
64
36
|
function expireThreshold() {
|
|
65
37
|
return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000);
|
|
66
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,oCAAoC,EAAC,MAAM,aAAa,CAAA;AAExF,OAAO,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAC,aAAa,EAAC,MAAM,uCAAuC,CAAA;AACnE,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAA;AAI1D;;GAEG;AACH,SAAS,cAAc,CAAC,eAAyB,EAAE,QAAuB;IACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAA;IACrC,IAAI,aAAa,EAAE,KAAK,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAA;IACxE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAgB,EAAE,OAA4B;IAClF,IAAI,CAAC,OAAO;QAAE,OAAO,iBAAiB,CAAA;IACtC,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC/D,IAAI,CAAC,cAAc;QAAE,OAAO,iBAAiB,CAAA;IAE7C,IAAI,CAAC,oCAAoC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5D,OAAO,iBAAiB,CAAA;IAC1B,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,GAAG,eAAe,EAAE,CAAA;IAC9D,WAAW,CAAC,uCAAuC,OAAO,EAAE,CAAC,CAAA;IAE7D,IAAI,OAAO;QAAE,OAAO,eAAe,CAAA;IAEnC,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC,6BAA6B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;AAC1F,CAAC","sourcesContent":["import {IdentityToken, Session, validateCachedIdentityTokenStructure} from './schema.js'\n\nimport {sessionConstants} from '../constants.js'\nimport {firstPartyDev} from '../../../public/node/context/local.js'\nimport {outputDebug} from '../../../public/node/output.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate.\n * With PCAT, only the identity token needs validation - no per-application tokens.\n * @param scopes - requested scopes to validate\n * @param session - current session with identity token\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(scopes: string[], session: Session | undefined): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n if (!scopesAreValid) return 'needs_full_auth'\n\n if (!validateCachedIdentityTokenStructure(session.identity)) {\n return 'needs_full_auth'\n }\n\n const expired = session.identity.expiresAt < expireThreshold()\n outputDebug(`- Token validation -> It's expired: ${expired}`)\n\n if (expired) return 'needs_refresh'\n\n return 'ok'\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { applicationId } from './session/identity.js';
|
|
2
1
|
import { validateSession } from './session/validate.js';
|
|
3
|
-
import { allDefaultScopes
|
|
4
|
-
import {
|
|
2
|
+
import { allDefaultScopes } from './session/scopes.js';
|
|
3
|
+
import { exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError, InvalidRequestError, } from './session/exchange.js';
|
|
5
4
|
import * as sessionStore from './session/store.js';
|
|
6
5
|
import { pollForDeviceAuthorization, requestDeviceAuthorization } from './session/device-authorization.js';
|
|
7
6
|
import { isThemeAccessSession } from './api/rest.js';
|
|
@@ -120,7 +119,7 @@ ${outputToken.json(scopes)}
|
|
|
120
119
|
For applications:
|
|
121
120
|
${outputToken.json(applications)}
|
|
122
121
|
`);
|
|
123
|
-
const validationResult = await validateSession(scopes,
|
|
122
|
+
const validationResult = await validateSession(scopes, currentSession);
|
|
124
123
|
let newSession = {};
|
|
125
124
|
if (validationResult === 'needs_full_auth') {
|
|
126
125
|
await throwOnNoPrompt(noPrompt);
|
|
@@ -130,7 +129,6 @@ ${outputToken.json(applications)}
|
|
|
130
129
|
else if (validationResult === 'needs_refresh' || forceRefresh) {
|
|
131
130
|
outputDebug(outputContent `The current session is valid but needs refresh. Refreshing...`);
|
|
132
131
|
try {
|
|
133
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
134
132
|
newSession = await refreshTokens(currentSession, applications);
|
|
135
133
|
}
|
|
136
134
|
catch (error) {
|
|
@@ -184,8 +182,6 @@ The CLI is currently unable to prompt for reauthentication.`, 'Restart the CLI p
|
|
|
184
182
|
*/
|
|
185
183
|
async function executeCompleteFlow(applications) {
|
|
186
184
|
const scopes = getFlattenScopes(applications);
|
|
187
|
-
const exchangeScopes = getExchangeScopes(applications);
|
|
188
|
-
const store = applications.adminApi?.storeFqdn;
|
|
189
185
|
if (firstPartyDev()) {
|
|
190
186
|
outputDebug(outputContent `Authenticating as Shopify Employee...`);
|
|
191
187
|
scopes.push('employee');
|
|
@@ -203,18 +199,16 @@ async function executeCompleteFlow(applications) {
|
|
|
203
199
|
outputDebug(outputContent `Starting polling for the identity token...`);
|
|
204
200
|
identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval);
|
|
205
201
|
}
|
|
206
|
-
|
|
207
|
-
outputDebug(outputContent `CLI token received. Exchanging it for application tokens...`);
|
|
208
|
-
const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store);
|
|
202
|
+
outputDebug(outputContent `CLI token received (PCAT). Using it directly for API access...`);
|
|
209
203
|
// Get the alias for the session (email or userId)
|
|
210
|
-
|
|
211
|
-
const alias = (await fetchEmail(
|
|
204
|
+
// Use the PCAT identity token directly to fetch the email
|
|
205
|
+
const alias = (await fetchEmail(identityToken.accessToken)) ?? identityToken.userId;
|
|
212
206
|
const session = {
|
|
213
207
|
identity: {
|
|
214
208
|
...identityToken,
|
|
215
209
|
alias,
|
|
216
210
|
},
|
|
217
|
-
applications:
|
|
211
|
+
applications: {},
|
|
218
212
|
};
|
|
219
213
|
outputCompleted(`Logged in.`);
|
|
220
214
|
return session;
|
|
@@ -224,53 +218,32 @@ async function executeCompleteFlow(applications) {
|
|
|
224
218
|
*
|
|
225
219
|
* @param session - The session to refresh.
|
|
226
220
|
*/
|
|
227
|
-
async function refreshTokens(session,
|
|
228
|
-
// Refresh Identity Token
|
|
221
|
+
async function refreshTokens(session, _applications) {
|
|
222
|
+
// Refresh Identity Token (PCAT) - no exchange needed
|
|
229
223
|
const identityToken = await refreshAccessToken(session.identity);
|
|
230
|
-
// Exchange new identity token for application tokens
|
|
231
|
-
const exchangeScopes = getExchangeScopes(applications);
|
|
232
|
-
const applicationTokens = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, applications.adminApi?.storeFqdn);
|
|
233
224
|
return {
|
|
234
225
|
identity: identityToken,
|
|
235
|
-
applications:
|
|
226
|
+
applications: {},
|
|
236
227
|
};
|
|
237
228
|
}
|
|
238
229
|
/**
|
|
239
230
|
* Get the application tokens for a given session.
|
|
231
|
+
* With PCAT, the identity token can be used directly for all APIs.
|
|
240
232
|
*
|
|
241
233
|
* @param applications - An object containing the applications we need the tokens for.
|
|
242
234
|
* @param session - The current session.
|
|
243
235
|
* @param fqdn - The identity FQDN.
|
|
244
236
|
*/
|
|
245
237
|
async function tokensFor(applications, session) {
|
|
246
|
-
const
|
|
238
|
+
const token = session.identity.accessToken;
|
|
239
|
+
return {
|
|
247
240
|
userId: session.identity.userId,
|
|
241
|
+
admin: applications.adminApi ? { token, storeFqdn: applications.adminApi.storeFqdn } : undefined,
|
|
242
|
+
partners: applications.partnersApi ? token : undefined,
|
|
243
|
+
storefront: applications.storefrontRendererApi ? token : undefined,
|
|
244
|
+
businessPlatform: applications.businessPlatformApi ? token : undefined,
|
|
245
|
+
appManagement: applications.appManagementApi ? token : undefined,
|
|
248
246
|
};
|
|
249
|
-
if (applications.adminApi) {
|
|
250
|
-
const appId = applicationId('admin');
|
|
251
|
-
const realAppId = `${applications.adminApi.storeFqdn}-${appId}`;
|
|
252
|
-
const token = session.applications[realAppId]?.accessToken;
|
|
253
|
-
if (token) {
|
|
254
|
-
tokens.admin = { token, storeFqdn: applications.adminApi.storeFqdn };
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (applications.partnersApi) {
|
|
258
|
-
const appId = applicationId('partners');
|
|
259
|
-
tokens.partners = session.applications[appId]?.accessToken;
|
|
260
|
-
}
|
|
261
|
-
if (applications.storefrontRendererApi) {
|
|
262
|
-
const appId = applicationId('storefront-renderer');
|
|
263
|
-
tokens.storefront = session.applications[appId]?.accessToken;
|
|
264
|
-
}
|
|
265
|
-
if (applications.businessPlatformApi) {
|
|
266
|
-
const appId = applicationId('business-platform');
|
|
267
|
-
tokens.businessPlatform = session.applications[appId]?.accessToken;
|
|
268
|
-
}
|
|
269
|
-
if (applications.appManagementApi) {
|
|
270
|
-
const appId = applicationId('app-management');
|
|
271
|
-
tokens.appManagement = session.applications[appId]?.accessToken;
|
|
272
|
-
}
|
|
273
|
-
return tokens;
|
|
274
247
|
}
|
|
275
248
|
// Scope Helpers
|
|
276
249
|
/**
|
|
@@ -288,26 +261,6 @@ function getFlattenScopes(apps) {
|
|
|
288
261
|
const requestedScopes = [...admin, ...partner, ...storefront, ...businessPlatform, ...appManagement];
|
|
289
262
|
return allDefaultScopes(requestedScopes);
|
|
290
263
|
}
|
|
291
|
-
/**
|
|
292
|
-
* Get the scopes for the given applications.
|
|
293
|
-
*
|
|
294
|
-
* @param apps - An object containing the applications we need the scopes for.
|
|
295
|
-
* @returns An object containing the scopes for each application.
|
|
296
|
-
*/
|
|
297
|
-
function getExchangeScopes(apps) {
|
|
298
|
-
const adminScope = apps.adminApi?.scopes ?? [];
|
|
299
|
-
const partnerScope = apps.partnersApi?.scopes ?? [];
|
|
300
|
-
const storefrontScopes = apps.storefrontRendererApi?.scopes ?? [];
|
|
301
|
-
const businessPlatformScopes = apps.businessPlatformApi?.scopes ?? [];
|
|
302
|
-
const appManagementScopes = apps.appManagementApi?.scopes ?? [];
|
|
303
|
-
return {
|
|
304
|
-
admin: apiScopes('admin', adminScope),
|
|
305
|
-
partners: apiScopes('partners', partnerScope),
|
|
306
|
-
storefront: apiScopes('storefront-renderer', storefrontScopes),
|
|
307
|
-
businessPlatform: apiScopes('business-platform', businessPlatformScopes),
|
|
308
|
-
appManagement: apiScopes('app-management', appManagementScopes),
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
264
|
function buildIdentityTokenFromEnv(scopes, identityTokenInformation) {
|
|
312
265
|
return {
|
|
313
266
|
...identityTokenInformation,
|
|
@@ -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 exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\nimport {IdentityToken, Session, Sessions} from './session/schema.js'\nimport * as sessionStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {isThemeAccessSession} from './api/rest.js'\nimport {getCurrentSessionId, setCurrentSessionId} from './conf-store.js'\nimport {UserEmailQueryString, UserEmailQuery} from './api/graphql/business-platform-destinations/user-email.js'\nimport {outputContent, outputToken, outputDebug, outputCompleted} from '../../public/node/output.js'\nimport {firstPartyDev, themeToken} from '../../public/node/context/local.js'\nimport {AbortError} from '../../public/node/error.js'\nimport {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {getIdentityTokenInformation, getPartnersToken} from '../../public/node/environment.js'\nimport {AdminSession, logout} from '../../public/node/session.js'\nimport {nonRandomUUID} from '../../public/node/crypto.js'\nimport {isEmpty} from '../../public/common/object.js'\nimport {businessPlatformRequest} from '../../public/node/api/business-platform.js'\n\n/**\n * Fetches the user's email from the Business Platform API\n * @param businessPlatformToken - The business platform token\n * @returns The user's email address or undefined if not found\n */\nasync function fetchEmail(businessPlatformToken: string | undefined): Promise<string | undefined> {\n if (!businessPlatformToken) return undefined\n\n try {\n const userEmailResult = await businessPlatformRequest<UserEmailQuery>(UserEmailQueryString, businessPlatformToken)\n return userEmailResult.currentUserAccount?.email\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(outputContent`Failed to fetch user email: ${(error as Error).message ?? String(error)}`)\n return undefined\n }\n}\n\n/**\n * A scope supported by the Shopify Admin API.\n */\nexport type AdminAPIScope = 'graphql' | 'themes' | 'collaborator'\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 */\nexport type PartnersAPIScope = 'cli'\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Developer Platform API.\n */\nexport type AppManagementAPIScope = 'https://api.shopify.com/auth/organization.apps.manage'\ninterface AppManagementAPIOauthOptions {\n /** List of scopes to request permissions for. */\n scopes: AppManagementAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\nexport type StorefrontRendererScope = 'devtools'\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\nexport type BusinessPlatformScope = 'destinations'\ninterface BusinessPlatformAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: BusinessPlatformScope[]\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 businessPlatformApi?: BusinessPlatformAPIOAuthOptions\n appManagementApi?: AppManagementAPIOauthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n businessPlatform?: string\n appManagement?: string\n userId: string\n}\n\ntype AuthMethod = 'partners_token' | 'device_auth' | 'theme_access_token' | 'custom_app_token' | 'none'\n\nlet userId: undefined | string\nlet authMethod: AuthMethod = 'none'\n\n/**\n * Retrieves the user ID from the current session or returns 'unknown' if not found.\n *\n * This function performs the following steps:\n * 1. Checks for a cached user ID in memory (obtained in the current run).\n * 2. Attempts to fetch it from the local storage (from a previous auth session).\n * 3. Checks if a custom token was used (either as a theme password or partners token).\n * 4. If a custom token is present in the environment, generates a UUID and uses it as userId.\n * 5. If after all this we don't have a userId, then reports as 'unknown'.\n *\n * @returns A Promise that resolves to the user ID as a string.\n */\nexport async function getLastSeenUserIdAfterAuth(): Promise<string> {\n if (userId) return userId\n\n const currentSessionId = getCurrentSessionId()\n if (currentSessionId) return currentSessionId\n\n const customToken = getPartnersToken() ?? themeToken()\n return customToken ? nonRandomUUID(customToken) : 'unknown'\n}\n\nexport function setLastSeenUserIdAfterAuth(id: string) {\n userId = id\n}\n\n/**\n * Retrieves the last seen authentication method used in the current session.\n *\n * This function checks for the authentication method in the following order:\n * 1. Returns the cached auth method if it's not 'none'.\n * 2. Checks for a cached session, which implies 'device_auth' was used.\n * 3. Checks for a partners token in the environment.\n * 4. Checks for a theme password in the environment.\n * 5. If none of the above are true, returns 'none'.\n *\n * @returns A Promise that resolves to the last seen authentication method as an AuthMethod type.\n */\nexport async function getLastSeenAuthMethod(): Promise<AuthMethod> {\n if (authMethod !== 'none') return authMethod\n\n if (getCurrentSessionId()) return 'device_auth'\n\n const partnersToken = getPartnersToken()\n if (partnersToken) return 'partners_token'\n\n const themePassword = themeToken()\n if (themePassword) {\n return isThemeAccessSession({token: themePassword, storeFqdn: ''}) ? 'theme_access_token' : 'custom_app_token'\n }\n\n return 'none'\n}\n\nexport function setLastSeenAuthMethod(method: AuthMethod) {\n authMethod = method\n}\n\nexport interface EnsureAuthenticatedAdditionalOptions {\n noPrompt?: boolean\n forceRefresh?: boolean\n forceNewSession?: boolean\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 options - Optional extra options to use.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n _env?: NodeJS.ProcessEnv,\n {forceRefresh = false, noPrompt = false, forceNewSession = false}: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const sessions = (await sessionStore.fetch()) ?? {}\n\n let currentSessionId = getCurrentSessionId()\n if (!currentSessionId) {\n const userIds = Object.keys(sessions[fqdn] ?? {})\n if (userIds.length > 0) currentSessionId = userIds[0]\n }\n const currentSession: Session | undefined =\n currentSessionId && !forceNewSession ? sessions[fqdn]?.[currentSessionId] : undefined\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\n const validationResult = await validateSession(scopes, applications, currentSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n await throwOnNoPrompt(noPrompt)\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n outputDebug(outputContent`The current session is valid but needs refresh. Refreshing...`)\n try {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n newSession = await refreshTokens(currentSession!, applications)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n await throwOnNoPrompt(noPrompt)\n newSession = await executeCompleteFlow(applications)\n } else if (error instanceof InvalidRequestError) {\n await sessionStore.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 = {...currentSession, ...newSession} as Session\n const newSessionId = completeSession.identity.userId\n const updatedSessions: Sessions = {\n ...sessions,\n [fqdn]: {...sessions[fqdn], [newSessionId]: completeSession},\n }\n\n // Save the new session info if it has changed\n if (!isEmpty(newSession)) {\n await sessionStore.store(updatedSessions)\n setCurrentSessionId(newSessionId)\n }\n\n const tokens = await tokensFor(applications, completeSession)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = getPartnersToken()\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n\n setLastSeenAuthMethod(envToken ? 'partners_token' : 'device_auth')\n setLastSeenUserIdAfterAuth(tokens.userId)\n return tokens\n}\n\nasync function throwOnNoPrompt(noPrompt: boolean) {\n if (!noPrompt) return\n await logout()\n throw new AbortError(\n `The currently available CLI credentials are invalid.\n\nThe CLI is currently unable to prompt for reauthentication.`,\n 'Restart the CLI process you were running. If in an interactive terminal, you will be prompted to reauthenticate. If in a non-interactive terminal, ensure the correct credentials are available in the program environment.',\n )\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 alias - Optional alias to use for the session.\n */\nasync function executeCompleteFlow(applications: OAuthApplications): 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 const identityTokenInformation = getIdentityTokenInformation()\n if (identityTokenInformation) {\n identityToken = buildIdentityTokenFromEnv(scopes, identityTokenInformation)\n } else {\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 }\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 // Get the alias for the session (email or userId)\n const businessPlatformToken = result[applicationId('business-platform')]?.accessToken\n const alias = (await fetchEmail(businessPlatformToken)) ?? identityToken.userId\n\n const session: Session = {\n identity: {\n ...identityToken,\n alias,\n },\n applications: result,\n }\n\n outputCompleted(`Logged in.`)\n\n return session\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param session - The session to refresh.\n */\nasync function refreshTokens(session: Session, applications: OAuthApplications): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(session.identity)\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 identity: identityToken,\n applications: applicationTokens,\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): Promise<OAuthSession> {\n const tokens: OAuthSession = {\n userId: session.identity.userId,\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.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 = session.applications[appId]?.accessToken\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n tokens.storefront = session.applications[appId]?.accessToken\n }\n\n if (applications.businessPlatformApi) {\n const appId = applicationId('business-platform')\n tokens.businessPlatform = session.applications[appId]?.accessToken\n }\n\n if (applications.appManagementApi) {\n const appId = applicationId('app-management')\n tokens.appManagement = session.applications[appId]?.accessToken\n }\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 businessPlatform = apps.businessPlatformApi?.scopes ?? []\n const appManagement = apps.appManagementApi?.scopes ?? []\n const requestedScopes = [...admin, ...partner, ...storefront, ...businessPlatform, ...appManagement]\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 const businessPlatformScopes = apps.businessPlatformApi?.scopes ?? []\n const appManagementScopes = apps.appManagementApi?.scopes ?? []\n return {\n admin: apiScopes('admin', adminScope),\n partners: apiScopes('partners', partnerScope),\n storefront: apiScopes('storefront-renderer', storefrontScopes),\n businessPlatform: apiScopes('business-platform', businessPlatformScopes),\n appManagement: apiScopes('app-management', appManagementScopes),\n }\n}\n\nfunction buildIdentityTokenFromEnv(\n scopes: string[],\n identityTokenInformation: {accessToken: string; refreshToken: string; userId: string},\n) {\n return {\n ...identityTokenInformation,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n scopes,\n alias: identityTokenInformation.userId,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/private/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {validateSession} from './session/validate.js'\nimport {allDefaultScopes} from './session/scopes.js'\nimport {\n exchangeCustomPartnerToken,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\nimport {IdentityToken, Session, Sessions} from './session/schema.js'\nimport * as sessionStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {isThemeAccessSession} from './api/rest.js'\nimport {getCurrentSessionId, setCurrentSessionId} from './conf-store.js'\nimport {UserEmailQueryString, UserEmailQuery} from './api/graphql/business-platform-destinations/user-email.js'\nimport {outputContent, outputToken, outputDebug, outputCompleted} from '../../public/node/output.js'\nimport {firstPartyDev, themeToken} from '../../public/node/context/local.js'\nimport {AbortError} from '../../public/node/error.js'\nimport {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js'\nimport {getIdentityTokenInformation, getPartnersToken} from '../../public/node/environment.js'\nimport {AdminSession, logout} from '../../public/node/session.js'\nimport {nonRandomUUID} from '../../public/node/crypto.js'\nimport {isEmpty} from '../../public/common/object.js'\nimport {businessPlatformRequest} from '../../public/node/api/business-platform.js'\n\n/**\n * Fetches the user's email from the Business Platform API\n * @param businessPlatformToken - The business platform token\n * @returns The user's email address or undefined if not found\n */\nasync function fetchEmail(businessPlatformToken: string | undefined): Promise<string | undefined> {\n if (!businessPlatformToken) return undefined\n\n try {\n const userEmailResult = await businessPlatformRequest<UserEmailQuery>(UserEmailQueryString, businessPlatformToken)\n return userEmailResult.currentUserAccount?.email\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n outputDebug(outputContent`Failed to fetch user email: ${(error as Error).message ?? String(error)}`)\n return undefined\n }\n}\n\n/**\n * A scope supported by the Shopify Admin API.\n */\nexport type AdminAPIScope = 'graphql' | 'themes' | 'collaborator'\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 */\nexport type PartnersAPIScope = 'cli'\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Developer Platform API.\n */\nexport type AppManagementAPIScope = 'https://api.shopify.com/auth/organization.apps.manage'\ninterface AppManagementAPIOauthOptions {\n /** List of scopes to request permissions for. */\n scopes: AppManagementAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\nexport type StorefrontRendererScope = 'devtools'\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\nexport type BusinessPlatformScope = 'destinations'\ninterface BusinessPlatformAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: BusinessPlatformScope[]\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 businessPlatformApi?: BusinessPlatformAPIOAuthOptions\n appManagementApi?: AppManagementAPIOauthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n businessPlatform?: string\n appManagement?: string\n userId: string\n}\n\ntype AuthMethod = 'partners_token' | 'device_auth' | 'theme_access_token' | 'custom_app_token' | 'none'\n\nlet userId: undefined | string\nlet authMethod: AuthMethod = 'none'\n\n/**\n * Retrieves the user ID from the current session or returns 'unknown' if not found.\n *\n * This function performs the following steps:\n * 1. Checks for a cached user ID in memory (obtained in the current run).\n * 2. Attempts to fetch it from the local storage (from a previous auth session).\n * 3. Checks if a custom token was used (either as a theme password or partners token).\n * 4. If a custom token is present in the environment, generates a UUID and uses it as userId.\n * 5. If after all this we don't have a userId, then reports as 'unknown'.\n *\n * @returns A Promise that resolves to the user ID as a string.\n */\nexport async function getLastSeenUserIdAfterAuth(): Promise<string> {\n if (userId) return userId\n\n const currentSessionId = getCurrentSessionId()\n if (currentSessionId) return currentSessionId\n\n const customToken = getPartnersToken() ?? themeToken()\n return customToken ? nonRandomUUID(customToken) : 'unknown'\n}\n\nexport function setLastSeenUserIdAfterAuth(id: string) {\n userId = id\n}\n\n/**\n * Retrieves the last seen authentication method used in the current session.\n *\n * This function checks for the authentication method in the following order:\n * 1. Returns the cached auth method if it's not 'none'.\n * 2. Checks for a cached session, which implies 'device_auth' was used.\n * 3. Checks for a partners token in the environment.\n * 4. Checks for a theme password in the environment.\n * 5. If none of the above are true, returns 'none'.\n *\n * @returns A Promise that resolves to the last seen authentication method as an AuthMethod type.\n */\nexport async function getLastSeenAuthMethod(): Promise<AuthMethod> {\n if (authMethod !== 'none') return authMethod\n\n if (getCurrentSessionId()) return 'device_auth'\n\n const partnersToken = getPartnersToken()\n if (partnersToken) return 'partners_token'\n\n const themePassword = themeToken()\n if (themePassword) {\n return isThemeAccessSession({token: themePassword, storeFqdn: ''}) ? 'theme_access_token' : 'custom_app_token'\n }\n\n return 'none'\n}\n\nexport function setLastSeenAuthMethod(method: AuthMethod) {\n authMethod = method\n}\n\nexport interface EnsureAuthenticatedAdditionalOptions {\n noPrompt?: boolean\n forceRefresh?: boolean\n forceNewSession?: boolean\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 options - Optional extra options to use.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n _env?: NodeJS.ProcessEnv,\n {forceRefresh = false, noPrompt = false, forceNewSession = false}: EnsureAuthenticatedAdditionalOptions = {},\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const sessions = (await sessionStore.fetch()) ?? {}\n\n let currentSessionId = getCurrentSessionId()\n if (!currentSessionId) {\n const userIds = Object.keys(sessions[fqdn] ?? {})\n if (userIds.length > 0) currentSessionId = userIds[0]\n }\n const currentSession: Session | undefined =\n currentSessionId && !forceNewSession ? sessions[fqdn]?.[currentSessionId] : undefined\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\n const validationResult = await validateSession(scopes, currentSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n await throwOnNoPrompt(noPrompt)\n outputDebug(outputContent`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications)\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(currentSession!, applications)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n await throwOnNoPrompt(noPrompt)\n newSession = await executeCompleteFlow(applications)\n } else if (error instanceof InvalidRequestError) {\n await sessionStore.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 = {...currentSession, ...newSession} as Session\n const newSessionId = completeSession.identity.userId\n const updatedSessions: Sessions = {\n ...sessions,\n [fqdn]: {...sessions[fqdn], [newSessionId]: completeSession},\n }\n\n // Save the new session info if it has changed\n if (!isEmpty(newSession)) {\n await sessionStore.store(updatedSessions)\n setCurrentSessionId(newSessionId)\n }\n\n const tokens = await tokensFor(applications, completeSession)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = getPartnersToken()\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n\n setLastSeenAuthMethod(envToken ? 'partners_token' : 'device_auth')\n setLastSeenUserIdAfterAuth(tokens.userId)\n return tokens\n}\n\nasync function throwOnNoPrompt(noPrompt: boolean) {\n if (!noPrompt) return\n await logout()\n throw new AbortError(\n `The currently available CLI credentials are invalid.\n\nThe CLI is currently unable to prompt for reauthentication.`,\n 'Restart the CLI process you were running. If in an interactive terminal, you will be prompted to reauthenticate. If in a non-interactive terminal, ensure the correct credentials are available in the program environment.',\n )\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 alias - Optional alias to use for the session.\n */\nasync function executeCompleteFlow(applications: OAuthApplications): Promise<Session> {\n const scopes = getFlattenScopes(applications)\n if (firstPartyDev()) {\n outputDebug(outputContent`Authenticating as Shopify Employee...`)\n scopes.push('employee')\n }\n\n let identityToken: IdentityToken\n const identityTokenInformation = getIdentityTokenInformation()\n if (identityTokenInformation) {\n identityToken = buildIdentityTokenFromEnv(scopes, identityTokenInformation)\n } else {\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 }\n\n outputDebug(outputContent`CLI token received (PCAT). Using it directly for API access...`)\n\n // Get the alias for the session (email or userId)\n // Use the PCAT identity token directly to fetch the email\n const alias = (await fetchEmail(identityToken.accessToken)) ?? identityToken.userId\n\n const session: Session = {\n identity: {\n ...identityToken,\n alias,\n },\n applications: {},\n }\n\n outputCompleted(`Logged in.`)\n\n return session\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param session - The session to refresh.\n */\nasync function refreshTokens(session: Session, _applications: OAuthApplications): Promise<Session> {\n // Refresh Identity Token (PCAT) - no exchange needed\n const identityToken = await refreshAccessToken(session.identity)\n\n return {\n identity: identityToken,\n applications: {},\n }\n}\n\n/**\n * Get the application tokens for a given session.\n * With PCAT, the identity token can be used directly for all APIs.\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): Promise<OAuthSession> {\n const token = session.identity.accessToken\n return {\n userId: session.identity.userId,\n admin: applications.adminApi ? {token, storeFqdn: applications.adminApi.storeFqdn} : undefined,\n partners: applications.partnersApi ? token : undefined,\n storefront: applications.storefrontRendererApi ? token : undefined,\n businessPlatform: applications.businessPlatformApi ? token : undefined,\n appManagement: applications.appManagementApi ? token : undefined,\n }\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 businessPlatform = apps.businessPlatformApi?.scopes ?? []\n const appManagement = apps.appManagementApi?.scopes ?? []\n const requestedScopes = [...admin, ...partner, ...storefront, ...businessPlatform, ...appManagement]\n return allDefaultScopes(requestedScopes)\n}\n\nfunction buildIdentityTokenFromEnv(\n scopes: string[],\n identityTokenInformation: {accessToken: string; refreshToken: string; userId: string},\n) {\n return {\n ...identityTokenInformation,\n expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),\n scopes,\n alias: identityTokenInformation.userId,\n }\n}\n"]}
|
|
@@ -73,7 +73,8 @@ export declare function sendInputAndWait(renderInstance: ReturnType<typeof rende
|
|
|
73
73
|
export declare function sendInputAndWaitForContent(renderInstance: ReturnType<typeof render>, content: string, ...inputs: string[]): Promise<void>;
|
|
74
74
|
/** Function that is useful when you want to check the last frame of a component that unmounted.
|
|
75
75
|
*
|
|
76
|
-
*
|
|
76
|
+
* With Ink 6 / React 19, the output is no longer cleared on unmount,
|
|
77
|
+
* so lastFrame() consistently returns the last rendered content.
|
|
77
78
|
*/
|
|
78
79
|
export declare function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>): string | undefined;
|
|
79
80
|
type TrackedPromise<T> = Promise<T> & {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isTruthy } from '../../../public/node/context/utilities.js';
|
|
2
1
|
import { Stdout } from '../ui.js';
|
|
3
2
|
import { render as inkRender } from 'ink';
|
|
4
3
|
import { EventEmitter } from 'events';
|
|
@@ -66,28 +65,23 @@ export function waitForInputsToBeReady() {
|
|
|
66
65
|
/**
|
|
67
66
|
* Wait for the last frame to change to anything.
|
|
68
67
|
*/
|
|
69
|
-
export function waitForChange(func, getChangingValue) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
68
|
+
export async function waitForChange(func, getChangingValue) {
|
|
69
|
+
const initialValue = getChangingValue();
|
|
70
|
+
func();
|
|
71
|
+
while (getChangingValue() === initialValue) {
|
|
72
|
+
// Yield via setImmediate so React 19's scheduler (which also uses
|
|
73
|
+
// setImmediate in Node.js) can flush batched renders, then yield
|
|
74
|
+
// via setTimeout(0) to let any follow-up microtasks settle.
|
|
75
|
+
// eslint-disable-next-line no-await-in-loop
|
|
76
|
+
await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)));
|
|
77
|
+
}
|
|
80
78
|
}
|
|
81
|
-
export function waitFor(func, condition) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
resolve();
|
|
88
|
-
}
|
|
89
|
-
}, 10);
|
|
90
|
-
});
|
|
79
|
+
export async function waitFor(func, condition) {
|
|
80
|
+
func();
|
|
81
|
+
while (!condition()) {
|
|
82
|
+
// eslint-disable-next-line no-await-in-loop
|
|
83
|
+
await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)));
|
|
84
|
+
}
|
|
91
85
|
}
|
|
92
86
|
/**
|
|
93
87
|
* Wait for the last frame to contain specific text.
|
|
@@ -124,13 +118,17 @@ export async function sendInputAndWait(renderInstance, waitTime, ...inputs) {
|
|
|
124
118
|
*/
|
|
125
119
|
export async function sendInputAndWaitForContent(renderInstance, content, ...inputs) {
|
|
126
120
|
await waitForContent(renderInstance, content, () => inputs.forEach((input) => renderInstance.stdin.write(input)));
|
|
121
|
+
// Yield so React 19's scheduler can flush effects (e.g. re-register useInput
|
|
122
|
+
// handlers with up-to-date closures) before subsequent input is sent.
|
|
123
|
+
await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)));
|
|
127
124
|
}
|
|
128
125
|
/** Function that is useful when you want to check the last frame of a component that unmounted.
|
|
129
126
|
*
|
|
130
|
-
*
|
|
127
|
+
* With Ink 6 / React 19, the output is no longer cleared on unmount,
|
|
128
|
+
* so lastFrame() consistently returns the last rendered content.
|
|
131
129
|
*/
|
|
132
130
|
export function getLastFrameAfterUnmount(renderInstance) {
|
|
133
|
-
return
|
|
131
|
+
return renderInstance.lastFrame();
|
|
134
132
|
}
|
|
135
133
|
function trackPromise(promise) {
|
|
136
134
|
let isPending = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../src/private/node/testing/ui.ts"],"names":[],"mappings":"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","sourcesContent":["import {isTruthy} from '../../../public/node/context/utilities.js'\nimport {Stdout} from '../ui.js'\nimport {ReactElement} from 'react'\nimport {render as inkRender} from 'ink'\nimport {EventEmitter} from 'events'\n\nclass Stderr extends EventEmitter {\n readonly frames: string[] = []\n private _lastFrame?: string\n\n write = (frame: string) => {\n this.frames.push(frame)\n this._lastFrame = frame\n }\n\n lastFrame = () => this._lastFrame\n}\n\nexport class Stdin extends EventEmitter {\n isTTY: boolean\n data: string | null = null\n\n constructor(options: {isTTY?: boolean} = {}) {\n super()\n this.isTTY = options.isTTY ?? true\n }\n\n write = (data: string) => {\n this.data = data\n this.emit('readable')\n }\n\n setEncoding() {}\n setRawMode() {}\n ref() {}\n unref() {}\n read: () => string | null = () => {\n const data = this.data\n\n this.data = null\n\n return data\n }\n}\n\ninterface Instance {\n rerender: (tree: ReactElement) => void\n unmount: () => void\n cleanup: () => void\n stdout: Stdout\n stderr: Stderr\n stdin: Stdin\n frames: string[]\n lastFrame: () => string | undefined\n waitUntilExit: () => TrackedPromise<void>\n}\n\ninterface RenderOptions {\n stdout?: EventEmitter\n stderr?: EventEmitter\n stdin?: EventEmitter\n}\n\nexport const render = (tree: ReactElement, options: RenderOptions = {}): Instance => {\n const stdout = new Stdout({columns: 100})\n const stderr = new Stderr()\n const stdin = new Stdin()\n\n const instance = inkRender(tree, {\n stdout: options.stdout ?? (stdout as any),\n\n stderr: options.stderr ?? (stderr as any),\n\n stdin: options.stdin ?? (stdin as any),\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n rerender: instance.rerender,\n unmount: instance.unmount,\n cleanup: instance.cleanup,\n waitUntilExit: () => trackPromise(instance.waitUntilExit()),\n stdout,\n stderr,\n stdin,\n frames: stdout.frames,\n lastFrame: stdout.lastFrame,\n }\n}\n\n/**\n * Wait for the component to be ready to accept input.\n */\nexport function waitForInputsToBeReady() {\n return new Promise((resolve) => setTimeout(resolve, 100))\n}\n\n/**\n * Wait for the last frame to change to anything.\n */\nexport function waitForChange(func: () => void, getChangingValue: () => string | number | undefined) {\n return new Promise<void>((resolve) => {\n const initialValue = getChangingValue()\n\n func()\n\n const interval = setInterval(() => {\n if (getChangingValue() !== initialValue) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\nexport function waitFor(func: () => void, condition: () => boolean) {\n return new Promise<void>((resolve) => {\n func()\n\n const interval = setInterval(() => {\n if (condition()) {\n clearInterval(interval)\n resolve()\n }\n }, 10)\n })\n}\n\n/**\n * Wait for the last frame to contain specific text.\n */\nexport function waitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n func: () => void = () => {},\n) {\n return waitFor(\n () => func(),\n\n () => renderInstance.lastFrame()!.includes(content),\n )\n}\n\n/**\n * Send input and wait for the last frame to change.\n *\n * Useful when you want to send some input and wait for anything to change in the interface.\n * If you need to wait for a specific change instead, you can use sendInputAndWaitForContent.\n */\nexport async function sendInputAndWaitForChange(renderInstance: ReturnType<typeof render>, ...inputs: string[]) {\n await waitForChange(() => inputs.forEach((input) => renderInstance.stdin.write(input)), renderInstance.lastFrame)\n // wait for another tick so we give time to react to update caches\n await new Promise((resolve) => setTimeout(resolve, 0))\n}\n\n/** Send input and wait a number of milliseconds.\n *\n * Useful if you know some what will happen after input will take a certain amount of time\n * and it will not cause any visible change so you can't use sendInputAndWaitForChange.\n * This function can also be used if you want to test that nothing changes after some input has been sent.\n */\nexport async function sendInputAndWait(\n renderInstance: ReturnType<typeof render>,\n waitTime: number,\n ...inputs: string[]\n) {\n inputs.forEach((input) => renderInstance.stdin.write(input))\n await new Promise((resolve) => setTimeout(resolve, waitTime))\n}\n\n/**\n * Send input and wait for the last frame to contain specific text.\n *\n * Useful when you want to send some input and wait for a specific change to happen.\n * If you need to wait for any change instead, you can use sendInputAndWaitForChange.\n */\nexport async function sendInputAndWaitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n ...inputs: string[]\n) {\n await waitForContent(renderInstance, content, () => inputs.forEach((input) => renderInstance.stdin.write(input)))\n}\n\n/** Function that is useful when you want to check the last frame of a component that unmounted.\n *\n * The reason this function exists is that in CI Ink will clear the last frame on unmount.\n */\nexport function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>) {\n return isTruthy(process.env.CI) ? renderInstance.frames[renderInstance.frames.length - 2] : renderInstance.lastFrame()\n}\n\ntype TrackedPromise<T> = Promise<T> & {\n isFulfilled: () => boolean\n isPending: () => boolean\n isRejected: () => boolean\n}\n\nfunction trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {\n let isPending = true\n let isRejected = false\n let isFulfilled = false\n\n const trackedPromise = promise.then(\n function (result) {\n isFulfilled = true\n isPending = false\n return result\n },\n function (error) {\n isRejected = true\n isPending = false\n throw error\n },\n ) as TrackedPromise<T>\n\n trackedPromise.isFulfilled = function () {\n return isFulfilled\n }\n trackedPromise.isPending = function () {\n return isPending\n }\n trackedPromise.isRejected = function () {\n return isRejected\n }\n\n return trackedPromise\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../src/private/node/testing/ui.ts"],"names":[],"mappings":"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","sourcesContent":["import {Stdout} from '../ui.js'\nimport {ReactElement} from 'react'\nimport {render as inkRender} from 'ink'\n\nimport {EventEmitter} from 'events'\n\nclass Stderr extends EventEmitter {\n readonly frames: string[] = []\n private _lastFrame?: string\n\n write = (frame: string) => {\n this.frames.push(frame)\n this._lastFrame = frame\n }\n\n lastFrame = () => this._lastFrame\n}\n\nexport class Stdin extends EventEmitter {\n isTTY: boolean\n data: string | null = null\n\n constructor(options: {isTTY?: boolean} = {}) {\n super()\n this.isTTY = options.isTTY ?? true\n }\n\n write = (data: string) => {\n this.data = data\n this.emit('readable')\n }\n\n setEncoding() {}\n setRawMode() {}\n ref() {}\n unref() {}\n read: () => string | null = () => {\n const data = this.data\n\n this.data = null\n\n return data\n }\n}\n\ninterface Instance {\n rerender: (tree: ReactElement) => void\n unmount: () => void\n cleanup: () => void\n stdout: Stdout\n stderr: Stderr\n stdin: Stdin\n frames: string[]\n lastFrame: () => string | undefined\n waitUntilExit: () => TrackedPromise<void>\n}\n\ninterface RenderOptions {\n stdout?: EventEmitter\n stderr?: EventEmitter\n stdin?: EventEmitter\n}\n\nexport const render = (tree: ReactElement, options: RenderOptions = {}): Instance => {\n const stdout = new Stdout({columns: 100})\n const stderr = new Stderr()\n const stdin = new Stdin()\n\n const instance = inkRender(tree, {\n stdout: options.stdout ?? (stdout as any),\n\n stderr: options.stderr ?? (stderr as any),\n\n stdin: options.stdin ?? (stdin as any),\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n rerender: instance.rerender,\n unmount: instance.unmount,\n cleanup: instance.cleanup,\n waitUntilExit: () => trackPromise(instance.waitUntilExit()),\n stdout,\n stderr,\n stdin,\n frames: stdout.frames,\n lastFrame: stdout.lastFrame,\n }\n}\n\n/**\n * Wait for the component to be ready to accept input.\n */\nexport function waitForInputsToBeReady() {\n return new Promise((resolve) => setTimeout(resolve, 100))\n}\n\n/**\n * Wait for the last frame to change to anything.\n */\nexport async function waitForChange(func: () => void, getChangingValue: () => string | number | undefined) {\n const initialValue = getChangingValue()\n\n func()\n\n while (getChangingValue() === initialValue) {\n // Yield via setImmediate so React 19's scheduler (which also uses\n // setImmediate in Node.js) can flush batched renders, then yield\n // via setTimeout(0) to let any follow-up microtasks settle.\n // eslint-disable-next-line no-await-in-loop\n await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)))\n }\n}\n\nexport async function waitFor(func: () => void, condition: () => boolean) {\n func()\n\n while (!condition()) {\n // eslint-disable-next-line no-await-in-loop\n await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)))\n }\n}\n\n/**\n * Wait for the last frame to contain specific text.\n */\nexport function waitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n func: () => void = () => {},\n) {\n return waitFor(\n () => func(),\n\n () => renderInstance.lastFrame()!.includes(content),\n )\n}\n\n/**\n * Send input and wait for the last frame to change.\n *\n * Useful when you want to send some input and wait for anything to change in the interface.\n * If you need to wait for a specific change instead, you can use sendInputAndWaitForContent.\n */\nexport async function sendInputAndWaitForChange(renderInstance: ReturnType<typeof render>, ...inputs: string[]) {\n await waitForChange(() => inputs.forEach((input) => renderInstance.stdin.write(input)), renderInstance.lastFrame)\n // wait for another tick so we give time to react to update caches\n await new Promise((resolve) => setTimeout(resolve, 0))\n}\n\n/** Send input and wait a number of milliseconds.\n *\n * Useful if you know some what will happen after input will take a certain amount of time\n * and it will not cause any visible change so you can't use sendInputAndWaitForChange.\n * This function can also be used if you want to test that nothing changes after some input has been sent.\n */\nexport async function sendInputAndWait(\n renderInstance: ReturnType<typeof render>,\n waitTime: number,\n ...inputs: string[]\n) {\n inputs.forEach((input) => renderInstance.stdin.write(input))\n await new Promise((resolve) => setTimeout(resolve, waitTime))\n}\n\n/**\n * Send input and wait for the last frame to contain specific text.\n *\n * Useful when you want to send some input and wait for a specific change to happen.\n * If you need to wait for any change instead, you can use sendInputAndWaitForChange.\n */\nexport async function sendInputAndWaitForContent(\n renderInstance: ReturnType<typeof render>,\n content: string,\n ...inputs: string[]\n) {\n await waitForContent(renderInstance, content, () => inputs.forEach((input) => renderInstance.stdin.write(input)))\n // Yield so React 19's scheduler can flush effects (e.g. re-register useInput\n // handlers with up-to-date closures) before subsequent input is sent.\n await new Promise((resolve) => setImmediate(() => setTimeout(resolve, 0)))\n}\n\n/** Function that is useful when you want to check the last frame of a component that unmounted.\n *\n * With Ink 6 / React 19, the output is no longer cleared on unmount,\n * so lastFrame() consistently returns the last rendered content.\n */\nexport function getLastFrameAfterUnmount(renderInstance: ReturnType<typeof render>) {\n return renderInstance.lastFrame()\n}\n\ntype TrackedPromise<T> = Promise<T> & {\n isFulfilled: () => boolean\n isPending: () => boolean\n isRejected: () => boolean\n}\n\nfunction trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {\n let isPending = true\n let isRejected = false\n let isFulfilled = false\n\n const trackedPromise = promise.then(\n function (result) {\n isFulfilled = true\n isPending = false\n return result\n },\n function (error) {\n isRejected = true\n isPending = false\n throw error\n },\n ) as TrackedPromise<T>\n\n trackedPromise.isFulfilled = function () {\n return isFulfilled\n }\n trackedPromise.isPending = function () {\n return isPending\n }\n trackedPromise.isRejected = function () {\n return isRejected\n }\n\n return trackedPromise\n}\n"]}
|
|
@@ -3,7 +3,6 @@ import { randomBytes } from 'crypto';
|
|
|
3
3
|
import { hostname } from 'os';
|
|
4
4
|
export const API_NAME_LIMIT = 50;
|
|
5
5
|
export function generateThemeName(context) {
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
7
6
|
const hostNameWithoutDomain = hostname().split('.')[0];
|
|
8
7
|
const hash = randomBytes(3).toString('hex');
|
|
9
8
|
const name = `${context} ()`;
|
|
@@ -1 +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,MAAM,cAAc,GAAG,EAAE,CAAA;AAEhC,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,
|
|
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,MAAM,cAAc,GAAG,EAAE,CAAA;AAEhC,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,GAAG,CAAC,CAAA;IAC7E,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\nexport const 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 - 1\n const identifier = replaceInvalidCharacters(`${hash}-${hostNameWithoutDomain.substring(0, hostNameCharacterLimit)}`)\n return `${context} (${identifier})`\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAa,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAA;AAEnC,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"alert.js","sourceRoot":"","sources":["../../../../src/private/node/ui/alert.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAa,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAA;AAEnC,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,MAAM,cAAc,GAAyC;IAC3D,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,OAAO;CACf,CAAA;AAMD,MAAM,UAAU,KAAK,CAAC,EACpB,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,SAAS,EACT,SAAS,EACT,IAAI,EACJ,cAAc,EACd,gBAAgB,GAAG,KAAK,EACxB,aAAa,GACA;IACb,8CAA8C;IAC9C,MAAM,EAAC,IAAI,EAAE,SAAS,EAAE,GAAG,WAAW,EAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;IAEtD,OAAO,UAAU,CACf,oBAAC,KAAK,IACJ,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,gBAAgB,EAAE,gBAAgB,EAClC,cAAc,EAAE,cAAc,GAC9B,EACF,EAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,aAAa,EAAC,CAChD,CAAA;AACH,CAAC","sourcesContent":["import {Alert, AlertProps} from './components/Alert.js'\nimport {renderOnce} from '../ui.js'\nimport {LogLevel} from '../../../public/node/output.js'\nimport React from 'react'\n\nimport {RenderOptions} from 'ink'\n\nconst typeToLogLevel: Record<AlertProps['type'], LogLevel> = {\n info: 'info',\n warning: 'warn',\n success: 'info',\n error: 'error',\n}\n\nexport interface AlertOptions extends AlertProps {\n renderOptions?: RenderOptions\n}\n\nexport function alert({\n type,\n headline,\n body,\n nextSteps,\n reference,\n link,\n customSections,\n orderedNextSteps = false,\n renderOptions,\n}: AlertOptions) {\n // eslint-disable-next-line prefer-rest-params\n const {type: alertType, ..._eventProps} = arguments[0]\n\n return renderOnce(\n <Alert\n type={type}\n headline={headline}\n body={body}\n nextSteps={nextSteps}\n reference={reference}\n link={link}\n orderedNextSteps={orderedNextSteps}\n customSections={customSections}\n />,\n {logLevel: typeToLogLevel[type], renderOptions},\n )\n}\n"]}
|
|
@@ -48,7 +48,7 @@ describe('Alert', async () => {
|
|
|
48
48
|
],
|
|
49
49
|
link: {
|
|
50
50
|
label: 'Link',
|
|
51
|
-
url: 'https://www.google.com
|
|
51
|
+
url: 'https://www.google.com',
|
|
52
52
|
},
|
|
53
53
|
customSections: [
|
|
54
54
|
{
|
|
@@ -100,9 +100,7 @@ describe('Alert', async () => {
|
|
|
100
100
|
│ │
|
|
101
101
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
102
102
|
[1] https://shopify.dev
|
|
103
|
-
[2] https://www.google.com
|
|
104
|
-
S832&oq=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j69i60.2711j0j7&sourc
|
|
105
|
-
eid=chrome&ie=UTF-8
|
|
103
|
+
[2] https://www.google.com
|
|
106
104
|
"
|
|
107
105
|
`);
|
|
108
106
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Alert.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAA;AAChC,OAAO,EAAC,QAAQ,EAAC,MAAM,mCAAmC,CAAA;AAC1D,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"Alert.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Alert.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Alert} from './Alert.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test} from 'vitest'\n\nimport React from 'react'\n\ndescribe('Alert', async () => {\n test('renders correctly with all the options', async () => {\n const options = {\n headline: [{userInput: 'my-app'}, 'initialized and ready to build.'],\n body: ['You can find the build files in the', {filePath: 'dist'}, 'folder.'],\n nextSteps: [\n [\n 'Run',\n {\n command: 'cd santorini-goods',\n },\n ],\n [\n 'To preview your project, run',\n {\n command: 'npm app dev',\n },\n ],\n [\n 'To add extensions, run',\n {\n command: 'npm generate extension',\n },\n ],\n ],\n reference: [\n [\n 'Run',\n {\n command: 'npm shopify help',\n },\n ],\n [\n // testing link wrapping behavior\n \"Press 'return' to open the really amazing and clean\",\n {\n link: {\n label: 'dev docs',\n url: 'https://shopify.dev',\n },\n },\n ],\n ],\n link: {\n label: 'Link',\n url: 'https://www.google.com',\n },\n customSections: [\n {\n title: 'Custom section',\n body: {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n },\n {\n title: 'Custom section 2',\n body: {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n },\n ],\n }\n\n const {lastFrame} = render(<Alert type=\"info\" {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"╭─ info ───────────────────────────────────────────────────────────────────────╮\n │ │\n │ my-app initialized and ready to build. │\n │ │\n │ You can find the build files in the dist folder. │\n │ │\n │ Next steps │\n │ • Run \\`cd santorini-goods\\` │\n │ • To preview your project, run \\`npm app dev\\` │\n │ • To add extensions, run \\`npm generate extension\\` │\n │ │\n │ Reference │\n │ • Run \\`npm shopify help\\` │\n │ • Press 'return' to open the really amazing and clean dev docs [1] │\n │ │\n │ Link [2] │\n │ │\n │ Custom section │\n │ • Item 1 │\n │ • Item 2 │\n │ • Item 3 │\n │ │\n │ Custom section 2 │\n │ • Item 1 │\n │ • Item 2 │\n │ • Item 3 │\n │ │\n ╰──────────────────────────────────────────────────────────────────────────────╯\n [1] https://shopify.dev\n [2] https://www.google.com\n \"\n `)\n })\n\n test('allows passing just a body', async () => {\n const options = {\n body: 'Title',\n }\n\n const {lastFrame} = render(<Alert type=\"info\" {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"╭─ info ───────────────────────────────────────────────────────────────────────╮\n │ │\n │ Title │\n │ │\n ╰──────────────────────────────────────────────────────────────────────────────╯\n \"\n `)\n })\n\n test('has the headline in bold', async () => {\n const options = {\n headline: 'Title.',\n }\n\n const {lastFrame} = render(<Alert type=\"info\" {...options} />)\n\n expect(lastFrame()).toMatchInlineSnapshot(`\n \"\u001b[2m╭─\u001b[22m info \u001b[2m───────────────────────────────────────────────────────────────────────╮\u001b[22m\n \u001b[2m│\u001b[22m \u001b[2m│\u001b[22m\n \u001b[2m│\u001b[22m \u001b[1mTitle.\u001b[22m \u001b[2m│\u001b[22m\n \u001b[2m│\u001b[22m \u001b[2m│\u001b[22m\n \u001b[2m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[22m\n \"\n `)\n })\n})\n"]}
|