Repository: apollographql/apollo-server
Pull request #7741 (2023-09-27 21:17:40)

Landing Pages: switch from `_latest` to `v*` cdn buckets to pin major versions of landing pages
I published these buckets once already. Circle CI changes [here](https://github.com/apollographql/embeddable-explorer/pull/280)

in AS5 we want to pin embeddable code versions. Question - should we pin up to patch decimal, not just major? Just in case?


Patch:
diff --git a/.changeset/cool-dancers-tickle.md b/.changeset/cool-dancers-tickle.md
new file mode 100644
index 000000000..e073bcee4
--- /dev/null
+++ b/.changeset/cool-dancers-tickle.md
@@ -0,0 +1,5 @@
+---
+'@apollo/server': patch
+---
+
+Pin major releases of embeddable Explorer & Sandbox code.
diff --git a/docs/source/api/plugin/landing-pages.mdx b/docs/source/api/plugin/landing-pages.mdx
index bd73aaafb..30945bb10 100644
--- a/docs/source/api/plugin/landing-pages.mdx
+++ b/docs/source/api/plugin/landing-pages.mdx
@@ -85,7 +85,7 @@ This landing page is designed for use in local development, where `NODE_ENV` is
 
 By default, this plugin uses the latest version of the landing page published to Apollo's CDN. If you'd like to pin the current version, you can specify it here.
 
-The current latest version is available at [this link](https://apollo-server-landing-page.cdn.apollographql.com/_latest/version.txt).
+The current latest version is available at [this link](https://apollo-server-landing-page.cdn.apollographql.com/latest/version.txt).
 
 </td>
 </tr>
@@ -363,7 +363,7 @@ This landing page is designed for use in production. It provides a copyable comm
 
 By default, this plugin uses the latest version of the landing page published to Apollo's CDN. If you'd like to pin the current version, you can specify it here.
 
-The current latest version is available at [this link](https://apollo-server-landing-page.cdn.apollographql.com/_latest/version.txt).
+The current latest version is available at [this link](https://apollo-server-landing-page.cdn.apollographql.com/latest/version.txt).
 
 </td>
 </tr>
diff --git a/packages/server/src/plugin/landingPage/default/index.ts b/packages/server/src/plugin/landingPage/default/index.ts
index 9a708450e..38522a9a1 100644
--- a/packages/server/src/plugin/landingPage/default/index.ts
+++ b/packages/server/src/plugin/landingPage/default/index.ts
@@ -78,6 +78,10 @@ const getNonEmbeddedLandingPageHTML = (
   )}/static/js/main.js?runtime=${apolloServerVersion}"></script>`;
 };
 
+export const DEFAULT_EMBEDDED_EXPLORER_VERSION = 'v3';
+export const DEFAULT_EMBEDDED_SANDBOX_VERSION = 'v2';
+export const DEFAULT_APOLLO_SERVER_LANDING_PAGE_VERSION = '_latest';
+
 // Helper for the two actual plugin functions.
 function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
   maybeVersion: string | undefined,
@@ -86,7 +90,10 @@ function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
     apolloStudioEnv: 'staging' | 'prod' | undefined;
   },
 ): ImplicitlyInstallablePlugin<TContext> {
-  const version = maybeVersion ?? '_latest';
+  const explorerVersion = maybeVersion ?? DEFAULT_EMBEDDED_EXPLORER_VERSION;
+  const sandboxVersion = maybeVersion ?? DEFAULT_EMBEDDED_SANDBOX_VERSION;
+  const apolloServerLandingPageVersion =
+    maybeVersion ?? DEFAULT_APOLLO_SERVER_LANDING_PAGE_VERSION;
   const apolloServerVersion = `@apollo/server@${packageVersion}`;
 
   const scriptSafeList = [
@@ -116,7 +123,9 @@ function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
       }
       return {
         async renderLandingPage() {
-          const encodedVersion = encodeURIComponent(version);
+          const encodedASLandingPageVersion = encodeURIComponent(
+            apolloServerLandingPageVersion,
+          );
           async function html() {
             const nonce =
               config.precomputedNonce ??
@@ -134,7 +143,7 @@ function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
     <meta http-equiv="Content-Security-Policy" content="${scriptCsp}; ${styleCsp}; ${imageCsp}; ${manifestCsp}; ${frameCsp}" />
     <link
       rel="icon"
-      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedVersion}/assets/favicon.png"
+      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedASLandingPageVersion}/assets/favicon.png"
     />
     <meta name="viewport" content="width=device-width,initial-scale=1" />
     <link rel="preconnect" href="https://fonts.gstatic.com" />
@@ -146,11 +155,11 @@ function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
     <meta name="description" content="Apollo server landing page" />
     <link
       rel="apple-touch-icon"
-      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedVersion}/assets/favicon.png"
+      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedASLandingPageVersion}/assets/favicon.png"
     />
     <link
       rel="manifest"
-      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedVersion}/manifest.json"
+      href="https://apollo-server-landing-page.cdn.apollographql.com/${encodedASLandingPageVersion}/manifest.json"
     />
     <title>Apollo Server</title>
   </head>
