@anthusai/papyrus 5.17.0 → 5.18.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.
@@ -4,7 +4,7 @@ import * as amplify from "aws-cdk-lib/aws-amplify";
4
4
  import { SecureStringParameter } from "./secure-string-parameter.js";
5
5
  import { GITHUB_OIDC_PROVIDER_HOST } from "./github-oidc-provider.js";
6
6
  import { cmsProductionBuildSpec, cmsStagingBuildSpec, readerBuildSpec } from "./build-specs.js";
7
- import { PROSPECTUS_PAPYRUS_SITE_ROUTES, hasCmsApp, isStagingEnabled, resolveRedirectSubDomainPrefix, resolveCmsHostName, githubOidcSubjects, resolveGithubRepository, resolveProspectusAccountsEndpoint, resolveProspectusSessionSealingParameterName, resolveRevalidateSecretParameterName, resolveStackName, resolveStagingDomainName, resolveStoragePreviewPrefix } from "./site-config.js";
7
+ import { PROSPECTUS_PAPYRUS_SITE_ROUTES, hasCmsApp, isStagingEnabled, resolveRedirectSubDomainPrefix, resolveCmsHostName, resolveSiteOrigin, githubOidcSubjects, resolveGithubRepository, resolveProspectusAccountsEndpoint, resolveProspectusSessionSealingParameterName, resolveRevalidateSecretParameterName, resolveStackName, resolveStagingDomainName, resolveStoragePreviewPrefix } from "./site-config.js";
8
8
  function environmentVariables(variables) {
9
9
  return Object.entries(variables).map(([name, value]) => ({ name, value }));
10
10
  }
