@shopify/cli-kit 3.79.2 → 3.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/private/node/session/exchange.d.ts +4 -0
  2. package/dist/private/node/session/exchange.js +7 -7
  3. package/dist/private/node/session/exchange.js.map +1 -1
  4. package/dist/public/common/version.d.ts +1 -1
  5. package/dist/public/common/version.js +1 -1
  6. package/dist/public/common/version.js.map +1 -1
  7. package/dist/public/node/api/admin.js +2 -2
  8. package/dist/public/node/api/admin.js.map +1 -1
  9. package/dist/public/node/api/app-management.d.ts +3 -2
  10. package/dist/public/node/api/app-management.js +3 -1
  11. package/dist/public/node/api/app-management.js.map +1 -1
  12. package/dist/public/node/api/graphql.d.ts +15 -2
  13. package/dist/public/node/api/graphql.js +52 -9
  14. package/dist/public/node/api/graphql.js.map +1 -1
  15. package/dist/public/node/api/partners.d.ts +5 -3
  16. package/dist/public/node/api/partners.js +7 -3
  17. package/dist/public/node/api/partners.js.map +1 -1
  18. package/dist/public/node/archiver.d.ts +39 -0
  19. package/dist/public/node/archiver.js +59 -2
  20. package/dist/public/node/archiver.js.map +1 -1
  21. package/dist/public/node/fs.d.ts +6 -0
  22. package/dist/public/node/fs.js +9 -1
  23. package/dist/public/node/fs.js.map +1 -1
  24. package/dist/public/node/git.d.ts +7 -0
  25. package/dist/public/node/git.js +12 -0
  26. package/dist/public/node/git.js.map +1 -1
  27. package/dist/public/node/hooks/prerun.js +2 -1
  28. package/dist/public/node/hooks/prerun.js.map +1 -1
  29. package/dist/public/node/http.js +2 -2
  30. package/dist/public/node/http.js.map +1 -1
  31. package/dist/public/node/tcp.js +8 -3
  32. package/dist/public/node/tcp.js.map +1 -1
  33. package/dist/public/node/ui/components.d.ts +1 -0
  34. package/dist/public/node/ui/components.js +1 -0
  35. package/dist/public/node/ui/components.js.map +1 -1
  36. package/dist/public/node/version.d.ts +8 -0
  37. package/dist/public/node/version.js +11 -1
  38. package/dist/public/node/version.js.map +1 -1
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +3 -1
@@ -1,4 +1,5 @@
1
1
  import { ApplicationToken, IdentityToken } from './schema.js';
2
+ import { API } from '../api.js';
2
3
  import { Result } from '../../../public/node/result.js';
3
4
  import { ExtendableError } from '../../../public/node/error.js';
4
5
  export declare class InvalidGrantError extends ExtendableError {
@@ -61,4 +62,7 @@ type IdentityDeviceError = 'authorization_pending' | 'access_denied' | 'expired_
61
62
  * @returns An instance with the identity access tokens.
62
63
  */
63
64
  export declare function exchangeDeviceCodeForAccessToken(deviceCode: string): Promise<Result<IdentityToken, IdentityDeviceError>>;
65
+ export declare function requestAppToken(api: API, token: string, scopes?: string[], store?: string): Promise<{
66
+ [x: string]: ApplicationToken;
67
+ }>;
64
68
  export {};
@@ -114,12 +114,12 @@ export async function exchangeDeviceCodeForAccessToken(deviceCode) {
114
114
  };
115
115
  const tokenResult = await tokenRequest(params);
116
116
  if (tokenResult.isErr()) {
117
- return err(tokenResult.error);
117
+ return err(tokenResult.error.error);
118
118
  }
119
119
  const identityToken = buildIdentityToken(tokenResult.value);
120
120
  return ok(identityToken);
121
121
  }