@@ -178,17 +187,27 @@ function ApolloServerPluginLandingPageDefault<TContext extends BaseContext>(
     ${
       config.embed
         ? 'graphRef' in config && config.graphRef
-          ? getEmbeddedExplorerHTML(version, config, apolloServerVersion, nonce)
+          ? getEmbeddedExplorerHTML(
+              explorerVersion,
+              config,
+              apolloServerVersion,
+              nonce,
+            )
           : !('graphRef' in config)
-          ? getEmbeddedSandboxHTML(version, config, apolloServerVersion, nonce)
+          ? getEmbeddedSandboxHTML(
+              sandboxVersion,
+              config,
+              apolloServerVersion,
+              nonce,
+            )
           : getNonEmbeddedLandingPageHTML(
-              version,
+              apolloServerLandingPageVersion,
               config,
               apolloServerVersion,
               nonce,
             )
         : getNonEmbeddedLandingPageHTML(
-            version,
+            apolloServerLandingPageVersion,
             config,
             apolloServerVersion,
             nonce,
diff --git a/packages/server/src/plugin/landingPage/default/types.ts b/packages/server/src/plugin/landingPage/default/types.ts
index 3ea9c02c9..5d15cc9e8 100644
--- a/packages/server/src/plugin/landingPage/default/types.ts
+++ b/packages/server/src/plugin/landingPage/default/types.ts
@@ -38,11 +38,12 @@ type InitialStateForEmbeds =
 
 export type ApolloServerPluginLandingPageDefaultBaseOptions = {
   /**
-   * By default, the landing page plugin uses the latest version of the landing
-   * page published to Apollo's CDN. If you'd like to pin the current version,
-   * pass the SHA served at
-   * https://apollo-server-landing-page.cdn.apollographql.com/_latest/version.txt
-   * here.
+   * Specify the major version of the landing page to use, i.e v2 or
+   * provide a specific commit from the
+   * [embeddable explorer](https://github.com/apollographql/embeddable-explorer)
+   * repo.
+   * We also support a `latest` tag but don't recommend using it
+   * as it's subject to major version updates.
    */
   version?: string;
   /**


Test patch:
diff --git a/packages/integration-testsuite/src/apolloServerTests.ts b/packages/integration-testsuite/src/apolloServerTests.ts
index 329c9078b..c045971ff 100644
--- a/packages/integration-testsuite/src/apolloServerTests.ts
+++ b/packages/integration-testsuite/src/apolloServerTests.ts
@@ -2912,7 +2912,7 @@ export function defineIntegrationTestSuiteApolloServerTests(
         url = (await createServer(makeServerConfig([]))).url;
         await get().expect(
           200,
-          /embeddable-sandbox.cdn.apollographql.com\/_latest\/embeddable-sandbox.umd.production.min.js/s,
+          /embeddable-sandbox.cdn.apollographql.com\/v2\/embeddable-sandbox.umd.production.min.js/s,
         );
       });
 
diff --git a/packages/server/src/__tests__/plugin/landingPage/getEmbeddedExplorerHTML.test.ts b/packages/server/src/__tests__/plugin/landingPage/getEmbeddedExplorerHTML.test.ts
index 87bd3bd56..d75720975 100644
--- a/packages/server/src/__tests__/plugin/landingPage/getEmbeddedExplorerHTML.test.ts
+++ b/packages/server/src/__tests__/plugin/landingPage/getEmbeddedExplorerHTML.test.ts
@@ -1,8 +1,9 @@
+import { DEFAULT_EMBEDDED_EXPLORER_VERSION } from '../../../plugin/landingPage/default';
 import { getEmbeddedExplorerHTML } from '../../../plugin/landingPage/default/getEmbeddedHTML';
 import type { ApolloServerPluginEmbeddedLandingPageProductionDefaultOptions } from '../../../plugin/landingPage/default/types';
 import { describe, it, expect } from '@jest/globals';
 
-const cdnVersion = '_latest';
+const cdnVersion = DEFAULT_EMBEDDED_EXPLORER_VERSION;
 expect.addSnapshotSerializer(require('jest-serializer-html'));
 const apolloServerVersion = '@apollo/server@4.0.0';
 
@@ -58,7 +59,7 @@ describe('Embedded Explorer Landing Page Config HTML', () => {
       <div id="embeddableExplorer">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-explorer.cdn.apollographql.com/_latest/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-explorer.cdn.apollographql.com/v3/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -108,7 +109,7 @@ describe('Embedded Explorer Landing Page Config HTML', () => {
       <div id="embeddableExplorer">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-explorer.cdn.apollographql.com/_latest/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-explorer.cdn.apollographql.com/v3/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -159,7 +160,7 @@ describe('Embedded Explorer Landing Page Config HTML', () => {
       <div id="embeddableExplorer">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-explorer.cdn.apollographql.com/_latest/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-explorer.cdn.apollographql.com/v3/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -208,7 +209,7 @@ describe('Embedded Explorer Landing Page Config HTML', () => {
       <div id="embeddableExplorer">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-explorer.cdn.apollographql.com/_latest/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-explorer.cdn.apollographql.com/v3/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -260,7 +261,7 @@ describe('Embedded Explorer Landing Page Config HTML', () => {
       <div id="embeddableExplorer">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-explorer.cdn.apollographql.com/_latest/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-explorer.cdn.apollographql.com/v3/embeddable-explorer.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
diff --git a/packages/server/src/__tests__/plugin/landingPage/getEmbeddedSandboxHTML.test.ts b/packages/server/src/__tests__/plugin/landingPage/getEmbeddedSandboxHTML.test.ts
index 51afe80a7..ad79e60d6 100644
--- a/packages/server/src/__tests__/plugin/landingPage/getEmbeddedSandboxHTML.test.ts
+++ b/packages/server/src/__tests__/plugin/landingPage/getEmbeddedSandboxHTML.test.ts
@@ -1,8 +1,9 @@
+import { DEFAULT_EMBEDDED_SANDBOX_VERSION } from '../../../plugin/landingPage/default';
 import { getEmbeddedSandboxHTML } from '../../../plugin/landingPage/default/getEmbeddedHTML';
 import type { ApolloServerPluginEmbeddedLandingPageLocalDefaultOptions } from '../../../plugin/landingPage/default/types';
 import { describe, it, expect } from '@jest/globals';
 
-const cdnVersion = '_latest';
+const cdnVersion = DEFAULT_EMBEDDED_SANDBOX_VERSION;
 expect.addSnapshotSerializer(require('jest-serializer-html'));
 const apolloServerVersion = '@apollo/server@4.0.0';
 
@@ -49,7 +50,7 @@ describe('Landing Page Config HTML', () => {
       <div id="embeddableSandbox">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-sandbox.cdn.apollographql.com/v2/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -99,7 +100,7 @@ describe('Landing Page Config HTML', () => {
       <div id="embeddableSandbox">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-sandbox.cdn.apollographql.com/v2/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -147,7 +148,7 @@ describe('Landing Page Config HTML', () => {
       <div id="embeddableSandbox">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-sandbox.cdn.apollographql.com/v2/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -197,7 +198,7 @@ describe('Landing Page Config HTML', () => {
       <div id="embeddableSandbox">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-sandbox.cdn.apollographql.com/v2/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">
@@ -252,7 +253,7 @@ describe('Landing Page Config HTML', () => {
       <div id="embeddableSandbox">
       </div>
       <script nonce="nonce"
-              src="https://embeddable-sandbox.cdn.apollographql.com/_latest/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
+              src="https://embeddable-sandbox.cdn.apollographql.com/v2/embeddable-sandbox.umd.production.min.js?runtime=%40apollo%2Fserver%404.0.0"
       >
       </script>
       <script nonce="nonce">