@shopify/cli-kit 3.82.1 → 3.83.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/cli/api/graphql/admin/generated/theme_duplicate.d.ts +20 -0
- package/dist/cli/api/graphql/admin/generated/theme_duplicate.js +75 -0
- package/dist/cli/api/graphql/admin/generated/theme_duplicate.js.map +1 -0
- package/dist/private/node/analytics.d.ts +1 -0
- package/dist/private/node/analytics.js +1 -0
- package/dist/private/node/analytics.js.map +1 -1
- package/dist/private/node/session/exchange.js +6 -11
- package/dist/private/node/session/exchange.js.map +1 -1
- package/dist/private/node/ui/components/AutocompletePrompt.js +11 -7
- package/dist/private/node/ui/components/AutocompletePrompt.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.js +9 -3
- package/dist/private/node/ui/components/TextAnimation.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.test.d.ts +1 -0
- package/dist/private/node/ui/components/TextAnimation.test.js +73 -0
- package/dist/private/node/ui/components/TextAnimation.test.js.map +1 -0
- package/dist/public/common/function.d.ts +16 -2
- package/dist/public/common/function.js +19 -1
- package/dist/public/common/function.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/api/admin.js +14 -4
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/base-command.d.ts +4 -2
- package/dist/public/node/base-command.js +6 -2
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/cli.d.ts +3 -3
- package/dist/public/node/custom-oclif-loader.d.ts +1 -1
- package/dist/public/node/custom-oclif-loader.js.map +1 -1
- package/dist/public/node/monorail.d.ts +1 -1
- package/dist/public/node/monorail.js +1 -1
- package/dist/public/node/monorail.js.map +1 -1
- package/dist/public/node/themes/api.d.ts +9 -0
- package/dist/public/node/themes/api.js +53 -2
- package/dist/public/node/themes/api.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -6
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Types from './types.js';
|
|
2
|
+
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
3
|
+
export type ThemeDuplicateMutationVariables = Types.Exact<{
|
|
4
|
+
id: Types.Scalars['ID']['input'];
|
|
5
|
+
name?: Types.InputMaybe<Types.Scalars['String']['input']>;
|
|
6
|
+
}>;
|
|
7
|
+
export type ThemeDuplicateMutation = {
|
|
8
|
+
themeDuplicate?: {
|
|
9
|
+
newTheme?: {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
role: Types.ThemeRole;
|
|
13
|
+
} | null;
|
|
14
|
+
userErrors: {
|
|
15
|
+
field?: string[] | null;
|
|
16
|
+
message: string;
|
|
17
|
+
}[];
|
|
18
|
+
} | null;
|
|
19
|
+
};
|
|
20
|
+
export declare const ThemeDuplicate: DocumentNode<ThemeDuplicateMutation, ThemeDuplicateMutationVariables>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const ThemeDuplicate = {
|
|
2
|
+
kind: 'Document',
|
|
3
|
+
definitions: [
|
|
4
|
+
{
|
|
5
|
+
kind: 'OperationDefinition',
|
|
6
|
+
operation: 'mutation',
|
|
7
|
+
name: { kind: 'Name', value: 'themeDuplicate' },
|
|
8
|
+
variableDefinitions: [
|
|
9
|
+
{
|
|
10
|
+
kind: 'VariableDefinition',
|
|
11
|
+
variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
|
|
12
|
+
type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } } },
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
kind: 'VariableDefinition',
|
|
16
|
+
variable: { kind: 'Variable', name: { kind: 'Name', value: 'name' } },
|
|
17
|
+
type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
selectionSet: {
|
|
21
|
+
kind: 'SelectionSet',
|
|
22
|
+
selections: [
|
|
23
|
+
{
|
|
24
|
+
kind: 'Field',
|
|
25
|
+
name: { kind: 'Name', value: 'themeDuplicate' },
|
|
26
|
+
arguments: [
|
|
27
|
+
{
|
|
28
|
+
kind: 'Argument',
|
|
29
|
+
name: { kind: 'Name', value: 'id' },
|
|
30
|
+
value: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
kind: 'Argument',
|
|
34
|
+
name: { kind: 'Name', value: 'name' },
|
|
35
|
+
value: { kind: 'Variable', name: { kind: 'Name', value: 'name' } },
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
selectionSet: {
|
|
39
|
+
kind: 'SelectionSet',
|
|
40
|
+
selections: [
|
|
41
|
+
{
|
|
42
|
+
kind: 'Field',
|
|
43
|
+
name: { kind: 'Name', value: 'newTheme' },
|
|
44
|
+
selectionSet: {
|
|
45
|
+
kind: 'SelectionSet',
|
|
46
|
+
selections: [
|
|
47
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
|
48
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
|
49
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'role' } },
|
|
50
|
+
{ kind: 'Field', name: { kind: 'Name', value: '__typename' } },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
kind: 'Field',
|
|
56
|
+
name: { kind: 'Name', value: 'userErrors' },
|
|
57
|
+
selectionSet: {
|
|
58
|
+
kind: 'SelectionSet',
|
|
59
|
+
selections: [
|
|
60
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'field' } },
|
|
61
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'message' } },
|
|
62
|
+
{ kind: 'Field', name: { kind: 'Name', value: '__typename' } },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{ kind: 'Field', name: { kind: 'Name', value: '__typename' } },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=theme_duplicate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme_duplicate.js","sourceRoot":"","sources":["../../../../../../src/cli/api/graphql/admin/generated/theme_duplicate.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-definitions */\nimport * as Types from './types.js'\n\nimport {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core'\n\nexport type ThemeDuplicateMutationVariables = Types.Exact<{\n id: Types.Scalars['ID']['input']\n name?: Types.InputMaybe<Types.Scalars['String']['input']>\n}>\n\nexport type ThemeDuplicateMutation = {\n themeDuplicate?: {\n newTheme?: {id: string; name: string; role: Types.ThemeRole} | null\n userErrors: {field?: string[] | null; message: string}[]\n } | null\n}\n\nexport const ThemeDuplicate = {\n kind: 'Document',\n definitions: [\n {\n kind: 'OperationDefinition',\n operation: 'mutation',\n name: {kind: 'Name', value: 'themeDuplicate'},\n variableDefinitions: [\n {\n kind: 'VariableDefinition',\n variable: {kind: 'Variable', name: {kind: 'Name', value: 'id'}},\n type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'ID'}}},\n },\n {\n kind: 'VariableDefinition',\n variable: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},\n type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}},\n },\n ],\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'themeDuplicate'},\n arguments: [\n {\n kind: 'Argument',\n name: {kind: 'Name', value: 'id'},\n value: {kind: 'Variable', name: {kind: 'Name', value: 'id'}},\n },\n {\n kind: 'Argument',\n name: {kind: 'Name', value: 'name'},\n value: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},\n },\n ],\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'newTheme'},\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {kind: 'Field', name: {kind: 'Name', value: 'id'}},\n {kind: 'Field', name: {kind: 'Name', value: 'name'}},\n {kind: 'Field', name: {kind: 'Name', value: 'role'}},\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n {\n kind: 'Field',\n name: {kind: 'Name', value: 'userErrors'},\n selectionSet: {\n kind: 'SelectionSet',\n selections: [\n {kind: 'Field', name: {kind: 'Name', value: 'field'}},\n {kind: 'Field', name: {kind: 'Name', value: 'message'}},\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n {kind: 'Field', name: {kind: 'Name', value: '__typename'}},\n ],\n },\n },\n ],\n },\n },\n ],\n} as unknown as DocumentNode<ThemeDuplicateMutation, ThemeDuplicateMutationVariables>\n"]}
|
|
@@ -22,6 +22,7 @@ interface EnvironmentData {
|
|
|
22
22
|
env_is_global: boolean;
|
|
23
23
|
env_auth_method: string;
|
|
24
24
|
env_is_wsl: boolean;
|
|
25
|
+
env_build_repository: string;
|
|
25
26
|
}
|
|
26
27
|
export declare function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData>;
|
|
27
28
|
export declare function getSensitiveEnvironmentData(config: Interfaces.Config): Promise<{
|
|
@@ -50,6 +50,7 @@ export async function getEnvironmentData(config) {
|
|
|
50
50
|
env_is_global: currentProcessIsGlobal(),
|
|
51
51
|
env_auth_method: await getLastSeenAuthMethod(),
|
|
52
52
|
env_is_wsl: await isWsl(),
|
|
53
|
+
env_build_repository: process.env.SHOPIFY_CLI_BUILD_REPO ?? 'unknown',
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
export async function getSensitiveEnvironmentData(config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAA;AAClD,OAAO,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAA;AACtD,OAAO,EAAC,iBAAiB,EAAE,2BAA2B,EAAC,MAAM,2CAA2C,CAAA;AAGxG,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AACzD,OAAO,EAAC,eAAe,EAAC,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAC,MAAM,oCAAoC,CAAA;AAC3F,OAAO,EAAC,GAAG,EAAC,MAAM,2BAA2B,CAAA;AAC7C,OAAO,EAAC,sBAAsB,EAAC,MAAM,gCAAgC,CAAA;AACrE,OAAO,EAAC,KAAK,EAAC,MAAM,6BAA6B,CAAA;AAUjD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EACnC,cAAc,EACd,IAAI,EACJ,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAClC,YAAY,GACC;IACb,IAAI,YAAY,GAAW,cAAc,CAAC,OAAO,CAAA;IACjD,IAAI,YAAY,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAChG,YAAY,GAAI,YAAmC,CAAC,qBAAqB,EAAE,IAAI,cAAc,CAAC,OAAO,CAAA;IACvG,CAAC;IAED,IAAI,UAAU,GAAG,YAAY,EAAE,MAAM,EAAE,IAAI,CAAA;IAC3C,IAAI,YAAY,IAAI,kBAAkB,IAAI,YAAY,EAAE,CAAC;QACvD,UAAU,GAAG,YAAY,CAAC,gBAA0B,CAAA;IACtD,CAAC;IAED,MAAM,QAAQ,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,CAAC;QACzC,mBAAmB,EAAE;YACnB,SAAS,EAAE,WAAW;YACtB,YAAY;YACZ,SAAS,EAAE,IAAI;SAChB;KACF,CAAC,CAAC,CAAA;IAEH,MAAM,QAAQ,CAAC,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAAC;QACtC,gBAAgB,EAAE,2BAA2B,EAAE;QAC/C,kBAAkB,EAAE,cAAc,CAAC,KAAK;QACxC,aAAa,EAAE,cAAc,CAAC,KAAK;QACnC,cAAc,EAAE,UAAU;QAC1B,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;KAC1F,CAAC,CAAC,CAAA;AACL,CAAC;
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/private/node/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {getLastSeenAuthMethod} from './session.js'\nimport {hashString} from '../../public/node/crypto.js'\nimport {getPackageManager, packageManagerFromUserAgent} from '../../public/node/node-package-manager.js'\nimport BaseCommand from '../../public/node/base-command.js'\nimport {CommandContent} from '../../public/node/hooks/prerun.js'\nimport * as metadata from '../../public/node/metadata.js'\nimport {platformAndArch} from '../../public/node/os.js'\nimport {ciPlatform, cloudEnvironment, macAddress} from '../../public/node/context/local.js'\nimport {cwd} from '../../public/node/path.js'\nimport {currentProcessIsGlobal} from '../../public/node/is-global.js'\nimport {isWsl} from '../../public/node/system.js'\nimport {Command, Interfaces} from '@oclif/core'\n\ninterface StartOptions {\n commandContent: CommandContent\n args: string[]\n currentTime?: number\n commandClass?: Command.Class | typeof BaseCommand\n}\n\nexport async function startAnalytics({\n commandContent,\n args,\n currentTime = new Date().getTime(),\n commandClass,\n}: StartOptions): Promise<void> {\n let startCommand: string = commandContent.command\n if (commandClass && Object.prototype.hasOwnProperty.call(commandClass, 'analyticsNameOverride')) {\n startCommand = (commandClass as typeof BaseCommand).analyticsNameOverride() ?? commandContent.command\n }\n\n let pluginName = commandClass?.plugin?.name\n if (commandClass && 'customPluginName' in commandClass) {\n pluginName = commandClass.customPluginName as string\n }\n\n await metadata.addSensitiveMetadata(() => ({\n commandStartOptions: {\n startTime: currentTime,\n startCommand,\n startArgs: args,\n },\n }))\n\n await metadata.addPublicMetadata(() => ({\n cmd_all_launcher: packageManagerFromUserAgent(),\n cmd_all_alias_used: commandContent.alias,\n cmd_all_topic: commandContent.topic,\n cmd_all_plugin: pluginName,\n cmd_all_force: flagIncluded('force', commandClass) ? args.includes('--force') : undefined,\n }))\n}\n\ninterface EnvironmentData {\n uname: string\n env_ci: boolean\n env_ci_platform?: string\n env_plugin_installed_any_custom: boolean\n env_plugin_installed_shopify: string\n env_shell: string\n env_web_ide: string | undefined\n env_device_id: string\n env_cloud: string\n env_package_manager: string\n env_is_global: boolean\n env_auth_method: string\n env_is_wsl: boolean\n env_build_repository: string\n}\n\nexport async function getEnvironmentData(config: Interfaces.Config): Promise<EnvironmentData> {\n const ciplatform = ciPlatform()\n\n const pluginNames = getPluginNames(config)\n const shopifyPlugins = pluginNames.filter((plugin) => plugin.startsWith('@shopify/'))\n\n const {platform, arch} = platformAndArch()\n\n return {\n uname: `${platform} ${arch}`,\n env_ci: ciplatform.isCI,\n env_ci_platform: ciplatform.name,\n env_plugin_installed_any_custom: pluginNames.length !== shopifyPlugins.length,\n env_plugin_installed_shopify: JSON.stringify(shopifyPlugins),\n env_shell: config.shell,\n env_web_ide: cloudEnvironment().editor ? cloudEnvironment().platform : undefined,\n env_device_id: hashString(await macAddress()),\n env_cloud: cloudEnvironment().platform,\n env_package_manager: await getPackageManager(cwd()),\n env_is_global: currentProcessIsGlobal(),\n env_auth_method: await getLastSeenAuthMethod(),\n env_is_wsl: await isWsl(),\n env_build_repository: process.env.SHOPIFY_CLI_BUILD_REPO ?? 'unknown',\n }\n}\n\nexport async function getSensitiveEnvironmentData(config: Interfaces.Config) {\n return {\n env_plugin_installed_all: JSON.stringify(getPluginNames(config)),\n }\n}\n\nfunction getPluginNames(config: Interfaces.Config) {\n const pluginNames = [...config.plugins.keys()]\n return pluginNames.sort().filter((plugin) => !plugin.startsWith('@oclif/'))\n}\n\nfunction flagIncluded(flag: string, commandClass?: Command.Class | typeof BaseCommand) {\n if (!commandClass) return false\n\n const commandFlags = commandClass.flags ?? {}\n return Object.keys(commandFlags).includes(flag)\n}\n"]}
|
|
@@ -142,16 +142,7 @@ export async function requestAppToken(api, token, scopes = [], store) {
|
|
|
142
142
|
return { [identifier]: appToken };
|
|
143
143
|
}
|
|
144
144
|
function tokenRequestErrorHandler({ error, store }) {
|
|
145
|
-
const invalidTargetErrorMessage = `You are not authorized to use the CLI to develop in the provided store${store ? `: ${store}` : '.'}
|
|
146
|
-
'\n\n' +
|
|
147
|
-
"You can't use Shopify CLI with development stores if you only have Partner " +
|
|
148
|
-
'staff member access. If you want to use Shopify CLI to work on a development store, then ' +
|
|
149
|
-
'you should be the store owner or create a staff account on the store.' +
|
|
150
|
-
'\n\n' +
|
|
151
|
-
"If you're the store owner, then you need to log in to the store directly using the " +
|
|
152
|
-
'store URL at least once before you log in using Shopify CLI. ' +
|
|
153
|
-
'Logging in to the Shopify admin directly connects the development ' +
|
|
154
|
-
'store with your Shopify login.';
|
|
145
|
+
const invalidTargetErrorMessage = `You are not authorized to use the CLI to develop in the provided store${store ? `: ${store}` : '.'}`;
|
|
155
146
|
if (error === 'invalid_grant') {
|
|
156
147
|
// There's an scenario when Identity returns "invalid_grant" when trying to refresh the token
|
|
157
148
|
// using a valid refresh token. When that happens, we take the user through the authentication flow.
|
|
@@ -163,7 +154,11 @@ function tokenRequestErrorHandler({ error, store }) {
|
|
|
163
154
|
return new InvalidRequestError();
|
|
164
155
|
}
|
|
165
156
|
if (error === 'invalid_target') {
|
|
166
|
-
return new InvalidTargetError(invalidTargetErrorMessage
|
|
157
|
+
return new InvalidTargetError(invalidTargetErrorMessage, '', [
|
|
158
|
+
'Ensure you have logged in to the store using the Shopify admin at least once.',
|
|
159
|
+
'Ensure you are the store owner, or have a staff account if you are attempting to log in to a development store.',
|
|
160
|
+
'Ensure you are using the permanent store domain, not a vanity domain.',
|
|
161
|
+
]);
|
|
167
162
|
}
|
|
168
163
|
// eslint-disable-next-line @shopify/cli/no-error-factory-functions
|
|
169
164
|
return new AbortError(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {tokenExchangeScopes} from './scopes.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, BugError, ExtendableError} from '../../../public/node/error.js'\nimport {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../session.js'\nimport {nonRandomUUID} from '../../../public/node/crypto.js'\nimport * as jose from 'jose'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\nclass InvalidTargetError extends AbortError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n appManagement: string[]\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n requestAppToken('app-management', token, scopes.appManagement),\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n ...appManagement,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value, currentToken.userId)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable request a valid API access token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @param apiName - The API to exchange for the access token\n * @param scopes - The scopes to request with the access token\n * @returns An instance with the application access tokens.\n */\nasync function exchangeCliTokenForAccessToken(\n apiName: API,\n token: string,\n scopes: string[],\n): Promise<{accessToken: string; userId: string}> {\n const appId = applicationId(apiName)\n try {\n const newToken = await requestAppToken(apiName, token, scopes)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const accessToken = newToken[appId]!.accessToken\n const userId = nonRandomUUID(token)\n setLastSeenUserIdAfterAuth(userId)\n setLastSeenAuthMethod('partners_token')\n return {accessToken, userId}\n } catch (error) {\n const prettyName = apiName.replace(/-/g, ' ').replace(/\\b\\w/g, (char) => char.toUpperCase())\n throw new AbortError(\n `The custom token provided can't be used for the ${prettyName} API.`,\n 'Ensure the token is correct and not expired.',\n )\n }\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid Partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('partners', token, tokenExchangeScopes('partners'))\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid App Management API token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCliTokenForAppManagementAccessToken(\n token: string,\n): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('app-management', token, tokenExchangeScopes('app-management'))\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCliTokenForBusinessPlatformAccessToken(\n token: string,\n): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('business-platform', token, tokenExchangeScopes('business-platform'))\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nexport async function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`, store}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n id_token?: string\n}\n\nfunction tokenRequestErrorHandler({error, store}: {error: string; store?: string}) {\n const invalidTargetErrorMessage =\n `You are not authorized to use the CLI to develop in the provided store${store ? `: ${store}` : '.'}` +\n '\\n\\n' +\n \"You can't use Shopify CLI with development stores if you only have Partner \" +\n 'staff member access. If you want to use Shopify CLI to work on a development store, then ' +\n 'you should be the store owner or create a staff account on the store.' +\n '\\n\\n' +\n \"If you're the store owner, then you need to log in to the store directly using the \" +\n 'store URL at least once before you log in using Shopify CLI. ' +\n 'Logging in to the Shopify admin directly connects the development ' +\n 'store with your Shopify login.'\n\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n if (error === 'invalid_target') {\n return new InvalidTargetError(invalidTargetErrorMessage)\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {\n [key: string]: string\n}): Promise<Result<TokenRequestResult, {error: string; store?: string}>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n\n return err({error: payload.error, store: params.store})\n}\n\nfunction buildIdentityToken(result: TokenRequestResult, existingUserId?: string): IdentityToken {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const userId = existingUserId ?? (result.id_token ? jose.decodeJwt(result.id_token).sub! : undefined)\n\n if (!userId) {\n throw new BugError('Error setting userId for session. No id_token or pre-existing user ID provided.')\n }\n\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n userId,\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exchange.js","sourceRoot":"","sources":["../../../../src/private/node/session/exchange.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApplicationToken, IdentityToken} from './schema.js'\nimport {applicationId, clientId as getIdentityClientId} from './identity.js'\nimport {tokenExchangeScopes} from './scopes.js'\nimport {API} from '../api.js'\nimport {identityFqdn} from '../../../public/node/context/fqdn.js'\nimport {shopifyFetch} from '../../../public/node/http.js'\nimport {err, ok, Result} from '../../../public/node/result.js'\nimport {AbortError, BugError, ExtendableError} from '../../../public/node/error.js'\nimport {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../session.js'\nimport {nonRandomUUID} from '../../../public/node/crypto.js'\nimport * as jose from 'jose'\n\nexport class InvalidGrantError extends ExtendableError {}\nexport class InvalidRequestError extends ExtendableError {}\nclass InvalidTargetError extends AbortError {}\n\nexport interface ExchangeScopes {\n admin: string[]\n partners: string[]\n storefront: string[]\n businessPlatform: string[]\n appManagement: string[]\n}\n\n/**\n * Given an identity token, request an application token.\n * @param identityToken - access token obtained in a previous step\n * @param store - the store to use, only needed for admin API\n * @returns An array with the application access tokens.\n */\nexport async function exchangeAccessForApplicationTokens(\n identityToken: IdentityToken,\n scopes: ExchangeScopes,\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const token = identityToken.accessToken\n\n const [partners, storefront, businessPlatform, admin, appManagement] = await Promise.all([\n requestAppToken('partners', token, scopes.partners),\n requestAppToken('storefront-renderer', token, scopes.storefront),\n requestAppToken('business-platform', token, scopes.businessPlatform),\n store ? requestAppToken('admin', token, scopes.admin, store) : {},\n requestAppToken('app-management', token, scopes.appManagement),\n ])\n\n return {\n ...partners,\n ...storefront,\n ...businessPlatform,\n ...admin,\n ...appManagement,\n }\n}\n\n/**\n * Given an expired access token, refresh it to get a new one.\n */\nexport async function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken> {\n const clientId = getIdentityClientId()\n const params = {\n grant_type: 'refresh_token',\n access_token: currentToken.accessToken,\n refresh_token: currentToken.refreshToken,\n client_id: clientId,\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n return buildIdentityToken(value, currentToken.userId)\n}\n\n/**\n * Given a custom CLI token passed as ENV variable request a valid API access token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @param apiName - The API to exchange for the access token\n * @param scopes - The scopes to request with the access token\n * @returns An instance with the application access tokens.\n */\nasync function exchangeCliTokenForAccessToken(\n apiName: API,\n token: string,\n scopes: string[],\n): Promise<{accessToken: string; userId: string}> {\n const appId = applicationId(apiName)\n try {\n const newToken = await requestAppToken(apiName, token, scopes)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const accessToken = newToken[appId]!.accessToken\n const userId = nonRandomUUID(token)\n setLastSeenUserIdAfterAuth(userId)\n setLastSeenAuthMethod('partners_token')\n return {accessToken, userId}\n } catch (error) {\n const prettyName = apiName.replace(/-/g, ' ').replace(/\\b\\w/g, (char) => char.toUpperCase())\n throw new AbortError(\n `The custom token provided can't be used for the ${prettyName} API.`,\n 'Ensure the token is correct and not expired.',\n )\n }\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid Partners API token\n * This token does not accept extra scopes, just the cli one.\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCustomPartnerToken(token: string): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('partners', token, tokenExchangeScopes('partners'))\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid App Management API token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCliTokenForAppManagementAccessToken(\n token: string,\n): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('app-management', token, tokenExchangeScopes('app-management'))\n}\n\n/**\n * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token\n * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN`\n * @returns An instance with the application access tokens.\n */\nexport async function exchangeCliTokenForBusinessPlatformAccessToken(\n token: string,\n): Promise<{accessToken: string; userId: string}> {\n return exchangeCliTokenForAccessToken('business-platform', token, tokenExchangeScopes('business-platform'))\n}\n\ntype IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_token' | 'slow_down' | 'unknown_failure'\n\n/**\n * Given a deviceCode obtained after starting a device identity flow, request an identity token.\n * @param deviceCode - The device code obtained after starting a device identity flow\n * @param scopes - The scopes to request\n * @returns An instance with the identity access tokens.\n */\nexport async function exchangeDeviceCodeForAccessToken(\n deviceCode: string,\n): Promise<Result<IdentityToken, IdentityDeviceError>> {\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceCode,\n client_id: clientId,\n }\n\n const tokenResult = await tokenRequest(params)\n if (tokenResult.isErr()) {\n return err(tokenResult.error.error as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nexport async function requestAppToken(\n api: API,\n token: string,\n scopes: string[] = [],\n store?: string,\n): Promise<{[x: string]: ApplicationToken}> {\n const appId = applicationId(api)\n const clientId = await getIdentityClientId()\n\n const params = {\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n requested_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',\n client_id: clientId,\n audience: appId,\n scope: scopes.join(' '),\n subject_token: token,\n ...(api === 'admin' && {destination: `https://${store}/admin`, store}),\n }\n\n let identifier = appId\n if (api === 'admin' && store) {\n identifier = `${store}-${appId}`\n }\n const tokenResult = await tokenRequest(params)\n const value = tokenResult.mapError(tokenRequestErrorHandler).valueOrBug()\n const appToken = buildApplicationToken(value)\n return {[identifier]: appToken}\n}\n\ninterface TokenRequestResult {\n access_token: string\n expires_in: number\n refresh_token: string\n scope: string\n id_token?: string\n}\n\nfunction tokenRequestErrorHandler({error, store}: {error: string; store?: string}) {\n const invalidTargetErrorMessage = `You are not authorized to use the CLI to develop in the provided store${\n store ? `: ${store}` : '.'\n }`\n\n if (error === 'invalid_grant') {\n // There's an scenario when Identity returns \"invalid_grant\" when trying to refresh the token\n // using a valid refresh token. When that happens, we take the user through the authentication flow.\n return new InvalidGrantError()\n }\n if (error === 'invalid_request') {\n // There's an scenario when Identity returns \"invalid_request\" when exchanging an identity token.\n // This means the token is invalid. We clear the session and throw an error to let the caller know.\n return new InvalidRequestError()\n }\n if (error === 'invalid_target') {\n return new InvalidTargetError(invalidTargetErrorMessage, '', [\n 'Ensure you have logged in to the store using the Shopify admin at least once.',\n 'Ensure you are the store owner, or have a staff account if you are attempting to log in to a development store.',\n 'Ensure you are using the permanent store domain, not a vanity domain.',\n ])\n }\n // eslint-disable-next-line @shopify/cli/no-error-factory-functions\n return new AbortError(error)\n}\n\nasync function tokenRequest(params: {\n [key: string]: string\n}): Promise<Result<TokenRequestResult, {error: string; store?: string}>> {\n const fqdn = await identityFqdn()\n const url = new URL(`https://${fqdn}/oauth/token`)\n url.search = new URLSearchParams(Object.entries(params)).toString()\n\n const res = await shopifyFetch(url.href, {method: 'POST'})\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const payload: any = await res.json()\n\n if (res.ok) return ok(payload)\n\n return err({error: payload.error, store: params.store})\n}\n\nfunction buildIdentityToken(result: TokenRequestResult, existingUserId?: string): IdentityToken {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const userId = existingUserId ?? (result.id_token ? jose.decodeJwt(result.id_token).sub! : undefined)\n\n if (!userId) {\n throw new BugError('Error setting userId for session. No id_token or pre-existing user ID provided.')\n }\n\n return {\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n userId,\n }\n}\n\nfunction buildApplicationToken(result: TokenRequestResult): ApplicationToken {\n return {\n accessToken: result.access_token,\n expiresAt: new Date(Date.now() + result.expires_in * 1000),\n scopes: result.scope.split(' '),\n }\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SelectInput } from './SelectInput.js';
|
|
2
2
|
import { TextInput } from './TextInput.js';
|
|
3
3
|
import { PromptLayout } from './Prompts/PromptLayout.js';
|
|
4
|
-
import {
|
|
4
|
+
import { throttle } from '../../../../public/common/function.js';
|
|
5
5
|
import usePrompt, { PromptState } from '../hooks/use-prompt.js';
|
|
6
6
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
7
|
import { Box, useApp } from 'ink';
|
|
@@ -38,9 +38,13 @@ function AutocompletePrompt({ message, choices, infoTable, onSubmit, search, has
|
|
|
38
38
|
// this is NOT the same as writing useRef(searchTerm)
|
|
39
39
|
const searchTermRef = useRef('');
|
|
40
40
|
searchTermRef.current = searchTerm;
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
// Keep current values in refs to avoid stale closures
|
|
42
|
+
const choicesRef = useRef(choices);
|
|
43
|
+
choicesRef.current = choices;
|
|
44
|
+
const initialHasPagesRef = useRef(initialHasMorePages);
|
|
45
|
+
initialHasPagesRef.current = initialHasMorePages;
|
|
46
|
+
// useMemo ensures debounceSearch is not recreated on every render
|
|
47
|
+
const debounceSearch = React.useMemo(() => throttle((term) => {
|
|
44
48
|
setLoadingWhenSlow.current = setTimeout(() => {
|
|
45
49
|
setPromptState(PromptState.Loading);
|
|
46
50
|
}, 100);
|
|
@@ -50,8 +54,8 @@ function AutocompletePrompt({ message, choices, infoTable, onSubmit, search, has
|
|
|
50
54
|
// has emptied the search term, so we want to show the default
|
|
51
55
|
// choices instead
|
|
52
56
|
if (searchTermRef.current.length === 0) {
|
|
53
|
-
setSearchResults(
|
|
54
|
-
setHasMorePages(
|
|
57
|
+
setSearchResults(choicesRef.current);
|
|
58
|
+
setHasMorePages(initialHasPagesRef.current);
|
|
55
59
|
}
|
|
56
60
|
else {
|
|
57
61
|
setSearchResults(result.data);
|
|
@@ -65,7 +69,7 @@ function AutocompletePrompt({ message, choices, infoTable, onSubmit, search, has
|
|
|
65
69
|
.finally(() => {
|
|
66
70
|
clearTimeout(setLoadingWhenSlow.current);
|
|
67
71
|
});
|
|
68
|
-
},
|
|
72
|
+
}, 400, { leading: true, trailing: true }), [paginatedSearch, setPromptState]);
|
|
69
73
|
return (React.createElement(PromptLayout, { message: message, state: promptState, infoTable: infoTable, infoMessage: infoMessage, abortSignal: abortSignal, header: promptState !== PromptState.Submitted && canSearch ? (React.createElement(Box, { marginLeft: 3 },
|
|
70
74
|
React.createElement(TextInput, { value: searchTerm, onChange: (term) => {
|
|
71
75
|
setSearchTerm(term);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {debounce} from '../../../../public/common/function.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react'\nimport {Box, useApp} from 'ink'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n groupOrder?: string[]\n}\n\nconst MIN_NUMBER_OF_ITEMS_FOR_SEARCH = 5\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n abortSignal,\n infoMessage,\n groupOrder,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const {exit: unmountInk} = useApp()\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(choices)\n const canSearch = choices.length > MIN_NUMBER_OF_ITEMS_FOR_SEARCH\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n return results\n },\n [search],\n )\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n if (promptState === PromptState.Idle) {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n }\n },\n [promptState, setAnswer, setPromptState],\n )\n\n useEffect(() => {\n if (promptState === PromptState.Submitted && answer) {\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n }, [answer, onSubmit, promptState, unmountInk])\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // disable exhaustive-deps because we want to memoize the debounce function itself\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debounceSearch = useCallback(\n debounce(\n (term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(choices)\n setHasMorePages(initialHasMorePages)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n },\n 300,\n {leading: true},\n ),\n [initialHasMorePages, choices, paginatedSearch, searchResults],\n )\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n infoTable={infoTable}\n infoMessage={infoMessage}\n abortSignal={abortSignal}\n header={\n promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(choices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null\n }\n submittedAnswerLabel={answer?.label}\n input={\n <SelectInput\n items={searchResults}\n initialItems={choices}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n onSubmit={submitAnswer}\n groupOrder={groupOrder}\n />\n }\n />\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|
|
1
|
+
{"version":3,"file":"AutocompletePrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/AutocompletePrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import {SelectInput, SelectInputProps, Item as SelectItem} from './SelectInput.js'\nimport {InfoTableProps} from './Prompts/InfoTable.js'\nimport {TextInput} from './TextInput.js'\nimport {InfoMessageProps} from './Prompts/InfoMessage.js'\nimport {Message, PromptLayout} from './Prompts/PromptLayout.js'\nimport {throttle} from '../../../../public/common/function.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport usePrompt, {PromptState} from '../hooks/use-prompt.js'\nimport React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react'\nimport {Box, useApp} from 'ink'\n\nexport interface SearchResults<T> {\n data: SelectItem<T>[]\n meta?: {\n hasNextPage: boolean\n }\n}\n\nexport interface AutocompletePromptProps<T> {\n message: Message\n choices: SelectInputProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: InfoTableProps['table']\n hasMorePages?: boolean\n search: (term: string) => Promise<SearchResults<T>>\n abortSignal?: AbortSignal\n infoMessage?: InfoMessageProps['message']\n groupOrder?: string[]\n}\n\nconst MIN_NUMBER_OF_ITEMS_FOR_SEARCH = 5\n\n// eslint-disable-next-line react/function-component-definition\nfunction AutocompletePrompt<T>({\n message,\n choices,\n infoTable,\n onSubmit,\n search,\n hasMorePages: initialHasMorePages = false,\n abortSignal,\n infoMessage,\n groupOrder,\n}: React.PropsWithChildren<AutocompletePromptProps<T>>): ReactElement | null {\n const {exit: unmountInk} = useApp()\n const [searchTerm, setSearchTerm] = useState('')\n const [searchResults, setSearchResults] = useState<SelectItem<T>[]>(choices)\n const canSearch = choices.length > MIN_NUMBER_OF_ITEMS_FOR_SEARCH\n const [hasMorePages, setHasMorePages] = useState(initialHasMorePages)\n const {promptState, setPromptState, answer, setAnswer} = usePrompt<SelectItem<T> | undefined>({\n initialAnswer: undefined,\n })\n\n const paginatedSearch = useCallback(\n async (term: string) => {\n const results = await search(term)\n return results\n },\n [search],\n )\n\n const submitAnswer = useCallback(\n (answer: SelectItem<T>) => {\n if (promptState === PromptState.Idle) {\n setAnswer(answer)\n setPromptState(PromptState.Submitted)\n }\n },\n [promptState, setAnswer, setPromptState],\n )\n\n useEffect(() => {\n if (promptState === PromptState.Submitted && answer) {\n setSearchTerm('')\n unmountInk()\n onSubmit(answer.value)\n }\n }, [answer, onSubmit, promptState, unmountInk])\n\n const setLoadingWhenSlow = useRef<NodeJS.Timeout>()\n\n // we want to set it each time so that searchTermRef always tracks searchTerm,\n // this is NOT the same as writing useRef(searchTerm)\n const searchTermRef = useRef('')\n searchTermRef.current = searchTerm\n\n // Keep current values in refs to avoid stale closures\n const choicesRef = useRef(choices)\n choicesRef.current = choices\n const initialHasPagesRef = useRef(initialHasMorePages)\n initialHasPagesRef.current = initialHasMorePages\n\n // useMemo ensures debounceSearch is not recreated on every render\n const debounceSearch = React.useMemo(\n () =>\n throttle(\n (term: string) => {\n setLoadingWhenSlow.current = setTimeout(() => {\n setPromptState(PromptState.Loading)\n }, 100)\n paginatedSearch(term)\n .then((result) => {\n // while we were waiting for the promise to resolve, the user\n // has emptied the search term, so we want to show the default\n // choices instead\n if (searchTermRef.current.length === 0) {\n setSearchResults(choicesRef.current)\n setHasMorePages(initialHasPagesRef.current)\n } else {\n setSearchResults(result.data)\n setHasMorePages(result.meta?.hasNextPage ?? false)\n }\n\n setPromptState(PromptState.Idle)\n })\n .catch(() => {\n setPromptState(PromptState.Error)\n })\n .finally(() => {\n clearTimeout(setLoadingWhenSlow.current)\n })\n },\n 400,\n {leading: true, trailing: true},\n ),\n [paginatedSearch, setPromptState],\n )\n\n return (\n <PromptLayout\n message={message}\n state={promptState}\n infoTable={infoTable}\n infoMessage={infoMessage}\n abortSignal={abortSignal}\n header={\n promptState !== PromptState.Submitted && canSearch ? (\n <Box marginLeft={3}>\n <TextInput\n value={searchTerm}\n onChange={(term) => {\n setSearchTerm(term)\n\n if (term.length > 0) {\n debounceSearch(term)\n } else {\n debounceSearch.cancel()\n setPromptState(PromptState.Idle)\n setSearchResults(choices)\n }\n }}\n placeholder=\"Type to search...\"\n />\n </Box>\n ) : null\n }\n submittedAnswerLabel={answer?.label}\n input={\n <SelectInput\n items={searchResults}\n initialItems={choices}\n enableShortcuts={false}\n emptyMessage=\"No results found.\"\n highlightedTerm={searchTerm}\n loading={promptState === PromptState.Loading}\n errorMessage={\n promptState === PromptState.Error\n ? 'There has been an error while searching. Please try again later.'\n : undefined\n }\n hasMorePages={hasMorePages}\n morePagesMessage=\"Find what you're looking for by typing its name.\"\n onSubmit={submitAnswer}\n groupOrder={groupOrder}\n />\n }\n />\n )\n}\n\nexport {AutocompletePrompt}\n"]}
|
|
@@ -26,9 +26,15 @@ const TextAnimation = memo(({ text, maxWidth }) => {
|
|
|
26
26
|
const timeout = useRef();
|
|
27
27
|
const { stdout } = useStdout();
|
|
28
28
|
const [width, setWidth] = useState(maxWidth ?? Math.floor(stdout.columns * 0.66));
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
useLayoutEffect(() => {
|
|
30
|
+
const handleResize = () => {
|
|
31
|
+
setWidth(Math.floor(stdout.columns * 0.66));
|
|
32
|
+
};
|
|
33
|
+
stdout.on('resize', handleResize);
|
|
34
|
+
return () => {
|
|
35
|
+
stdout.off('resize', handleResize);
|
|
36
|
+
};
|
|
37
|
+
}, [stdout]);
|
|
32
38
|
const renderAnimation = useCallback(() => {
|
|
33
39
|
const newFrame = frame.current + 1;
|
|
34
40
|
frame.current = newFrame;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAnimation.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextAnimation.tsx"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAC,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AACnC,OAAO,KAAK,EAAE,EAAC,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACjF,OAAO,QAAQ,MAAM,iBAAiB,CAAA;AAOtC,SAAS,OAAO,CAAC,IAAY,EAAE,KAAa;IAC1C,MAAM,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;IACrB,MAAM,SAAS,GAAG,EAAC,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAC,CAAA;IAC9C,MAAM,UAAU,GAAG,EAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAC,CAAA;IACrD,OAAO,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,EAAC,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAC,CAAC,CAAA;AACvF,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,KAAa;IAC1C,MAAM,eAAe,GAAG,KAAK,GAAG,IAAI,CAAC,MAAM,CAAA;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAA;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAA;IAC3C,OAAO,KAAK,GAAG,GAAG,CAAA;AACpB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY,EAAE,QAA4B;IAC3D,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,EAAC,IAAI,EAAE,QAAQ,EAAqB,EAAe,EAAE;IAC/E,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACvB,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,MAAM,EAAkB,CAAA;IACxC,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAC5B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAA;IAEjF,
|
|
1
|
+
{"version":3,"file":"TextAnimation.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextAnimation.tsx"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable id-length */\nimport {Text, useStdout} from 'ink'\nimport React, {memo, useCallback, useLayoutEffect, useRef, useState} from 'react'\nimport gradient from 'gradient-string'\n\ninterface TextAnimationProps {\n text: string\n maxWidth?: number\n}\n\nfunction rainbow(text: string, frame: number) {\n const hue = 5 * frame\n const leftColor = {h: hue % 360, s: 0.8, v: 1}\n const rightColor = {h: (hue + 1) % 360, s: 0.8, v: 1}\n return gradient(leftColor, rightColor)(text, {interpolation: 'hsv', hsvSpin: 'long'})\n}\n\nfunction rotated(text: string, steps: number) {\n const normalizedSteps = steps % text.length\n const start = text.slice(-normalizedSteps)\n const end = text.slice(0, -normalizedSteps)\n return start + end\n}\n\nfunction truncated(text: string, maxWidth: number | undefined): string {\n return maxWidth ? text.slice(0, maxWidth) : text\n}\n\n/**\n * `TextAnimation` applies a rainbow animation to text.\n */\nconst TextAnimation = memo(({text, maxWidth}: TextAnimationProps): JSX.Element => {\n const frame = useRef(0)\n const [renderedFrame, setRenderedFrame] = useState(text)\n const timeout = useRef<NodeJS.Timeout>()\n const {stdout} = useStdout()\n const [width, setWidth] = useState(maxWidth ?? Math.floor(stdout.columns * 0.66))\n\n useLayoutEffect(() => {\n const handleResize = () => {\n setWidth(Math.floor(stdout.columns * 0.66))\n }\n\n stdout.on('resize', handleResize)\n\n return () => {\n stdout.off('resize', handleResize)\n }\n }, [stdout])\n\n const renderAnimation = useCallback(() => {\n const newFrame = frame.current + 1\n frame.current = newFrame\n\n setRenderedFrame(rainbow(truncated(rotated(text, frame.current), width), frame.current))\n\n timeout.current = setTimeout(() => {\n renderAnimation()\n }, 35)\n }, [text, width])\n\n useLayoutEffect(() => {\n renderAnimation()\n\n return () => {\n clearTimeout(timeout.current)\n }\n }, [renderAnimation])\n\n return <Text>{renderedFrame}</Text>\n})\n\nTextAnimation.displayName = 'TextAnimation'\n\nexport {TextAnimation}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { TextAnimation } from './TextAnimation.js';
|
|
2
|
+
import { render } from '../../testing/ui.js';
|
|
3
|
+
import { Stdout } from '../../ui.js';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
6
|
+
import { useStdout } from 'ink';
|
|
7
|
+
vi.mock('ink', async () => {
|
|
8
|
+
const original = await vi.importActual('ink');
|
|
9
|
+
return {
|
|
10
|
+
...original,
|
|
11
|
+
useStdout: vi.fn(),
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
describe('TextAnimation', () => {
|
|
15
|
+
let stdout;
|
|
16
|
+
let onSpy;
|
|
17
|
+
let offSpy;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
stdout = new Stdout({
|
|
20
|
+
columns: 80,
|
|
21
|
+
rows: 80,
|
|
22
|
+
});
|
|
23
|
+
onSpy = vi.spyOn(stdout, 'on');
|
|
24
|
+
offSpy = vi.spyOn(stdout, 'off');
|
|
25
|
+
vi.mocked(useStdout).mockReturnValue({
|
|
26
|
+
stdout: stdout,
|
|
27
|
+
write: () => { },
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
test('removes resize listener on unmount', async () => {
|
|
31
|
+
const renderInstance = render(React.createElement(TextAnimation, { text: "Loading..." }));
|
|
32
|
+
expect(onSpy).toHaveBeenCalledWith('resize', expect.any(Function));
|
|
33
|
+
expect(onSpy).toHaveBeenCalledTimes(1);
|
|
34
|
+
const resizeHandler = onSpy.mock.calls[0][1];
|
|
35
|
+
renderInstance.unmount();
|
|
36
|
+
expect(offSpy).toHaveBeenCalledWith('resize', resizeHandler);
|
|
37
|
+
expect(offSpy).toHaveBeenCalledTimes(1);
|
|
38
|
+
});
|
|
39
|
+
test('renders animated text', async () => {
|
|
40
|
+
const renderInstance = render(React.createElement(TextAnimation, { text: "Loading..." }));
|
|
41
|
+
expect(renderInstance.lastFrame()).toBeDefined();
|
|
42
|
+
// The text is rendered with ANSI color codes, so we need to check for the content
|
|
43
|
+
// without the color codes. The actual output contains the text but with color formatting.
|
|
44
|
+
const frame = renderInstance.lastFrame() ?? '';
|
|
45
|
+
expect(frame).toBeTruthy();
|
|
46
|
+
expect(frame.length).toBeGreaterThan(0);
|
|
47
|
+
renderInstance.unmount();
|
|
48
|
+
});
|
|
49
|
+
test('updates width when stdout resizes', async () => {
|
|
50
|
+
const renderInstance = render(React.createElement(TextAnimation, { text: "Loading..." }));
|
|
51
|
+
expect(onSpy).toHaveBeenCalledWith('resize', expect.any(Function));
|
|
52
|
+
const resizeHandler = onSpy.mock.calls[0][1];
|
|
53
|
+
stdout.columns = 120;
|
|
54
|
+
resizeHandler();
|
|
55
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
56
|
+
renderInstance.unmount();
|
|
57
|
+
});
|
|
58
|
+
test('respects maxWidth prop when provided', async () => {
|
|
59
|
+
const renderInstance = render(React.createElement(TextAnimation, { text: "Loading...", maxWidth: 20 }));
|
|
60
|
+
expect(renderInstance.lastFrame()).toBeDefined();
|
|
61
|
+
renderInstance.unmount();
|
|
62
|
+
});
|
|
63
|
+
test('cleans up animation timeout on unmount', async () => {
|
|
64
|
+
vi.useFakeTimers();
|
|
65
|
+
const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout');
|
|
66
|
+
const renderInstance = render(React.createElement(TextAnimation, { text: "Loading..." }));
|
|
67
|
+
vi.advanceTimersByTime(50);
|
|
68
|
+
renderInstance.unmount();
|
|
69
|
+
expect(clearTimeoutSpy).toHaveBeenCalled();
|
|
70
|
+
vi.useRealTimers();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=TextAnimation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextAnimation.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TextAnimation.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TextAnimation} from './TextAnimation.js'\nimport {render} from '../../testing/ui.js'\nimport {Stdout} from '../../ui.js'\nimport React from 'react'\nimport {beforeEach, describe, expect, test, vi} from 'vitest'\nimport {useStdout} from 'ink'\n\nvi.mock('ink', async () => {\n const original: any = await vi.importActual('ink')\n return {\n ...original,\n useStdout: vi.fn(),\n }\n})\n\ndescribe('TextAnimation', () => {\n let stdout: Stdout\n let onSpy: any\n let offSpy: any\n\n beforeEach(() => {\n stdout = new Stdout({\n columns: 80,\n rows: 80,\n })\n\n onSpy = vi.spyOn(stdout, 'on')\n offSpy = vi.spyOn(stdout, 'off')\n\n vi.mocked(useStdout).mockReturnValue({\n stdout: stdout as any,\n write: () => {},\n })\n })\n\n test('removes resize listener on unmount', async () => {\n const renderInstance = render(<TextAnimation text=\"Loading...\" />)\n\n expect(onSpy).toHaveBeenCalledWith('resize', expect.any(Function))\n expect(onSpy).toHaveBeenCalledTimes(1)\n\n const resizeHandler = onSpy.mock.calls[0]![1]\n\n renderInstance.unmount()\n\n expect(offSpy).toHaveBeenCalledWith('resize', resizeHandler)\n expect(offSpy).toHaveBeenCalledTimes(1)\n })\n\n test('renders animated text', async () => {\n const renderInstance = render(<TextAnimation text=\"Loading...\" />)\n\n expect(renderInstance.lastFrame()).toBeDefined()\n // The text is rendered with ANSI color codes, so we need to check for the content\n // without the color codes. The actual output contains the text but with color formatting.\n const frame = renderInstance.lastFrame() ?? ''\n expect(frame).toBeTruthy()\n expect(frame.length).toBeGreaterThan(0)\n\n renderInstance.unmount()\n })\n\n test('updates width when stdout resizes', async () => {\n const renderInstance = render(<TextAnimation text=\"Loading...\" />)\n\n expect(onSpy).toHaveBeenCalledWith('resize', expect.any(Function))\n const resizeHandler = onSpy.mock.calls[0]![1] as () => void\n\n stdout.columns = 120\n resizeHandler()\n\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n renderInstance.unmount()\n })\n\n test('respects maxWidth prop when provided', async () => {\n const renderInstance = render(<TextAnimation text=\"Loading...\" maxWidth={20} />)\n\n expect(renderInstance.lastFrame()).toBeDefined()\n\n renderInstance.unmount()\n })\n\n test('cleans up animation timeout on unmount', async () => {\n vi.useFakeTimers()\n const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout')\n\n const renderInstance = render(<TextAnimation text=\"Loading...\" />)\n\n vi.advanceTimersByTime(50)\n\n renderInstance.unmount()\n\n expect(clearTimeoutSpy).toHaveBeenCalled()\n\n vi.useRealTimers()\n })\n})\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DebouncedFunc, DebounceSettings } from 'lodash';
|
|
1
|
+
import type { DebouncedFunc, DebounceSettings, ThrottleSettings } from 'lodash';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a function that memoizes the result of func. If resolver is provided it determines the cache key for
|
|
4
4
|
* storing the result based on the arguments provided to the memoized function. By default, the first argument
|
|
@@ -20,7 +20,7 @@ export declare function memoize<T extends (...args: any) => any>(func: T, resolv
|
|
|
20
20
|
* Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only
|
|
21
21
|
* if the the debounced function is invoked more than once during the wait timeout.
|
|
22
22
|
*
|
|
23
|
-
* See David Corbacho
|
|
23
|
+
* See David Corbacho's article for details over the differences between _.debounce and _.throttle.
|
|
24
24
|
*
|
|
25
25
|
* @param func - The function to debounce.
|
|
26
26
|
* @param wait - The number of milliseconds to delay.
|
|
@@ -28,3 +28,17 @@ export declare function memoize<T extends (...args: any) => any>(func: T, resolv
|
|
|
28
28
|
* @returns Returns the new debounced function.
|
|
29
29
|
*/
|
|
30
30
|
export declare function debounce<T extends (...args: any) => any>(func: T, wait?: number, options?: DebounceSettings): DebouncedFunc<T>;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a throttled function that only invokes func at most once per every wait milliseconds.
|
|
33
|
+
* The throttled function comes with a cancel method to cancel delayed invocations and a flush method to immediately invoke them.
|
|
34
|
+
* Provide an options object to indicate whether func should be invoked on the leading and/or trailing edge of the wait timeout.
|
|
35
|
+
* Subsequent calls to the throttled function return the result of the last func invocation.
|
|
36
|
+
*
|
|
37
|
+
* See David Corbacho's article for details over the differences between _.debounce and _.throttle.
|
|
38
|
+
*
|
|
39
|
+
* @param func - The function to throttle.
|
|
40
|
+
* @param wait - The number of milliseconds to throttle invocations to.
|
|
41
|
+
* @param options - The options object.
|
|
42
|
+
* @returns Returns the new throttled function.
|
|
43
|
+
*/
|
|
44
|
+
export declare function throttle<T extends (...args: any) => any>(func: T, wait?: number, options?: ThrottleSettings): DebouncedFunc<T>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import lodashMemoize from 'lodash/memoize.js';
|
|
2
2
|
import lodashDebounce from 'lodash/debounce.js';
|
|
3
|
+
import lodashThrottle from 'lodash/throttle.js';
|
|
3
4
|
/**
|
|
4
5
|
* Creates a function that memoizes the result of func. If resolver is provided it determines the cache key for
|
|
5
6
|
* storing the result based on the arguments provided to the memoized function. By default, the first argument
|
|
@@ -24,7 +25,7 @@ export function memoize(func, resolver) {
|
|
|
24
25
|
* Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only
|
|
25
26
|
* if the the debounced function is invoked more than once during the wait timeout.
|
|
26
27
|
*
|
|
27
|
-
* See David Corbacho
|
|
28
|
+
* See David Corbacho's article for details over the differences between _.debounce and _.throttle.
|
|
28
29
|
*
|
|
29
30
|
* @param func - The function to debounce.
|
|
30
31
|
* @param wait - The number of milliseconds to delay.
|
|
@@ -35,4 +36,21 @@ export function memoize(func, resolver) {
|
|
|
35
36
|
export function debounce(func, wait, options) {
|
|
36
37
|
return lodashDebounce(func, wait, options);
|
|
37
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a throttled function that only invokes func at most once per every wait milliseconds.
|
|
41
|
+
* The throttled function comes with a cancel method to cancel delayed invocations and a flush method to immediately invoke them.
|
|
42
|
+
* Provide an options object to indicate whether func should be invoked on the leading and/or trailing edge of the wait timeout.
|
|
43
|
+
* Subsequent calls to the throttled function return the result of the last func invocation.
|
|
44
|
+
*
|
|
45
|
+
* See David Corbacho's article for details over the differences between _.debounce and _.throttle.
|
|
46
|
+
*
|
|
47
|
+
* @param func - The function to throttle.
|
|
48
|
+
* @param wait - The number of milliseconds to throttle invocations to.
|
|
49
|
+
* @param options - The options object.
|
|
50
|
+
* @returns Returns the new throttled function.
|
|
51
|
+
*/
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
export function throttle(func, wait, options) {
|
|
54
|
+
return lodashThrottle(func, wait, options);
|
|
55
|
+
}
|
|
38
56
|
//# sourceMappingURL=function.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"function.js","sourceRoot":"","sources":["../../../src/public/common/function.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,mBAAmB,CAAA;AAC7C,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAG/C;;;;;;;;;GASG;AACH,8DAA8D;AAC9D,MAAM,UAAU,OAAO,CAAkC,IAAO,EAAE,QAA8C;IAC9G,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,IAAO,EACP,IAAa,EACb,OAA0B;IAE1B,OAAO,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC","sourcesContent":["import lodashMemoize from 'lodash/memoize.js'\nimport lodashDebounce from 'lodash/debounce.js'\nimport type {DebouncedFunc, DebounceSettings} from 'lodash'\n\n/**\n * Creates a function that memoizes the result of func. If resolver is provided it determines the cache key for\n * storing the result based on the arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is coerced to a string and used as the cache key. The func is invoked with\n * the this binding of the memoized function.\n *\n * @param func - The function to have its output memoized.\n * @param resolver - The function to resolve the cache key.\n * @returns Returns the new memoizing function.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function memoize<T extends (...args: any) => any>(func: T, resolver?: (...args: Parameters<T>) => unknown): T {\n return lodashMemoize(func, resolver)\n}\n\n/**\n * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since\n * the last time the debounced function was invoked. The debounced function comes with a cancel method to\n * cancel delayed invocations and a flush method to immediately invoke them. Provide an options object to\n * indicate that func should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent\n * calls to the debounced function return the result of the last func invocation.\n *\n * Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only\n * if the the debounced function is invoked more than once during the wait timeout.\n *\n * See David Corbacho
|
|
1
|
+
{"version":3,"file":"function.js","sourceRoot":"","sources":["../../../src/public/common/function.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,mBAAmB,CAAA;AAC7C,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAC/C,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAG/C;;;;;;;;;GASG;AACH,8DAA8D;AAC9D,MAAM,UAAU,OAAO,CAAkC,IAAO,EAAE,QAA8C;IAC9G,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,IAAO,EACP,IAAa,EACb,OAA0B;IAE1B,OAAO,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,IAAO,EACP,IAAa,EACb,OAA0B;IAE1B,OAAO,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC","sourcesContent":["import lodashMemoize from 'lodash/memoize.js'\nimport lodashDebounce from 'lodash/debounce.js'\nimport lodashThrottle from 'lodash/throttle.js'\nimport type {DebouncedFunc, DebounceSettings, ThrottleSettings} from 'lodash'\n\n/**\n * Creates a function that memoizes the result of func. If resolver is provided it determines the cache key for\n * storing the result based on the arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is coerced to a string and used as the cache key. The func is invoked with\n * the this binding of the memoized function.\n *\n * @param func - The function to have its output memoized.\n * @param resolver - The function to resolve the cache key.\n * @returns Returns the new memoizing function.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function memoize<T extends (...args: any) => any>(func: T, resolver?: (...args: Parameters<T>) => unknown): T {\n return lodashMemoize(func, resolver)\n}\n\n/**\n * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since\n * the last time the debounced function was invoked. The debounced function comes with a cancel method to\n * cancel delayed invocations and a flush method to immediately invoke them. Provide an options object to\n * indicate that func should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent\n * calls to the debounced function return the result of the last func invocation.\n *\n * Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only\n * if the the debounced function is invoked more than once during the wait timeout.\n *\n * See David Corbacho's article for details over the differences between _.debounce and _.throttle.\n *\n * @param func - The function to debounce.\n * @param wait - The number of milliseconds to delay.\n * @param options - The options object.\n * @returns Returns the new debounced function.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function debounce<T extends (...args: any) => any>(\n func: T,\n wait?: number,\n options?: DebounceSettings,\n): DebouncedFunc<T> {\n return lodashDebounce(func, wait, options)\n}\n\n/**\n * Creates a throttled function that only invokes func at most once per every wait milliseconds.\n * The throttled function comes with a cancel method to cancel delayed invocations and a flush method to immediately invoke them.\n * Provide an options object to indicate whether func should be invoked on the leading and/or trailing edge of the wait timeout.\n * Subsequent calls to the throttled function return the result of the last func invocation.\n *\n * See David Corbacho's article for details over the differences between _.debounce and _.throttle.\n *\n * @param func - The function to throttle.\n * @param wait - The number of milliseconds to throttle invocations to.\n * @param options - The options object.\n * @returns Returns the new throttled function.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any) => any>(\n func: T,\n wait?: number,\n options?: ThrottleSettings,\n): DebouncedFunc<T> {\n return lodashThrottle(func, wait, options)\n}\n"]}
|