@anthusai/papyrus 2.0.0-next.16 → 2.0.0-next.18

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.
@@ -12,6 +12,9 @@ async function lookUpRedirectTarget(uri) {
12
12
  }
13
13
 
14
14
  function rewriteToIndexDocument(uri) {
15
+ if (uri === "/404") {
16
+ return "/404.html";
17
+ }
15
18
  if (uri.endsWith("/")) {
16
19
  return uri + "index.html";
17
20
  }
@@ -1,5 +1,8 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
+ /** Mirrors DIRECTORY_HTML_PATTERN and DIRECTORY_SLASH_PATTERN in standard/config.py. */
4
+ const DIRECTORY_HTML_PATTERN = "^/(?!(?:.*/)?index\\.html$)(.+)\\.html$";
5
+ const DIRECTORY_SLASH_PATTERN = "^/((?:[^/]+/)*[^/.]+)$";
3
6
  const START_MARKER = "/*PAPYRUS_PATTERN_RULES*/";
4
7
  const END_MARKER = "/*END_PAPYRUS_PATTERN_RULES*/";
5
8
  /**
@@ -14,7 +17,9 @@ export function edgeRulesFromSettings(settings) {
14
17
  x: rule.except ?? [],
15
18
  }));
16
19
  if (settings.urls?.style === "directory") {
17
- rules.push({ p: "^/(.+)\\.html$", t: "/$1/", s: 301, x: ["/404.html"] });
20
+ // /x.html to /x/ (a directory index file such as /x/index.html is served as it is), then /x to /x/.
21
+ rules.push({ p: DIRECTORY_HTML_PATTERN, t: "/$1/", s: 301, x: ["/404.html"] });
22
+ rules.push({ p: DIRECTORY_SLASH_PATTERN, t: "/$1/", s: 301, x: ["/404"] });
18
23
  }
19
24
  return rules;
20
25
  }
@@ -4,6 +4,10 @@ import { resolve } from "node:path";
4
4
  /** One pattern redirect as the edge function reads it: regex, target with $1..$9, status, excluded paths. */
5
5
  export type EdgeRedirectRule = { p: string; t: string; s: number; x: string[] };
6
6
 
7
+ /** Mirrors DIRECTORY_HTML_PATTERN and DIRECTORY_SLASH_PATTERN in standard/config.py. */
8
+ const DIRECTORY_HTML_PATTERN = "^/(?!(?:.*/)?index\\.html$)(.+)\\.html$";
9
+ const DIRECTORY_SLASH_PATTERN = "^/((?:[^/]+/)*[^/.]+)$";
10
+
7
11
  const START_MARKER = "/*PAPYRUS_PATTERN_RULES*/";
8
12
  const END_MARKER = "/*END_PAPYRUS_PATTERN_RULES*/";
9
13
 
@@ -22,7 +26,9 @@ export function edgeRulesFromSettings(settings: ProjectionSettings): EdgeRedirec
22
26
  x: rule.except ?? [],
23
27
  }));
24
28
  if (settings.urls?.style === "directory") {
25
- rules.push({ p: "^/(.+)\\.html$", t: "/$1/", s: 301, x: ["/404.html"] });
29
+ // /x.html to /x/ (a directory index file such as /x/index.html is served as it is), then /x to /x/.
30
+ rules.push({ p: DIRECTORY_HTML_PATTERN, t: "/$1/", s: 301, x: ["/404.html"] });
31
+ rules.push({ p: DIRECTORY_SLASH_PATTERN, t: "/$1/", s: 301, x: ["/404"] });
26
32
  }
27
33
  return rules;
28
34
  }
@@ -19,6 +19,7 @@ const USAGE = [
19
19
  " papyrus-infra synth --account-stack github-oidc [--out cdk.out] [--account A] [--region R]",
20
20
  " papyrus-infra print-buildspec --site infra/site.json --app cms-production|cms-staging|reader",
21
21
  " papyrus-infra deploy-edge --stack NAME --template FILE [--adoption-template FILE --adopt-resources FILE] [--parameter KEY=VALUE]... [--delete-function NAME] [--only-branch main] [--only-app-id ID] [--region R]",
22
+ " papyrus-infra compile-edge-function --static-dir web [--out FILE]",
22
23
  " papyrus-infra deploy --site infra/site.json [--only-branch main] [--only-app-id ID] [--out cdk.out] [--account A] [--region R]",
23
24
  ].join("\n");
24
25
 
@@ -36,11 +37,29 @@ const resolveEnvironmentOrExit = () => {
36
37
  }
37
38
  };
38
39
  const command = args[0];
39
- if (command !== "synth" && command !== "print-buildspec" && command !== "deploy" && command !== "deploy-edge") {
40
+ if (command !== "synth" && command !== "print-buildspec" && command !== "deploy" && command !== "deploy-edge" && command !== "compile-edge-function") {
40
41
  console.error(USAGE);
41
42
  process.exit(command ? 1 : 0);
42
43
  }
43
44
 
45
+ if (command === "compile-edge-function") {
46
+ // The viewer-request CloudFront Function with the site's projection.json rules compiled in: for an edge stack that is
47
+ // not deployed by the CMS backend, so that no site writes its own redirect function.
48
+ const staticDir = opt("static-dir");
49
+ if (!staticDir) {
50
+ console.error(USAGE);
51
+ process.exit(1);
52
+ }
53
+ const { compileRedirectFunctionSource, readEdgeConfig } = await import("../amplify/publication/redirect-rules.js");
54
+ const functionSource = fs.readFileSync(new URL("../amplify/publication/redirect-and-index.js", import.meta.url), "utf8");
55
+ const config = readEdgeConfig(staticDir);
56
+ const compiled = compileRedirectFunctionSource(functionSource, config.rules, { negotiateMarkdown: config.negotiateMarkdown });
57
+ const out = opt("out");
58
+ if (out) fs.writeFileSync(path.resolve(out), compiled);
59
+ else process.stdout.write(compiled);
60
+ process.exit(0);
61
+ }
62
+
44
63
  if (command === "deploy-edge") {
45
64
  const buildAppId = process.env.AWS_APP_ID;
46
65
  const buildBranch = process.env.AWS_BRANCH;
package/package.json CHANGED
@@ -406,7 +406,7 @@
406
406
  "optional": true
407
407
  }
408
408
  },
409
- "version": "2.0.0-next.16",
409
+ "version": "2.0.0-next.18",
410
410
  "dependencies": {
411
411
  "@aws-amplify/adapter-nextjs": "^1.7.3",
412
412
  "@aws-crypto/sha256-js": "5.2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.0-next.16",
2
+ "version": "2.0.0-next.18",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",