@@ -159,11 +159,14 @@ export class AmplifyAppShellStack extends Stack {
159
159
  ? `https://${stagingDomainName}/`
160
160
  : Fn.join("", ["https://staging.", cmsApp.attrDefaultDomain, "/"]);
161
161
  // The compute adapter's request URL is https://localhost:3000, so the site names its own public origin.
162
- const productionSiteOrigin = cmsHostName ? `https://${cmsHostName}` : Fn.join("", ["https://main.", cmsApp.attrDefaultDomain]);
162
+ // A site served by its own edge (cms.siteOrigin) has no Amplify domain, so the edge host is its origin.
163
+ const siteOrigin = resolveSiteOrigin(config);
164
+ const productionSiteOrigin = cmsHostName ? `https://${cmsHostName}` : siteOrigin ?? Fn.join("", ["https://main.", cmsApp.attrDefaultDomain]);
163
165
  const stagingSiteOrigin = stagingDomainName ? `https://${stagingDomainName}` : Fn.join("", ["https://staging.", cmsApp.attrDefaultDomain]);
164
166
  const sharedRootDomain = config.cms.domainPrefix !== undefined;
165
167
  const defaultOriginsToAllow = [
166
168
  ...(config.cms.domainName ? [] : [productionOrigin]),
169
+ ...(siteOrigin ? [`${siteOrigin}/`] : []),
167
170
  ...(stagingEnabled && !stagingDomainName ? [stagingOrigin] : []),
168
171
  ];
169
172
  const oauthRedirectUrls = defaultOriginsToAllow.length === 0
@@ -5,7 +5,7 @@ import * as amplify from "aws-cdk-lib/aws-amplify";
5
5
  import { SecureStringParameter } from "./secure-string-parameter";
6
6
  import { GITHUB_OIDC_PROVIDER_HOST } from "./github-oidc-provider";
7
7
  import { cmsProductionBuildSpec, cmsStagingBuildSpec, readerBuildSpec } from "./build-specs";
8
- import { AmplifyAppShellSiteConfig, PROSPECTUS_PAPYRUS_SITE_ROUTES, ReaderCustomHeaderRule, hasCmsApp, isStagingEnabled, resolveRedirectSubDomainPrefix, resolveCmsHostName, githubOidcSubjects, resolveGithubRepository, resolveProspectusAccountsEndpoint, resolveProspectusSessionSealingParameterName, resolveRevalidateSecretParameterName, resolveStackName, resolveStagingDomainName, resolveStoragePreviewPrefix } from "./site-config";
8
+ import { AmplifyAppShellSiteConfig, PROSPECTUS_PAPYRUS_SITE_ROUTES, ReaderCustomHeaderRule, hasCmsApp, isStagingEnabled, resolveRedirectSubDomainPrefix, resolveCmsHostName, resolveSiteOrigin, githubOidcSubjects, resolveGithubRepository, resolveProspectusAccountsEndpoint, resolveProspectusSessionSealingParameterName, resolveRevalidateSecretParameterName, resolveStackName, resolveStagingDomainName, resolveStoragePreviewPrefix } from "./site-config";
9
9
 
10
10
  function environmentVariables(variables: Record<string, string>): amplify.CfnBranch.EnvironmentVariableProperty[] {
11
11
  return Object.entries(variables).map(([name, value]) => ({ name, value }));
@@ -178,11 +178,14 @@ export class AmplifyAppShellStack extends Stack {
178
178
  ? `https://${stagingDomainName}/`
179
179
  : Fn.join("", ["https://staging.", cmsApp.attrDefaultDomain, "/"]);
180
180
  // The compute adapter's request URL is https://localhost:3000, so the site names its own public origin.
181
- const productionSiteOrigin = cmsHostName ? `https://${cmsHostName}` : Fn.join("", ["https://main.", cmsApp.attrDefaultDomain]);
181
+ // A site served by its own edge (cms.siteOrigin) has no Amplify domain, so the edge host is its origin.
182
+ const siteOrigin = resolveSiteOrigin(config);
183
+ const productionSiteOrigin = cmsHostName ? `https://${cmsHostName}` : siteOrigin ?? Fn.join("", ["https://main.", cmsApp.attrDefaultDomain]);
182
184
  const stagingSiteOrigin = stagingDomainName ? `https://${stagingDomainName}` : Fn.join("", ["https://staging.", cmsApp.attrDefaultDomain]);
183
185
  const sharedRootDomain = config.cms.domainPrefix !== undefined;
184
186
  const defaultOriginsToAllow = [
185
187
  ...(config.cms.domainName ? [] : [productionOrigin]),
188
+ ...(siteOrigin ? [`${siteOrigin}/`] : []),
186
189
  ...(stagingEnabled && !stagingDomainName ? [stagingOrigin] : []),
187
190
  ];
188
191
  const oauthRedirectUrls = defaultOriginsToAllow.length === 0
@@ -24,6 +24,7 @@ const REPOSITORY_PATTERN = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_
24
24
  const SECRETS_MANAGER_SECRET_ARN_PATTERN = /^arn:aws:secretsmanager:[a-z0-9-]+:\d{12}:secret:[A-Za-z0-9/_+=.@-]+$/;
25
25
  const HOSTED_ZONE_ID_PATTERN = /^Z[A-Z0-9]+$/;
26
26
  const HOST_NAME_PATTERN = /^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/;
27
+ const SITE_ORIGIN_PATTERN = /^https:\/\/([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}(:\d{1,5})?$/;
27
28
  const DOMAIN_PREFIX_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
28
29
  const APP_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9 _.-]*$/;
29
30
  const STACK_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9-]{0,127}$/;
@@ -187,6 +188,9 @@ export function resolveCmsHostName(config) {
187
188
  return undefined;
188
189
  return config.cms.domainPrefix ? `${config.cms.domainPrefix}.${config.cms.domainName}` : config.cms.domainName;
189
190
  }
191
+ export function resolveSiteOrigin(config) {
192
+ return config.cms.siteOrigin;
193
+ }
190
194
  export function resolveStagingDomainName(config) {
191
195
  if (!isStagingEnabled(config))
192
196
  return undefined;
@@ -218,7 +222,7 @@ function parseStagingPreview(value) {
218
222
  }
219
223
  function parseCms(value) {
220
224
  const cmsRecord = requireObject(value, "cms");
221
- rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "applyCognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName", "domainPrefix", "stagingDomainPrefix", "redirects", "stagingPreview", "prospectusAccountsApiStageArn", "deployStackInBuild"], "cms");
225
+ rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "applyCognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName", "domainPrefix", "siteOrigin", "stagingDomainPrefix", "redirects", "stagingPreview", "prospectusAccountsApiStageArn", "deployStackInBuild"], "cms");
222
226
  const buildComputeType = cmsRecord.buildComputeType;
