getaura 0.4.0 → 0.5.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.
- package/dist/index.js +1402 -939
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/guides/security-headers.md +58 -0
- package/templates/vite/ErrorBoundary.tsx +32 -0
- package/templates/vite/NotFound.tsx +15 -0
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add security headers to a single-page app
|
|
3
|
+
summary: Where a Vite app (Lovable, Bolt, v0) sets security headers on Vercel, Netlify, Cloudflare Pages and Lovable's own hosting.
|
|
4
|
+
services: [vercel]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Add security headers to a single-page app
|
|
8
|
+
|
|
9
|
+
Security headers tell browsers to block common attacks: loading your site over plain HTTP, embedding it in another site to trick people into clicking (clickjacking), guessing file types, and leaking full addresses to other sites. A single-page app made with Vite (Lovable, Bolt, v0) can't send them itself: whoever hosts it does. This takes about ten minutes.
|
|
10
|
+
|
|
11
|
+
Run `aura apply add-security-headers` first. When Aura can tell where the app is hosted, it adds the headers for you in a pull request. Otherwise, follow the section for your host.
|
|
12
|
+
|
|
13
|
+
## Vercel
|
|
14
|
+
|
|
15
|
+
Add a `vercel.json` file at the top of the repo (or add `headers` to the one you have):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"headers": [
|
|
20
|
+
{
|
|
21
|
+
"source": "/(.*)",
|
|
22
|
+
"headers": [
|
|
23
|
+
{ "key": "Strict-Transport-Security", "value": "max-age=63072000" },
|
|
24
|
+
{ "key": "X-Content-Type-Options", "value": "nosniff" },
|
|
25
|
+
{ "key": "X-Frame-Options", "value": "DENY" },
|
|
26
|
+
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
|
|
27
|
+
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Netlify or Cloudflare Pages
|
|
35
|
+
|
|
36
|
+
Add a file called `_headers` (no extension) in the `public/` folder:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
/*
|
|
40
|
+
Strict-Transport-Security: max-age=63072000
|
|
41
|
+
X-Content-Type-Options: nosniff
|
|
42
|
+
X-Frame-Options: DENY
|
|
43
|
+
Referrer-Policy: strict-origin-when-cross-origin
|
|
44
|
+
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Lovable's hosting
|
|
48
|
+
|
|
49
|
+
Lovable's own hosting doesn't let an app set its own headers yet. You have two options:
|
|
50
|
+
|
|
51
|
+
1. Publish the app on Vercel or Netlify instead. Connect the GitHub repo there; Lovable keeps working on the same repo. Then follow the section above.
|
|
52
|
+
2. Keep Lovable's hosting and put Cloudflare in front of your custom domain, then add the headers with a Cloudflare **Transform Rule** (**Rules**, then **Transform Rules**, then **Modify Response Header**).
|
|
53
|
+
|
|
54
|
+
## Check it worked
|
|
55
|
+
|
|
56
|
+
After the next deploy, open your site, then open the browser's developer tools (**Network** tab), reload, click the first request and look under **Response Headers**. You should see the five headers above.
|
|
57
|
+
|
|
58
|
+
Aura only reads your files. It never changes your hosting settings or deploys.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
// Shown when something in the app breaks while drawing the screen, instead of a blank white page.
|
|
4
|
+
// Visitors never see the technical details: they go to the browser console for whoever is debugging.
|
|
5
|
+
|
|
6
|
+
type Props = { children: ReactNode };
|
|
7
|
+
type State = { failed: boolean };
|
|
8
|
+
|
|
9
|
+
export default class ErrorBoundary extends Component<Props, State> {
|
|
10
|
+
state: State = { failed: false };
|
|
11
|
+
|
|
12
|
+
static getDerivedStateFromError(): State {
|
|
13
|
+
return { failed: true };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
componentDidCatch(error: Error, info: ErrorInfo) {
|
|
17
|
+
console.error("The app crashed while drawing the screen", error, info.componentStack);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
render() {
|
|
21
|
+
if (!this.state.failed) return this.props.children;
|
|
22
|
+
return (
|
|
23
|
+
<main className="aura-page">
|
|
24
|
+
<h1 className="aura-title">Something went wrong</h1>
|
|
25
|
+
<p className="aura-text">Sorry, this page didn’t load. Please try again. If it keeps happening, come back in a few minutes.</p>
|
|
26
|
+
<button type="button" onClick={() => window.location.reload()} className="aura-button">
|
|
27
|
+
Reload the page
|
|
28
|
+
</button>
|
|
29
|
+
</main>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Link } from "react-router-dom";
|
|
2
|
+
|
|
3
|
+
// Shown for any address the app doesn't know, so a mistyped or old link still leads somewhere.
|
|
4
|
+
|
|
5
|
+
export default function NotFound() {
|
|
6
|
+
return (
|
|
7
|
+
<main className="aura-page">
|
|
8
|
+
<h1 className="aura-title">Page not found</h1>
|
|
9
|
+
<p className="aura-text">There’s nothing at this address. It may have moved, or the link may be mistyped.</p>
|
|
10
|
+
<Link to="/" className="aura-link">
|
|
11
|
+
Go to the home page
|
|
12
|
+
</Link>
|
|
13
|
+
</main>
|
|
14
|
+
);
|
|
15
|
+
}
|