@anthusai/papyrus 1.0.0-next.11 → 1.0.0-next.13
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/app/page.tsx +8 -3
- package/infra/amplify-app-shell.js +7 -1
- package/infra/amplify-app-shell.ts +7 -1
- package/infra/site-config.js +14 -1
- package/infra/site-config.ts +21 -1
- package/lib/root-route-redirect.ts +16 -0
- package/package.json +2 -1
- package/routes.manifest.json +1 -1
package/app/page.tsx
CHANGED
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
} from "../lib/public-placeholder-config";
|
|
16
16
|
import type { PublicationItem } from "../lib/publication-items";
|
|
17
17
|
import { SITE_BRAND, rootRoute } from "../lib/site-brand";
|
|
18
|
-
import { redirect } from "next/navigation";
|
|
18
|
+
import { notFound, redirect } from "next/navigation";
|
|
19
|
+
import { buildRootRedirectTarget } from "../lib/root-route-redirect";
|
|
19
20
|
import NewsDeskRootPage, { type NewsDeskRootSearchParams } from "./newsroom/page";
|
|
20
21
|
|
|
21
22
|
export const dynamic = "force-dynamic";
|
|
@@ -41,8 +42,12 @@ export default async function Home({ searchParams }: HomePageProps) {
|
|
|
41
42
|
return <NewsDeskRootPage searchParams={searchParams} />;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
if (rootRoute.kind === "redirect"
|
|
45
|
-
redirect(rootRoute.destination);
|
|
45
|
+
if (rootRoute.kind === "redirect") {
|
|
46
|
+
redirect(buildRootRedirectTarget(rootRoute.destination, resolvedSearchParams));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (SITE_BRAND.renderer.kind === "markus") {
|
|
50
|
+
notFound();
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
// Resolved only on the reader path: Markus brands (renderer "markus") have
|
|
@@ -19,7 +19,11 @@ function environmentVariables(variables) {
|
|
|
19
19
|
* URL is used), IAM service and compute roles
|
|
20
20
|
* - `cms.staging: false` omits the staging branch and its domain
|
|
21
21
|
*
|
|
22
|
-
*
|
|
22
|
+
* Google sign-in is always on: the branches never set PAPYRUS_DISABLE_GOOGLE_OAUTH,
|
|
23
|
+
and `cms.cognitoDomainPrefix` becomes the stable hosted-UI domain
|
|
24
|
+
(PAPYRUS_COGNITO_DOMAIN_PREFIX). The secrets GOOGLE_CLIENT_ID and
|
|
25
|
+
GOOGLE_CLIENT_SECRET are Amplify backend secrets set in the console, never here.
|
|
26
|
+
The stack also creates the `<siteId>-papyrus-authoring` role. The CLI signs
|
|
23
27
|
* AppSync requests (SigV4) with credentials for that role (SSO, OIDC or any
|
|
24
28
|
* principal in the account that may assume it); no token is stored anywhere.
|
|
25
29
|
*
|
|
@@ -83,6 +87,7 @@ export class AmplifyAppShellStack extends Stack {
|
|
|
83
87
|
enablePerformanceMode: false,
|
|
84
88
|
environmentVariables: environmentVariables({
|
|
85
89
|
...config.cms.environment,
|
|
90
|
+
PAPYRUS_COGNITO_DOMAIN_PREFIX: config.cms.cognitoDomainPrefix,
|
|
86
91
|
PAPYRUS_OAUTH_REDIRECT_URLS: oauthRedirectUrls,
|
|
87
92
|
PAPYRUS_SITE_BRAND: config.brand,
|
|
88
93
|
SITE_ENV: "production",
|
|
@@ -99,6 +104,7 @@ export class AmplifyAppShellStack extends Stack {
|
|
|
99
104
|
buildSpec: cmsStagingBuildSpec(config),
|
|
100
105
|
environmentVariables: environmentVariables({
|
|
101
106
|
...config.cms.environment,
|
|
107
|
+
PAPYRUS_COGNITO_DOMAIN_PREFIX: config.cms.cognitoDomainPrefix,
|
|
102
108
|
PAPYRUS_OAUTH_REDIRECT_URLS: oauthRedirectUrls,
|
|
103
109
|
PAPYRUS_SITE_BRAND: config.brand,
|
|
104
110
|
SITE_ENV: "staging",
|
|
@@ -22,7 +22,11 @@ function environmentVariables(variables: Record<string, string>): amplify.CfnBra
|
|
|
22
22
|
* URL is used), IAM service and compute roles
|
|
23
23
|
* - `cms.staging: false` omits the staging branch and its domain
|
|
24
24
|
*
|
|
25
|
-
*
|
|
25
|
+
* Google sign-in is always on: the branches never set PAPYRUS_DISABLE_GOOGLE_OAUTH,
|
|
26
|
+
and `cms.cognitoDomainPrefix` becomes the stable hosted-UI domain
|
|
27
|
+
(PAPYRUS_COGNITO_DOMAIN_PREFIX). The secrets GOOGLE_CLIENT_ID and
|
|
28
|
+
GOOGLE_CLIENT_SECRET are Amplify backend secrets set in the console, never here.
|
|
29
|
+
The stack also creates the `<siteId>-papyrus-authoring` role. The CLI signs
|
|
26
30
|
* AppSync requests (SigV4) with credentials for that role (SSO, OIDC or any
|
|
27
31
|
* principal in the account that may assume it); no token is stored anywhere.
|
|
28
32
|
*
|
|
@@ -94,6 +98,7 @@ export class AmplifyAppShellStack extends Stack {
|
|
|
94
98
|
enablePerformanceMode: false,
|
|
95
99
|
environmentVariables: environmentVariables({
|
|
96
100
|
...config.cms.environment,
|
|
101
|
+
PAPYRUS_COGNITO_DOMAIN_PREFIX: config.cms.cognitoDomainPrefix,
|
|
97
102
|
PAPYRUS_OAUTH_REDIRECT_URLS: oauthRedirectUrls,
|
|
98
103
|
PAPYRUS_SITE_BRAND: config.brand,
|
|
99
104
|
SITE_ENV: "production",
|
|
@@ -111,6 +116,7 @@ export class AmplifyAppShellStack extends Stack {
|
|
|
111
116
|
buildSpec: cmsStagingBuildSpec(config),
|
|
112
117
|
environmentVariables: environmentVariables({
|
|
113
118
|
...config.cms.environment,
|
|
119
|
+
PAPYRUS_COGNITO_DOMAIN_PREFIX: config.cms.cognitoDomainPrefix,
|
|
114
120
|
PAPYRUS_OAUTH_REDIRECT_URLS: oauthRedirectUrls,
|
|
115
121
|
PAPYRUS_SITE_BRAND: config.brand,
|
|
116
122
|
SITE_ENV: "staging",
|
package/infra/site-config.js
CHANGED
|
@@ -9,6 +9,9 @@ const BRANCH_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9/_.-]*$/;
|
|
|
9
9
|
const PAPYRUS_VERSION_PATTERN = /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+\.\d+)?$/;
|
|
10
10
|
const GITHUB_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
|
|
11
11
|
const GITHUB_REPO_PATTERN = /^[A-Za-z0-9_.-]+$/;
|
|
12
|
+
const COGNITO_DOMAIN_PREFIX_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
13
|
+
const COGNITO_RESERVED_WORDS = ["aws", "amazon", "cognito"];
|
|
14
|
+
const TEMPLATE_MANAGED_ENVIRONMENT_KEYS = ["PAPYRUS_COGNITO_DOMAIN_PREFIX", "PAPYRUS_DISABLE_GOOGLE_OAUTH"];
|
|
12
15
|
const LOCAL_DEVELOPMENT_ORIGIN = "http://localhost:3001/";
|
|
13
16
|
function fail(field, problem) {
|
|
14
17
|
throw new Error(`site.json: ${field} ${problem}`);
|
|
@@ -81,7 +84,7 @@ export function parseSiteConfig(raw) {
|
|
|
81
84
|
const papyrusVersion = requireString(record.papyrusVersion, "papyrusVersion", PAPYRUS_VERSION_PATTERN, "exact version such as 1.0.0 or 1.0.0-next.1");
|
|
82
85
|
const storagePreviewPrefix = optionalString(record.storagePreviewPrefix, "storagePreviewPrefix", /^[A-Za-z0-9._-]+\/$/, "must end with /");
|
|
83
86
|
const cmsRecord = requireObject(record.cms, "cms");
|
|
84
|
-
rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "buildComputeType", "environment", "stagingDomainName"], "cms");
|
|
87
|
+
rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName"], "cms");
|
|
85
88
|
const buildComputeType = cmsRecord.buildComputeType;
|
|
86
89
|
if (buildComputeType !== undefined && buildComputeType !== "STANDARD" && buildComputeType !== "STANDARD_8GB") {
|
|
87
90
|
fail("cms.buildComputeType", `must be "STANDARD" or "STANDARD_8GB", got ${JSON.stringify(buildComputeType)}`);
|
|
@@ -93,10 +96,20 @@ export function parseSiteConfig(raw) {
|
|
|
93
96
|
appName: optionalString(cmsRecord.appName, "cms.appName", APP_NAME_PATTERN),
|
|
94
97
|
domainName: optionalString(cmsRecord.domainName, "cms.domainName", HOST_NAME_PATTERN, "host name"),
|
|
95
98
|
staging: cmsRecord.staging,
|
|
99
|
+
cognitoDomainPrefix: requireString(cmsRecord.cognitoDomainPrefix, "cms.cognitoDomainPrefix", COGNITO_DOMAIN_PREFIX_PATTERN, "lowercase letters, digits and hyphens; globally unique per region"),
|
|
96
100
|
buildComputeType: buildComputeType,
|
|
97
101
|
environment: requireStringRecord(cmsRecord.environment, "cms.environment"),
|
|
98
102
|
stagingDomainName: optionalString(cmsRecord.stagingDomainName, "cms.stagingDomainName", HOST_NAME_PATTERN, "host name"),
|
|
99
103
|
};
|
|
104
|
+
const reservedWord = COGNITO_RESERVED_WORDS.find((word) => cms.cognitoDomainPrefix.includes(word));
|
|
105
|
+
if (reservedWord) {
|
|
106
|
+
fail("cms.cognitoDomainPrefix", `must not contain "${reservedWord}" (Cognito reserves it): ${JSON.stringify(cms.cognitoDomainPrefix)}`);
|
|
107
|
+
}
|
|
108
|
+
for (const key of TEMPLATE_MANAGED_ENVIRONMENT_KEYS) {
|
|
109
|
+
if (key in cms.environment) {
|
|
110
|
+
fail(`cms.environment.${key}`, "is managed by the template: Google sign-in is always on and the Cognito domain comes from cms.cognitoDomainPrefix");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
100
113
|
if (cms.staging === false && cms.stagingDomainName) {
|
|
101
114
|
fail("cms.stagingDomainName", "must not be set when cms.staging is false");
|
|
102
115
|
}
|
package/infra/site-config.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type AmplifyAppShellSiteConfig = {
|
|
|
9
9
|
appName?: string;
|
|
10
10
|
domainName?: string;
|
|
11
11
|
staging?: boolean;
|
|
12
|
+
cognitoDomainPrefix: string;
|
|
12
13
|
buildComputeType?: "STANDARD" | "STANDARD_8GB";
|
|
13
14
|
environment: Record<string, string>;
|
|
14
15
|
stagingDomainName?: string;
|
|
@@ -43,6 +44,9 @@ const BRANCH_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9/_.-]*$/;
|
|
|
43
44
|
const PAPYRUS_VERSION_PATTERN = /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+\.\d+)?$/;
|
|
44
45
|
const GITHUB_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
|
|
45
46
|
const GITHUB_REPO_PATTERN = /^[A-Za-z0-9_.-]+$/;
|
|
47
|
+
const COGNITO_DOMAIN_PREFIX_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
48
|
+
const COGNITO_RESERVED_WORDS = ["aws", "amazon", "cognito"];
|
|
49
|
+
const TEMPLATE_MANAGED_ENVIRONMENT_KEYS = ["PAPYRUS_COGNITO_DOMAIN_PREFIX", "PAPYRUS_DISABLE_GOOGLE_OAUTH"];
|
|
46
50
|
const LOCAL_DEVELOPMENT_ORIGIN = "http://localhost:3001/";
|
|
47
51
|
|
|
48
52
|
function fail(field: string, problem: string): never {
|
|
@@ -127,7 +131,7 @@ export function parseSiteConfig(raw: unknown): AmplifyAppShellSiteConfig {
|
|
|
127
131
|
const storagePreviewPrefix = optionalString(record.storagePreviewPrefix, "storagePreviewPrefix", /^[A-Za-z0-9._-]+\/$/, "must end with /");
|
|
128
132
|
|
|
129
133
|
const cmsRecord = requireObject(record.cms, "cms");
|
|
130
|
-
rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "buildComputeType", "environment", "stagingDomainName"], "cms");
|
|
134
|
+
rejectUnknownKeys(cmsRecord, ["appName", "domainName", "staging", "cognitoDomainPrefix", "buildComputeType", "environment", "stagingDomainName"], "cms");
|
|
131
135
|
const buildComputeType = cmsRecord.buildComputeType;
|
|
132
136
|
if (buildComputeType !== undefined && buildComputeType !== "STANDARD" && buildComputeType !== "STANDARD_8GB") {
|
|
133
137
|
fail("cms.buildComputeType", `must be "STANDARD" or "STANDARD_8GB", got ${JSON.stringify(buildComputeType)}`);
|
|
@@ -139,11 +143,27 @@ export function parseSiteConfig(raw: unknown): AmplifyAppShellSiteConfig {
|
|
|
139
143
|
appName: optionalString(cmsRecord.appName, "cms.appName", APP_NAME_PATTERN),
|
|
140
144
|
domainName: optionalString(cmsRecord.domainName, "cms.domainName", HOST_NAME_PATTERN, "host name"),
|
|
141
145
|
staging: cmsRecord.staging as boolean | undefined,
|
|
146
|
+
cognitoDomainPrefix: requireString(
|
|
147
|
+
cmsRecord.cognitoDomainPrefix,
|
|
148
|
+
"cms.cognitoDomainPrefix",
|
|
149
|
+
COGNITO_DOMAIN_PREFIX_PATTERN,
|
|
150
|
+
"lowercase letters, digits and hyphens; globally unique per region",
|
|
151
|
+
),
|
|
142
152
|
buildComputeType: buildComputeType as "STANDARD" | "STANDARD_8GB" | undefined,
|
|
143
153
|
environment: requireStringRecord(cmsRecord.environment, "cms.environment"),
|
|
144
154
|
stagingDomainName: optionalString(cmsRecord.stagingDomainName, "cms.stagingDomainName", HOST_NAME_PATTERN, "host name"),
|
|
145
155
|
};
|
|
146
156
|
|
|
157
|
+
const reservedWord = COGNITO_RESERVED_WORDS.find((word) => cms.cognitoDomainPrefix.includes(word));
|
|
158
|
+
if (reservedWord) {
|
|
159
|
+
fail("cms.cognitoDomainPrefix", `must not contain "${reservedWord}" (Cognito reserves it): ${JSON.stringify(cms.cognitoDomainPrefix)}`);
|
|
160
|
+
}
|
|
161
|
+
for (const key of TEMPLATE_MANAGED_ENVIRONMENT_KEYS) {
|
|
162
|
+
if (key in cms.environment) {
|
|
163
|
+
fail(`cms.environment.${key}`, "is managed by the template: Google sign-in is always on and the Cognito domain comes from cms.cognitoDomainPrefix");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
if (cms.staging === false && cms.stagingDomainName) {
|
|
148
168
|
fail("cms.stagingDomainName", "must not be set when cms.staging is false");
|
|
149
169
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type RootSearchParams = Record<string, string | string[] | undefined>;
|
|
2
|
+
|
|
3
|
+
export function buildRootRedirectTarget(destination: string, searchParams: RootSearchParams | undefined): string {
|
|
4
|
+
const query = new URLSearchParams();
|
|
5
|
+
for (const [name, value] of Object.entries(searchParams ?? {})) {
|
|
6
|
+
if (Array.isArray(value)) {
|
|
7
|
+
for (const entry of value) query.append(name, entry);
|
|
8
|
+
} else if (value !== undefined) {
|
|
9
|
+
query.append(name, value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const serialized = query.toString();
|
|
13
|
+
if (!serialized) return destination;
|
|
14
|
+
const separator = destination.includes("?") ? "&" : "?";
|
|
15
|
+
return `${destination}${separator}${serialized}`;
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -189,6 +189,7 @@
|
|
|
189
189
|
"./lib/renderer-config": "./lib/renderer-config.ts",
|
|
190
190
|
"./lib/renderer": "./lib/renderer.ts",
|
|
191
191
|
"./lib/reporting-story-budget": "./lib/reporting-story-budget.ts",
|
|
192
|
+
"./lib/root-route-redirect": "./lib/root-route-redirect.ts",
|
|
192
193
|
"./lib/semantic-graph": "./lib/semantic-graph.ts",
|
|
193
194
|
"./lib/site-brand-tenant": "./lib/site-brand-tenant.ts",
|
|
194
195
|
"./lib/site-brand": "./lib/site-brand.ts",
|
|
@@ -276,7 +277,7 @@
|
|
|
276
277
|
"optional": true
|
|
277
278
|
}
|
|
278
279
|
},
|
|
279
|
-
"version": "1.0.0-next.
|
|
280
|
+
"version": "1.0.0-next.13",
|
|
280
281
|
"dependencies": {
|
|
281
282
|
"@aws-amplify/adapter-nextjs": "^1.7.3",
|
|
282
283
|
"@aws-sdk/client-cognito-identity-provider": "3.1045.0",
|
package/routes.manifest.json
CHANGED