@batijs/cli 0.0.260 → 0.0.261
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/boilerplates/@batijs/aws/files/$README.md.js +109 -0
- package/dist/boilerplates/@batijs/aws/files/$package.json.js +138 -0
- package/dist/boilerplates/@batijs/aws/files/$tsconfig.json.js +15 -0
- package/dist/boilerplates/@batijs/aws/files/cdk/$stack-name-suffix.json.js +19 -0
- package/dist/boilerplates/@batijs/aws/files/cdk/bin/infrastructure.ts +85 -0
- package/dist/boilerplates/@batijs/aws/files/cdk/lib/vike-stack.ts +186 -0
- package/dist/boilerplates/@batijs/aws/files/cdk.json +72 -0
- package/dist/boilerplates/@batijs/aws/files/tests/aws_handler.spec.ts +116 -0
- package/dist/boilerplates/@batijs/aws/files/vitest.config.ts +8 -0
- package/dist/boilerplates/@batijs/aws/types/cdk/bin/infrastructure.d.ts +11 -0
- package/dist/boilerplates/@batijs/aws/types/cdk/lib/vike-stack.d.ts +13 -0
- package/dist/boilerplates/@batijs/aws/types/tests/aws_handler.spec.d.ts +1 -0
- package/dist/boilerplates/@batijs/aws/types/vitest.config.d.ts +2 -0
- package/dist/boilerplates/@batijs/hattip/files/$package.json.js +12 -1
- package/dist/boilerplates/@batijs/hattip/files/entry_aws_lambda.ts +37 -0
- package/dist/boilerplates/@batijs/hattip/types/entry_aws_lambda.d.ts +2 -0
- package/dist/boilerplates/@batijs/hono/files/$package.json.js +8 -1
- package/dist/boilerplates/@batijs/hono/files/entry_aws_lambda.ts +37 -0
- package/dist/boilerplates/@batijs/hono/types/entry_aws_lambda.d.ts +3 -0
- package/dist/boilerplates/boilerplates.json +11 -0
- package/dist/index.js +5 -1
- package/package.json +5 -5
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// files/$README.md.ts
|
|
2
|
+
import { loadReadme } from "@batijs/core";
|
|
3
|
+
async function getReadme(props) {
|
|
4
|
+
const content = await loadReadme(props);
|
|
5
|
+
const todo = `
|
|
6
|
+
## *AWS CDK Deployment*
|
|
7
|
+
|
|
8
|
+
This is a boilerplate for deploying your Vike app to AWS using the AWS Cloud Development Kit (CDK) including creating a custom domain in Route53.
|
|
9
|
+
|
|
10
|
+
**Architecture:**
|
|
11
|
+
- S3 Bucket for static client assets (\`/dist/client/assets\`).
|
|
12
|
+
- Lambda function for the backend and SSR.
|
|
13
|
+
- CloudFront distribution for CDN and routing requests \`/assets/*\` to the S3 bucket.
|
|
14
|
+
|
|
15
|
+
This boilerplate is a starting point for deploying your Vike app to AWS. You can customize the deployment by modifying the \`cdk/lib/vike-stack.ts\` file.
|
|
16
|
+
|
|
17
|
+
### Prerequisites
|
|
18
|
+
|
|
19
|
+
Before you get started, make sure to configure your AWS credentials.
|
|
20
|
+
|
|
21
|
+
**Loading from a file:**
|
|
22
|
+
|
|
23
|
+
You can keep your AWS credentials in a file. The credentials are found at:
|
|
24
|
+
|
|
25
|
+
\`~/.aws/credentials\` on Linux, Unix, and macOS;
|
|
26
|
+
\`C:\\Users\\USER_NAME\\.aws\\credentials\` on Windows
|
|
27
|
+
|
|
28
|
+
If the credentials file does not exist on your machine:
|
|
29
|
+
|
|
30
|
+
Download the AWS CLI from [here](https://aws.amazon.com/cli/) and configure your AWS credentials using the following command:
|
|
31
|
+
\`aws configure\`
|
|
32
|
+
|
|
33
|
+
And then use this guide to configure the credentials
|
|
34
|
+
The credentials file should look like:
|
|
35
|
+
|
|
36
|
+
\`
|
|
37
|
+
[default]
|
|
38
|
+
aws_access_key_id = <YOUR_ACCESS_KEY_ID>
|
|
39
|
+
aws_secret_access_key = <YOUR_SECRET_ACCESS_KEY>
|
|
40
|
+
\`
|
|
41
|
+
|
|
42
|
+
**Loading from environment variables:**
|
|
43
|
+
|
|
44
|
+
AWS SDK automatically detects AWS credentials in your environment and uses them for making requests to AWS. The environment variables that you need to set are:
|
|
45
|
+
|
|
46
|
+
\`AWS_ACCESS_KEY_ID\`
|
|
47
|
+
\`AWS_SECRET_ACCESS_KEY\`
|
|
48
|
+
If you are using temporary credentials, also set:
|
|
49
|
+
|
|
50
|
+
\`AWS_SESSION_TOKEN\`
|
|
51
|
+
This is often the most convenient way to configure credentials when deploying your AWS CDK app in a CI environment.
|
|
52
|
+
|
|
53
|
+
> [!NOTE]
|
|
54
|
+
> You should change the stack name to give your app stack a distinctive name in your AWS environment. You can do so by modifying the \`infrastructure.ts.ts\` file in the \`cdk/bin\` directory.
|
|
55
|
+
|
|
56
|
+
### Deployment to AWS
|
|
57
|
+
|
|
58
|
+
If you want to have a look at the synthesized CloudFormation template, you can run \`pnpm cdk synth\` and see the template as YAML on screen or in \`cdk.out/VikeStack.template.json\`.
|
|
59
|
+
|
|
60
|
+
> [!NOTE]
|
|
61
|
+
> If this is your **first time deploying a CDK app** in this environment you need to **bootstrap**:
|
|
62
|
+
> \`pnpm cdk bootstrap\`. (The default region based on your AWS CLI configuration will be used)
|
|
63
|
+
|
|
64
|
+
You can deploy your Vike App via the following command:
|
|
65
|
+
\`pnpm deploy:aws\` or \`pnpm cdk deploy\`
|
|
66
|
+
|
|
67
|
+
The URL to the CloudFront distribution will be displayed in the output of the deployment.
|
|
68
|
+
You can also access the CloudFront distribution domainname in the AWS SSM registry und \`vike/distribution/url\`.
|
|
69
|
+
|
|
70
|
+
### Stack Configuration
|
|
71
|
+
|
|
72
|
+
You can configure the stack in the \`cdk/bin/infrastructure.ts\` file:
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| Variable | Examples | Description |
|
|
75
|
+
| \`domainName: "example.com",\` | "example.com" | |
|
|
76
|
+
| \`subDomain: "www",\` |"www" | |
|
|
77
|
+
| \`certificate: undefined,\` | "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012" or a certificatemanager.ICertificate | reuse an existing AWS Certificate |
|
|
78
|
+
| \`hostedZone: undefined,\` | route53.HostedZone.fromLookup(stack, "MyHostedZone", { domainName: "example.com" }) | |
|
|
79
|
+
|
|
80
|
+
If \`domainName\` is managed by **Route53**, the \`hostedZone\` will be updated with by lookup in Route53 based on the \`domainName\`.
|
|
81
|
+
|
|
82
|
+
These scenarios are supported:
|
|
83
|
+
A. \`domainName\` exists in Route53, \`subDomain\` is given - the subdomain with the domain are used as alternative domains for the CloudFront Distribution. An new Certificate for the url is created and assigned to the CF-Distribution. An Alias-Record pointing to the CF-Distribution ist created in Route53.
|
|
84
|
+
B. \`domainName\` exists in Route53, \`subDomain\` is given - the subdomain with the domain are used as alternative domains for the CloudFront Distribution. If \`certificate\` contains a valid entry it will be assigned to the CF-Distribution. An Alias-Record pointing to the CF-Distribution ist created in Route53.
|
|
85
|
+
C. \`domainName\` **does not exist** in Route53, \`subDomain\` is given - the subdomain with the domain are used as alternative domains for the CloudFront Distribution. If \`certificate\` contains a valid entry it will be assigned to the CF-Distribution. A manual created CNAME or A-Record should pointing to the CF-Distribution.
|
|
86
|
+
|
|
87
|
+
#### Custom Domain
|
|
88
|
+
|
|
89
|
+
If you have a custom domain, you can add it to the stack configuration in the \`cdk/bin/infrastructure.ts\` file:
|
|
90
|
+
|
|
91
|
+
> [!NOTE]
|
|
92
|
+
> If you deploy your App to a region different than \`us-east-1\` and you have never deployed to this region before, you will need to bootstrap this region too:
|
|
93
|
+
\`CDK_DEFAULT_REGION=us-east-1 pnpm deploy:cdk bootstrap\`
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
### Destroying the Stack on AWS
|
|
97
|
+
|
|
98
|
+
To destroy the stack on AWS, run the following command:
|
|
99
|
+
\`pnpm cdk destroy\`
|
|
100
|
+
|
|
101
|
+
Or delete the CloudFormation stack which starts with "VikeStack-<Your App Name>" created by this project.
|
|
102
|
+
|
|
103
|
+
`;
|
|
104
|
+
content.addTodo(todo);
|
|
105
|
+
return content.finalize();
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
getReadme as default
|
|
109
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// package.json
|
|
28
|
+
var require_package = __commonJS({
|
|
29
|
+
"package.json"(exports, module) {
|
|
30
|
+
module.exports = {
|
|
31
|
+
name: "@batijs/aws",
|
|
32
|
+
private: true,
|
|
33
|
+
version: "0.0.1",
|
|
34
|
+
description: "",
|
|
35
|
+
type: "module",
|
|
36
|
+
scripts: {
|
|
37
|
+
"check-types": "tsc --noEmit",
|
|
38
|
+
build: "bati-compile-boilerplate"
|
|
39
|
+
},
|
|
40
|
+
keywords: [],
|
|
41
|
+
author: "",
|
|
42
|
+
license: "MIT",
|
|
43
|
+
devDependencies: {
|
|
44
|
+
"@batijs/compile": "workspace:*",
|
|
45
|
+
"@types/node": "^18.19.14",
|
|
46
|
+
"@types/which": "^3.0.4",
|
|
47
|
+
"aws-cdk": "^2.154.1",
|
|
48
|
+
"aws-cdk-lib": "^2.154.1",
|
|
49
|
+
cdk: "^2.154.1",
|
|
50
|
+
constructs: "^10.3.0",
|
|
51
|
+
esbuild: "^0.23.1",
|
|
52
|
+
"source-map-support": "^0.5.21",
|
|
53
|
+
tsx: "^4.19.0",
|
|
54
|
+
typescript: "^5.5.4",
|
|
55
|
+
vitest: "^2.0.5",
|
|
56
|
+
which: "^4.0.0"
|
|
57
|
+
},
|
|
58
|
+
dependencies: {
|
|
59
|
+
"@batijs/core": "workspace:*"
|
|
60
|
+
},
|
|
61
|
+
files: [
|
|
62
|
+
"dist/"
|
|
63
|
+
],
|
|
64
|
+
bati: {
|
|
65
|
+
if: {
|
|
66
|
+
flag: "aws"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
exports: {
|
|
70
|
+
"./vitest.config": {
|
|
71
|
+
types: "./dist/types/vitest.config.d.ts"
|
|
72
|
+
},
|
|
73
|
+
"./cdk/lib/vike-stack": {
|
|
74
|
+
types: "./dist/types/cdk/lib/vike-stack.d.ts"
|
|
75
|
+
},
|
|
76
|
+
"./cdk/bin/infrastructure": {
|
|
77
|
+
types: "./dist/types/cdk/bin/infrastructure.d.ts"
|
|
78
|
+
},
|
|
79
|
+
"./tests/aws_handler.spec": {
|
|
80
|
+
types: "./dist/types/tests/aws_handler.spec.d.ts"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
typesVersions: {
|
|
84
|
+
"*": {
|
|
85
|
+
"vitest.config": [
|
|
86
|
+
"./dist/types/vitest.config.d.ts"
|
|
87
|
+
],
|
|
88
|
+
"cdk/lib/vike-stack": [
|
|
89
|
+
"./dist/types/cdk/lib/vike-stack.d.ts"
|
|
90
|
+
],
|
|
91
|
+
"cdk/bin/infrastructure": [
|
|
92
|
+
"./dist/types/cdk/bin/infrastructure.d.ts"
|
|
93
|
+
],
|
|
94
|
+
"tests/aws_handler.spec": [
|
|
95
|
+
"./dist/types/tests/aws_handler.spec.d.ts"
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// files/$package.json.ts
|
|
104
|
+
import { addDependency, loadAsJson, setScripts } from "@batijs/core";
|
|
105
|
+
async function getPackageJson(props) {
|
|
106
|
+
const packageJson = await loadAsJson(props);
|
|
107
|
+
setScripts(packageJson, {
|
|
108
|
+
test: {
|
|
109
|
+
value: "vitest",
|
|
110
|
+
precedence: 0
|
|
111
|
+
},
|
|
112
|
+
"deploy:cdk": {
|
|
113
|
+
value: "cdk",
|
|
114
|
+
precedence: 0
|
|
115
|
+
},
|
|
116
|
+
"deploy:aws": {
|
|
117
|
+
value: "pnpm run build && cdk deploy --all",
|
|
118
|
+
precedence: 0
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return addDependency(packageJson, await Promise.resolve().then(() => __toESM(require_package(), 1)).then((x) => x.default), {
|
|
122
|
+
devDependencies: [
|
|
123
|
+
"cdk",
|
|
124
|
+
"aws-cdk",
|
|
125
|
+
"@types/node",
|
|
126
|
+
"tsx",
|
|
127
|
+
"typescript",
|
|
128
|
+
"esbuild",
|
|
129
|
+
"vitest",
|
|
130
|
+
"which",
|
|
131
|
+
"@types/which"
|
|
132
|
+
],
|
|
133
|
+
dependencies: ["aws-cdk-lib", "constructs", "source-map-support"]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
getPackageJson as default
|
|
138
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// files/$tsconfig.json.ts
|
|
2
|
+
import { loadAsJson } from "@batijs/core";
|
|
3
|
+
async function getTsConfig(props) {
|
|
4
|
+
const tsConfig = await loadAsJson(props);
|
|
5
|
+
tsConfig.compilerOptions.types = [
|
|
6
|
+
...tsConfig.compilerOptions.types ?? [],
|
|
7
|
+
"@types/node",
|
|
8
|
+
"vitest/globals",
|
|
9
|
+
"@types/which"
|
|
10
|
+
];
|
|
11
|
+
return tsConfig;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
getTsConfig as default
|
|
15
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// files/cdk/$stack-name-suffix.json.ts
|
|
2
|
+
async function getDataJson() {
|
|
3
|
+
const dataJson = {
|
|
4
|
+
stackNameSuffix: generateRandomPrefix(8)
|
|
5
|
+
};
|
|
6
|
+
return dataJson;
|
|
7
|
+
}
|
|
8
|
+
function generateRandomPrefix(length) {
|
|
9
|
+
if (process.env.NODE_ENV === "test") return "TEST";
|
|
10
|
+
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
11
|
+
let result = "";
|
|
12
|
+
for (let i = 0; i < length; i++) {
|
|
13
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
getDataJson as default
|
|
19
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "source-map-support/register";
|
|
3
|
+
import * as cdk from "aws-cdk-lib";
|
|
4
|
+
import { VikeStack } from "../lib/vike-stack";
|
|
5
|
+
|
|
6
|
+
import * as certificatemanager from "aws-cdk-lib/aws-certificatemanager";
|
|
7
|
+
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
8
|
+
|
|
9
|
+
//# BATI.has("REMOVE-COMMENT") || "remove-comments-only"
|
|
10
|
+
// @ts-ignore file will be generated by the transformer
|
|
11
|
+
import { stackNameSuffix } from "../stack-name-suffix.json";
|
|
12
|
+
|
|
13
|
+
const env: cdk.Environment = {
|
|
14
|
+
account: process.env.CDK_DEFAULT_ACCOUNT,
|
|
15
|
+
region: process.env.CDK_DEFAULT_REGION,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type CustomStackProps = cdk.StackProps & {
|
|
19
|
+
domainName?: string;
|
|
20
|
+
subDomain?: string;
|
|
21
|
+
certificate?: string | certificatemanager.ICertificate;
|
|
22
|
+
hostedZone?: route53.IHostedZone;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Here you can configure the stack:
|
|
26
|
+
const customStackProps: CustomStackProps = {
|
|
27
|
+
domainName: undefined, // e.g. "example.com"
|
|
28
|
+
subDomain: undefined, // e.g. "www"
|
|
29
|
+
certificate: undefined, // e.g. "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012" or a certificatemanager.ICertificate
|
|
30
|
+
hostedZone: undefined, // e.g. route53.HostedZone.fromLookup(stack, "MyHostedZone", { domainName: "example.com" })
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const app = new cdk.App();
|
|
34
|
+
|
|
35
|
+
const usEast1Stack = customStackProps?.domainName
|
|
36
|
+
? new cdk.Stack(app, `VikeStack-Cert-${stackNameSuffix}`, {
|
|
37
|
+
env: {
|
|
38
|
+
...env,
|
|
39
|
+
region: "us-east-1",
|
|
40
|
+
},
|
|
41
|
+
crossRegionReferences: true,
|
|
42
|
+
})
|
|
43
|
+
: undefined;
|
|
44
|
+
|
|
45
|
+
customStackProps.hostedZone = usEast1Stack
|
|
46
|
+
? customStackProps?.hostedZone
|
|
47
|
+
? customStackProps?.hostedZone
|
|
48
|
+
: customStackProps?.domainName
|
|
49
|
+
? route53.HostedZone.fromLookup(usEast1Stack, "MyHostedZone", {
|
|
50
|
+
domainName: customStackProps.domainName,
|
|
51
|
+
})
|
|
52
|
+
: undefined
|
|
53
|
+
: undefined;
|
|
54
|
+
|
|
55
|
+
customStackProps.certificate = usEast1Stack ? loadCertificate(usEast1Stack, customStackProps) : undefined;
|
|
56
|
+
|
|
57
|
+
const mainStack = new VikeStack(app, `VikeStack-${stackNameSuffix}`, {
|
|
58
|
+
env,
|
|
59
|
+
crossRegionReferences: true,
|
|
60
|
+
customStackProps,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (usEast1Stack) {
|
|
64
|
+
mainStack.addDependency(usEast1Stack);
|
|
65
|
+
app.synth();
|
|
66
|
+
}
|
|
67
|
+
function loadCertificate(stack: cdk.Stack, stackConfig: CustomStackProps): certificatemanager.ICertificate | undefined {
|
|
68
|
+
const { domainName, subDomain, certificate, hostedZone } = stackConfig;
|
|
69
|
+
if (typeof certificate === "string") {
|
|
70
|
+
certificatemanager.Certificate.fromCertificateArn(stack, "Certificate", certificate);
|
|
71
|
+
} else if (certificate) {
|
|
72
|
+
return certificate;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!domainName) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const siteDomainName = `${(subDomain?.length ?? 0 > 0) ? `${subDomain}.` : ""}${domainName}`;
|
|
80
|
+
return new certificatemanager.Certificate(stack, "Certificate", {
|
|
81
|
+
domainName: siteDomainName,
|
|
82
|
+
//subjectAlternativeNames: props.domainAliases,
|
|
83
|
+
validation: certificatemanager.CertificateValidation.fromDns(hostedZone),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "source-map-support/register";
|
|
3
|
+
import { Construct } from "constructs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import * as cdk from "aws-cdk-lib";
|
|
7
|
+
import * as ssm from "aws-cdk-lib/aws-ssm";
|
|
8
|
+
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
9
|
+
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";
|
|
10
|
+
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
11
|
+
import * as logs from "aws-cdk-lib/aws-logs";
|
|
12
|
+
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
|
|
13
|
+
import * as nodejs from "aws-cdk-lib/aws-lambda-nodejs";
|
|
14
|
+
import * as origin from "aws-cdk-lib/aws-cloudfront-origins";
|
|
15
|
+
import * as api from "aws-cdk-lib/aws-apigatewayv2";
|
|
16
|
+
import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
|
|
17
|
+
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
18
|
+
import * as targets from "aws-cdk-lib/aws-route53-targets";
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
import type { CustomStackProps } from "../bin/infrastructure";
|
|
21
|
+
|
|
22
|
+
type VikeStackProps = cdk.StackProps & {
|
|
23
|
+
customStackProps: CustomStackProps;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Define __dirname for ES module scope
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
const __dirname = join(__filename, "..");
|
|
29
|
+
|
|
30
|
+
export class VikeStack extends cdk.Stack {
|
|
31
|
+
readonly distributionUrlParameterName = `/${this.stackName}/distribution/url`;
|
|
32
|
+
|
|
33
|
+
constructor(scope: Construct, id: string, props: VikeStackProps) {
|
|
34
|
+
super(scope, id, props);
|
|
35
|
+
|
|
36
|
+
const certificate =
|
|
37
|
+
props.customStackProps?.certificate && typeof props.customStackProps?.certificate !== "string"
|
|
38
|
+
? props.customStackProps?.certificate
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
41
|
+
const hostedZone = props.customStackProps?.hostedZone;
|
|
42
|
+
const subDomain = props.customStackProps?.subDomain;
|
|
43
|
+
const domainName = props.customStackProps?.domainName;
|
|
44
|
+
const siteDomainName = domainName
|
|
45
|
+
? `${(subDomain?.length ?? 0 > 0) ? `${subDomain}.` : ""}${domainName}`
|
|
46
|
+
: undefined;
|
|
47
|
+
|
|
48
|
+
const bucket = new s3.Bucket(this, "StaticAssetsBucket", {
|
|
49
|
+
/**
|
|
50
|
+
* The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete
|
|
51
|
+
* the new bucket, and it will remain in your account until manually deleted. By setting the policy to
|
|
52
|
+
* DESTROY, cdk destroy will attempt to delete the bucket, but will error if the bucket is not empty.
|
|
53
|
+
*/
|
|
54
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY, // NOT recommended for production code
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* For sample purposes only, if you create an S3 bucket then populate it, stack destruction fails. This
|
|
58
|
+
* setting will enable full cleanup of the demo.
|
|
59
|
+
*/
|
|
60
|
+
autoDeleteObjects: true, // NOT recommended for production code
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Create a Lambda function for the backend
|
|
64
|
+
const banner =
|
|
65
|
+
"const require = (await import('node:module')).createRequire(import.meta.url);const __filename = (await import('node:url')).fileURLToPath(import.meta.url);const __dirname = (await import('node:path')).dirname(__filename);";
|
|
66
|
+
|
|
67
|
+
const fn = new nodejs.NodejsFunction(this, "RequestHandler", {
|
|
68
|
+
handler: "handler",
|
|
69
|
+
entry: join(__dirname, "../../entry_aws_lambda.ts"),
|
|
70
|
+
// fix error: "Cannot find a package lock file ..." when using "bun" javascript package manager and runtime
|
|
71
|
+
depsLockFilePath: findBunLockFile(),
|
|
72
|
+
environment: {
|
|
73
|
+
NODE_ENV: "production",
|
|
74
|
+
},
|
|
75
|
+
bundling: {
|
|
76
|
+
banner,
|
|
77
|
+
format: nodejs.OutputFormat.ESM,
|
|
78
|
+
minify: true,
|
|
79
|
+
target: "esnext",
|
|
80
|
+
//nodeModules: ["react", "react-dom"],
|
|
81
|
+
esbuildArgs: {
|
|
82
|
+
"--tree-shaking": true,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
runtime: lambda.Runtime.NODEJS_20_X,
|
|
86
|
+
architecture: lambda.Architecture.ARM_64,
|
|
87
|
+
memorySize: 256,
|
|
88
|
+
timeout: cdk.Duration.seconds(10),
|
|
89
|
+
logRetention: logs.RetentionDays.THREE_DAYS,
|
|
90
|
+
tracing: lambda.Tracing.ACTIVE,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const integration = new HttpLambdaIntegration("RequestHandlerIntegration", fn, {
|
|
94
|
+
payloadFormatVersion: api.PayloadFormatVersion.VERSION_2_0,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const httpApi = new api.HttpApi(this, "WebsiteApi", {
|
|
98
|
+
defaultIntegration: integration,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const httpApiUrl = `${httpApi.httpApiId}.execute-api.${cdk.Stack.of(this).region}.${cdk.Stack.of(this).urlSuffix}`;
|
|
102
|
+
|
|
103
|
+
// Create a CloudFront distribution with custom behaviors
|
|
104
|
+
const requestHandlerOrigin = new origin.HttpOrigin(httpApiUrl);
|
|
105
|
+
|
|
106
|
+
const requestHandlerBehavior: cloudfront.AddBehaviorOptions = {
|
|
107
|
+
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
|
|
108
|
+
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
109
|
+
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
|
|
110
|
+
// https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html
|
|
111
|
+
originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
|
|
112
|
+
compress: true,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const assetOrigin = new origin.S3Origin(bucket);
|
|
116
|
+
const assetBehaviorOptions = {
|
|
117
|
+
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
118
|
+
compress: true,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const distribution = new cloudfront.Distribution(this, "CloudFront", {
|
|
122
|
+
defaultBehavior: {
|
|
123
|
+
origin: requestHandlerOrigin,
|
|
124
|
+
...requestHandlerBehavior,
|
|
125
|
+
},
|
|
126
|
+
domainNames: siteDomainName ? [siteDomainName] : undefined,
|
|
127
|
+
certificate,
|
|
128
|
+
enableIpv6: true,
|
|
129
|
+
minimumProtocolVersion: cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
|
|
130
|
+
httpVersion: cloudfront.HttpVersion.HTTP2_AND_3,
|
|
131
|
+
priceClass: cloudfront.PriceClass.PRICE_CLASS_100,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
distribution.addBehavior("/assets/*", assetOrigin, assetBehaviorOptions);
|
|
135
|
+
|
|
136
|
+
// Deploy static assets to the S3 bucket and invalidate the CloudFront cache
|
|
137
|
+
new s3deploy.BucketDeployment(this, "DeployStaticAssets", {
|
|
138
|
+
sources: [s3deploy.Source.asset(join(__dirname, "../../dist/client"))],
|
|
139
|
+
destinationBucket: bucket,
|
|
140
|
+
distribution,
|
|
141
|
+
distributionPaths: ["/*"],
|
|
142
|
+
prune: true,
|
|
143
|
+
cacheControl: [
|
|
144
|
+
s3deploy.CacheControl.maxAge(cdk.Duration.days(365)),
|
|
145
|
+
s3deploy.CacheControl.sMaxAge(cdk.Duration.days(365)),
|
|
146
|
+
],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Create a Route 53 alias record pointing to the CloudFront distribution
|
|
150
|
+
if (hostedZone) {
|
|
151
|
+
new route53.ARecord(this, "AliasRecord", {
|
|
152
|
+
zone: hostedZone,
|
|
153
|
+
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
|
|
154
|
+
recordName: subDomain ?? "", // This will create a record for www.example.com
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Store the CloudFront URL in an SSM parameter
|
|
159
|
+
new ssm.StringParameter(this, "DistributionUrlParameter", {
|
|
160
|
+
parameterName: this.distributionUrlParameterName,
|
|
161
|
+
stringValue: siteDomainName ? siteDomainName! : distribution.distributionDomainName,
|
|
162
|
+
tier: ssm.ParameterTier.STANDARD,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Output the CloudFront URL and API endpoint
|
|
166
|
+
new cdk.CfnOutput(this, "CloudFrontURL", {
|
|
167
|
+
value: `https://${siteDomainName ? siteDomainName : distribution.distributionDomainName}`,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
new cdk.CfnOutput(this, "CloudFrontID", {
|
|
171
|
+
value: distribution.distributionId,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function findBunLockFile() {
|
|
177
|
+
let bunLockFile = join(__dirname, "../../", "bun.lockb");
|
|
178
|
+
if (existsSync(bunLockFile)) {
|
|
179
|
+
return bunLockFile;
|
|
180
|
+
}
|
|
181
|
+
bunLockFile = join(__dirname, "../../", "../../", "bun.lockb"); // special case for bat tests
|
|
182
|
+
if (existsSync(bunLockFile)) {
|
|
183
|
+
return bunLockFile;
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "pnpm tsx cdk/bin/infrastructure.ts",
|
|
3
|
+
"watch": {
|
|
4
|
+
"include": [
|
|
5
|
+
"**"
|
|
6
|
+
],
|
|
7
|
+
"exclude": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"cdk*.json",
|
|
10
|
+
"**/*.d.ts",
|
|
11
|
+
"**/*.js",
|
|
12
|
+
"tsconfig.json",
|
|
13
|
+
"package*.json",
|
|
14
|
+
"yarn.lock",
|
|
15
|
+
"node_modules",
|
|
16
|
+
"test"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"context": {
|
|
20
|
+
"@aws-cdk/core:newStyleStackSynthesis": true,
|
|
21
|
+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
|
22
|
+
"@aws-cdk/core:checkSecretUsage": true,
|
|
23
|
+
"@aws-cdk/core:target-partitions": [
|
|
24
|
+
"aws",
|
|
25
|
+
"aws-cn"
|
|
26
|
+
],
|
|
27
|
+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
|
28
|
+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
|
29
|
+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
|
|
30
|
+
"@aws-cdk/aws-iam:minimizePolicies": true,
|
|
31
|
+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
|
32
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
|
33
|
+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
|
34
|
+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
|
35
|
+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
|
|
36
|
+
"@aws-cdk/core:enablePartitionLiterals": true,
|
|
37
|
+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
|
|
38
|
+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
|
|
39
|
+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
|
|
40
|
+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
|
|
41
|
+
"@aws-cdk/aws-route53-patters:useCertificate": true,
|
|
42
|
+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
|
|
43
|
+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
|
|
44
|
+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
|
|
45
|
+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
|
|
46
|
+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
|
|
47
|
+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
|
|
48
|
+
"@aws-cdk/aws-redshift:columnId": true,
|
|
49
|
+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
|
|
50
|
+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
|
|
51
|
+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
|
|
52
|
+
"@aws-cdk/aws-kms:aliasNameRef": true,
|
|
53
|
+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
|
|
54
|
+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
|
|
55
|
+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
|
|
56
|
+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
|
|
57
|
+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
|
|
58
|
+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
|
|
59
|
+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
|
|
60
|
+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
|
|
61
|
+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
|
|
62
|
+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
|
|
63
|
+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
|
|
64
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
|
|
65
|
+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
|
|
66
|
+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
|
|
67
|
+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
|
|
68
|
+
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
|
|
69
|
+
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
|
|
70
|
+
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import * as which from "which";
|
|
7
|
+
|
|
8
|
+
const bunExists = which.sync("bun", { nothrow: true }) !== null;
|
|
9
|
+
const npmCli = bunExists ? "bun" : "pnpm";
|
|
10
|
+
|
|
11
|
+
console.log("RUN TESTS ***");
|
|
12
|
+
|
|
13
|
+
describe("AWSHandler", () => {
|
|
14
|
+
beforeAll(
|
|
15
|
+
async () => {
|
|
16
|
+
if (existsSync(path.join(process.cwd(), "cdk.out"))) {
|
|
17
|
+
rmSync(path.join(process.cwd(), "cdk.out"), { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
/*
|
|
20
|
+
* `--build "${npmCli} run build"` is required to build the project before synth
|
|
21
|
+
*/
|
|
22
|
+
const synthCommand = `${npmCli} run cdk --json --build "${npmCli} run build" synth`;
|
|
23
|
+
execSync(synthCommand, {
|
|
24
|
+
encoding: "utf8",
|
|
25
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
26
|
+
env: {
|
|
27
|
+
BUN_LOCKFILE: "../../bun.lockb", // This is to make sure that the correct lockfile is used in a bun project
|
|
28
|
+
PATH: process.env.PATH,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
2 * 60 * 1000,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
it("should request a page from the AWS handler", async () => {
|
|
36
|
+
const cdkOutPath = path.join(process.cwd(), "cdk.out");
|
|
37
|
+
const templateFilePath = readdirSync(cdkOutPath).find(
|
|
38
|
+
(file) => file.startsWith("VikeStack-") && file.endsWith(".template.json"),
|
|
39
|
+
);
|
|
40
|
+
const templateFullPath = path.join(cdkOutPath, templateFilePath!);
|
|
41
|
+
expect(existsSync(templateFullPath)).toBe(true);
|
|
42
|
+
const cloudfrontTemplateJson = readFileSync(templateFullPath, "utf8");
|
|
43
|
+
const requestHandlerFolder = extractRequestHandlerPath(
|
|
44
|
+
JSON.parse(cloudfrontTemplateJson),
|
|
45
|
+
"/RequestHandler/Resource",
|
|
46
|
+
);
|
|
47
|
+
const requestHandlerPath = path.join(process.cwd(), "cdk.out", requestHandlerFolder!, "index.mjs");
|
|
48
|
+
expect(existsSync(requestHandlerPath)).toBe(true);
|
|
49
|
+
|
|
50
|
+
const { handler } = await import(requestHandlerPath);
|
|
51
|
+
const event = {
|
|
52
|
+
version: "2.0",
|
|
53
|
+
routeKey: "$default",
|
|
54
|
+
rawPath: "/",
|
|
55
|
+
rawQueryString: "",
|
|
56
|
+
headers: {
|
|
57
|
+
accept: "*/*",
|
|
58
|
+
"content-length": "0",
|
|
59
|
+
host: "example.com",
|
|
60
|
+
"user-agent": "PostmanRuntime/7.26.8",
|
|
61
|
+
"x-amzn-trace-id": "Root=1-5f84c7a9-0e5b1e1e1e1e1e1e1e1e1e1e",
|
|
62
|
+
"x-forwarded-for": "127.0.0.1",
|
|
63
|
+
"x-forwarded-port": "443",
|
|
64
|
+
"x-forwarded-proto": "https",
|
|
65
|
+
},
|
|
66
|
+
requestContext: {
|
|
67
|
+
accountId: "123456789012",
|
|
68
|
+
apiId: "api-id",
|
|
69
|
+
domainName: "example.com",
|
|
70
|
+
domainPrefix: "example",
|
|
71
|
+
http: {
|
|
72
|
+
method: "GET",
|
|
73
|
+
path: "/",
|
|
74
|
+
protocol: "HTTP/1.1",
|
|
75
|
+
sourceIp: "127.0.0.1",
|
|
76
|
+
userAgent: "PostmanRuntime/7.26.8",
|
|
77
|
+
},
|
|
78
|
+
requestId: "id",
|
|
79
|
+
routeKey: "$default",
|
|
80
|
+
stage: "$default",
|
|
81
|
+
time: "12/Mar/2021:19:03:58 +0000",
|
|
82
|
+
timeEpoch: 1615578238000,
|
|
83
|
+
},
|
|
84
|
+
isBase64Encoded: false,
|
|
85
|
+
};
|
|
86
|
+
const response = await handler(event, {});
|
|
87
|
+
expect(response.statusCode).toBe(200);
|
|
88
|
+
const body = response.isBase64Encoded ? Buffer.from(response.body, "base64").toString("utf8") : response.body;
|
|
89
|
+
expect(body).toContain("My Vike App");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
94
|
+
type JsonData = Record<string, any>;
|
|
95
|
+
|
|
96
|
+
function extractRequestHandlerPath(jsonData: JsonData, targetCdkPath: string): string | null {
|
|
97
|
+
let assetPath: string | null = null;
|
|
98
|
+
|
|
99
|
+
function traverse(obj: JsonData) {
|
|
100
|
+
if (typeof obj !== "object" || obj === null) return;
|
|
101
|
+
|
|
102
|
+
if (obj?.["aws:cdk:path"]?.endsWith(targetCdkPath)) {
|
|
103
|
+
assetPath = obj?.["aws:asset:path"];
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
for (const key in obj) {
|
|
108
|
+
if (obj?.[key]) {
|
|
109
|
+
traverse(obj[key]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
traverse(jsonData);
|
|
115
|
+
return assetPath;
|
|
116
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "source-map-support/register";
|
|
3
|
+
import * as cdk from "aws-cdk-lib";
|
|
4
|
+
import * as certificatemanager from "aws-cdk-lib/aws-certificatemanager";
|
|
5
|
+
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
6
|
+
export type CustomStackProps = cdk.StackProps & {
|
|
7
|
+
domainName?: string;
|
|
8
|
+
subDomain?: string;
|
|
9
|
+
certificate?: string | certificatemanager.ICertificate;
|
|
10
|
+
hostedZone?: route53.IHostedZone;
|
|
11
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "source-map-support/register";
|
|
3
|
+
import { Construct } from "constructs";
|
|
4
|
+
import * as cdk from "aws-cdk-lib";
|
|
5
|
+
import type { CustomStackProps } from "../bin/infrastructure";
|
|
6
|
+
type VikeStackProps = cdk.StackProps & {
|
|
7
|
+
customStackProps: CustomStackProps;
|
|
8
|
+
};
|
|
9
|
+
export declare class VikeStack extends cdk.Stack {
|
|
10
|
+
readonly distributionUrlParameterName: string;
|
|
11
|
+
constructor(scope: Construct, id: string, props: VikeStackProps);
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -58,6 +58,10 @@ var require_package = __commonJS({
|
|
|
58
58
|
"@hattip/core": "^0.0.47",
|
|
59
59
|
"@hattip/router": "^0.0.47",
|
|
60
60
|
"@hattip/vite": "^0.0.47",
|
|
61
|
+
"@hattip/adapter-aws-lambda": "^0.0.47",
|
|
62
|
+
"@hattip/static": "^0.0.47",
|
|
63
|
+
"@hattip/walk": "^0.0.47",
|
|
64
|
+
"@types/aws-lambda": "^8.10.143",
|
|
61
65
|
"@trpc/server": "^10.45.2",
|
|
62
66
|
"@types/node": "^18.19.14",
|
|
63
67
|
"@universal-middleware/hattip": "^0.2.4",
|
|
@@ -82,12 +86,18 @@ var require_package = __commonJS({
|
|
|
82
86
|
exports: {
|
|
83
87
|
"./hattip-entry": {
|
|
84
88
|
types: "./dist/types/hattip-entry.d.ts"
|
|
89
|
+
},
|
|
90
|
+
"./entry_aws_lambda": {
|
|
91
|
+
types: "./dist/types/entry_aws_lambda.d.ts"
|
|
85
92
|
}
|
|
86
93
|
},
|
|
87
94
|
typesVersions: {
|
|
88
95
|
"*": {
|
|
89
96
|
"hattip-entry": [
|
|
90
97
|
"./dist/types/hattip-entry.d.ts"
|
|
98
|
+
],
|
|
99
|
+
entry_aws_lambda: [
|
|
100
|
+
"./dist/types/entry_aws_lambda.d.ts"
|
|
91
101
|
]
|
|
92
102
|
}
|
|
93
103
|
}
|
|
@@ -136,7 +146,8 @@ async function getPackageJson(props) {
|
|
|
136
146
|
"vite",
|
|
137
147
|
"vike",
|
|
138
148
|
"@universal-middleware/hattip",
|
|
139
|
-
...props.meta.BATI.has("vercel") ? ["@hattip/adapter-vercel-edge"] : []
|
|
149
|
+
...props.meta.BATI.has("vercel") ? ["@hattip/adapter-vercel-edge"] : [],
|
|
150
|
+
...props.meta.BATI.has("aws") ? ["@types/aws-lambda", "@hattip/adapter-aws-lambda", "@hattip/static", "@hattip/walk"] : []
|
|
140
151
|
]
|
|
141
152
|
});
|
|
142
153
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*{ @if (it.BATI.has("aws")) }*/
|
|
2
|
+
/*
|
|
3
|
+
entry_aws_lambda.ts
|
|
4
|
+
|
|
5
|
+
This file is the entry point for AWS Lambda
|
|
6
|
+
|
|
7
|
+
Notes:
|
|
8
|
+
* The file name must not have any special characters or dots except for the extension. https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#API_CreateFunction_RequestSyntax
|
|
9
|
+
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import awsLambdaAdapter from "@hattip/adapter-aws-lambda";
|
|
14
|
+
import { walk } from "@hattip/walk";
|
|
15
|
+
import type { FileInfo } from "@hattip/walk";
|
|
16
|
+
import { createStaticMiddleware } from "@hattip/static";
|
|
17
|
+
import { createFileReader } from "@hattip/static/fs";
|
|
18
|
+
import hattipHandler from "@batijs/hattip/hattip-entry";
|
|
19
|
+
import type { Handler, APIGatewayProxyResultV2, APIGatewayProxyEventV2 } from "aws-lambda";
|
|
20
|
+
|
|
21
|
+
const root = new URL("./dist/client", import.meta.url);
|
|
22
|
+
const staticRootExists = existsSync(root);
|
|
23
|
+
const files = staticRootExists ? walk(root) : new Map<string, FileInfo>();
|
|
24
|
+
const staticMiddleware = staticRootExists
|
|
25
|
+
? createStaticMiddleware(files, createFileReader(root), {
|
|
26
|
+
urlRoot: "/",
|
|
27
|
+
})
|
|
28
|
+
: undefined;
|
|
29
|
+
|
|
30
|
+
const awsHandler = awsLambdaAdapter((ctx) => {
|
|
31
|
+
if (hattipHandler === undefined) throw new Error("hattipHandler is undefined");
|
|
32
|
+
if (staticMiddleware === undefined) return hattipHandler(ctx);
|
|
33
|
+
return staticMiddleware(ctx) || hattipHandler(ctx);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const handler: Handler<APIGatewayProxyEventV2, APIGatewayProxyResultV2> = awsHandler;
|
|
37
|
+
/*{ /if }*/
|
|
@@ -55,6 +55,7 @@ var require_package = __commonJS({
|
|
|
55
55
|
"@cloudflare/workers-types": "^4.20240821.1",
|
|
56
56
|
"@hono/node-server": "^1.12.2",
|
|
57
57
|
"@hono/vite-dev-server": "^0.15.1",
|
|
58
|
+
"@types/aws-lambda": "^8.10.145",
|
|
58
59
|
"@trpc/server": "^10.45.2",
|
|
59
60
|
"@types/node": "^18.19.14",
|
|
60
61
|
"@universal-middleware/hono": "^0.2.5",
|
|
@@ -81,6 +82,9 @@ var require_package = __commonJS({
|
|
|
81
82
|
"./hono-entry": {
|
|
82
83
|
types: "./dist/types/hono-entry.d.ts"
|
|
83
84
|
},
|
|
85
|
+
"./entry_aws_lambda": {
|
|
86
|
+
types: "./dist/types/entry_aws_lambda.d.ts"
|
|
87
|
+
},
|
|
84
88
|
"./hono-entry.node": {
|
|
85
89
|
types: "./dist/types/hono-entry.node.d.ts"
|
|
86
90
|
}
|
|
@@ -90,6 +94,9 @@ var require_package = __commonJS({
|
|
|
90
94
|
"hono-entry": [
|
|
91
95
|
"./dist/types/hono-entry.d.ts"
|
|
92
96
|
],
|
|
97
|
+
entry_aws_lambda: [
|
|
98
|
+
"./dist/types/entry_aws_lambda.d.ts"
|
|
99
|
+
],
|
|
93
100
|
"hono-entry.node": [
|
|
94
101
|
"./dist/types/hono-entry.node.d.ts"
|
|
95
102
|
]
|
|
@@ -120,7 +127,7 @@ async function getPackageJson(props) {
|
|
|
120
127
|
}
|
|
121
128
|
});
|
|
122
129
|
return addDependency(packageJson, await Promise.resolve().then(() => __toESM(require_package(), 1)).then((x) => x.default), {
|
|
123
|
-
devDependencies: ["@hono/vite-dev-server", "@types/node"],
|
|
130
|
+
devDependencies: ["@hono/vite-dev-server", "@types/node", "@types/aws-lambda"],
|
|
124
131
|
dependencies: [
|
|
125
132
|
"@hono/node-server",
|
|
126
133
|
"@universal-middleware/hono",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*{ @if (it.BATI.has("aws")) }*/
|
|
2
|
+
/*
|
|
3
|
+
entry_aws_lambda.ts
|
|
4
|
+
|
|
5
|
+
This file is the entry point for AWS Lambda
|
|
6
|
+
|
|
7
|
+
Notes:
|
|
8
|
+
* The file name must not have any special characters or dots except for the extension. https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#API_CreateFunction_RequestSyntax
|
|
9
|
+
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Hono } from "hono";
|
|
13
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
14
|
+
import { handle } from "hono/aws-lambda";
|
|
15
|
+
import type { LambdaEvent, LambdaContext } from "hono/aws-lambda";
|
|
16
|
+
import app from "@batijs/hono/hono-entry"; // file is provided by hono
|
|
17
|
+
import type { Handler, APIGatewayProxyResult } from "aws-lambda";
|
|
18
|
+
|
|
19
|
+
type Bindings = {
|
|
20
|
+
event: LambdaEvent;
|
|
21
|
+
lambdaContext: LambdaContext;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const lambdaApp = new Hono<{ Bindings: Bindings }>();
|
|
25
|
+
|
|
26
|
+
lambdaApp.use(
|
|
27
|
+
"/*",
|
|
28
|
+
serveStatic({
|
|
29
|
+
root: `./dist/client/`,
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
lambdaApp.route("/", app!);
|
|
34
|
+
const awsHandler = handle(lambdaApp);
|
|
35
|
+
|
|
36
|
+
export const handler: Handler<LambdaEvent, APIGatewayProxyResult> = awsHandler;
|
|
37
|
+
/*{ /if }*/
|
package/dist/index.js
CHANGED
|
@@ -1677,7 +1677,7 @@ var createDefaultQueryTester = function(query, options) {
|
|
|
1677
1677
|
// package.json
|
|
1678
1678
|
var package_default = {
|
|
1679
1679
|
name: "@batijs/cli",
|
|
1680
|
-
version: "0.0.
|
|
1680
|
+
version: "0.0.261",
|
|
1681
1681
|
type: "module",
|
|
1682
1682
|
scripts: {
|
|
1683
1683
|
"check-types": "tsc --noEmit",
|
|
@@ -1760,6 +1760,10 @@ Choose one of them, or simply remove selected Server`
|
|
|
1760
1760
|
[RulesMessage.ERROR_LUCIA_R_COMPAT_DATABASE]: error(
|
|
1761
1761
|
`${inverse(bold("Lucia"))} requires a ${inverse(bold("Database"))}, and is only compatible with ${inverse(bold("SQLite"))} or ${inverse(bold("Drizzle"))}`
|
|
1762
1762
|
),
|
|
1763
|
+
[RulesMessage.ERROR_AWS_R_COMPAT_SERVER]: error(
|
|
1764
|
+
`${inverse(bold("AWS"))} is only compatible with ${inverse(bold("Hono"))} or ${inverse(bold("HatTip"))}.
|
|
1765
|
+
Choose one of them, or simply remove selected Server`
|
|
1766
|
+
),
|
|
1763
1767
|
[RulesMessage.INFO_DRIZZLE_STACKBLITZ]: null
|
|
1764
1768
|
};
|
|
1765
1769
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@batijs/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.261",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"description": "Next-gen scaffolder. Get started with fully-functional apps, and choose any tool you want",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"typescript": "^5.5.4",
|
|
21
21
|
"unplugin-purge-polyfills": "^0.0.5",
|
|
22
22
|
"vite": "^5.4.2",
|
|
23
|
-
"@batijs/
|
|
24
|
-
"@batijs/
|
|
23
|
+
"@batijs/compile": "0.0.261",
|
|
24
|
+
"@batijs/build": "0.0.261"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@batijs/
|
|
28
|
-
"@batijs/
|
|
27
|
+
"@batijs/core": "0.0.261",
|
|
28
|
+
"@batijs/features": "0.0.261"
|
|
29
29
|
},
|
|
30
30
|
"bin": "./dist/index.js",
|
|
31
31
|
"exports": {
|