@stacksjs/ts-cloud 0.2.11 → 0.2.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/dist/bin/cli.js +261 -261
- package/dist/generators/infrastructure.d.ts +3 -0
- package/dist/index.js +91 -4
- package/package.json +3 -3
|
@@ -25,6 +25,9 @@ export declare class InfrastructureGenerator {
|
|
|
25
25
|
*/
|
|
26
26
|
private shouldDeploy;
|
|
27
27
|
private resolveApiOriginPort;
|
|
28
|
+
private normalizeMountPath;
|
|
29
|
+
private storageBucketLogicalId;
|
|
30
|
+
private pathMountRewriteFunctionCode;
|
|
28
31
|
/**
|
|
29
32
|
* Generate complete infrastructure
|
|
30
33
|
* Auto-detects what to generate based on configuration
|
package/dist/index.js
CHANGED
|
@@ -62098,6 +62098,19 @@ class InfrastructureGenerator {
|
|
|
62098
62098
|
const port = Number(configuredPort || 3008);
|
|
62099
62099
|
return Number.isFinite(port) && port > 0 ? port : 3008;
|
|
62100
62100
|
}
|
|
62101
|
+
normalizeMountPath(config6) {
|
|
62102
|
+
const rawPath = config6?.mountPath || config6?.path;
|
|
62103
|
+
if (!rawPath || rawPath === "/")
|
|
62104
|
+
return;
|
|
62105
|
+
const normalized = `/${rawPath}`.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
62106
|
+
return normalized === "/" ? undefined : normalized;
|
|
62107
|
+
}
|
|
62108
|
+
storageBucketLogicalId(slug, env, name) {
|
|
62109
|
+
return `${slug}-${env}-s3-${name}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
62110
|
+
}
|
|
62111
|
+
pathMountRewriteFunctionCode(mountPath) {
|
|
62112
|
+
return `function handler(event) { var request = event.request; var prefix = ${JSON.stringify(mountPath)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = uri + '/index.html'; return request; } request.uri = uri; return request; }`;
|
|
62113
|
+
}
|
|
62101
62114
|
generate() {
|
|
62102
62115
|
const slug = this.mergedConfig.project.slug;
|
|
62103
62116
|
const env = this.environment;
|
|
@@ -62952,9 +62965,6 @@ class InfrastructureGenerator {
|
|
|
62952
62965
|
}
|
|
62953
62966
|
return d;
|
|
62954
62967
|
});
|
|
62955
|
-
if (this.mergedConfig.infrastructure?.storage?.docs && !subdomains.includes("docs")) {
|
|
62956
|
-
subdomains.push("docs");
|
|
62957
|
-
}
|
|
62958
62968
|
const { certificate, logicalId: certLogicalId } = Security.createCertificate({
|
|
62959
62969
|
domain: primaryDomain,
|
|
62960
62970
|
subdomains,
|
|
@@ -62984,6 +62994,12 @@ class InfrastructureGenerator {
|
|
|
62984
62994
|
}
|
|
62985
62995
|
});
|
|
62986
62996
|
}
|
|
62997
|
+
const pathMountedWebsiteBuckets = Object.entries(this.mergedConfig.infrastructure.storage).map(([bucketName, bucketConfig]) => ({
|
|
62998
|
+
name: bucketName,
|
|
62999
|
+
config: bucketConfig,
|
|
63000
|
+
mountPath: this.normalizeMountPath(bucketConfig),
|
|
63001
|
+
logicalId: this.storageBucketLogicalId(slug, env, bucketName)
|
|
63002
|
+
})).filter((bucket) => bucket.name !== "public" && bucket.config.website && bucket.mountPath);
|
|
62987
63003
|
for (const [name, storageConfig] of Object.entries(this.mergedConfig.infrastructure.storage)) {
|
|
62988
63004
|
const serveViaCloudFront = !!(storageConfig.website && sharedOacLogicalId);
|
|
62989
63005
|
const { bucket, logicalId } = Storage.createBucket({
|
|
@@ -63009,7 +63025,8 @@ class InfrastructureGenerator {
|
|
|
63009
63025
|
const enhanced = Storage.enableWebsiteHosting(bucket, websiteConfig.indexDocument || "index.html", websiteConfig.errorDocument);
|
|
63010
63026
|
this.builder.addResource(logicalId, enhanced);
|
|
63011
63027
|
}
|
|
63012
|
-
|
|
63028
|
+
const mountPath = this.normalizeMountPath(storageConfig);
|
|
63029
|
+
if (serveViaCloudFront && sharedOacLogicalId && domain && !(mountPath && name !== "public")) {
|
|
63013
63030
|
const distLogicalId = `${slug}${env}${name}CDN`.replace(/[^a-zA-Z0-9]/g, "");
|
|
63014
63031
|
const aliases = [];
|
|
63015
63032
|
if (storageConfig.aliases && storageConfig.aliases.length > 0) {
|
|
@@ -63111,6 +63128,47 @@ else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`
|
|
|
63111
63128
|
OriginRequestPolicyId: "b689b0a8-53d0-40ab-baf2-68738e2966ac"
|
|
63112
63129
|
});
|
|
63113
63130
|
}
|
|
63131
|
+
for (const mountedBucket of pathMountedWebsiteBuckets) {
|
|
63132
|
+
const mountedOriginId = `S3-${slug}-${env}-${mountedBucket.name}`;
|
|
63133
|
+
const mountedFunctionLogicalId = `${slug}${env}${mountedBucket.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g, "");
|
|
63134
|
+
this.builder.addResource(mountedFunctionLogicalId, {
|
|
63135
|
+
Type: "AWS::CloudFront::Function",
|
|
63136
|
+
Properties: {
|
|
63137
|
+
Name: `${slug}-${env}-${mountedBucket.name}-path-mount-rewrite`,
|
|
63138
|
+
AutoPublish: true,
|
|
63139
|
+
FunctionConfig: {
|
|
63140
|
+
Comment: `Path mount rewrite for ${slug} ${env} ${mountedBucket.name} at ${mountedBucket.mountPath}`,
|
|
63141
|
+
Runtime: "cloudfront-js-2.0"
|
|
63142
|
+
},
|
|
63143
|
+
FunctionCode: this.pathMountRewriteFunctionCode(mountedBucket.mountPath)
|
|
63144
|
+
}
|
|
63145
|
+
});
|
|
63146
|
+
origins.push({
|
|
63147
|
+
Id: mountedOriginId,
|
|
63148
|
+
DomainName: { "Fn::Sub": `\${${mountedBucket.logicalId}}.s3.${region}.amazonaws.com` },
|
|
63149
|
+
OriginPath: "",
|
|
63150
|
+
S3OriginConfig: {
|
|
63151
|
+
OriginAccessIdentity: ""
|
|
63152
|
+
},
|
|
63153
|
+
OriginAccessControlId: { Ref: sharedOacLogicalId }
|
|
63154
|
+
});
|
|
63155
|
+
extraDependsOn.push(mountedBucket.logicalId, mountedFunctionLogicalId);
|
|
63156
|
+
for (const pathPattern of [mountedBucket.mountPath, `${mountedBucket.mountPath}/*`]) {
|
|
63157
|
+
cacheBehaviors.push({
|
|
63158
|
+
PathPattern: pathPattern,
|
|
63159
|
+
TargetOriginId: mountedOriginId,
|
|
63160
|
+
ViewerProtocolPolicy: "redirect-to-https",
|
|
63161
|
+
AllowedMethods: ["GET", "HEAD", "OPTIONS"],
|
|
63162
|
+
CachedMethods: ["GET", "HEAD", "OPTIONS"],
|
|
63163
|
+
Compress: true,
|
|
63164
|
+
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
|
|
63165
|
+
FunctionAssociations: [{
|
|
63166
|
+
EventType: "viewer-request",
|
|
63167
|
+
FunctionARN: { "Fn::GetAtt": [mountedFunctionLogicalId, "FunctionARN"] }
|
|
63168
|
+
}]
|
|
63169
|
+
});
|
|
63170
|
+
}
|
|
63171
|
+
}
|
|
63114
63172
|
}
|
|
63115
63173
|
const distribution = {
|
|
63116
63174
|
Type: "AWS::CloudFront::Distribution",
|
|
@@ -63174,6 +63232,35 @@ else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`
|
|
|
63174
63232
|
}
|
|
63175
63233
|
}
|
|
63176
63234
|
});
|
|
63235
|
+
if (name === "public") {
|
|
63236
|
+
for (const mountedBucket of pathMountedWebsiteBuckets) {
|
|
63237
|
+
const mountedPolicyLogicalId = `${mountedBucket.logicalId}CloudFrontPolicy`;
|
|
63238
|
+
this.builder.addResource(mountedPolicyLogicalId, {
|
|
63239
|
+
Type: "AWS::S3::BucketPolicy",
|
|
63240
|
+
DependsOn: [mountedBucket.logicalId, distLogicalId],
|
|
63241
|
+
Properties: {
|
|
63242
|
+
Bucket: { Ref: mountedBucket.logicalId },
|
|
63243
|
+
PolicyDocument: {
|
|
63244
|
+
Version: "2012-10-17",
|
|
63245
|
+
Statement: [{
|
|
63246
|
+
Sid: "AllowCloudFrontServicePrincipal",
|
|
63247
|
+
Effect: "Allow",
|
|
63248
|
+
Principal: {
|
|
63249
|
+
Service: "cloudfront.amazonaws.com"
|
|
63250
|
+
},
|
|
63251
|
+
Action: "s3:GetObject",
|
|
63252
|
+
Resource: { "Fn::Sub": `arn:aws:s3:::\${${mountedBucket.logicalId}}/*` },
|
|
63253
|
+
Condition: {
|
|
63254
|
+
StringEquals: {
|
|
63255
|
+
"AWS:SourceArn": { "Fn::Sub": `arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${distLogicalId}}` }
|
|
63256
|
+
}
|
|
63257
|
+
}
|
|
63258
|
+
}]
|
|
63259
|
+
}
|
|
63260
|
+
}
|
|
63261
|
+
});
|
|
63262
|
+
}
|
|
63263
|
+
}
|
|
63177
63264
|
if (aliases.length > 0) {
|
|
63178
63265
|
websiteBucketDistributions.push({
|
|
63179
63266
|
name,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/ts-cloud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.13",
|
|
5
5
|
"description": "A lightweight, performant infrastructure-as-code library and CLI for deploying both server-based (EC2) and serverless applications.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"test": "bun test"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@ts-cloud/aws-types": "0.2.
|
|
89
|
-
"@ts-cloud/core": "0.2.
|
|
88
|
+
"@ts-cloud/aws-types": "0.2.13",
|
|
89
|
+
"@ts-cloud/core": "0.2.13",
|
|
90
90
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|