@shopify/shopify-app-remix 4.0.5 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/server/adapters/node/index.js +0 -1
- package/dist/cjs/server/adapters/node/index.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/authenticate.js +0 -1
- package/dist/cjs/server/authenticate/admin/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/cancel.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/cancel.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/check.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/check.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/create-usage-record.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/create-usage-record.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/request.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/request.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/require.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/require.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/billing/update-usage-subscription-capped-amount.js +0 -1
- package/dist/cjs/server/authenticate/admin/billing/update-usage-subscription-capped-amount.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/auth-code-flow.js +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/auth-code-flow.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/merchant-custom-app.js +0 -1
- package/dist/cjs/server/authenticate/admin/strategies/merchant-custom-app.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/token-exchange.js +5 -2
- package/dist/cjs/server/authenticate/admin/strategies/token-exchange.js.map +1 -1
- package/dist/cjs/server/authenticate/flow/authenticate.js +5 -3
- package/dist/cjs/server/authenticate/flow/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/fulfillment-service/authenticate.js +3 -4
- package/dist/cjs/server/authenticate/fulfillment-service/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/public/appProxy/authenticate.js +5 -3
- package/dist/cjs/server/authenticate/public/appProxy/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/public/extension/authenticate.js +0 -1
- package/dist/cjs/server/authenticate/public/extension/authenticate.js.map +1 -1
- package/dist/cjs/server/authenticate/webhooks/authenticate.js +3 -3
- package/dist/cjs/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/dist/cjs/server/future/flags.js.map +1 -1
- package/dist/cjs/server/{authenticate/helpers → helpers}/create-or-load-offline-session.js +2 -2
- package/dist/cjs/server/helpers/create-or-load-offline-session.js.map +1 -0
- package/dist/cjs/server/helpers/ensure-offline-token-is-not-expired.js +23 -0
- package/dist/cjs/server/helpers/ensure-offline-token-is-not-expired.js.map +1 -0
- package/dist/cjs/server/helpers/ensure-valid-offline-session.js +14 -0
- package/dist/cjs/server/helpers/ensure-valid-offline-session.js.map +1 -0
- package/dist/cjs/server/helpers/refresh-token.js +31 -0
- package/dist/cjs/server/helpers/refresh-token.js.map +1 -0
- package/dist/cjs/server/unauthenticated/admin/factory.js +4 -2
- package/dist/cjs/server/unauthenticated/admin/factory.js.map +1 -1
- package/dist/cjs/server/unauthenticated/storefront/factory.js +4 -2
- package/dist/cjs/server/unauthenticated/storefront/factory.js.map +1 -1
- package/dist/cjs/server/version.js +1 -1
- package/dist/cjs/server/version.js.map +1 -1
- package/dist/esm/server/adapters/node/index.mjs +0 -1
- package/dist/esm/server/adapters/node/index.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/authenticate.mjs +0 -1
- package/dist/esm/server/authenticate/admin/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/cancel.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/cancel.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/check.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/check.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/create-usage-record.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/create-usage-record.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/request.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/request.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/require.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/require.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/billing/update-usage-subscription-capped-amount.mjs +0 -1
- package/dist/esm/server/authenticate/admin/billing/update-usage-subscription-capped-amount.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/auth-code-flow.mjs +1 -1
- package/dist/esm/server/authenticate/admin/strategies/auth-code-flow.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/merchant-custom-app.mjs +0 -1
- package/dist/esm/server/authenticate/admin/strategies/merchant-custom-app.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/token-exchange.mjs +5 -2
- package/dist/esm/server/authenticate/admin/strategies/token-exchange.mjs.map +1 -1
- package/dist/esm/server/authenticate/flow/authenticate.mjs +5 -3
- package/dist/esm/server/authenticate/flow/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/fulfillment-service/authenticate.mjs +3 -4
- package/dist/esm/server/authenticate/fulfillment-service/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/public/appProxy/authenticate.mjs +5 -3
- package/dist/esm/server/authenticate/public/appProxy/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/public/extension/authenticate.mjs +0 -1
- package/dist/esm/server/authenticate/public/extension/authenticate.mjs.map +1 -1
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs +3 -3
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs.map +1 -1
- package/dist/esm/server/future/flags.mjs.map +1 -1
- package/dist/esm/server/{authenticate/helpers → helpers}/create-or-load-offline-session.mjs +2 -2
- package/dist/esm/server/helpers/create-or-load-offline-session.mjs.map +1 -0
- package/dist/esm/server/helpers/ensure-offline-token-is-not-expired.mjs +20 -0
- package/dist/esm/server/helpers/ensure-offline-token-is-not-expired.mjs.map +1 -0
- package/dist/esm/server/helpers/ensure-valid-offline-session.mjs +12 -0
- package/dist/esm/server/helpers/ensure-valid-offline-session.mjs.map +1 -0
- package/dist/esm/server/helpers/refresh-token.mjs +27 -0
- package/dist/esm/server/helpers/refresh-token.mjs.map +1 -0
- package/dist/esm/server/unauthenticated/admin/factory.mjs +4 -2
- package/dist/esm/server/unauthenticated/admin/factory.mjs.map +1 -1
- package/dist/esm/server/unauthenticated/storefront/factory.mjs +4 -2
- package/dist/esm/server/unauthenticated/storefront/factory.mjs.map +1 -1
- package/dist/esm/server/version.mjs +1 -1
- package/dist/esm/server/version.mjs.map +1 -1
- package/dist/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/strategies/token-exchange.d.ts.map +1 -1
- package/dist/ts/server/authenticate/flow/authenticate.d.ts.map +1 -1
- package/dist/ts/server/authenticate/helpers/index.d.ts +0 -1
- package/dist/ts/server/authenticate/helpers/index.d.ts.map +1 -1
- package/dist/ts/server/authenticate/public/appProxy/authenticate.d.ts.map +1 -1
- package/dist/ts/server/future/flags.d.ts +8 -1
- package/dist/ts/server/future/flags.d.ts.map +1 -1
- package/dist/ts/server/helpers/create-or-load-offline-session.d.ts +3 -0
- package/dist/ts/server/helpers/create-or-load-offline-session.d.ts.map +1 -0
- package/dist/ts/server/helpers/ensure-offline-token-is-not-expired.d.ts +5 -0
- package/dist/ts/server/helpers/ensure-offline-token-is-not-expired.d.ts.map +1 -0
- package/dist/ts/server/helpers/ensure-valid-offline-session.d.ts +3 -0
- package/dist/ts/server/helpers/ensure-valid-offline-session.d.ts.map +1 -0
- package/dist/ts/server/helpers/index.d.ts +5 -0
- package/dist/ts/server/helpers/index.d.ts.map +1 -0
- package/dist/ts/server/helpers/refresh-token.d.ts +4 -0
- package/dist/ts/server/helpers/refresh-token.d.ts.map +1 -0
- package/dist/ts/server/unauthenticated/storefront/factory.d.ts.map +1 -1
- package/dist/ts/server/version.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/dist/cjs/server/authenticate/helpers/create-or-load-offline-session.js.map +0 -1
- package/dist/esm/server/authenticate/helpers/create-or-load-offline-session.mjs.map +0 -1
- package/dist/ts/server/authenticate/helpers/create-or-load-offline-session.d.ts +0 -3
- package/dist/ts/server/authenticate/helpers/create-or-load-offline-session.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-code-flow.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/auth-code-flow.ts"],"sourcesContent":["import {\n CookieNotFound,\n GraphqlQueryError,\n HttpResponseError,\n InvalidHmacError,\n InvalidOAuthError,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n beginAuth,\n handleClientErrorFactory,\n redirectToAuthPage,\n redirectToShopifyOrAppRoot,\n redirectWithExitIframe,\n triggerAfterAuthHook,\n validateShopAndHostParams,\n} from '../helpers';\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {getSessionTokenHeader} from '../../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class AuthCodeFlowStrategy<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void | never> {\n const {api, config} = this;\n\n const url = new URL(request.url);\n const isAuthRequest = url.pathname === config.auth.path;\n const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;\n\n if (isAuthRequest || isAuthCallbackRequest) {\n const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!);\n if (!shop) throw new Response('Shop param is invalid', {status: 400});\n\n if (isAuthRequest) {\n throw await this.handleAuthBeginRequest(request, shop);\n } else {\n throw await this.handleAuthCallbackRequest(request, shop);\n }\n }\n\n if (!getSessionTokenHeader(request)) {\n // This is a document request that doesn't contain a session token. We check if the app is installed.\n // If the app isn't installed, we initiate the OAuth auth code flow.\n // Requests with a header can only happen after the app is installed.\n await this.ensureInstalledOnShop(request);\n }\n }\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {api, config, logger} = this;\n\n const {shop, session} = sessionContext;\n\n if (!session) {\n logger.debug('No session found, redirecting to OAuth', {shop});\n await redirectToAuthPage({config, logger, api}, request, shop);\n } else if (!session.isActive(config.scopes)) {\n logger.debug(\n 'Found a session, but it has expired, redirecting to OAuth',\n {shop},\n );\n await redirectToAuthPage({config, logger, api}, request, shop);\n }\n\n logger.debug('Found a valid session', {shop});\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n throw await redirectToAuthPage(\n {api, config, logger},\n request,\n session.shop,\n );\n }\n },\n });\n }\n\n private async ensureInstalledOnShop(request: Request) {\n const {api, config, logger} = this;\n\n validateShopAndHostParams({api, config, logger}, request);\n\n const url = new URL(request.url);\n let shop = url.searchParams.get('shop');\n\n // Ensure app is installed\n logger.debug('Ensuring app is installed on shop', {shop});\n\n if (!(await this.hasValidOfflineId(request))) {\n logger.info(\"Could not find a shop, can't authenticate request\");\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const offlineSession = await this.getOfflineSession(request);\n const isEmbedded = url.searchParams.get('embedded') === '1';\n\n if (!offlineSession) {\n logger.info(\"Shop hasn't installed app yet, redirecting to OAuth\", {\n shop,\n });\n if (isEmbedded) {\n redirectWithExitIframe({api, config, logger}, request, shop!);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop!);\n }\n }\n\n shop = shop || offlineSession.shop;\n\n if (config.isEmbeddedApp && !isEmbedded) {\n try {\n logger.debug('Ensuring offline session is valid before embedding', {\n shop,\n });\n await this.testSession(offlineSession);\n\n logger.debug('Offline session is still valid, embedding app', {shop});\n } catch (error) {\n await this.handleInvalidOfflineSession(error, request, shop);\n }\n }\n }\n\n private async handleAuthBeginRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth begin request', {shop});\n\n // If we're loading from an iframe, we need to break out of it\n if (\n config.isEmbeddedApp &&\n request.headers.get('Sec-Fetch-Dest') === 'iframe'\n ) {\n logger.debug('Auth request in iframe detected, exiting iframe', {shop});\n throw redirectWithExitIframe({api, config, logger}, request, shop);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop);\n }\n }\n\n private async handleAuthCallbackRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth callback request', {shop});\n\n try {\n const {session, headers: responseHeaders} = await api.auth.callback({\n rawRequest: request,\n });\n\n await config.sessionStorage!.storeSession(session);\n\n if (config.useOnlineTokens && !session.isOnline) {\n logger.info('Requesting online access token for offline session', {\n shop,\n });\n await beginAuth({api, config, logger}, request, true, shop);\n }\n\n logger.debug('Request is valid, loaded session from OAuth callback', {\n shop: session.shop,\n isOnline: session.isOnline,\n });\n\n await triggerAfterAuthHook({api, config, logger}, session, request, this);\n\n throw await redirectToShopifyOrAppRoot(\n request,\n {api, config, logger},\n responseHeaders,\n );\n } catch (error) {\n if (error instanceof Response) throw error;\n\n throw await this.oauthCallbackError(error, request, shop);\n }\n }\n\n private async getOfflineSession(\n request: Request,\n ): Promise<Session | undefined> {\n const offlineId = await this.getOfflineSessionId(request);\n return this.config.sessionStorage!.loadSession(offlineId!);\n }\n\n private async hasValidOfflineId(request: Request) {\n return Boolean(await this.getOfflineSessionId(request));\n }\n\n private async getOfflineSessionId(\n request: Request,\n ): Promise<string | undefined> {\n const {api} = this;\n const url = new URL(request.url);\n const shop = url.searchParams.get('shop');\n\n return shop\n ? api.session.getOfflineId(shop)\n : api.session.getCurrentId({isOnline: false, rawRequest: request});\n }\n\n private async testSession(session: Session): Promise<void> {\n const {api} = this;\n\n const client = new api.clients.Graphql({\n session,\n });\n\n await client.request(`#graphql\n query shopifyAppShopName {\n shop {\n name\n }\n }\n `);\n }\n\n private async oauthCallbackError(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {logger} = this;\n logger.error('Error during OAuth callback', {shop, error: error.message});\n\n if (error instanceof CookieNotFound) {\n return this.handleAuthBeginRequest(request, shop);\n }\n\n if (\n error instanceof InvalidHmacError ||\n error instanceof InvalidOAuthError\n ) {\n return new Response(undefined, {\n status: 400,\n statusText: 'Invalid OAuth Request',\n });\n }\n\n return new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n private async handleInvalidOfflineSession(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {api, logger, config} = this;\n if (error instanceof HttpResponseError) {\n if (error.response.code === 401) {\n logger.info('Shop session is no longer valid, redirecting to OAuth', {\n shop,\n });\n throw await beginAuth({api, config, logger}, request, false, shop);\n } else {\n const message = JSON.stringify(error.response.body, null, 2);\n logger.error(`Unexpected error during session validation: ${message}`, {\n shop,\n });\n\n throw new Response(undefined, {\n status: error.response.code,\n statusText: error.response.statusText,\n });\n }\n } else if (error instanceof GraphqlQueryError) {\n const context: Record<string, string> = {shop};\n if (error.response) {\n context.response = JSON.stringify(error.body);\n }\n\n logger.error(\n `Unexpected error during session validation: ${error.message}`,\n context,\n );\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth-code-flow.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/auth-code-flow.ts"],"sourcesContent":["import {\n CookieNotFound,\n GraphqlQueryError,\n HttpResponseError,\n InvalidHmacError,\n InvalidOAuthError,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n beginAuth,\n handleClientErrorFactory,\n redirectToAuthPage,\n redirectToShopifyOrAppRoot,\n redirectWithExitIframe,\n triggerAfterAuthHook,\n validateShopAndHostParams,\n} from '../helpers';\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {getSessionTokenHeader} from '../../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class AuthCodeFlowStrategy<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void | never> {\n const {api, config} = this;\n\n const url = new URL(request.url);\n const isAuthRequest = url.pathname === config.auth.path;\n const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;\n\n if (isAuthRequest || isAuthCallbackRequest) {\n const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!);\n if (!shop) throw new Response('Shop param is invalid', {status: 400});\n\n if (isAuthRequest) {\n throw await this.handleAuthBeginRequest(request, shop);\n } else {\n throw await this.handleAuthCallbackRequest(request, shop);\n }\n }\n\n if (!getSessionTokenHeader(request)) {\n // This is a document request that doesn't contain a session token. We check if the app is installed.\n // If the app isn't installed, we initiate the OAuth auth code flow.\n // Requests with a header can only happen after the app is installed.\n await this.ensureInstalledOnShop(request);\n }\n }\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {api, config, logger} = this;\n\n const {shop, session} = sessionContext;\n\n if (!session) {\n logger.debug('No session found, redirecting to OAuth', {shop});\n await redirectToAuthPage({config, logger, api}, request, shop);\n } else if (!session.isActive(config.scopes)) {\n logger.debug(\n 'Found a session, but it has expired, redirecting to OAuth',\n {shop},\n );\n await redirectToAuthPage({config, logger, api}, request, shop);\n }\n\n logger.debug('Found a valid session', {shop});\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n throw await redirectToAuthPage(\n {api, config, logger},\n request,\n session.shop,\n );\n }\n },\n });\n }\n\n private async ensureInstalledOnShop(request: Request) {\n const {api, config, logger} = this;\n\n validateShopAndHostParams({api, config, logger}, request);\n\n const url = new URL(request.url);\n let shop = url.searchParams.get('shop');\n\n // Ensure app is installed\n logger.debug('Ensuring app is installed on shop', {shop});\n\n if (!(await this.hasValidOfflineId(request))) {\n logger.info(\"Could not find a shop, can't authenticate request\");\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const offlineSession = await this.getOfflineSession(request);\n const isEmbedded = url.searchParams.get('embedded') === '1';\n\n if (!offlineSession) {\n logger.info(\"Shop hasn't installed app yet, redirecting to OAuth\", {\n shop,\n });\n if (isEmbedded) {\n redirectWithExitIframe({api, config, logger}, request, shop!);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop!);\n }\n }\n\n shop = shop || offlineSession.shop;\n\n if (config.isEmbeddedApp && !isEmbedded) {\n try {\n logger.debug('Ensuring offline session is valid before embedding', {\n shop,\n });\n await this.testSession(offlineSession);\n\n logger.debug('Offline session is still valid, embedding app', {shop});\n } catch (error) {\n await this.handleInvalidOfflineSession(error, request, shop);\n }\n }\n }\n\n private async handleAuthBeginRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth begin request', {shop});\n\n // If we're loading from an iframe, we need to break out of it\n if (\n config.isEmbeddedApp &&\n request.headers.get('Sec-Fetch-Dest') === 'iframe'\n ) {\n logger.debug('Auth request in iframe detected, exiting iframe', {shop});\n throw redirectWithExitIframe({api, config, logger}, request, shop);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop);\n }\n }\n\n private async handleAuthCallbackRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth callback request', {shop});\n\n try {\n const {session, headers: responseHeaders} = await api.auth.callback({\n rawRequest: request,\n expiring: config.future.expiringOfflineAccessTokens,\n });\n\n await config.sessionStorage!.storeSession(session);\n\n if (config.useOnlineTokens && !session.isOnline) {\n logger.info('Requesting online access token for offline session', {\n shop,\n });\n await beginAuth({api, config, logger}, request, true, shop);\n }\n\n logger.debug('Request is valid, loaded session from OAuth callback', {\n shop: session.shop,\n isOnline: session.isOnline,\n });\n\n await triggerAfterAuthHook({api, config, logger}, session, request, this);\n\n throw await redirectToShopifyOrAppRoot(\n request,\n {api, config, logger},\n responseHeaders,\n );\n } catch (error) {\n if (error instanceof Response) throw error;\n\n throw await this.oauthCallbackError(error, request, shop);\n }\n }\n\n private async getOfflineSession(\n request: Request,\n ): Promise<Session | undefined> {\n const offlineId = await this.getOfflineSessionId(request);\n return this.config.sessionStorage!.loadSession(offlineId!);\n }\n\n private async hasValidOfflineId(request: Request) {\n return Boolean(await this.getOfflineSessionId(request));\n }\n\n private async getOfflineSessionId(\n request: Request,\n ): Promise<string | undefined> {\n const {api} = this;\n const url = new URL(request.url);\n const shop = url.searchParams.get('shop');\n\n return shop\n ? api.session.getOfflineId(shop)\n : api.session.getCurrentId({isOnline: false, rawRequest: request});\n }\n\n private async testSession(session: Session): Promise<void> {\n const {api} = this;\n\n const client = new api.clients.Graphql({\n session,\n });\n\n await client.request(`#graphql\n query shopifyAppShopName {\n shop {\n name\n }\n }\n `);\n }\n\n private async oauthCallbackError(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {logger} = this;\n logger.error('Error during OAuth callback', {shop, error: error.message});\n\n if (error instanceof CookieNotFound) {\n return this.handleAuthBeginRequest(request, shop);\n }\n\n if (\n error instanceof InvalidHmacError ||\n error instanceof InvalidOAuthError\n ) {\n return new Response(undefined, {\n status: 400,\n statusText: 'Invalid OAuth Request',\n });\n }\n\n return new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n private async handleInvalidOfflineSession(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {api, logger, config} = this;\n if (error instanceof HttpResponseError) {\n if (error.response.code === 401) {\n logger.info('Shop session is no longer valid, redirecting to OAuth', {\n shop,\n });\n throw await beginAuth({api, config, logger}, request, false, shop);\n } else {\n const message = JSON.stringify(error.response.body, null, 2);\n logger.error(`Unexpected error during session validation: ${message}`, {\n shop,\n });\n\n throw new Response(undefined, {\n status: error.response.code,\n statusText: error.response.statusText,\n });\n }\n } else if (error instanceof GraphqlQueryError) {\n const context: Record<string, string> = {shop};\n if (error.response) {\n context.response = JSON.stringify(error.body);\n }\n\n logger.error(\n `Unexpected error during session validation: ${error.message}`,\n context,\n );\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ import '@remix-run/server-runtime';
|
|
|
3
3
|
import { handleClientErrorFactory } from '../helpers/handle-client-error.mjs';
|
|
4
4
|
import { getShopFromRequest } from '../../helpers/get-shop-from-request.mjs';
|
|
5
5
|
import 'isbot';
|
|
6
|
-
import '../../../types.mjs';
|
|
7
6
|
|
|
8
7
|
class MerchantCustomAuth {
|
|
9
8
|
api;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merchant-custom-app.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/merchant-custom-app.ts"],"sourcesContent":["import {Session, Shopify, ShopifyError} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {ApiConfigWithFutureFlags, ApiFutureFlags} from '../../../future/flags';\nimport {HandleAdminClientError} from '../../../clients';\nimport {handleClientErrorFactory} from '../helpers';\nimport {getShopFromRequest} from '../../helpers';\n\nimport {AuthorizationStrategy, OnErrorOptions, SessionContext} from './types';\n\nexport class MerchantCustomAuth<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void> {\n this.logger.debug('Skipping OAuth request for merchant custom app', {\n shop: getShopFromRequest(request),\n });\n }\n\n public async authenticate(\n _request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {shop} = sessionContext;\n\n this.logger.debug(\n 'Building session from configured access token for merchant custom app',\n {shop},\n );\n const session = this.api.session.customAppSession(shop);\n\n return session;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n return handleClientErrorFactory({\n request,\n onError: async ({error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n this.logger.info(\n 'Request failed with 401. Review your API credentials or generate new tokens. https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/generate-app-access-tokens-admin#rotating-api-credentials-for-admin-created-apps ',\n );\n throw new ShopifyError(\n 'Unauthorized: Access token has been revoked.',\n );\n }\n },\n });\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"merchant-custom-app.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/merchant-custom-app.ts"],"sourcesContent":["import {Session, Shopify, ShopifyError} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {ApiConfigWithFutureFlags, ApiFutureFlags} from '../../../future/flags';\nimport {HandleAdminClientError} from '../../../clients';\nimport {handleClientErrorFactory} from '../helpers';\nimport {getShopFromRequest} from '../../helpers';\n\nimport {AuthorizationStrategy, OnErrorOptions, SessionContext} from './types';\n\nexport class MerchantCustomAuth<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void> {\n this.logger.debug('Skipping OAuth request for merchant custom app', {\n shop: getShopFromRequest(request),\n });\n }\n\n public async authenticate(\n _request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {shop} = sessionContext;\n\n this.logger.debug(\n 'Building session from configured access token for merchant custom app',\n {shop},\n );\n const session = this.api.session.customAppSession(shop);\n\n return session;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n return handleClientErrorFactory({\n request,\n onError: async ({error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n this.logger.info(\n 'Request failed with 401. Review your API credentials or generate new tokens. https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/generate-app-access-tokens-admin#rotating-api-credentials-for-admin-created-apps ',\n );\n throw new ShopifyError(\n 'Unauthorized: Access token has been revoked.',\n );\n }\n },\n });\n }\n}\n"],"names":[],"mappings":";;;;;;MAWa,kBAAkB,CAAA;AAGnB,IAAA,GAAG;AAKH,IAAA,MAAM;AACN,IAAA,MAAM;AAEhB,IAAA,WAAA,CAAmB,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAgC,EAAA;AACrE,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACtB;IAEO,MAAM,sBAAsB,CAAC,OAAgB,EAAA;AAClD,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gDAAgD,EAAE;AAClE,YAAA,IAAI,EAAE,kBAAkB,CAAC,OAAO,CAAC;AAClC,SAAA,CAAC;IACJ;AAEO,IAAA,MAAM,YAAY,CACvB,QAAiB,EACjB,cAA8B,EAAA;AAE9B,QAAA,MAAM,EAAC,IAAI,EAAC,GAAG,cAAc;QAE7B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,uEAAuE,EACvE,EAAC,IAAI,EAAC,CACP;AACD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC;AAEvD,QAAA,OAAO,OAAO;IAChB;AAEO,IAAA,iBAAiB,CAAC,OAAgB,EAAA;AACvC,QAAA,OAAO,wBAAwB,CAAC;YAC9B,OAAO;AACP,YAAA,OAAO,EAAE,OAAO,EAAC,KAAK,EAAiB,KAAI;gBACzC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG,EAAE;AAC/B,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,oPAAoP,CACrP;AACD,oBAAA,MAAM,IAAI,YAAY,CACpB,8CAA8C,CAC/C;gBACH;YACF,CAAC;AACF,SAAA,CAAC;IACJ;AACD;;;;"}
|
|
@@ -3,10 +3,11 @@ import { respondToInvalidSessionToken } from '../../helpers/respond-to-invalid-s
|
|
|
3
3
|
import { getShopFromRequest } from '../../helpers/get-shop-from-request.mjs';
|
|
4
4
|
import { invalidateAccessToken } from '../../helpers/invalidate-access-token.mjs';
|
|
5
5
|
import 'isbot';
|
|
6
|
-
import '../../../types.mjs';
|
|
7
6
|
import '@remix-run/server-runtime';
|
|
8
7
|
import { handleClientErrorFactory } from '../helpers/handle-client-error.mjs';
|
|
9
8
|
import { triggerAfterAuthHook } from '../helpers/trigger-after-auth-hook.mjs';
|
|
9
|
+
import '../../../types.mjs';
|
|
10
|
+
import { WITHIN_MILLISECONDS_OF_EXPIRY } from '../../../helpers/ensure-offline-token-is-not-expired.mjs';
|
|
10
11
|
|
|
11
12
|
class TokenExchangeStrategy {
|
|
12
13
|
api;
|
|
@@ -23,7 +24,8 @@ class TokenExchangeStrategy {
|
|
|
23
24
|
const { shop, session, sessionToken } = sessionContext;
|
|
24
25
|
if (!sessionToken)
|
|
25
26
|
throw new InvalidJwtError();
|
|
26
|
-
if (!session ||
|
|
27
|
+
if (!session ||
|
|
28
|
+
!session.isActive(undefined, WITHIN_MILLISECONDS_OF_EXPIRY)) {
|
|
27
29
|
logger.info('No valid session found', { shop });
|
|
28
30
|
logger.info('Requesting offline access token', { shop });
|
|
29
31
|
const { session: offlineSession } = await this.exchangeToken({
|
|
@@ -90,6 +92,7 @@ class TokenExchangeStrategy {
|
|
|
90
92
|
sessionToken,
|
|
91
93
|
shop,
|
|
92
94
|
requestedTokenType,
|
|
95
|
+
expiring: config.future.expiringOfflineAccessTokens,
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-exchange.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/token-exchange.ts"],"sourcesContent":["import {\n HttpResponseError,\n InvalidJwtError,\n RequestedTokenType,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n respondToInvalidSessionToken,\n invalidateAccessToken,\n getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class TokenExchangeStrategy<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(_request: Request): Promise<void> {}\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session> {\n const {api, config, logger} = this;\n const {shop, session, sessionToken} = sessionContext;\n\n if (!sessionToken) throw new InvalidJwtError();\n\n if (!session
|
|
1
|
+
{"version":3,"file":"token-exchange.mjs","sources":["../../../../../../../src/server/authenticate/admin/strategies/token-exchange.ts"],"sourcesContent":["import {\n HttpResponseError,\n InvalidJwtError,\n RequestedTokenType,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n respondToInvalidSessionToken,\n invalidateAccessToken,\n getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\nimport {WITHIN_MILLISECONDS_OF_EXPIRY} from '../../../helpers';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class TokenExchangeStrategy<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(_request: Request): Promise<void> {}\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session> {\n const {api, config, logger} = this;\n const {shop, session, sessionToken} = sessionContext;\n\n if (!sessionToken) throw new InvalidJwtError();\n\n if (\n !session ||\n !session.isActive(undefined, WITHIN_MILLISECONDS_OF_EXPIRY)\n ) {\n logger.info('No valid session found', {shop});\n logger.info('Requesting offline access token', {shop});\n const {session: offlineSession} = await this.exchangeToken({\n request,\n sessionToken,\n shop,\n requestedTokenType: RequestedTokenType.OfflineAccessToken,\n });\n\n await config.sessionStorage!.storeSession(offlineSession);\n\n let newSession = offlineSession;\n\n if (config.useOnlineTokens) {\n logger.info('Requesting online access token', {shop});\n const {session: onlineSession} = await this.exchangeToken({\n request,\n sessionToken,\n shop,\n requestedTokenType: RequestedTokenType.OnlineAccessToken,\n });\n\n await config.sessionStorage!.storeSession(onlineSession);\n newSession = onlineSession;\n }\n\n logger.debug('Request is valid, loaded session from session token', {\n shop: newSession.shop,\n isOnline: newSession.isOnline,\n });\n\n try {\n await this.handleAfterAuthHook(\n {api, config, logger},\n newSession,\n request,\n sessionToken,\n );\n } catch (errorOrResponse) {\n if (errorOrResponse instanceof Response) {\n throw errorOrResponse;\n }\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n return newSession;\n }\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n logger.debug('Responding to invalid access token', {\n shop: getShopFromRequest(request),\n });\n await invalidateAccessToken({config, api, logger}, session);\n\n respondToInvalidSessionToken({\n params: {config, api, logger},\n request,\n });\n }\n },\n });\n }\n\n private async exchangeToken({\n request,\n shop,\n sessionToken,\n requestedTokenType,\n }: {\n request: Request;\n shop: string;\n sessionToken: string;\n requestedTokenType: RequestedTokenType;\n }): Promise<{session: Session}> {\n const {api, config, logger} = this;\n\n try {\n return await api.auth.tokenExchange({\n sessionToken,\n shop,\n requestedTokenType,\n expiring: config.future.expiringOfflineAccessTokens,\n });\n } catch (error) {\n if (\n error instanceof InvalidJwtError ||\n (error instanceof HttpResponseError &&\n error.response.code === 400 &&\n error.response.body?.error === 'invalid_subject_token')\n ) {\n throw respondToInvalidSessionToken({\n params: {api, config, logger},\n request,\n retryRequest: true,\n });\n }\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n\n private async handleAfterAuthHook(\n params: BasicParams,\n session: Session,\n request: Request,\n sessionToken: string,\n ) {\n const {config} = params;\n await config.idempotentPromiseHandler.handlePromise({\n promiseFunction: () => {\n return triggerAfterAuthHook(params, session, request, this);\n },\n identifier: sessionToken,\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { adminClientFactory } from '../../clients/admin/factory.mjs';
|
|
2
|
+
import { ensureValidOfflineSession } from '../../helpers/ensure-valid-offline-session.mjs';
|
|
3
|
+
import '../../types.mjs';
|
|
4
|
+
import '@shopify/shopify-api';
|
|
2
5
|
|
|
3
6
|
function authenticateFlowFactory(params) {
|
|
4
|
-
const { api,
|
|
7
|
+
const { api, logger } = params;
|
|
5
8
|
return async function authenticate(request) {
|
|
6
9
|
logger.info('Authenticating flow request');
|
|
7
10
|
if (request.method !== 'POST') {
|
|
@@ -27,8 +30,7 @@ function authenticateFlowFactory(params) {
|
|
|
27
30
|
logger.debug('Flow request is valid, looking for an offline session', {
|
|
28
31
|
shop: payload.shopify_domain,
|
|
29
32
|
});
|
|
30
|
-
const
|
|
31
|
-
const session = await config.sessionStorage.loadSession(sessionId);
|
|
33
|
+
const session = await ensureValidOfflineSession(params, payload.shopify_domain);
|
|
32
34
|
if (!session) {
|
|
33
35
|
logger.info('Flow request could not find session', {
|
|
34
36
|
shop: payload.shopify_domain,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/flow/authenticate.ts"],"sourcesContent":["import {adminClientFactory} from '../../clients/admin';\nimport {BasicParams} from '../../types';\n\nimport type {AuthenticateFlow, FlowContext} from './types';\n\nexport function authenticateFlowFactory(params: BasicParams): AuthenticateFlow {\n const {api,
|
|
1
|
+
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/flow/authenticate.ts"],"sourcesContent":["import {adminClientFactory} from '../../clients/admin';\nimport {ensureValidOfflineSession} from '../../helpers';\nimport {BasicParams} from '../../types';\n\nimport type {AuthenticateFlow, FlowContext} from './types';\n\nexport function authenticateFlowFactory(params: BasicParams): AuthenticateFlow {\n const {api, logger} = params;\n\n return async function authenticate(request: Request): Promise<FlowContext> {\n logger.info('Authenticating flow request');\n\n if (request.method !== 'POST') {\n logger.debug(\n 'Received a non-POST request for flow. Only POST requests are allowed.',\n {url: request.url, method: request.method},\n );\n throw new Response(undefined, {\n status: 405,\n statusText: 'Method not allowed',\n });\n }\n\n const rawBody = await request.text();\n const result = await api.flow.validate({\n rawBody,\n rawRequest: request,\n });\n\n if (!result.valid) {\n logger.error('Received an invalid flow request', {reason: result.reason});\n\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const payload = JSON.parse(rawBody);\n\n logger.debug('Flow request is valid, looking for an offline session', {\n shop: payload.shopify_domain,\n });\n\n const session = await ensureValidOfflineSession(\n params,\n payload.shopify_domain,\n );\n\n if (!session) {\n logger.info('Flow request could not find session', {\n shop: payload.shopify_domain,\n });\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n logger.debug('Found a session for the flow request', {shop: session.shop});\n\n return {\n session,\n payload,\n admin: adminClientFactory({params, session}),\n };\n };\n}\n"],"names":[],"mappings":";;;;;AAMM,SAAU,uBAAuB,CAAC,MAAmB,EAAA;AACzD,IAAA,MAAM,EAAC,GAAG,EAAE,MAAM,EAAC,GAAG,MAAM;AAE5B,IAAA,OAAO,eAAe,YAAY,CAAC,OAAgB,EAAA;AACjD,QAAA,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC;AAE1C,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE;AAC7B,YAAA,MAAM,CAAC,KAAK,CACV,uEAAuE,EACvE,EAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAC,CAC3C;AACD,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,oBAAoB;AACjC,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;QACpC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;YACrC,OAAO;AACP,YAAA,UAAU,EAAE,OAAO;AACpB,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AACjB,YAAA,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,EAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAC,CAAC;AAEzE,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,aAAa;AAC1B,aAAA,CAAC;QACJ;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AAEnC,QAAA,MAAM,CAAC,KAAK,CAAC,uDAAuD,EAAE;YACpE,IAAI,EAAE,OAAO,CAAC,cAAc;AAC7B,SAAA,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAC7C,MAAM,EACN,OAAO,CAAC,cAAc,CACvB;QAED,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE;gBACjD,IAAI,EAAE,OAAO,CAAC,cAAc;AAC7B,aAAA,CAAC;AACF,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,aAAa;AAC1B,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE,EAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAC,CAAC;QAE1E,OAAO;YACL,OAAO;YACP,OAAO;YACP,KAAK,EAAE,kBAAkB,CAAC,EAAC,MAAM,EAAE,OAAO,EAAC,CAAC;SAC7C;AACH,IAAA,CAAC;AACH;;;;"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { ShopifyHeader } from '@shopify/shopify-api';
|
|
2
2
|
import { adminClientFactory } from '../../clients/admin/factory.mjs';
|
|
3
|
-
import '
|
|
4
|
-
import '
|
|
5
|
-
import { createOrLoadOfflineSession } from '../helpers/create-or-load-offline-session.mjs';
|
|
3
|
+
import { ensureValidOfflineSession } from '../../helpers/ensure-valid-offline-session.mjs';
|
|
4
|
+
import '../../types.mjs';
|
|
6
5
|
|
|
7
6
|
function authenticateFulfillmentServiceFactory(params) {
|
|
8
7
|
const { api, logger } = params;
|
|
@@ -34,7 +33,7 @@ function authenticateFulfillmentServiceFactory(params) {
|
|
|
34
33
|
logger.debug('Fulfillment service request is valid, looking for an offline session', {
|
|
35
34
|
shop,
|
|
36
35
|
});
|
|
37
|
-
const session = await
|
|
36
|
+
const session = await ensureValidOfflineSession(params, shop);
|
|
38
37
|
if (!session) {
|
|
39
38
|
logger.info('Fulfillment service request could not find session', {
|
|
40
39
|
shop,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/fulfillment-service/authenticate.ts"],"sourcesContent":["import {ShopifyHeader} from '@shopify/shopify-api';\n\nimport {adminClientFactory} from '../../clients/admin';\nimport {BasicParams} from '../../types';\nimport {
|
|
1
|
+
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/fulfillment-service/authenticate.ts"],"sourcesContent":["import {ShopifyHeader} from '@shopify/shopify-api';\n\nimport {adminClientFactory} from '../../clients/admin';\nimport {BasicParams} from '../../types';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n AuthenticateFulfillmentService,\n FulfillmentServiceContext,\n} from './types';\n\nexport function authenticateFulfillmentServiceFactory(\n params: BasicParams,\n): AuthenticateFulfillmentService {\n const {api, logger} = params;\n\n return async function authenticate(\n request: Request,\n ): Promise<FulfillmentServiceContext> {\n logger.info('Authenticating fulfillment service request');\n\n if (request.method !== 'POST') {\n logger.debug(\n 'Received a non-POST request for fulfillment service. Only POST requests are allowed.',\n {url: request.url, method: request.method},\n );\n throw new Response(undefined, {\n status: 405,\n statusText: 'Method not allowed',\n });\n }\n\n const rawBody = await request.text();\n const result = await api.fulfillmentService.validate({\n rawBody,\n rawRequest: request,\n });\n\n if (!result.valid) {\n logger.error('Received an invalid fulfillment service request', {\n reason: result.reason,\n });\n\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const payload = JSON.parse(rawBody);\n const shop = request.headers.get(ShopifyHeader.Domain) || '';\n\n logger.debug(\n 'Fulfillment service request is valid, looking for an offline session',\n {\n shop,\n },\n );\n\n const session = await ensureValidOfflineSession(params, shop);\n\n if (!session) {\n logger.info('Fulfillment service request could not find session', {\n shop,\n });\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n logger.debug('Found a session for the fulfillment service request', {\n shop,\n });\n\n return {\n session,\n payload,\n admin: adminClientFactory({params, session}),\n };\n };\n}\n"],"names":[],"mappings":";;;;;AAWM,SAAU,qCAAqC,CACnD,MAAmB,EAAA;AAEnB,IAAA,MAAM,EAAC,GAAG,EAAE,MAAM,EAAC,GAAG,MAAM;AAE5B,IAAA,OAAO,eAAe,YAAY,CAChC,OAAgB,EAAA;AAEhB,QAAA,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC;AAEzD,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE;AAC7B,YAAA,MAAM,CAAC,KAAK,CACV,sFAAsF,EACtF,EAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAC,CAC3C;AACD,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,oBAAoB;AACjC,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;QACpC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC;YACnD,OAAO;AACP,YAAA,UAAU,EAAE,OAAO;AACpB,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;AACjB,YAAA,MAAM,CAAC,KAAK,CAAC,iDAAiD,EAAE;gBAC9D,MAAM,EAAE,MAAM,CAAC,MAAM;AACtB,aAAA,CAAC;AAEF,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,aAAa;AAC1B,aAAA,CAAC;QACJ;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AACnC,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE;AAE5D,QAAA,MAAM,CAAC,KAAK,CACV,sEAAsE,EACtE;YACE,IAAI;AACL,SAAA,CACF;QAED,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC;QAE7D,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,CAAC,IAAI,CAAC,oDAAoD,EAAE;gBAChE,IAAI;AACL,aAAA,CAAC;AACF,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,aAAa;AAC1B,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE;YAClE,IAAI;AACL,SAAA,CAAC;QAEF,OAAO;YACL,OAAO;YACP,OAAO;YACP,KAAK,EAAE,kBAAkB,CAAC,EAAC,MAAM,EAAE,OAAO,EAAC,CAAC;SAC7C;AACH,IAAA,CAAC;AACH;;;;"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { adminClientFactory } from '../../../clients/admin/factory.mjs';
|
|
2
2
|
import { storefrontClientFactory } from '../../../clients/storefront/factory.mjs';
|
|
3
|
+
import { ensureValidOfflineSession } from '../../../helpers/ensure-valid-offline-session.mjs';
|
|
4
|
+
import '../../../types.mjs';
|
|
5
|
+
import '@shopify/shopify-api';
|
|
3
6
|
|
|
4
7
|
function authenticateAppProxyFactory(params) {
|
|
5
|
-
const {
|
|
8
|
+
const { logger } = params;
|
|
6
9
|
return async function authenticate(request) {
|
|
7
10
|
const url = new URL(request.url);
|
|
8
11
|
const shop = url.searchParams.get('shop');
|
|
@@ -14,8 +17,7 @@ function authenticateAppProxyFactory(params) {
|
|
|
14
17
|
statusText: 'Bad Request',
|
|
15
18
|
});
|
|
16
19
|
}
|
|
17
|
-
const
|
|
18
|
-
const session = await config.sessionStorage.loadSession(sessionId);
|
|
20
|
+
const session = await ensureValidOfflineSession(params, shop);
|
|
19
21
|
if (!session) {
|
|
20
22
|
logger.debug('Could not find offline session, returning empty context', {
|
|
21
23
|
shop,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../../src/server/authenticate/public/appProxy/authenticate.ts"],"sourcesContent":["import {adminClientFactory, storefrontClientFactory} from '../../../clients';\nimport {BasicParams} from '../../../types';\n\nimport {\n AppProxyContext,\n AppProxyContextWithSession,\n AuthenticateAppProxy,\n LiquidResponseFunction,\n} from './types';\n\nexport function authenticateAppProxyFactory(\n params: BasicParams,\n): AuthenticateAppProxy {\n const {
|
|
1
|
+
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../../src/server/authenticate/public/appProxy/authenticate.ts"],"sourcesContent":["import {adminClientFactory, storefrontClientFactory} from '../../../clients';\nimport {ensureValidOfflineSession} from '../../../helpers';\nimport {BasicParams} from '../../../types';\n\nimport {\n AppProxyContext,\n AppProxyContextWithSession,\n AuthenticateAppProxy,\n LiquidResponseFunction,\n} from './types';\n\nexport function authenticateAppProxyFactory(\n params: BasicParams,\n): AuthenticateAppProxy {\n const {logger} = params;\n\n return async function authenticate(\n request: Request,\n ): Promise<AppProxyContext | AppProxyContextWithSession> {\n const url = new URL(request.url);\n const shop = url.searchParams.get('shop')!;\n logger.info('Authenticating app proxy request', {shop});\n\n if (!(await validateAppProxyHmac(params, url))) {\n logger.info('App proxy request has invalid signature', {shop});\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const session = await ensureValidOfflineSession(params, shop);\n\n if (!session) {\n logger.debug('Could not find offline session, returning empty context', {\n shop,\n ...Object.fromEntries(url.searchParams.entries()),\n });\n\n const context: AppProxyContext = {\n liquid,\n session: undefined,\n admin: undefined,\n storefront: undefined,\n };\n\n return context;\n }\n\n const context: AppProxyContextWithSession = {\n liquid,\n session,\n admin: adminClientFactory({params, session}),\n storefront: storefrontClientFactory({params, session}),\n };\n\n return context;\n };\n}\n\nconst liquid: LiquidResponseFunction = (body, initAndOptions) => {\n const processedBody = processLiquidBody(body);\n\n if (typeof initAndOptions !== 'object') {\n return new Response(processedBody, {\n status: initAndOptions || 200,\n headers: {\n 'Content-Type': 'application/liquid',\n },\n });\n }\n\n const {layout, ...responseInit} = initAndOptions || {};\n const responseBody =\n layout === false ? `{% layout none %} ${processedBody}` : processedBody;\n\n const headers = new Headers(responseInit.headers);\n headers.set('Content-Type', 'application/liquid');\n\n return new Response(responseBody, {\n ...responseInit,\n headers,\n });\n};\n\nasync function validateAppProxyHmac(\n params: BasicParams,\n url: URL,\n): Promise<boolean> {\n const {api, logger} = params;\n\n try {\n let searchParams = new URLSearchParams(url.search);\n if (!searchParams.get('index')) {\n searchParams.delete('index');\n }\n\n let isValid = await api.utils.validateHmac(\n Object.fromEntries(searchParams.entries()),\n {signator: 'appProxy'},\n );\n\n if (!isValid) {\n const cleanPath = url.pathname\n .replace(/^\\//, '')\n .replace(/\\/$/, '')\n .replaceAll('/', '.');\n const data = `routes%2F${cleanPath}`;\n\n searchParams = new URLSearchParams(\n `?_data=${data}&${searchParams.toString().replace(/^\\?/, '')}`,\n );\n\n isValid = await api.utils.validateHmac(\n Object.fromEntries(searchParams.entries()),\n {signator: 'appProxy'},\n );\n\n if (!isValid) {\n const searchParams = new URLSearchParams(\n `?_data=${data}._index&${url.search.replace(/^\\?/, '')}`,\n );\n\n isValid = await api.utils.validateHmac(\n Object.fromEntries(searchParams.entries()),\n {signator: 'appProxy'},\n );\n }\n }\n\n return isValid;\n } catch (error) {\n const shop = url.searchParams.get('shop')!;\n logger.info(error.message, {shop});\n throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n }\n}\n\nfunction processLiquidBody(body: string) {\n return (\n body\n // Add trailing slashes to relative form action URLs\n .replaceAll(\n /<(form[^>]+)action=\"(\\/[^\"?]+)(\\?[^\"]+)?\">/g,\n '<$1action=\"$2/$3\">',\n )\n // Add trailing slashes to relative link href URLs\n .replaceAll(/<(a[^>]+)href=\"(\\/[^\"?]+)(\\?[^\"]+)?\">/g, '<$1href=\"$2/$3\">')\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@ import { getSessionTokenHeader } from '../../helpers/get-session-token-header.mj
|
|
|
4
4
|
import { respondToBotRequest } from '../../helpers/reject-bot-request.mjs';
|
|
5
5
|
import { respondToOptionsRequest } from '../../helpers/respond-to-options-request.mjs';
|
|
6
6
|
import '@remix-run/server-runtime';
|
|
7
|
-
import '../../../types.mjs';
|
|
8
7
|
import { getShopFromRequest } from '../../helpers/get-shop-from-request.mjs';
|
|
9
8
|
|
|
10
9
|
function authenticateExtensionFactory(params, requestType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../../src/server/authenticate/public/extension/authenticate.ts"],"sourcesContent":["import {BasicParams} from '../../../types';\nimport {\n respondToBotRequest,\n respondToOptionsRequest,\n getSessionTokenHeader,\n validateSessionToken,\n ensureCORSHeadersFactory,\n getShopFromRequest,\n} from '../../helpers';\n\nimport {AuthenticateExtension, ExtensionContext} from './types';\n\nexport function authenticateExtensionFactory(\n params: BasicParams,\n requestType: string,\n): AuthenticateExtension {\n return async function authenticateExtension(\n request,\n options = {},\n ): Promise<ExtensionContext> {\n const {logger} = params;\n\n const corsHeaders = options.corsHeaders ?? [];\n\n respondToBotRequest(params, request);\n respondToOptionsRequest(params, request, corsHeaders);\n\n const sessionTokenHeader = getSessionTokenHeader(request);\n\n logger.info(`Authenticating ${requestType} request`, {\n shop: getShopFromRequest(request),\n });\n\n if (!sessionTokenHeader) {\n logger.debug('Request did not contain a session token', {\n shop: getShopFromRequest(request),\n });\n throw new Response(undefined, {\n status: 401,\n statusText: 'Unauthorized',\n });\n }\n\n return {\n sessionToken: await validateSessionToken(\n params,\n request,\n sessionTokenHeader,\n {checkAudience: false, retryRequest: false},\n ),\n cors: ensureCORSHeadersFactory(params, request, corsHeaders),\n };\n };\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../../src/server/authenticate/public/extension/authenticate.ts"],"sourcesContent":["import {BasicParams} from '../../../types';\nimport {\n respondToBotRequest,\n respondToOptionsRequest,\n getSessionTokenHeader,\n validateSessionToken,\n ensureCORSHeadersFactory,\n getShopFromRequest,\n} from '../../helpers';\n\nimport {AuthenticateExtension, ExtensionContext} from './types';\n\nexport function authenticateExtensionFactory(\n params: BasicParams,\n requestType: string,\n): AuthenticateExtension {\n return async function authenticateExtension(\n request,\n options = {},\n ): Promise<ExtensionContext> {\n const {logger} = params;\n\n const corsHeaders = options.corsHeaders ?? [];\n\n respondToBotRequest(params, request);\n respondToOptionsRequest(params, request, corsHeaders);\n\n const sessionTokenHeader = getSessionTokenHeader(request);\n\n logger.info(`Authenticating ${requestType} request`, {\n shop: getShopFromRequest(request),\n });\n\n if (!sessionTokenHeader) {\n logger.debug('Request did not contain a session token', {\n shop: getShopFromRequest(request),\n });\n throw new Response(undefined, {\n status: 401,\n statusText: 'Unauthorized',\n });\n }\n\n return {\n sessionToken: await validateSessionToken(\n params,\n request,\n sessionTokenHeader,\n {checkAudience: false, retryRequest: false},\n ),\n cors: ensureCORSHeadersFactory(params, request, corsHeaders),\n };\n };\n}\n"],"names":[],"mappings":";;;;;;;;AAYM,SAAU,4BAA4B,CAC1C,MAAmB,EACnB,WAAmB,EAAA;IAEnB,OAAO,eAAe,qBAAqB,CACzC,OAAO,EACP,OAAO,GAAG,EAAE,EAAA;AAEZ,QAAA,MAAM,EAAC,MAAM,EAAC,GAAG,MAAM;AAEvB,QAAA,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE;AAE7C,QAAA,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC;AACpC,QAAA,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC;AAErD,QAAA,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,CAAC;AAEzD,QAAA,MAAM,CAAC,IAAI,CAAC,CAAA,eAAA,EAAkB,WAAW,UAAU,EAAE;AACnD,YAAA,IAAI,EAAE,kBAAkB,CAAC,OAAO,CAAC;AAClC,SAAA,CAAC;QAEF,IAAI,CAAC,kBAAkB,EAAE;AACvB,YAAA,MAAM,CAAC,KAAK,CAAC,yCAAyC,EAAE;AACtD,gBAAA,IAAI,EAAE,kBAAkB,CAAC,OAAO,CAAC;AAClC,aAAA,CAAC;AACF,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,cAAc;AAC3B,aAAA,CAAC;QACJ;QAEA,OAAO;AACL,YAAA,YAAY,EAAE,MAAM,oBAAoB,CACtC,MAAM,EACN,OAAO,EACP,kBAAkB,EAClB,EAAC,aAAa,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAC,CAC5C;YACD,IAAI,EAAE,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC;SAC7D;AACH,IAAA,CAAC;AACH;;;;"}
|
|
@@ -2,8 +2,8 @@ import { WebhookValidationErrorReason } from '@shopify/shopify-api';
|
|
|
2
2
|
import { adminClientFactory } from '../../clients/admin/factory.mjs';
|
|
3
3
|
import '@remix-run/server-runtime';
|
|
4
4
|
import { handleClientErrorFactory } from '../admin/helpers/handle-client-error.mjs';
|
|
5
|
-
import '
|
|
6
|
-
import
|
|
5
|
+
import { ensureValidOfflineSession } from '../../helpers/ensure-valid-offline-session.mjs';
|
|
6
|
+
import '../../types.mjs';
|
|
7
7
|
|
|
8
8
|
function authenticateWebhookFactory(params) {
|
|
9
9
|
const { api, logger } = params;
|
|
@@ -33,7 +33,7 @@ function authenticateWebhookFactory(params) {
|
|
|
33
33
|
throw new Response(undefined, { status: 400, statusText: 'Bad Request' });
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
const session = await
|
|
36
|
+
const session = await ensureValidOfflineSession(params, check.domain);
|
|
37
37
|
const webhookContext = {
|
|
38
38
|
apiVersion: check.apiVersion,
|
|
39
39
|
shop: check.domain,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/webhooks/authenticate.ts"],"sourcesContent":["import {WebhookValidationErrorReason} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients';\nimport {handleClientErrorFactory} from '../admin/helpers';\nimport {
|
|
1
|
+
{"version":3,"file":"authenticate.mjs","sources":["../../../../../../src/server/authenticate/webhooks/authenticate.ts"],"sourcesContent":["import {WebhookValidationErrorReason} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients';\nimport {handleClientErrorFactory} from '../admin/helpers';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n AuthenticateWebhook,\n WebhookContext,\n WebhookContextWithoutSession,\n} from './types';\n\nexport function authenticateWebhookFactory<Topics extends string>(\n params: BasicParams,\n): AuthenticateWebhook<Topics> {\n const {api, logger} = params;\n\n return async function authenticate(\n request: Request,\n ): Promise<WebhookContext<Topics>> {\n if (request.method !== 'POST') {\n logger.debug(\n 'Received a non-POST request for a webhook. Only POST requests are allowed.',\n {url: request.url, method: request.method},\n );\n throw new Response(undefined, {\n status: 405,\n statusText: 'Method not allowed',\n });\n }\n\n const rawBody = await request.text();\n\n const check = await api.webhooks.validate({\n rawBody,\n rawRequest: request,\n });\n\n if (!check.valid) {\n if (check.reason === WebhookValidationErrorReason.InvalidHmac) {\n logger.debug('Webhook HMAC validation failed', check);\n throw new Response(undefined, {\n status: 401,\n statusText: 'Unauthorized',\n });\n } else {\n logger.debug('Webhook validation failed', check);\n throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n }\n }\n const session = await ensureValidOfflineSession(params, check.domain);\n const webhookContext: WebhookContextWithoutSession<Topics> = {\n apiVersion: check.apiVersion,\n shop: check.domain,\n topic: check.topic as Topics,\n webhookId: check.webhookId,\n payload: JSON.parse(rawBody),\n subTopic: check.subTopic || undefined,\n session: undefined,\n admin: undefined,\n };\n\n if (!session) {\n return webhookContext;\n }\n\n const admin = adminClientFactory({\n params,\n session,\n handleClientError: handleClientErrorFactory({request}),\n });\n\n return {\n ...webhookContext,\n session,\n admin,\n };\n };\n}\n"],"names":[],"mappings":";;;;;;;AAaM,SAAU,0BAA0B,CACxC,MAAmB,EAAA;AAEnB,IAAA,MAAM,EAAC,GAAG,EAAE,MAAM,EAAC,GAAG,MAAM;AAE5B,IAAA,OAAO,eAAe,YAAY,CAChC,OAAgB,EAAA;AAEhB,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE;AAC7B,YAAA,MAAM,CAAC,KAAK,CACV,4EAA4E,EAC5E,EAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAC,CAC3C;AACD,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,oBAAoB;AACjC,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE;QAEpC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACxC,OAAO;AACP,YAAA,UAAU,EAAE,OAAO;AACpB,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;YAChB,IAAI,KAAK,CAAC,MAAM,KAAK,4BAA4B,CAAC,WAAW,EAAE;AAC7D,gBAAA,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC;AACrD,gBAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,oBAAA,MAAM,EAAE,GAAG;AACX,oBAAA,UAAU,EAAE,cAAc;AAC3B,iBAAA,CAAC;YACJ;iBAAO;AACL,gBAAA,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC;AAChD,gBAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE,EAAC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,aAAa,EAAC,CAAC;YACzE;QACF;QACA,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;AACrE,QAAA,MAAM,cAAc,GAAyC;YAC3D,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,KAAK,CAAC,MAAM;YAClB,KAAK,EAAE,KAAK,CAAC,KAAe;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;AAC1B,YAAA,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AAC5B,YAAA,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;AACrC,YAAA,OAAO,EAAE,SAAS;AAClB,YAAA,KAAK,EAAE,SAAS;SACjB;QAED,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,OAAO,cAAc;QACvB;QAEA,MAAM,KAAK,GAAG,kBAAkB,CAAC;YAC/B,MAAM;YACN,OAAO;AACP,YAAA,iBAAiB,EAAE,wBAAwB,CAAC,EAAC,OAAO,EAAC,CAAC;AACvD,SAAA,CAAC;QAEF,OAAO;AACL,YAAA,GAAG,cAAc;YACjB,OAAO;YACP,KAAK;SACN;AACH,IAAA,CAAC;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.mjs","sources":["../../../../../src/server/future/flags.ts"],"sourcesContent":["import type {ConfigParams, Shopify} from '@shopify/shopify-api';\n\nimport {AppConfig} from '../config-types';\n\n// When adding new flags, you should also add them to the `TEST_FUTURE_FLAGS` object in `test-config.ts` to ensure that\n// it doesn't cause regressions.\nexport interface FutureFlags {\n /**\n * When enabled, embedded apps will fetch access tokens via [token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange).\n * This assumes the app has scopes declared for [Shopify managing installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).\n *\n * Learn more about this [new embedded app auth strategy](https://shopify.dev/docs/api/shopify-app-remix#embedded-auth-strategy).\n *\n * @default false\n */\n unstable_newEmbeddedAuthStrategy?: boolean;\n}\n\n// When adding new flags, use this format:\n// apiFutureFlag: Future extends FutureFlags ? Future['remixFutureFlag'] : false;\nexport interface ApiFutureFlags<
|
|
1
|
+
{"version":3,"file":"flags.mjs","sources":["../../../../../src/server/future/flags.ts"],"sourcesContent":["import type {ConfigParams, Shopify} from '@shopify/shopify-api';\n\nimport {AppConfig} from '../config-types';\n\n// When adding new flags, you should also add them to the `TEST_FUTURE_FLAGS` object in `test-config.ts` to ensure that\n// it doesn't cause regressions.\nexport interface FutureFlags {\n /**\n * When enabled, embedded apps will fetch access tokens via [token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange).\n * This assumes the app has scopes declared for [Shopify managing installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).\n *\n * Learn more about this [new embedded app auth strategy](https://shopify.dev/docs/api/shopify-app-remix#embedded-auth-strategy).\n *\n * @default false\n */\n unstable_newEmbeddedAuthStrategy?: boolean;\n /**\n * When enabled, the app will start using expiring offline access tokens and automatically refresh them when they are close to expiring.\n *\n * @default false\n */\n expiringOfflineAccessTokens?: boolean;\n}\n\n// When adding new flags, use this format:\n// apiFutureFlag: Future extends FutureFlags ? Future['remixFutureFlag'] : false;\nexport interface ApiFutureFlags<Future extends FutureFlagOptions> {\n expiringOfflineAccessTokens: Future extends FutureFlags\n ? Future['expiringOfflineAccessTokens']\n : false;\n unstable_managedPricingSupport: true;\n}\n\nexport type ApiConfigWithFutureFlags<Future extends FutureFlagOptions> =\n ConfigParams<ApiFutureFlags<Future>>;\n\nexport type FutureFlagOptions = FutureFlags | undefined;\n\nexport type FeatureEnabled<\n Future extends FutureFlagOptions,\n Flag extends keyof FutureFlags,\n> = Future extends FutureFlags\n ? Future[Flag] extends true\n ? true\n : false\n : false;\n\nexport function logDisabledFutureFlags(\n config: AppConfig,\n logger: Shopify['logger'],\n) {\n const logFlag = (flag: string, message: string) =>\n logger.info(`Future flag ${flag} is disabled.\\n\\n ${message}\\n`);\n\n if (!config.future.unstable_newEmbeddedAuthStrategy) {\n logFlag(\n 'unstable_newEmbeddedAuthStrategy',\n 'Enable this to use OAuth token exchange instead of auth code to generate API access tokens.' +\n '\\n Your app must be using Shopify managed install: https://shopify.dev/docs/apps/auth/installation',\n );\n }\n}\n"],"names":[],"mappings":"AA+CM,SAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAyB,EAAA;AAEzB,IAAA,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,OAAe,KAC5C,MAAM,CAAC,IAAI,CAAC,CAAA,YAAA,EAAe,IAAI,sBAAsB,OAAO,CAAA,EAAA,CAAI,CAAC;AAEnE,IAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,gCAAgC,EAAE;QACnD,OAAO,CACL,kCAAkC,EAClC,6FAA6F;AAC3F,YAAA,qGAAqG,CACxG;IACH;AACF;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AppDistribution } from '
|
|
1
|
+
import { AppDistribution } from '../types.mjs';
|
|
2
2
|
|
|
3
|
-
async function createOrLoadOfflineSession(
|
|
3
|
+
async function createOrLoadOfflineSession({ api, config, logger }, shop) {
|
|
4
4
|
if (config.distribution === AppDistribution.ShopifyAdmin) {
|
|
5
5
|
logger.debug('Creating custom app session from configured access token', {
|
|
6
6
|
shop,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-or-load-offline-session.mjs","sources":["../../../../../src/server/helpers/create-or-load-offline-session.ts"],"sourcesContent":["import {AppDistribution, BasicParams} from '../types';\n\nexport async function createOrLoadOfflineSession(\n {api, config, logger}: BasicParams,\n shop: string,\n) {\n if (config.distribution === AppDistribution.ShopifyAdmin) {\n logger.debug('Creating custom app session from configured access token', {\n shop,\n });\n return api.session.customAppSession(shop);\n } else {\n logger.debug('Loading offline session from session storage', {shop});\n const offlineSessionId = api.session.getOfflineId(shop);\n const session = await config.sessionStorage!.loadSession(offlineSessionId);\n\n return session;\n }\n}\n"],"names":[],"mappings":";;AAEO,eAAe,0BAA0B,CAC9C,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAc,EAClC,IAAY,EAAA;IAEZ,IAAI,MAAM,CAAC,YAAY,KAAK,eAAe,CAAC,YAAY,EAAE;AACxD,QAAA,MAAM,CAAC,KAAK,CAAC,0DAA0D,EAAE;YACvE,IAAI;AACL,SAAA,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC;IAC3C;SAAO;QACL,MAAM,CAAC,KAAK,CAAC,8CAA8C,EAAE,EAAC,IAAI,EAAC,CAAC;QACpE,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC;QACvD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC;AAE1E,QAAA,OAAO,OAAO;IAChB;AACF;;;;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AppDistribution } from '../types.mjs';
|
|
2
|
+
import refreshToken from './refresh-token.mjs';
|
|
3
|
+
|
|
4
|
+
// 5 minutes
|
|
5
|
+
const WITHIN_MILLISECONDS_OF_EXPIRY = 5 * 60 * 1000;
|
|
6
|
+
async function ensureOfflineTokenIsNotExpired(session, params, shop) {
|
|
7
|
+
const { config } = params;
|
|
8
|
+
if (config.future?.expiringOfflineAccessTokens &&
|
|
9
|
+
session.isExpired(WITHIN_MILLISECONDS_OF_EXPIRY) &&
|
|
10
|
+
config.distribution !== AppDistribution.ShopifyAdmin &&
|
|
11
|
+
session.refreshToken) {
|
|
12
|
+
const offlineSession = await refreshToken(params, shop, session.refreshToken);
|
|
13
|
+
await config.sessionStorage.storeSession(offlineSession);
|
|
14
|
+
return offlineSession;
|
|
15
|
+
}
|
|
16
|
+
return session;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { WITHIN_MILLISECONDS_OF_EXPIRY, ensureOfflineTokenIsNotExpired };
|
|
20
|
+
//# sourceMappingURL=ensure-offline-token-is-not-expired.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-offline-token-is-not-expired.mjs","sources":["../../../../../src/server/helpers/ensure-offline-token-is-not-expired.ts"],"sourcesContent":["import {Session} from '@shopify/shopify-api';\n\nimport {AppDistribution, BasicParams} from '../types';\n\nimport refreshToken from './refresh-token';\n\n// 5 minutes\nexport const WITHIN_MILLISECONDS_OF_EXPIRY = 5 * 60 * 1000;\n\nexport async function ensureOfflineTokenIsNotExpired(\n session: Session,\n params: BasicParams,\n shop: string,\n) {\n const {config} = params;\n if (\n config.future?.expiringOfflineAccessTokens &&\n session.isExpired(WITHIN_MILLISECONDS_OF_EXPIRY) &&\n config.distribution !== AppDistribution.ShopifyAdmin &&\n session.refreshToken\n ) {\n const offlineSession = await refreshToken(\n params,\n shop,\n session.refreshToken,\n );\n\n await config.sessionStorage!.storeSession(offlineSession);\n return offlineSession;\n }\n return session;\n}\n"],"names":[],"mappings":";;;AAMA;MACa,6BAA6B,GAAG,CAAC,GAAG,EAAE,GAAG;AAE/C,eAAe,8BAA8B,CAClD,OAAgB,EAChB,MAAmB,EACnB,IAAY,EAAA;AAEZ,IAAA,MAAM,EAAC,MAAM,EAAC,GAAG,MAAM;AACvB,IAAA,IACE,MAAM,CAAC,MAAM,EAAE,2BAA2B;AAC1C,QAAA,OAAO,CAAC,SAAS,CAAC,6BAA6B,CAAC;AAChD,QAAA,MAAM,CAAC,YAAY,KAAK,eAAe,CAAC,YAAY;QACpD,OAAO,CAAC,YAAY,EACpB;AACA,QAAA,MAAM,cAAc,GAAG,MAAM,YAAY,CACvC,MAAM,EACN,IAAI,EACJ,OAAO,CAAC,YAAY,CACrB;QAED,MAAM,MAAM,CAAC,cAAe,CAAC,YAAY,CAAC,cAAc,CAAC;AACzD,QAAA,OAAO,cAAc;IACvB;AACA,IAAA,OAAO,OAAO;AAChB;;;;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createOrLoadOfflineSession } from './create-or-load-offline-session.mjs';
|
|
2
|
+
import { ensureOfflineTokenIsNotExpired } from './ensure-offline-token-is-not-expired.mjs';
|
|
3
|
+
|
|
4
|
+
async function ensureValidOfflineSession(params, shop) {
|
|
5
|
+
const session = await createOrLoadOfflineSession(params, shop);
|
|
6
|
+
if (!session)
|
|
7
|
+
return undefined;
|
|
8
|
+
return ensureOfflineTokenIsNotExpired(session, params, shop);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { ensureValidOfflineSession };
|
|
12
|
+
//# sourceMappingURL=ensure-valid-offline-session.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ensure-valid-offline-session.mjs","sources":["../../../../../src/server/helpers/ensure-valid-offline-session.ts"],"sourcesContent":["import {BasicParams} from '../types';\n\nimport {createOrLoadOfflineSession} from './create-or-load-offline-session';\nimport {ensureOfflineTokenIsNotExpired} from './ensure-offline-token-is-not-expired';\n\nexport async function ensureValidOfflineSession(\n params: BasicParams,\n shop: string,\n) {\n const session = await createOrLoadOfflineSession(params, shop);\n\n if (!session) return undefined;\n\n return ensureOfflineTokenIsNotExpired(session, params, shop);\n}\n"],"names":[],"mappings":";;;AAKO,eAAe,yBAAyB,CAC7C,MAAmB,EACnB,IAAY,EAAA;IAEZ,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAAC,MAAM,EAAE,IAAI,CAAC;AAE9D,IAAA,IAAI,CAAC,OAAO;AAAE,QAAA,OAAO,SAAS;IAE9B,OAAO,8BAA8B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC;AAC9D;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { InvalidJwtError, HttpResponseError } from '@shopify/shopify-api';
|
|
2
|
+
|
|
3
|
+
async function refreshToken(params, shop, refreshToken) {
|
|
4
|
+
const { api } = params;
|
|
5
|
+
try {
|
|
6
|
+
const { session } = await api.auth.refreshToken({
|
|
7
|
+
shop,
|
|
8
|
+
refreshToken,
|
|
9
|
+
});
|
|
10
|
+
return session;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof InvalidJwtError ||
|
|
14
|
+
(error instanceof HttpResponseError &&
|
|
15
|
+
error.response.code === 400 &&
|
|
16
|
+
error.response.body?.error === 'invalid_subject_token')) {
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
throw new Response(undefined, {
|
|
20
|
+
status: 500,
|
|
21
|
+
statusText: 'Internal Server Error',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { refreshToken as default };
|
|
27
|
+
//# sourceMappingURL=refresh-token.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-token.mjs","sources":["../../../../../src/server/helpers/refresh-token.ts"],"sourcesContent":["import {\n HttpResponseError,\n InvalidJwtError,\n Session,\n} from '@shopify/shopify-api';\n\nimport {BasicParams} from '../types';\n\nexport default async function refreshToken(\n params: BasicParams,\n shop: string,\n refreshToken: string,\n): Promise<Session> {\n const {api} = params;\n try {\n const {session} = await api.auth.refreshToken({\n shop,\n refreshToken,\n });\n return session;\n } catch (error) {\n if (\n error instanceof InvalidJwtError ||\n (error instanceof HttpResponseError &&\n error.response.code === 400 &&\n error.response.body?.error === 'invalid_subject_token')\n ) {\n throw error;\n }\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n}\n"],"names":[],"mappings":";;AAQe,eAAe,YAAY,CACxC,MAAmB,EACnB,IAAY,EACZ,YAAoB,EAAA;AAEpB,IAAA,MAAM,EAAC,GAAG,EAAC,GAAG,MAAM;AACpB,IAAA,IAAI;QACF,MAAM,EAAC,OAAO,EAAC,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;YAC5C,IAAI;YACJ,YAAY;AACb,SAAA,CAAC;AACF,QAAA,OAAO,OAAO;IAChB;IAAE,OAAO,KAAK,EAAE;QACd,IACE,KAAK,YAAY,eAAe;aAC/B,KAAK,YAAY,iBAAiB;AACjC,gBAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG;gBAC3B,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,KAAK,uBAAuB,CAAC,EACzD;AACA,YAAA,MAAM,KAAK;QACb;AACA,QAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,YAAA,MAAM,EAAE,GAAG;AACX,YAAA,UAAU,EAAE,uBAAuB;AACpC,SAAA,CAAC;IACJ;AACF;;;;"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ensureValidOfflineSession } from '../../helpers/ensure-valid-offline-session.mjs';
|
|
2
|
+
import '../../types.mjs';
|
|
3
|
+
import '@shopify/shopify-api';
|
|
2
4
|
import { SessionNotFoundError } from '../../errors.mjs';
|
|
3
5
|
import { adminClientFactory } from '../../clients/admin/factory.mjs';
|
|
4
6
|
|
|
5
7
|
function unauthenticatedAdminContextFactory(params) {
|
|
6
8
|
return async (shop) => {
|
|
7
|
-
const session = await
|
|
9
|
+
const session = await ensureValidOfflineSession(params, shop);
|
|
8
10
|
if (!session) {
|
|
9
11
|
throw new SessionNotFoundError(`Could not find a session for shop ${shop} when creating unauthenticated admin context`);
|
|
10
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.mjs","sources":["../../../../../../src/server/unauthenticated/admin/factory.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"factory.mjs","sources":["../../../../../../src/server/unauthenticated/admin/factory.ts"],"sourcesContent":["import {ensureValidOfflineSession} from '../../helpers';\nimport {SessionNotFoundError} from '../../errors';\nimport {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients/admin';\n\nimport {UnauthenticatedAdminContext} from './types';\n\nexport function unauthenticatedAdminContextFactory(params: BasicParams) {\n return async (shop: string): Promise<UnauthenticatedAdminContext> => {\n const session = await ensureValidOfflineSession(params, shop);\n\n if (!session) {\n throw new SessionNotFoundError(\n `Could not find a session for shop ${shop} when creating unauthenticated admin context`,\n );\n }\n\n return {\n session,\n admin: adminClientFactory({params, session}),\n };\n };\n}\n"],"names":[],"mappings":";;;;;;AAOM,SAAU,kCAAkC,CAAC,MAAmB,EAAA;AACpE,IAAA,OAAO,OAAO,IAAY,KAA0C;QAClE,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC;QAE7D,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,IAAI,oBAAoB,CAC5B,qCAAqC,IAAI,CAAA,4CAAA,CAA8C,CACxF;QACH;QAEA,OAAO;YACL,OAAO;YACP,KAAK,EAAE,kBAAkB,CAAC,EAAC,MAAM,EAAE,OAAO,EAAC,CAAC;SAC7C;AACH,IAAA,CAAC;AACH;;;;"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { createOrLoadOfflineSession } from '../../authenticate/helpers/create-or-load-offline-session.mjs';
|
|
2
1
|
import { SessionNotFoundError } from '../../errors.mjs';
|
|
3
2
|
import { storefrontClientFactory } from '../../clients/storefront/factory.mjs';
|
|
3
|
+
import { ensureValidOfflineSession } from '../../helpers/ensure-valid-offline-session.mjs';
|
|
4
|
+
import '../../types.mjs';
|
|
5
|
+
import '@shopify/shopify-api';
|
|
4
6
|
|
|
5
7
|
function unauthenticatedStorefrontContextFactory(params) {
|
|
6
8
|
return async (shop) => {
|
|
7
|
-
const session = await
|
|
9
|
+
const session = await ensureValidOfflineSession(params, shop);
|
|
8
10
|
if (!session) {
|
|
9
11
|
throw new SessionNotFoundError(`Could not find a session for shop ${shop} when creating unauthenticated storefront context`);
|
|
10
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.mjs","sources":["../../../../../../src/server/unauthenticated/storefront/factory.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"factory.mjs","sources":["../../../../../../src/server/unauthenticated/storefront/factory.ts"],"sourcesContent":["import {SessionNotFoundError} from '../../errors';\nimport {BasicParams} from '../../types';\nimport {storefrontClientFactory} from '../../clients/storefront';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport {\n UnauthenticatedStorefrontContext,\n GetUnauthenticatedStorefrontContext,\n} from './types';\n\nexport function unauthenticatedStorefrontContextFactory(\n params: BasicParams,\n): GetUnauthenticatedStorefrontContext {\n return async (shop: string): Promise<UnauthenticatedStorefrontContext> => {\n const session = await ensureValidOfflineSession(params, shop);\n\n if (!session) {\n throw new SessionNotFoundError(\n `Could not find a session for shop ${shop} when creating unauthenticated storefront context`,\n );\n }\n\n return {\n session,\n storefront: storefrontClientFactory({params, session}),\n };\n };\n}\n"],"names":[],"mappings":";;;;;;AAUM,SAAU,uCAAuC,CACrD,MAAmB,EAAA;AAEnB,IAAA,OAAO,OAAO,IAAY,KAA+C;QACvE,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC;QAE7D,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,MAAM,IAAI,oBAAoB,CAC5B,qCAAqC,IAAI,CAAA,iDAAA,CAAmD,CAC7F;QACH;QAEA,OAAO;YACL,OAAO;YACP,UAAU,EAAE,uBAAuB,CAAC,EAAC,MAAM,EAAE,OAAO,EAAC,CAAC;SACvD;AACH,IAAA,CAAC;AACH;;;;"}
|