122
- async function requestAppToken(api, token, scopes = [], store) {
122
+ export async function requestAppToken(api, token, scopes = [], store) {
123
123
  const appId = applicationId(api);
124
124
  const clientId = await getIdentityClientId();
125
125
  const params = {
@@ -130,7 +130,7 @@ async function requestAppToken(api, token, scopes = [], store) {
130
130
  audience: appId,
131
131
  scope: scopes.join(' '),
132
132
  subject_token: token,
133
- ...(api === 'admin' && { destination: `https://${store}/admin` }),
133
+ ...(api === 'admin' && { destination: `https://${store}/admin`, store }),
134
134
  };
135
135
  let identifier = appId;
136
136
  if (api === 'admin' && store) {
@@ -141,15 +141,15 @@ async function requestAppToken(api, token, scopes = [], store) {
141
141
  const appToken = buildApplicationToken(value);
142
142
  return { [identifier]: appToken };
143
143
  }
144
- function tokenRequestErrorHandler(error) {
145
- const invalidTargetErrorMessage = 'You are not authorized to use the CLI to develop in the provided store.' +
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
146
  '\n\n' +
147
147
  "You can't use Shopify CLI with development stores if you only have Partner " +
148
148
  'staff member access. If you want to use Shopify CLI to work on a development store, then ' +
149
149
  'you should be the store owner or create a staff account on the store.' +
150
150
  '\n\n' +
151
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.' +
152
+ 'store URL at least once before you log in using Shopify CLI. ' +
153
153
  'Logging in to the Shopify admin directly connects the development ' +
154
154
  'store with your Shopify login.';
155
155
  if (error === 'invalid_grant') {
@@ -177,7 +177,7 @@ async function tokenRequest(params) {
177
177
  const payload = await res.json();
178
178
  if (res.ok)
179
179
  return ok(payload);
180
- return err(payload.error);
180
+ return err({ error: payload.error, store: params.store });
181
181
  }
182
182
  function buildIdentityToken(result, existingUserId) {
183
183
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -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 * as jose from 'jose'\nimport {nonRandomUUID} from '@shopify/cli-kit/node/crypto'\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 as IdentityDeviceError)\n }\n const identityToken = buildIdentityToken(tokenResult.value)\n return ok(identityToken)\n}\n\nasync 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`}),\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: string) {\n const invalidTargetErrorMessage =\n 'You are not authorized to use the CLI to develop in the provided 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 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: {[key: string]: string}): Promise<Result<TokenRequestResult, 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 return err(payload.error)\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 * as jose from 'jose'\nimport {nonRandomUUID} from '@shopify/cli-kit/node/crypto'\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 +1 @@
1
- export declare const CLI_KIT_VERSION = "3.79.2";
1
+ export declare const CLI_KIT_VERSION = "3.80.0";
@@ -1,2 +1,2 @@
1
- export const CLI_KIT_VERSION = '3.79.2';
1
+ export const CLI_KIT_VERSION = '3.80.0';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.79.2'\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.80.0'\n"]}
@@ -1,4 +1,4 @@
1
- import { graphqlRequest, graphqlRequestDoc } from './graphql.js';
1
+ import { graphqlRequest, graphqlRequestDoc, } from './graphql.js';
2
2
  import { outputContent, outputToken } from '../../../public/node/output.js';
3
3
  import { AbortError, BugError } from '../error.js';
4
4
  import { restRequestBody, restRequestHeaders, restRequestUrl, isThemeAccessSession, } from '../../../private/node/api/rest.js';
@@ -46,7 +46,7 @@ export async function adminRequestDoc(options) {
46
46
  };
47
47
  let unauthorizedHandler;
48
48
  if ('refresh' in session) {
49
- unauthorizedHandler = session.refresh;
49
+ unauthorizedHandler = { type: 'simple', handler: session.refresh };
50
50
  }
51
51
  const result = graphqlRequestDoc({
52
52
  ...opts,
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../src/public/node/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {graphqlRequest, graphqlRequestDoc, GraphQLResponseOptions, GraphQLVariables} from './graphql.js'\nimport {AdminSession} from '../session.js'\nimport {outputContent, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../error.js'\nimport {\n restRequestBody,\n restRequestHeaders,\n restRequestUrl,\n isThemeAccessSession,\n} from '../../../private/node/api/rest.js'\nimport {RequestModeInput, shopifyFetch} from '../http.js'\nimport {PublicApiVersions} from '../../../cli/api/graphql/admin/generated/public_api_versions.js'\nimport {normalizeStoreFqdn} from '../context/fqdn.js'\nimport {themeKitAccessDomain} from '../../../private/node/constants.js'\nimport {ClientError, Variables} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\n\nconst LatestApiVersionByFQDN = new Map<string, string>()\n\n/**\n * Executes a GraphQL query against the Admin API.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @returns The response of the query of generic type <T>.\n */\nexport async function adminRequest<T>(query: string, session: AdminSession, variables?: GraphQLVariables): Promise<T> {\n const api = 'Admin'\n const version = await fetchLatestSupportedApiVersion(session)\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const url = adminUrl(store, version, session)\n const addedHeaders = themeAccessHeaders(session)\n return graphqlRequest({query, api, addedHeaders, url, token: session.token, variables})\n}\n\nexport interface AdminRequestOptions<TResult, TVariables extends Variables> {\n /** GraphQL query to execute. */\n query: TypedDocumentNode<TResult, TVariables>\n /** Shopify admin session including token and Store FQDN. */\n session: AdminSession\n /** GraphQL variables to pass to the query. */\n variables?: TVariables\n /** API version. */\n version?: string\n /** Control how API responses will be handled. */\n responseOptions?: GraphQLResponseOptions<TResult>\n /** Custom request behaviour for retries and timeouts. */\n requestBehaviour?: RequestModeInput\n}\n\n/**\n * Executes a GraphQL query against the Admin API. Uses typed documents.\n *\n * @param options - Admin request options.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function adminRequestDoc<TResult, TVariables extends Variables>(\n options: AdminRequestOptions<TResult, TVariables>,\n): Promise<TResult> {\n const {query, session, variables, version, responseOptions, requestBehaviour} = options\n\n let apiVersion = version ?? LatestApiVersionByFQDN.get(session.storeFqdn)\n if (!apiVersion) {\n apiVersion = await fetchLatestSupportedApiVersion(session)\n }\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const addedHeaders = themeAccessHeaders(session)\n const opts = {\n url: adminUrl(store, apiVersion, session),\n api: 'Admin',\n token: session.token,\n addedHeaders,\n }\n let unauthorizedHandler\n if ('refresh' in session) {\n unauthorizedHandler = session.refresh as () => Promise<void>\n }\n const result = graphqlRequestDoc<TResult, TVariables>({\n ...opts,\n query,\n variables,\n responseOptions,\n unauthorizedHandler,\n requestBehaviour,\n })\n return result\n}\n\nfunction themeAccessHeaders(session: AdminSession): {[header: string]: string} {\n return isThemeAccessSession(session)\n ? {'X-Shopify-Shop': session.storeFqdn, 'X-Shopify-Access-Token': session.token}\n : {}\n}\n\n/**\n * GraphQL query to retrieve the latest supported API version.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - The latest supported API version.\n */\nasync function fetchLatestSupportedApiVersion(session: AdminSession): Promise<string> {\n const apiVersions = await supportedApiVersions(session)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const latest = apiVersions.reverse()[0]!\n LatestApiVersionByFQDN.set(session.storeFqdn, latest)\n return latest\n}\n\n/**\n * GraphQL query to retrieve all supported API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported API versions.\n */\nexport async function supportedApiVersions(session: AdminSession): Promise<string[]> {\n const apiVersions = await fetchApiVersions(session)\n return apiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n}\n\n/**\n * GraphQL query to retrieve all API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported and unsupported API versions.\n */\nasync function fetchApiVersions(session: AdminSession): Promise<ApiVersion[]> {\n try {\n const response = await adminRequestDoc({\n query: PublicApiVersions,\n session,\n variables: {},\n version: 'unstable',\n responseOptions: {handleErrors: false},\n })\n return response.publicApiVersions\n } catch (error) {\n if (error instanceof ClientError && error.response.status === 403) {\n const storeName = session.storeFqdn.replace('.myshopify.com', '')\n throw new AbortError(\n outputContent`Looks like you don't have access this dev store: (${outputToken.link(\n storeName,\n `https://${session.storeFqdn}`,\n )})`,\n outputContent`If you're not the owner, create a dev store staff account for yourself`,\n )\n }\n if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {\n throw new AbortError(\n `Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`,\n )\n } else {\n throw new BugError(\n `Unknown error connecting to your store ${session.storeFqdn}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n}\n\n/**\n * Returns the Admin API URL for the given store and version.\n *\n * @param store - Store FQDN.\n * @param version - API version.\n * @param session - User session.\n * @returns - Admin API URL.\n */\nexport function adminUrl(store: string, version: string | undefined, session?: AdminSession): string {\n const realVersion = version ?? 'unstable'\n\n const url =\n session && isThemeAccessSession(session)\n ? `https://${themeKitAccessDomain}/cli/admin/api/${realVersion}/graphql.json`\n : `https://${store}/admin/api/${realVersion}/graphql.json`\n return url\n}\n\ninterface ApiVersion {\n handle: string\n supported: boolean\n}\n\n/**\n * Executes a REST request against the Admin API.\n *\n * @param method - Request's HTTP method.\n * @param path - Path of the REST resource.\n * @param session - Shopify Admin session including token and Store FQDN.\n * @param requestBody - Request body of including REST resource specific parameters.\n * @param searchParams - Search params, appended to the URL.\n * @param apiVersion - Admin API version.\n * @returns - The {@link RestResponse}.\n */\nexport async function restRequest<T>(\n method: string,\n path: string,\n session: AdminSession,\n requestBody?: T,\n searchParams: {[name: string]: string} = {},\n apiVersion = 'unstable',\n): Promise<RestResponse> {\n const url = restRequestUrl(session, apiVersion, path, searchParams)\n const body = restRequestBody<T>(requestBody)\n\n const headers = restRequestHeaders(session)\n const response = await shopifyFetch(url, {\n headers,\n method,\n body,\n })\n\n const json = await response.json().catch(() => ({}))\n\n return {\n json,\n status: response.status,\n headers: response.headers.raw(),\n }\n}\n\n/**\n * Respose of a REST request.\n */\nexport interface RestResponse {\n /**\n * REST JSON respose.\n */\n // Using `any` to avoid introducing extra DTO layers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n json: any\n\n /**\n * HTTP response status.\n */\n status: number\n\n /**\n * HTTP response headers.\n */\n headers: {[key: string]: string[]}\n}\n"]}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../../src/public/node/api/admin.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n graphqlRequest,\n graphqlRequestDoc,\n GraphQLResponseOptions,\n GraphQLVariables,\n UnauthorizedHandler,\n} from './graphql.js'\nimport {AdminSession} from '../session.js'\nimport {outputContent, outputToken} from '../../../public/node/output.js'\nimport {AbortError, BugError} from '../error.js'\nimport {\n restRequestBody,\n restRequestHeaders,\n restRequestUrl,\n isThemeAccessSession,\n} from '../../../private/node/api/rest.js'\nimport {RequestModeInput, shopifyFetch} from '../http.js'\nimport {PublicApiVersions} from '../../../cli/api/graphql/admin/generated/public_api_versions.js'\nimport {normalizeStoreFqdn} from '../context/fqdn.js'\nimport {themeKitAccessDomain} from '../../../private/node/constants.js'\nimport {ClientError, Variables} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\n\nconst LatestApiVersionByFQDN = new Map<string, string>()\n\n/**\n * Executes a GraphQL query against the Admin API.\n *\n * @param query - GraphQL query to execute.\n * @param session - Shopify admin session including token and Store FQDN.\n * @param variables - GraphQL variables to pass to the query.\n * @returns The response of the query of generic type <T>.\n */\nexport async function adminRequest<T>(query: string, session: AdminSession, variables?: GraphQLVariables): Promise<T> {\n const api = 'Admin'\n const version = await fetchLatestSupportedApiVersion(session)\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const url = adminUrl(store, version, session)\n const addedHeaders = themeAccessHeaders(session)\n return graphqlRequest({query, api, addedHeaders, url, token: session.token, variables})\n}\n\nexport interface AdminRequestOptions<TResult, TVariables extends Variables> {\n /** GraphQL query to execute. */\n query: TypedDocumentNode<TResult, TVariables>\n /** Shopify admin session including token and Store FQDN. */\n session: AdminSession\n /** GraphQL variables to pass to the query. */\n variables?: TVariables\n /** API version. */\n version?: string\n /** Control how API responses will be handled. */\n responseOptions?: GraphQLResponseOptions<TResult>\n /** Custom request behaviour for retries and timeouts. */\n requestBehaviour?: RequestModeInput\n}\n\n/**\n * Executes a GraphQL query against the Admin API. Uses typed documents.\n *\n * @param options - Admin request options.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function adminRequestDoc<TResult, TVariables extends Variables>(\n options: AdminRequestOptions<TResult, TVariables>,\n): Promise<TResult> {\n const {query, session, variables, version, responseOptions, requestBehaviour} = options\n\n let apiVersion = version ?? LatestApiVersionByFQDN.get(session.storeFqdn)\n if (!apiVersion) {\n apiVersion = await fetchLatestSupportedApiVersion(session)\n }\n const store = await normalizeStoreFqdn(session.storeFqdn)\n const addedHeaders = themeAccessHeaders(session)\n const opts = {\n url: adminUrl(store, apiVersion, session),\n api: 'Admin',\n token: session.token,\n addedHeaders,\n }\n let unauthorizedHandler: UnauthorizedHandler | undefined\n if ('refresh' in session) {\n unauthorizedHandler = {type: 'simple', handler: session.refresh as () => Promise<void>}\n }\n const result = graphqlRequestDoc<TResult, TVariables>({\n ...opts,\n query,\n variables,\n responseOptions,\n unauthorizedHandler,\n requestBehaviour,\n })\n return result\n}\n\nfunction themeAccessHeaders(session: AdminSession): {[header: string]: string} {\n return isThemeAccessSession(session)\n ? {'X-Shopify-Shop': session.storeFqdn, 'X-Shopify-Access-Token': session.token}\n : {}\n}\n\n/**\n * GraphQL query to retrieve the latest supported API version.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - The latest supported API version.\n */\nasync function fetchLatestSupportedApiVersion(session: AdminSession): Promise<string> {\n const apiVersions = await supportedApiVersions(session)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const latest = apiVersions.reverse()[0]!\n LatestApiVersionByFQDN.set(session.storeFqdn, latest)\n return latest\n}\n\n/**\n * GraphQL query to retrieve all supported API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported API versions.\n */\nexport async function supportedApiVersions(session: AdminSession): Promise<string[]> {\n const apiVersions = await fetchApiVersions(session)\n return apiVersions\n .filter((item) => item.supported)\n .map((item) => item.handle)\n .sort()\n}\n\n/**\n * GraphQL query to retrieve all API versions.\n *\n * @param session - Shopify admin session including token and Store FQDN.\n * @returns - An array of supported and unsupported API versions.\n */\nasync function fetchApiVersions(session: AdminSession): Promise<ApiVersion[]> {\n try {\n const response = await adminRequestDoc({\n query: PublicApiVersions,\n session,\n variables: {},\n version: 'unstable',\n responseOptions: {handleErrors: false},\n })\n return response.publicApiVersions\n } catch (error) {\n if (error instanceof ClientError && error.response.status === 403) {\n const storeName = session.storeFqdn.replace('.myshopify.com', '')\n throw new AbortError(\n outputContent`Looks like you don't have access this dev store: (${outputToken.link(\n storeName,\n `https://${session.storeFqdn}`,\n )})`,\n outputContent`If you're not the owner, create a dev store staff account for yourself`,\n )\n }\n if (error instanceof ClientError && (error.response.status === 401 || error.response.status === 404)) {\n throw new AbortError(\n `Error connecting to your store ${session.storeFqdn}: ${error.message} ${error.response.status} ${error.response.data}`,\n )\n } else {\n throw new BugError(\n `Unknown error connecting to your store ${session.storeFqdn}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n}\n\n/**\n * Returns the Admin API URL for the given store and version.\n *\n * @param store - Store FQDN.\n * @param version - API version.\n * @param session - User session.\n * @returns - Admin API URL.\n */\nexport function adminUrl(store: string, version: string | undefined, session?: AdminSession): string {\n const realVersion = version ?? 'unstable'\n\n const url =\n session && isThemeAccessSession(session)\n ? `https://${themeKitAccessDomain}/cli/admin/api/${realVersion}/graphql.json`\n : `https://${store}/admin/api/${realVersion}/graphql.json`\n return url\n}\n\ninterface ApiVersion {\n handle: string\n supported: boolean\n}\n\n/**\n * Executes a REST request against the Admin API.\n *\n * @param method - Request's HTTP method.\n * @param path - Path of the REST resource.\n * @param session - Shopify Admin session including token and Store FQDN.\n * @param requestBody - Request body of including REST resource specific parameters.\n * @param searchParams - Search params, appended to the URL.\n * @param apiVersion - Admin API version.\n * @returns - The {@link RestResponse}.\n */\nexport async function restRequest<T>(\n method: string,\n path: string,\n session: AdminSession,\n requestBody?: T,\n searchParams: {[name: string]: string} = {},\n apiVersion = 'unstable',\n): Promise<RestResponse> {\n const url = restRequestUrl(session, apiVersion, path, searchParams)\n const body = restRequestBody<T>(requestBody)\n\n const headers = restRequestHeaders(session)\n const response = await shopifyFetch(url, {\n headers,\n method,\n body,\n })\n\n const json = await response.json().catch(() => ({}))\n\n return {\n json,\n status: response.status,\n headers: response.headers.raw(),\n }\n}\n\n/**\n * Respose of a REST request.\n */\nexport interface RestResponse {\n /**\n * REST JSON respose.\n */\n // Using `any` to avoid introducing extra DTO layers.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n json: any\n\n /**\n * HTTP response status.\n */\n status: number\n\n /**\n * HTTP response headers.\n */\n headers: {[key: string]: string[]}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { CacheOptions, GraphQLResponse } from './graphql.js';
1
+ import { CacheOptions, GraphQLResponse, UnauthorizedHandler } from './graphql.js';
2
2
  import { RequestModeInput } from '../http.js';
3
3
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
4
4
  import { Variables } from 'graphql-request';
@@ -21,9 +21,10 @@ export interface RequestOptions {
21
21
  * @param variables - GraphQL variables to pass to the query.
22
22
  * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
23
23
  * @param requestOptions - Preferred behaviour for the request.
24
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
24
25
  * @returns The response of the query of generic type <T>.
25
26
  */
26
- export declare function appManagementRequestDoc<TResult, TVariables extends Variables>(orgId: string, query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, cacheOptions?: CacheOptions, requestOptions?: RequestOptions): Promise<TResult>;
27
+ export declare function appManagementRequestDoc<TResult, TVariables extends Variables>(orgId: string, query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, cacheOptions?: CacheOptions, requestOptions?: RequestOptions, unauthorizedHandler?: UnauthorizedHandler): Promise<TResult>;
27
28
  /**
28
29
  * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)
29
30
  * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).
@@ -39,9 +39,10 @@ export const appManagementAppLogsUrl = async (organizationId, cursor, filters) =
39
39
  * @param variables - GraphQL variables to pass to the query.
40
40
  * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.
41
41
  * @param requestOptions - Preferred behaviour for the request.
42
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
42
43
  * @returns The response of the query of generic type <T>.
43
44
  */
44
- export async function appManagementRequestDoc(orgId, query, token, variables, cacheOptions, requestOptions) {
45
+ export async function appManagementRequestDoc(orgId, query, token, variables, cacheOptions, requestOptions, unauthorizedHandler) {
45
46
  // For app management, we need to cache the response based on the orgId.
46
47
  const cacheExtraKey = (cacheOptions?.cacheExtraKey ?? '') + orgId;
47
48
  const newCacheOptions = cacheOptions ? { ...cacheOptions, cacheExtraKey } : undefined;
@@ -51,6 +52,7 @@ export async function appManagementRequestDoc(orgId, query, token, variables, ca
51
52
  variables,
52
53
  cacheOptions: newCacheOptions,
53
54
  preferredBehaviour: requestOptions?.requestMode,
55
+ unauthorizedHandler,
54
56
  }));
55
57
  return result;
56
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"app-management.js","sourceRoot":"","sources":["../../../../src/public/node/api/app-management.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,iBAAiB,EAAC,MAAM,cAAc,CAAA;AAC7E,OAAO,EAAC,+BAA+B,EAAC,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAC,sBAAsB,EAAC,MAAM,qDAAqD,CAAA;AAC1F,OAAO,EAAC,YAAY,EAAC,MAAM,sCAAsC,CAAA;AAEjE,OAAO,UAAU,MAAM,YAAY,CAAA;AAInC,sEAAsE;AACtE,yEAAyE;AACzE,iDAAiD;AACjD,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC;IAC7B,OAAO,EAAE,GAAG;IACZ,aAAa,EAAE,EAAE;CAClB,CAAC,CAAA;AAEF,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,KAAa;IACtD,MAAM,GAAG,GAAG,gBAAgB,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAA;IACtC,MAAM,GAAG,GAAG,WAAW,IAAI,0CAA0C,KAAK,eAAe,CAAA;IACzF,OAAO;QACL,KAAK;QACL,GAAG;QACH,GAAG;QACH,eAAe,EAAE,EAAC,UAAU,EAAE,kBAAkB,EAAC;KAClD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAA2B,EAAE;IAC7E,OAAO,YAAY,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAC1C,cAAsB,EACtB,MAAe,EACf,OAGC,EACgB,EAAE;IACnB,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAA;IACtC,MAAM,GAAG,GAAG,WAAW,IAAI,0CAA0C,cAAc,gBAAgB,CAAA;IACnG,OAAO,+BAA+B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;AAC9D,CAAC,CAAA;AAMD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa,EACb,KAA6C,EAC7C,KAAa,EACb,SAAsB,EACtB,YAA2B,EAC3B,cAA+B;IAE/B,wEAAwE;IACxE,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,aAAa,IAAI,EAAE,CAAC,GAAG,KAAK,CAAA;IACjE,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,CAAC,EAAC,GAAG,YAAY,EAAE,aAAa,EAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEnF,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAU,KAAK,IAAI,EAAE,CAClD,iBAAiB,CAAsB;QACrC,GAAG,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACrC,KAAK;QACL,SAAS;QACT,YAAY,EAAE,eAAe;QAC7B,kBAAkB,EAAE,cAAc,EAAE,WAAW;KAChD,CAAC,CACH,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAI,QAA4B;IAChE,IAAI,CAAC,QAAQ,CAAC,UAAU;QAAE,OAAM;IAEhC,MAAM,gBAAgB,GAAW,EAAE,CAAA;IACnC,KAAK,MAAM,WAAW,IAAK,QAAQ,CAAC,UAA+B,CAAC,YAAY,EAAE,CAAC;QACjF,IAAI,WAAW,CAAC,kBAAkB,EAAE,CAAC;YACnC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAED,sBAAsB,CAAC,gBAAgB,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import {CacheOptions, GraphQLResponse, graphqlRequestDoc} from './graphql.js'\nimport {addCursorAndFiltersToAppLogsUrl} from './utilities.js'\nimport {appManagementFqdn} from '../context/fqdn.js'\nimport {setNextDeprecationDate} from '../../../private/node/context/deprecations-store.js'\nimport {buildHeaders} from '../../../private/node/api/headers.js'\nimport {RequestModeInput} from '../http.js'\nimport Bottleneck from 'bottleneck'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\nimport {Variables} from 'graphql-request'\n\n// API Rate limiter for partners API (Limit is 10 requests per second)\n// Jobs are launched every 150ms to add an extra 50ms margin per request.\n// Only 10 requests can be executed concurrently.\nconst limiter = new Bottleneck({\n minTime: 150,\n maxConcurrent: 10,\n})\n\nasync function setupRequest(orgId: string, token: string) {\n const api = 'App Management'\n const fqdn = await appManagementFqdn()\n const url = `https://${fqdn}/app_management/unstable/organizations/${orgId}/graphql.json`\n return {\n token,\n api,\n url,\n responseOptions: {onResponse: handleDeprecations},\n }\n}\n\nexport const appManagementHeaders = (token: string): {[key: string]: string} => {\n return buildHeaders(token)\n}\n\nexport const appManagementAppLogsUrl = async (\n organizationId: string,\n cursor?: string,\n filters?: {\n status?: string\n source?: string\n },\n): Promise<string> => {\n const fqdn = await appManagementFqdn()\n const url = `https://${fqdn}/app_management/unstable/organizations/${organizationId}/app_logs/poll`\n return addCursorAndFiltersToAppLogsUrl(url, cursor, filters)\n}\n\nexport interface RequestOptions {\n requestMode: RequestModeInput\n}\n\n/**\n * Executes an org-scoped GraphQL query against the App Management API. Uses typed documents.\n *\n * @param orgId - The organization ID.\n * @param query - GraphQL query to execute.\n * @param token - Partners token.\n * @param variables - GraphQL variables to pass to the query.\n * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.\n * @param requestOptions - Preferred behaviour for the request.\n * @returns The response of the query of generic type <T>.\n */\nexport async function appManagementRequestDoc<TResult, TVariables extends Variables>(\n orgId: string,\n query: TypedDocumentNode<TResult, TVariables>,\n token: string,\n variables?: TVariables,\n cacheOptions?: CacheOptions,\n requestOptions?: RequestOptions,\n): Promise<TResult> {\n // For app management, we need to cache the response based on the orgId.\n const cacheExtraKey = (cacheOptions?.cacheExtraKey ?? '') + orgId\n const newCacheOptions = cacheOptions ? {...cacheOptions, cacheExtraKey} : undefined\n\n const result = limiter.schedule<TResult>(async () =>\n graphqlRequestDoc<TResult, TVariables>({\n ...(await setupRequest(orgId, token)),\n query,\n variables,\n cacheOptions: newCacheOptions,\n preferredBehaviour: requestOptions?.requestMode,\n }),\n )\n\n return result\n}\n\ninterface Deprecation {\n supportedUntilDate?: string\n}\n\ninterface WithDeprecations {\n deprecations: Deprecation[]\n}\n\n/**\n * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)\n * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).\n *\n * @param response - The response of the query.\n */\nexport function handleDeprecations<T>(response: GraphQLResponse<T>): void {\n if (!response.extensions) return\n\n const deprecationDates: Date[] = []\n for (const deprecation of (response.extensions as WithDeprecations).deprecations) {\n if (deprecation.supportedUntilDate) {\n deprecationDates.push(new Date(deprecation.supportedUntilDate))\n }\n }\n\n setNextDeprecationDate(deprecationDates)\n}\n"]}
1
+ {"version":3,"file":"app-management.js","sourceRoot":"","sources":["../../../../src/public/node/api/app-management.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,iBAAiB,EAAC,MAAM,cAAc,CAAA;AAClG,OAAO,EAAC,+BAA+B,EAAC,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAC,sBAAsB,EAAC,MAAM,qDAAqD,CAAA;AAC1F,OAAO,EAAC,YAAY,EAAC,MAAM,sCAAsC,CAAA;AAEjE,OAAO,UAAU,MAAM,YAAY,CAAA;AAInC,sEAAsE;AACtE,yEAAyE;AACzE,iDAAiD;AACjD,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC;IAC7B,OAAO,EAAE,GAAG;IACZ,aAAa,EAAE,EAAE;CAClB,CAAC,CAAA;AAEF,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,KAAa;IACtD,MAAM,GAAG,GAAG,gBAAgB,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAA;IACtC,MAAM,GAAG,GAAG,WAAW,IAAI,0CAA0C,KAAK,eAAe,CAAA;IACzF,OAAO;QACL,KAAK;QACL,GAAG;QACH,GAAG;QACH,eAAe,EAAE,EAAC,UAAU,EAAE,kBAAkB,EAAC;KAClD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAA2B,EAAE;IAC7E,OAAO,YAAY,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAC1C,cAAsB,EACtB,MAAe,EACf,OAGC,EACgB,EAAE;IACnB,MAAM,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAA;IACtC,MAAM,GAAG,GAAG,WAAW,IAAI,0CAA0C,cAAc,gBAAgB,CAAA;IACnG,OAAO,+BAA+B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;AAC9D,CAAC,CAAA;AAMD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa,EACb,KAA6C,EAC7C,KAAa,EACb,SAAsB,EACtB,YAA2B,EAC3B,cAA+B,EAC/B,mBAAyC;IAEzC,wEAAwE;IACxE,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,aAAa,IAAI,EAAE,CAAC,GAAG,KAAK,CAAA;IACjE,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,CAAC,EAAC,GAAG,YAAY,EAAE,aAAa,EAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEnF,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAU,KAAK,IAAI,EAAE,CAClD,iBAAiB,CAAsB;QACrC,GAAG,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACrC,KAAK;QACL,SAAS;QACT,YAAY,EAAE,eAAe;QAC7B,kBAAkB,EAAE,cAAc,EAAE,WAAW;QAC/C,mBAAmB;KACpB,CAAC,CACH,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAI,QAA4B;IAChE,IAAI,CAAC,QAAQ,CAAC,UAAU;QAAE,OAAM;IAEhC,MAAM,gBAAgB,GAAW,EAAE,CAAA;IACnC,KAAK,MAAM,WAAW,IAAK,QAAQ,CAAC,UAA+B,CAAC,YAAY,EAAE,CAAC;QACjF,IAAI,WAAW,CAAC,kBAAkB,EAAE,CAAC;YACnC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAED,sBAAsB,CAAC,gBAAgB,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["import {CacheOptions, GraphQLResponse, UnauthorizedHandler, graphqlRequestDoc} from './graphql.js'\nimport {addCursorAndFiltersToAppLogsUrl} from './utilities.js'\nimport {appManagementFqdn} from '../context/fqdn.js'\nimport {setNextDeprecationDate} from '../../../private/node/context/deprecations-store.js'\nimport {buildHeaders} from '../../../private/node/api/headers.js'\nimport {RequestModeInput} from '../http.js'\nimport Bottleneck from 'bottleneck'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\nimport {Variables} from 'graphql-request'\n\n// API Rate limiter for partners API (Limit is 10 requests per second)\n// Jobs are launched every 150ms to add an extra 50ms margin per request.\n// Only 10 requests can be executed concurrently.\nconst limiter = new Bottleneck({\n minTime: 150,\n maxConcurrent: 10,\n})\n\nasync function setupRequest(orgId: string, token: string) {\n const api = 'App Management'\n const fqdn = await appManagementFqdn()\n const url = `https://${fqdn}/app_management/unstable/organizations/${orgId}/graphql.json`\n return {\n token,\n api,\n url,\n responseOptions: {onResponse: handleDeprecations},\n }\n}\n\nexport const appManagementHeaders = (token: string): {[key: string]: string} => {\n return buildHeaders(token)\n}\n\nexport const appManagementAppLogsUrl = async (\n organizationId: string,\n cursor?: string,\n filters?: {\n status?: string\n source?: string\n },\n): Promise<string> => {\n const fqdn = await appManagementFqdn()\n const url = `https://${fqdn}/app_management/unstable/organizations/${organizationId}/app_logs/poll`\n return addCursorAndFiltersToAppLogsUrl(url, cursor, filters)\n}\n\nexport interface RequestOptions {\n requestMode: RequestModeInput\n}\n\n/**\n * Executes an org-scoped GraphQL query against the App Management API. Uses typed documents.\n *\n * @param orgId - The organization ID.\n * @param query - GraphQL query to execute.\n * @param token - Partners token.\n * @param variables - GraphQL variables to pass to the query.\n * @param cacheOptions - Cache options for the request. If not present, the request will not be cached.\n * @param requestOptions - Preferred behaviour for the request.\n * @param unauthorizedHandler - Optional handler for unauthorized requests.\n * @returns The response of the query of generic type <T>.\n */\nexport async function appManagementRequestDoc<TResult, TVariables extends Variables>(\n orgId: string,\n query: TypedDocumentNode<TResult, TVariables>,\n token: string,\n variables?: TVariables,\n cacheOptions?: CacheOptions,\n requestOptions?: RequestOptions,\n unauthorizedHandler?: UnauthorizedHandler,\n): Promise<TResult> {\n // For app management, we need to cache the response based on the orgId.\n const cacheExtraKey = (cacheOptions?.cacheExtraKey ?? '') + orgId\n const newCacheOptions = cacheOptions ? {...cacheOptions, cacheExtraKey} : undefined\n\n const result = limiter.schedule<TResult>(async () =>\n graphqlRequestDoc<TResult, TVariables>({\n ...(await setupRequest(orgId, token)),\n query,\n variables,\n cacheOptions: newCacheOptions,\n preferredBehaviour: requestOptions?.requestMode,\n unauthorizedHandler,\n }),\n )\n\n return result\n}\n\ninterface Deprecation {\n supportedUntilDate?: string\n}\n\ninterface WithDeprecations {\n deprecations: Deprecation[]\n}\n\n/**\n * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)\n * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).\n *\n * @param response - The response of the query.\n */\nexport function handleDeprecations<T>(response: GraphQLResponse<T>): void {\n if (!response.extensions) return\n\n const deprecationDates: Date[] = []\n for (const deprecation of (response.extensions as WithDeprecations).deprecations) {\n if (deprecation.supportedUntilDate) {\n deprecationDates.push(new Date(deprecation.supportedUntilDate))\n }\n }\n\n setNextDeprecationDate(deprecationDates)\n}\n"]}
@@ -17,6 +17,19 @@ export interface CacheOptions {
17
17
  cacheExtraKey?: string;
18
18
  cacheStore?: LocalStorage<ConfSchema>;
19
19
  }
20
+ interface RefreshedTokenOnAuthorizedResponse {
21
+ token?: string;
22
+ }
23
+ export type RefreshTokenOnAuthorizedResponse = Promise<RefreshedTokenOnAuthorizedResponse>;
24
+ interface SimpleUnauthorizedHandler {
25
+ type: 'simple';
26
+ handler: () => Promise<void>;
27
+ }
28
+ interface TokenRefreshHandler {
29
+ type: 'token_refresh';
30
+ handler: () => RefreshTokenOnAuthorizedResponse;
31
+ }
32
+ export type UnauthorizedHandler = SimpleUnauthorizedHandler | TokenRefreshHandler;
20
33
  interface GraphQLRequestBaseOptions<TResult> {
21
34
  api: string;
22
35
  url: string;
@@ -31,7 +44,7 @@ interface GraphQLRequestBaseOptions<TResult> {
31
44
  export type GraphQLRequestOptions<T> = GraphQLRequestBaseOptions<T> & {
32
45
  query: RequestDocument;
33
46
  variables?: Variables;
34
- unauthorizedHandler?: () => Promise<void>;
47
+ unauthorizedHandler?: UnauthorizedHandler;
35
48
  requestBehaviour?: RequestModeInput;
36
49
  };
37
50
  export type GraphQLRequestDocOptions<TResult, TVariables> = GraphQLRequestBaseOptions<TResult> & {
@@ -39,7 +52,7 @@ export type GraphQLRequestDocOptions<TResult, TVariables> = GraphQLRequestBaseOp
39
52
  [key: string]: never;
40
53
  }>>;
41
54
  variables?: TVariables;
42
- unauthorizedHandler?: () => Promise<void>;
55
+ unauthorizedHandler?: UnauthorizedHandler;
43
56
  requestBehaviour?: RequestModeInput;
44
57
  };
45
58
  export interface GraphQLResponseOptions<T> {
@@ -8,6 +8,17 @@ import { cacheRetrieveOrRepopulate, timeIntervalToMilliseconds, } from '../../..
8
8
  import { abortSignalFromRequestBehaviour, requestMode } from '../http.js';
9
9
  import { GraphQLClient, resolveRequestDocument, ClientError, } from 'graphql-request';
10
10
  import { CLI_KIT_VERSION } from '@shopify/cli-kit/common/version';
11
+ async function createGraphQLClient({ url, addedHeaders, token, }) {
12
+ const headers = {
13
+ ...addedHeaders,
14
+ ...buildHeaders(token),
15
+ };
16
+ const clientOptions = { agent: await httpsAgent(), headers };
17
+ return {
18
+ client: new GraphQLClient(url, clientOptions),
19
+ headers,
20
+ };
21
+ }
11
22
  /**
12
23
  * Handles execution of a GraphQL query.
13
24
  *
@@ -15,15 +26,10 @@ import { CLI_KIT_VERSION } from '@shopify/cli-kit/common/version';
15
26
  */
16
27
  async function performGraphQLRequest(options) {
17
28
  const { token, addedHeaders, queryAsString, variables, api, url, responseOptions, unauthorizedHandler, cacheOptions } = options;
18
- const headers = {
19
- ...addedHeaders,
20
- ...buildHeaders(token),
21
- };
22
- debugLogRequestInfo(api, queryAsString, url, variables, headers);
23
29
  const requestBehaviour = requestMode(options.preferredBehaviour ?? 'default');
24
- const clientOptions = { agent: await httpsAgent(), headers };
25
- const client = new GraphQLClient(url, clientOptions);
26
- const performRequest = async () => {
30
+ let { headers, client } = await createGraphQLClient({ url, addedHeaders, token });
31
+ debugLogRequestInfo(api, queryAsString, url, variables, headers);
32
+ const rawGraphQLRequest = async () => {
27
33
  let fullResponse;
28
34
  // there is a errorPolicy option which returns rather than throwing on errors, but we _do_ ultimately want to
29
35
  // throw.
@@ -44,8 +50,45 @@ async function performGraphQLRequest(options) {
44
50
  throw error;
45
51
  }
46
52
  };
53
+ const simpleUnauthorizedHandler = unauthorizedHandler?.type === 'simple' ? unauthorizedHandler.handler : undefined;
54
+ const tokenRefreshHandler = unauthorizedHandler?.type === 'token_refresh' ? unauthorizedHandler.handler : undefined;
55
+ const tokenRefreshUnauthorizedHandlerFunction = tokenRefreshHandler
56
+ ? async () => {
57
+ const refreshTokenResult = await tokenRefreshHandler();
58
+ if (refreshTokenResult.token) {
59
+ const { client: newClient, headers: newHeaders } = await createGraphQLClient({
60
+ url,
61
+ addedHeaders,
62
+ token: refreshTokenResult.token,
63
+ });
64
+ client = newClient;
65
+ headers = newHeaders;
66
+ return true;
67
+ }
68
+ else {
69
+ return false;
70
+ }
71
+ }
72
+ : undefined;
73
+ const request = () => retryAwareRequest({ request: rawGraphQLRequest, url, ...requestBehaviour }, responseOptions?.handleErrors === false ? undefined : errorHandler(api), simpleUnauthorizedHandler);
47
74
  const executeWithTimer = () => runWithTimer('cmd_all_timing_network_ms')(async () => {
48
- const response = await retryAwareRequest({ request: performRequest, url, ...requestBehaviour }, responseOptions?.handleErrors === false ? undefined : errorHandler(api), unauthorizedHandler);
75
+ let response;
76
+ try {
77
+ response = await request();
78
+ }
79
+ catch (error) {
80
+ if (error instanceof ClientError && error.response.status === 401 && tokenRefreshUnauthorizedHandlerFunction) {
81
+ if (await tokenRefreshUnauthorizedHandlerFunction()) {
82
+ response = await request();
83
+ }
84
+ else {
85
+ throw error;
86
+ }
87
+ }
88
+ else {
89
+ throw error;
90
+ }
91
+ }
49
92
  if (responseOptions?.onResponse) {
50
93
  responseOptions.onResponse(response);
51
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/public/node/api/graphql.ts"],"names":[],"mappings":"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","sourcesContent":["import {buildHeaders, httpsAgent} from '../../../private/node/api/headers.js'\nimport {debugLogRequestInfo, errorHandler} from '../../../private/node/api/graphql.js'\nimport {addPublicMetadata, runWithTimer} from '../metadata.js'\nimport {retryAwareRequest} from '../../../private/node/api.js'\nimport {requestIdsCollection} from '../../../private/node/request-ids.js'\nimport {nonRandomUUID} from '../crypto.js'\nimport {\n cacheRetrieveOrRepopulate,\n ConfSchema,\n GraphQLRequestKey,\n TimeInterval,\n timeIntervalToMilliseconds,\n} from '../../../private/node/conf-store.js'\nimport {LocalStorage} from '../local-storage.js'\nimport {abortSignalFromRequestBehaviour, requestMode, RequestModeInput} from '../http.js'\nimport {\n GraphQLClient,\n rawRequest,\n RequestDocument,\n resolveRequestDocument,\n Variables,\n ClientError,\n} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\nimport {CLI_KIT_VERSION} from '@shopify/cli-kit/common/version'\n\n// to replace TVariable type when there graphql query has no variables\nexport type Exact<T extends {[key: string]: unknown}> = {[K in keyof T]: T[K]}\n\nexport interface GraphQLVariables {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\nexport type GraphQLResponse<T> = Awaited<ReturnType<typeof rawRequest<T>>>\n\nexport interface CacheOptions {\n cacheTTL: TimeInterval\n cacheExtraKey?: string\n cacheStore?: LocalStorage<ConfSchema>\n}\n\ninterface GraphQLRequestBaseOptions<TResult> {\n api: string\n url: string\n token?: string\n addedHeaders?: {[header: string]: string}\n responseOptions?: GraphQLResponseOptions<TResult>\n cacheOptions?: CacheOptions\n preferredBehaviour?: RequestModeInput\n}\n\ntype PerformGraphQLRequestOptions<TResult> = GraphQLRequestBaseOptions<TResult> & {\n queryAsString: string\n variables?: Variables\n unauthorizedHandler?: () => Promise<void>\n requestBehaviour?: RequestModeInput\n}\n\nexport type GraphQLRequestOptions<T> = GraphQLRequestBaseOptions<T> & {\n query: RequestDocument\n variables?: Variables\n unauthorizedHandler?: () => Promise<void>\n requestBehaviour?: RequestModeInput\n}\n\nexport type GraphQLRequestDocOptions<TResult, TVariables> = GraphQLRequestBaseOptions<TResult> & {\n query: TypedDocumentNode<TResult, TVariables> | TypedDocumentNode<TResult, Exact<{[key: string]: never}>>\n variables?: TVariables\n unauthorizedHandler?: () => Promise<void>\n requestBehaviour?: RequestModeInput\n}\n\nexport interface GraphQLResponseOptions<T> {\n handleErrors?: boolean\n onResponse?: (response: GraphQLResponse<T>) => void\n}\n\n/**\n * Handles execution of a GraphQL query.\n *\n * @param options - GraphQL request options.\n */\nasync function performGraphQLRequest<TResult>(options: PerformGraphQLRequestOptions<TResult>) {\n const {token, addedHeaders, queryAsString, variables, api, url, responseOptions, unauthorizedHandler, cacheOptions} =\n options\n const headers = {\n ...addedHeaders,\n ...buildHeaders(token),\n }\n\n debugLogRequestInfo(api, queryAsString, url, variables, headers)\n\n const requestBehaviour = requestMode(options.preferredBehaviour ?? 'default')\n\n const clientOptions = {agent: await httpsAgent(), headers}\n const client = new GraphQLClient(url, clientOptions)\n\n const performRequest = async () => {\n let fullResponse: GraphQLResponse<TResult>\n // there is a errorPolicy option which returns rather than throwing on errors, but we _do_ ultimately want to\n // throw.\n try {\n // mapping signal to any due to polyfill meaning types don't exactly match (but are functionally equivalent)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n client.requestConfig.signal = abortSignalFromRequestBehaviour(requestBehaviour) as any\n fullResponse = await client.rawRequest<TResult>(queryAsString, variables)\n await logLastRequestIdFromResponse(fullResponse)\n return fullResponse\n } catch (error) {\n if (error instanceof ClientError) {\n // error.response does have a headers property like a normal response, but it's not typed as such.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await logLastRequestIdFromResponse(error.response as any)\n }\n throw error\n }\n }\n\n const executeWithTimer = () =>\n runWithTimer('cmd_all_timing_network_ms')(async () => {\n const response = await retryAwareRequest(\n {request: performRequest, url, ...requestBehaviour},\n responseOptions?.handleErrors === false ? undefined : errorHandler(api),\n unauthorizedHandler,\n )\n\n if (responseOptions?.onResponse) {\n responseOptions.onResponse(response)\n }\n return response.data\n })\n\n // If there is no cache config for this query, just execute it and return the result.\n if (cacheOptions === undefined) {\n return executeWithTimer()\n }\n\n const {cacheTTL, cacheExtraKey, cacheStore} = cacheOptions\n\n // The cache key is a combination of the hashed query and variables, with an optional extra key provided by the user.\n const queryHash = nonRandomUUID(queryAsString)\n const variablesHash = nonRandomUUID(JSON.stringify(variables ?? {}))\n const cacheKey: GraphQLRequestKey = `q-${queryHash}-${variablesHash}-${CLI_KIT_VERSION}-${cacheExtraKey ?? ''}`\n\n const result = await cacheRetrieveOrRepopulate(\n cacheKey,\n async () => {\n const result = await executeWithTimer()\n return JSON.stringify(result)\n },\n timeIntervalToMilliseconds(cacheTTL),\n cacheStore,\n )\n\n return JSON.parse(result) as TResult\n}\n\nasync function logLastRequestIdFromResponse(response: GraphQLResponse<unknown>) {\n try {\n const requestId = response.headers.get('x-request-id')\n requestIdsCollection.addRequestId(requestId)\n await addPublicMetadata(() => ({\n cmd_all_last_graphql_request_id: requestId ?? undefined,\n }))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n // no problem if unable to get request ID.\n }\n}\n\n/**\n * Executes a GraphQL query to an endpoint.\n *\n * @param options - GraphQL request options.\n * @returns The response of the query of generic type <T>.\n */\nexport async function graphqlRequest<T>(options: GraphQLRequestOptions<T>): Promise<T> {\n return performGraphQLRequest<T>({\n ...options,\n queryAsString: options.query as string,\n })\n}\n\n/**\n * Executes a GraphQL query to an endpoint. Uses typed documents.\n *\n * @param options - GraphQL request options.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function graphqlRequestDoc<TResult, TVariables extends Variables>(\n options: GraphQLRequestDocOptions<TResult, TVariables>,\n): Promise<TResult> {\n return performGraphQLRequest<TResult>({\n ...options,\n queryAsString: resolveRequestDocument(options.query).query,\n })\n}\n"]}
1
+ {"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../../../src/public/node/api/graphql.ts"],"names":[],"mappings":"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","sourcesContent":["import {buildHeaders, httpsAgent} from '../../../private/node/api/headers.js'\nimport {debugLogRequestInfo, errorHandler} from '../../../private/node/api/graphql.js'\nimport {addPublicMetadata, runWithTimer} from '../metadata.js'\nimport {retryAwareRequest} from '../../../private/node/api.js'\nimport {requestIdsCollection} from '../../../private/node/request-ids.js'\nimport {nonRandomUUID} from '../crypto.js'\nimport {\n cacheRetrieveOrRepopulate,\n ConfSchema,\n GraphQLRequestKey,\n TimeInterval,\n timeIntervalToMilliseconds,\n} from '../../../private/node/conf-store.js'\nimport {LocalStorage} from '../local-storage.js'\nimport {abortSignalFromRequestBehaviour, requestMode, RequestModeInput} from '../http.js'\nimport {\n GraphQLClient,\n rawRequest,\n RequestDocument,\n resolveRequestDocument,\n Variables,\n ClientError,\n} from 'graphql-request'\nimport {TypedDocumentNode} from '@graphql-typed-document-node/core'\nimport {CLI_KIT_VERSION} from '@shopify/cli-kit/common/version'\n\n// to replace TVariable type when there graphql query has no variables\nexport type Exact<T extends {[key: string]: unknown}> = {[K in keyof T]: T[K]}\n\nexport interface GraphQLVariables {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\nexport type GraphQLResponse<T> = Awaited<ReturnType<typeof rawRequest<T>>>\n\nexport interface CacheOptions {\n cacheTTL: TimeInterval\n cacheExtraKey?: string\n cacheStore?: LocalStorage<ConfSchema>\n}\n\ninterface RefreshedTokenOnAuthorizedResponse {\n token?: string\n}\n\nexport type RefreshTokenOnAuthorizedResponse = Promise<RefreshedTokenOnAuthorizedResponse>\n\ninterface SimpleUnauthorizedHandler {\n type: 'simple'\n handler: () => Promise<void>\n}\n\ninterface TokenRefreshHandler {\n type: 'token_refresh'\n handler: () => RefreshTokenOnAuthorizedResponse\n}\n\nexport type UnauthorizedHandler = SimpleUnauthorizedHandler | TokenRefreshHandler\n\ninterface GraphQLRequestBaseOptions<TResult> {\n api: string\n url: string\n token?: string\n addedHeaders?: {[header: string]: string}\n responseOptions?: GraphQLResponseOptions<TResult>\n cacheOptions?: CacheOptions\n preferredBehaviour?: RequestModeInput\n}\n\ntype PerformGraphQLRequestOptions<TResult> = GraphQLRequestBaseOptions<TResult> & {\n queryAsString: string\n variables?: Variables\n unauthorizedHandler?: UnauthorizedHandler\n requestBehaviour?: RequestModeInput\n}\n\nexport type GraphQLRequestOptions<T> = GraphQLRequestBaseOptions<T> & {\n query: RequestDocument\n variables?: Variables\n unauthorizedHandler?: UnauthorizedHandler\n requestBehaviour?: RequestModeInput\n}\n\nexport type GraphQLRequestDocOptions<TResult, TVariables> = GraphQLRequestBaseOptions<TResult> & {\n query: TypedDocumentNode<TResult, TVariables> | TypedDocumentNode<TResult, Exact<{[key: string]: never}>>\n variables?: TVariables\n unauthorizedHandler?: UnauthorizedHandler\n requestBehaviour?: RequestModeInput\n}\n\nexport interface GraphQLResponseOptions<T> {\n handleErrors?: boolean\n onResponse?: (response: GraphQLResponse<T>) => void\n}\n\nasync function createGraphQLClient({\n url,\n addedHeaders,\n token,\n}: {\n url: string\n token: string | undefined\n addedHeaders?: {[header: string]: string}\n}) {\n const headers = {\n ...addedHeaders,\n ...buildHeaders(token),\n }\n const clientOptions = {agent: await httpsAgent(), headers}\n\n return {\n client: new GraphQLClient(url, clientOptions),\n headers,\n }\n}\n\n/**\n * Handles execution of a GraphQL query.\n *\n * @param options - GraphQL request options.\n */\nasync function performGraphQLRequest<TResult>(options: PerformGraphQLRequestOptions<TResult>) {\n const {token, addedHeaders, queryAsString, variables, api, url, responseOptions, unauthorizedHandler, cacheOptions} =\n options\n const requestBehaviour = requestMode(options.preferredBehaviour ?? 'default')\n\n let {headers, client} = await createGraphQLClient({url, addedHeaders, token})\n debugLogRequestInfo(api, queryAsString, url, variables, headers)\n\n const rawGraphQLRequest = async () => {\n let fullResponse: GraphQLResponse<TResult>\n // there is a errorPolicy option which returns rather than throwing on errors, but we _do_ ultimately want to\n // throw.\n try {\n // mapping signal to any due to polyfill meaning types don't exactly match (but are functionally equivalent)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n client.requestConfig.signal = abortSignalFromRequestBehaviour(requestBehaviour) as any\n fullResponse = await client.rawRequest<TResult>(queryAsString, variables)\n await logLastRequestIdFromResponse(fullResponse)\n return fullResponse\n } catch (error) {\n if (error instanceof ClientError) {\n // error.response does have a headers property like a normal response, but it's not typed as such.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await logLastRequestIdFromResponse(error.response as any)\n }\n throw error\n }\n }\n\n const simpleUnauthorizedHandler = unauthorizedHandler?.type === 'simple' ? unauthorizedHandler.handler : undefined\n const tokenRefreshHandler = unauthorizedHandler?.type === 'token_refresh' ? unauthorizedHandler.handler : undefined\n\n const tokenRefreshUnauthorizedHandlerFunction = tokenRefreshHandler\n ? async () => {\n const refreshTokenResult = await tokenRefreshHandler()\n if (refreshTokenResult.token) {\n const {client: newClient, headers: newHeaders} = await createGraphQLClient({\n url,\n addedHeaders,\n token: refreshTokenResult.token,\n })\n client = newClient\n headers = newHeaders\n return true\n } else {\n return false\n }\n }\n : undefined\n\n const request = () =>\n retryAwareRequest(\n {request: rawGraphQLRequest, url, ...requestBehaviour},\n responseOptions?.handleErrors === false ? undefined : errorHandler(api),\n simpleUnauthorizedHandler,\n )\n\n const executeWithTimer = () =>\n runWithTimer('cmd_all_timing_network_ms')(async () => {\n let response\n try {\n response = await request()\n } catch (error) {\n if (error instanceof ClientError && error.response.status === 401 && tokenRefreshUnauthorizedHandlerFunction) {\n if (await tokenRefreshUnauthorizedHandlerFunction()) {\n response = await request()\n } else {\n throw error\n }\n } else {\n throw error\n }\n }\n\n if (responseOptions?.onResponse) {\n responseOptions.onResponse(response)\n }\n return response.data\n })\n\n // If there is no cache config for this query, just execute it and return the result.\n if (cacheOptions === undefined) {\n return executeWithTimer()\n }\n\n const {cacheTTL, cacheExtraKey, cacheStore} = cacheOptions\n\n // The cache key is a combination of the hashed query and variables, with an optional extra key provided by the user.\n const queryHash = nonRandomUUID(queryAsString)\n const variablesHash = nonRandomUUID(JSON.stringify(variables ?? {}))\n const cacheKey: GraphQLRequestKey = `q-${queryHash}-${variablesHash}-${CLI_KIT_VERSION}-${cacheExtraKey ?? ''}`\n\n const result = await cacheRetrieveOrRepopulate(\n cacheKey,\n async () => {\n const result = await executeWithTimer()\n return JSON.stringify(result)\n },\n timeIntervalToMilliseconds(cacheTTL),\n cacheStore,\n )\n\n return JSON.parse(result) as TResult\n}\n\nasync function logLastRequestIdFromResponse(response: GraphQLResponse<unknown>) {\n try {\n const requestId = response.headers.get('x-request-id')\n requestIdsCollection.addRequestId(requestId)\n await addPublicMetadata(() => ({\n cmd_all_last_graphql_request_id: requestId ?? undefined,\n }))\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch {\n // no problem if unable to get request ID.\n }\n}\n\n/**\n * Executes a GraphQL query to an endpoint.\n *\n * @param options - GraphQL request options.\n * @returns The response of the query of generic type <T>.\n */\nexport async function graphqlRequest<T>(options: GraphQLRequestOptions<T>): Promise<T> {\n return performGraphQLRequest<T>({\n ...options,\n queryAsString: options.query as string,\n })\n}\n\n/**\n * Executes a GraphQL query to an endpoint. Uses typed documents.\n *\n * @param options - GraphQL request options.\n * @returns The response of the query of generic type <TResult>.\n */\nexport async function graphqlRequestDoc<TResult, TVariables extends Variables>(\n options: GraphQLRequestDocOptions<TResult, TVariables>,\n): Promise<TResult> {\n return performGraphQLRequest<TResult>({\n ...options,\n queryAsString: resolveRequestDocument(options.query).query,\n })\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { GraphQLVariables, GraphQLResponse, CacheOptions } from './graphql.js';
1
+ import { GraphQLVariables, GraphQLResponse, CacheOptions, UnauthorizedHandler } from './graphql.js';
2
2
  import { RequestModeInput } from '../http.js';
3
3
  import { Variables } from 'graphql-request';
4
4
  import { TypedDocumentNode } from '@graphql-typed-document-node/core';
@@ -10,9 +10,10 @@ import { TypedDocumentNode } from '@graphql-typed-document-node/core';
10
10
  * @param variables - GraphQL variables to pass to the query.
11
11
  * @param cacheOptions - Cache options.
12
12
  * @param preferredBehaviour - Preferred behaviour for the request.
13
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
13
14
  * @returns The response of the query of generic type <T>.
14
15
  */
15
- export declare function partnersRequest<T>(query: string, token: string, variables?: GraphQLVariables, cacheOptions?: CacheOptions, preferredBehaviour?: RequestModeInput): Promise<T>;
16
+ export declare function partnersRequest<T>(query: string, token: string, variables?: GraphQLVariables, cacheOptions?: CacheOptions, preferredBehaviour?: RequestModeInput, unauthorizedHandler?: UnauthorizedHandler): Promise<T>;
16
17
  export declare const generateFetchAppLogUrl: (cursor?: string, filters?: {
17
18
  status?: string;
18
19
  source?: string;
@@ -24,9 +25,10 @@ export declare const generateFetchAppLogUrl: (cursor?: string, filters?: {
24
25
  * @param token - Partners token.
25
26
  * @param variables - GraphQL variables to pass to the query.
26
27
  * @param preferredBehaviour - Preferred behaviour for the request.
28
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
27
29
  * @returns The response of the query of generic type <TResult>.
28
30
  */
29
- export declare function partnersRequestDoc<TResult, TVariables extends Variables>(query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, preferredBehaviour?: RequestModeInput): Promise<TResult>;
31
+ export declare function partnersRequestDoc<TResult, TVariables extends Variables>(query: TypedDocumentNode<TResult, TVariables>, token: string, variables?: TVariables, preferredBehaviour?: RequestModeInput, unauthorizedHandler?: UnauthorizedHandler): Promise<TResult>;
30
32
  /**
31
33
  * Sets the next deprecation date from [GraphQL response extensions](https://www.apollographql.com/docs/resources/graphql-glossary/#extensions)
32
34
  * if `response.extensions.deprecations` objects contain a `supportedUntilDate` (ISO 8601-formatted string).
@@ -1,4 +1,4 @@
1
- import { graphqlRequest, graphqlRequestDoc } from './graphql.js';
1
+ import { graphqlRequest, graphqlRequestDoc, } from './graphql.js';
2
2
  import { addCursorAndFiltersToAppLogsUrl } from './utilities.js';
3
3
  import { partnersFqdn } from '../context/fqdn.js';
4
4
  import { setNextDeprecationDate } from '../../../private/node/context/deprecations-store.js';
@@ -38,9 +38,10 @@ async function setupRequest(token) {
38
38
  * @param variables - GraphQL variables to pass to the query.
39
39
  * @param cacheOptions - Cache options.
40
40
  * @param preferredBehaviour - Preferred behaviour for the request.
41
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
41
42
  * @returns The response of the query of generic type <T>.
42
43
  */
43
- export async function partnersRequest(query, token, variables, cacheOptions, preferredBehaviour) {
44
+ export async function partnersRequest(query, token, variables, cacheOptions, preferredBehaviour, unauthorizedHandler) {
44
45
  const opts = await setupRequest(token);
45
46
  const result = limiter.schedule(() => graphqlRequest({
46
47
  ...opts,
@@ -48,6 +49,7 @@ export async function partnersRequest(query, token, variables, cacheOptions, pre
48
49
  variables,
49
50
  cacheOptions,
50
51
  preferredBehaviour,
52
+ unauthorizedHandler,
51
53
  }));
52
54
  return result;
53
55
  }
@@ -63,9 +65,10 @@ export const generateFetchAppLogUrl = async (cursor, filters) => {
63
65
  * @param token - Partners token.
64
66
  * @param variables - GraphQL variables to pass to the query.
65
67
  * @param preferredBehaviour - Preferred behaviour for the request.
68
+ * @param unauthorizedHandler - Optional handler for unauthorized requests.
66
69
  * @returns The response of the query of generic type <TResult>.
67
70
  */
68
- export async function partnersRequestDoc(query, token, variables, preferredBehaviour) {
71
+ export async function partnersRequestDoc(query, token, variables, preferredBehaviour, unauthorizedHandler) {
69
72
  try {
70
73
  const opts = await setupRequest(token);
71
74
  const result = limiter.schedule(() => graphqlRequestDoc({
@@ -73,6 +76,7 @@ export async function partnersRequestDoc(query, token, variables, preferredBehav
73
76
  query,
74
77
  variables,
75
78
  preferredBehaviour,
79
+ unauthorizedHandler,
76
80
  }));
77
81
  return result;
78
82
  // eslint-disable-next-line @typescript-eslint/no-explicit-any