223
227
  if (buildComputeType !== undefined && buildComputeType !== "STANDARD" && buildComputeType !== "STANDARD_8GB") {
224
228
  fail("cms.buildComputeType", `must be "STANDARD" or "STANDARD_8GB", got ${JSON.stringify(buildComputeType)}`);
@@ -236,6 +240,7 @@ function parseCms(value) {
236
240
  appName: optionalString(cmsRecord.appName, "cms.appName", APP_NAME_PATTERN),
237
241
  domainName: optionalString(cmsRecord.domainName, "cms.domainName", HOST_NAME_PATTERN, "host name"),
238
242
  domainPrefix: optionalString(cmsRecord.domainPrefix, "cms.domainPrefix", DOMAIN_PREFIX_PATTERN, "single DNS label"),
243
+ siteOrigin: optionalString(cmsRecord.siteOrigin, "cms.siteOrigin", SITE_ORIGIN_PATTERN, "https origin with no path, query or trailing slash, such as https://shipped.anth.us"),
239
244
  staging: cmsRecord.staging,
240
245
  cognitoDomainPrefix: requireString(cmsRecord.cognitoDomainPrefix, "cms.cognitoDomainPrefix", COGNITO_DOMAIN_PREFIX_PATTERN, "lowercase letters, digits and hyphens; globally unique per region"),
241
246
  applyCognitoDomainPrefix: cmsRecord.applyCognitoDomainPrefix,
@@ -257,6 +262,9 @@ function parseCms(value) {
257
262
  fail(`cms.environment.${key}`, "is managed by the template: Google sign-in is always on, the Cognito domain comes from cms.cognitoDomainPrefix, the revalidation secret parameter is derived from siteId and the Prospectus endpoint comes from cms.prospectusAccountsApiStageArn and the public site origin comes from the site host");
258
263
  }
259
264
  }
265
+ if (cms.siteOrigin && cms.domainName) {
266
+ fail("cms.siteOrigin", "is for sites whose host is served by their own edge; remove it when cms.domainName is set");
267
+ }
260
268
  if (cms.staging === false && cms.stagingDomainName) {
261
269
  fail("cms.stagingDomainName", "must not be set when cms.staging is false");
262
270
  }
@@ -32,6 +32,8 @@ export type CmsConfig = {
32
32
  appName?: string;
33
33
  domainName?: string;
34
34
  domainPrefix?: string;
35
+ /** Public https origin of a site whose host is served by its own edge (no Amplify domain association). */
36
+ siteOrigin?: string;
35
37
  staging?: boolean;
36
38
  stagingPreview?: StagingPreviewConfig;
37
39
  cognitoDomainPrefix: string;
@@ -133,6 +135,7 @@ const REPOSITORY_PATTERN = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_
133
135
  const SECRETS_MANAGER_SECRET_ARN_PATTERN = /^arn:aws:secretsmanager:[a-z0-9-]+:\d{12}:secret:[A-Za-z0-9/_+=.@-]+$/;
134
136
  const HOSTED_ZONE_ID_PATTERN = /^Z[A-Z0-9]+$/;
135
137
  const HOST_NAME_PATTERN = /^([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/;
138
+ const SITE_ORIGIN_PATTERN = /^https:\/\/([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}(:\d{1,5})?$/;
136
139
  const DOMAIN_PREFIX_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
137
140
  const APP_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9 _.-]*$/;
138
141
  const STACK_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9-]{0,127}$/;
@@ -298,6 +301,10 @@ export function resolveCmsHostName(config: Pick<CmsSiteConfig, "cms">): string |
298
301
  return config.cms.domainPrefix ? `${config.cms.domainPrefix}.${config.cms.domainName}` : config.cms.domainName;
299
302
  }
300
303
 
304
+ export function resolveSiteOrigin(config: Pick<CmsSiteConfig, "cms">): string | undefined {
305
+ return config.cms.siteOrigin;
306
+ }
307
+
301
308
  export function resolveStagingDomainName(config: Pick<CmsSiteConfig, "cms">): string | undefined {
302
309
  if (!isStagingEnabled(config)) return undefined;
303
310
  if (config.cms.domainPrefix) {
@@ -329,7 +336,7 @@ function parseStagingPreview(value: unknown): StagingPreviewConfig | undefined {
329
336
 
330
337
  function parseCms(value: unknown): CmsConfig {
331
338
  const cmsRecord = requireObject(value, "cms");
332
- rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "applyCognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName", "domainPrefix", "stagingDomainPrefix", "redirects", "stagingPreview", "prospectusAccountsApiStageArn", "deployStackInBuild"], "cms");
339
+ rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "applyCognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName", "domainPrefix", "siteOrigin", "stagingDomainPrefix", "redirects", "stagingPreview", "prospectusAccountsApiStageArn", "deployStackInBuild"], "cms");
333
340
  const buildComputeType = cmsRecord.buildComputeType;
334
341
  if (buildComputeType !== undefined && buildComputeType !== "STANDARD" && buildComputeType !== "STANDARD_8GB") {
335
342
  fail("cms.buildComputeType", `must be "STANDARD" or "STANDARD_8GB", got ${JSON.stringify(buildComputeType)}`);
@@ -347,6 +354,7 @@ function parseCms(value: unknown): CmsConfig {
347
354
  appName: optionalString(cmsRecord.appName, "cms.appName", APP_NAME_PATTERN),
348
355
  domainName: optionalString(cmsRecord.domainName, "cms.domainName", HOST_NAME_PATTERN, "host name"),
349
356
  domainPrefix: optionalString(cmsRecord.domainPrefix, "cms.domainPrefix", DOMAIN_PREFIX_PATTERN, "single DNS label"),
357
+ siteOrigin: optionalString(cmsRecord.siteOrigin, "cms.siteOrigin", SITE_ORIGIN_PATTERN, "https origin with no path, query or trailing slash, such as https://shipped.anth.us"),
350
358
  staging: cmsRecord.staging as boolean | undefined,
351
359
  cognitoDomainPrefix: requireString(
352
360
  cmsRecord.cognitoDomainPrefix,
@@ -380,6 +388,9 @@ function parseCms(value: unknown): CmsConfig {
380
388
  }
381
389
  }
382
390
 
391
+ if (cms.siteOrigin && cms.domainName) {
392
+ fail("cms.siteOrigin", "is for sites whose host is served by their own edge; remove it when cms.domainName is set");
393
+ }
383
394
  if (cms.staging === false && cms.stagingDomainName) {
384
395
  fail("cms.stagingDomainName", "must not be set when cms.staging is false");
385
396
  }
package/package.json CHANGED
@@ -407,7 +407,7 @@
407
407
  "optional": true
408
408
  }
409
409
  },
410
- "version": "5.17.0",
410
+ "version": "5.18.0",
411
411
  "dependencies": {
412
412
  "@aws-amplify/adapter-nextjs": "^1.7.3",
413
413
  "@aws-crypto/sha256-js": "5.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.17.0",
2
+ "version": "5.18.0",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",