Skip to content

feat: add SPA route rewrite CloudFront Function to StaticSiteConstruct#65

Merged
ncipollina merged 5 commits intomainfrom
feat/spa-rewrite-cloudfront-function
Apr 6, 2026
Merged

feat: add SPA route rewrite CloudFront Function to StaticSiteConstruct#65
ncipollina merged 5 commits intomainfrom
feat/spa-rewrite-cloudfront-function

Conversation

@ncipollina
Copy link
Copy Markdown
Contributor

Summary

Adds a CloudFront Function (viewer request event) to the default S3 behavior in StaticSiteConstruct that rewrites requests with no file extension to /index.html. This enables correct client-side routing for Blazor WASM and other SPAs — specifically fixing cases where routes like /profile or /authentication/login-callback returned 404 instead of loading the app.

The previous workaround (distribution-level 404 → /index.html error response) couldn't be used because it would also swallow legitimate API 404 responses. The CloudFront Function approach is safe because API requests match the /api/* behavior (a separate Lambda origin) and never reach the default behavior where this function runs.

Changes

  • StaticSiteConstruct.cs — creates a CloudFront.Function with a JS_2_0 viewer request handler and attaches it to DefaultBehavior.FunctionAssociations

Rewrite logic:

function handler(event) {
    var uri = event.request.uri;
    if (!uri.match(/\.[a-zA-Z0-9]+$/)) {
        event.request.uri = '/index.html';
    }
    return event.request;
}

Validation

  • dotnet build passes with 0 warnings across net8.0 / net9.0 / net10.0 targets
  • Extension matching covers all Blazor WASM asset types: .js, .wasm, .css, .json, .br, .gz, .ico, .png, .svg
  • SPA routes (/profile, /authentication/login-callback, /) correctly rewrite to /index.html
  • API paths (/api/*) use a separate CloudFront behavior and are never affected

Notes for Reviewers

The existing 403 → /index.html distribution-level error response is retained as a safety net for any S3 access-denied scenarios. The CloudFront Function handles the primary SPA routing case at the request level before S3 is ever reached.

This change applies to all consumers of StaticSiteConstruct — any static site using this construct is a SPA and benefits from this behavior unconditionally.

Attaches a CloudFront Function (viewer request) to the default S3
behavior that rewrites requests with no file extension to /index.html.
This enables client-side routing for Blazor WASM and other SPAs without
affecting API 404s, which are served via the /api/* behavior (a separate
origin) and never reach the default behavior.

Previously, missing SPA routes returned a CloudFront-level 404 because
the S3 website endpoint serves its error document with a 404 status, and
adding a distribution-level 404 → /index.html error response would also
swallow legitimate API not-found responses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

ncipollina and others added 2 commits April 6, 2026 12:25
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Construct

Callers can now supply an optional IFunction via PostConfirmationTrigger on
ICognitoUserPoolConstructProps; when provided it is wired to the UserPool via
AddTrigger(UserPoolOperation.POST_CONFIRMATION, ...).

Also bumps Amazon.CDK.Lib from 2.246.0 to 2.248.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds CloudFront viewer-request rewriting to support SPA client-side routing in StaticSiteConstruct, plus an optional Cognito User Pool post-confirmation trigger hook, and bumps package/library versions.

Changes:

  • Add a CloudFront Function to rewrite extensionless paths to /index.html on the default behavior (SPA routing fix).
  • Add optional PostConfirmationTrigger support to CognitoUserPoolConstruct.
  • Bump Amazon.CDK.Lib and the library VersionPrefix.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/LayeredCraft.Cdk.Constructs/StaticSiteConstruct.cs Introduces a CloudFront Function and associates it with the default behavior to enable SPA route rewrites.
src/LayeredCraft.Cdk.Constructs/Models/CognitoUserPoolConstructProps.cs Extends Cognito props with an optional post-confirmation Lambda trigger property.
src/LayeredCraft.Cdk.Constructs/CognitoUserPoolConstruct.cs Wires the optional post-confirmation trigger into the created Cognito User Pool.
Directory.Packages.props Updates Amazon.CDK.Lib dependency version.
Directory.Build.props Bumps package version prefix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

ncipollina and others added 2 commits April 6, 2026 15:27
…on trigger

Adds a cognito-idp:AdminAddUserToGroup policy statement to the trigger
function's execution role when a PostConfirmationTrigger is provided,
resolving the circular dependency caused by referencing the UserPool ARN
in the role policy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ncipollina ncipollina merged commit 5817c56 into main Apr 6, 2026
1 check passed
@ncipollina ncipollina deleted the feat/spa-rewrite-cloudfront-function branch April 6, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants