sst 2.21.7 → 2.22.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/bootstrap.js +23 -15
- package/cli/local/server.js +27 -7
- package/constructs/BaseSite.d.ts +6 -0
- package/constructs/Function.d.ts +45 -10
- package/constructs/Function.js +0 -10
- package/constructs/RemixSite.js +6 -4
- package/constructs/SsrSite.d.ts +57 -1
- package/constructs/SsrSite.js +15 -9
- package/constructs/StaticSite.d.ts +4 -8
- package/constructs/util/permission.js +3 -0
- package/package.json +1 -1
- package/runtime/handlers/go.js +19 -3
- package/runtime/handlers/rust.js +17 -5
- package/sst.mjs +107 -38
package/bootstrap.js
CHANGED
|
@@ -5,7 +5,7 @@ import { spawn } from "child_process";
|
|
|
5
5
|
import { DescribeStacksCommand, CloudFormationClient, } from "@aws-sdk/client-cloudformation";
|
|
6
6
|
import { App, DefaultStackSynthesizer, Duration, CfnOutput, Tags, Stack, RemovalPolicy, } from "aws-cdk-lib/core";
|
|
7
7
|
import { Function, Runtime, Code } from "aws-cdk-lib/aws-lambda";
|
|
8
|
-
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
8
|
+
import { ManagedPolicy, PermissionsBoundary, PolicyStatement, } from "aws-cdk-lib/aws-iam";
|
|
9
9
|
import { Rule } from "aws-cdk-lib/aws-events";
|
|
10
10
|
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
|
|
11
11
|
import { BlockPublicAccess, Bucket, BucketEncryption, } from "aws-cdk-lib/aws-s3";
|
|
@@ -29,10 +29,12 @@ export const useBootstrap = Context.memo(async () => {
|
|
|
29
29
|
loadSSTStatus(),
|
|
30
30
|
]);
|
|
31
31
|
Logger.debug("Loaded bootstrap status");
|
|
32
|
-
const needToBootstrapCDK =
|
|
33
|
-
const needToBootstrapSST =
|
|
32
|
+
const needToBootstrapCDK = cdkStatus.status !== "ready";
|
|
33
|
+
const needToBootstrapSST = sstStatus.status !== "ready";
|
|
34
34
|
if (needToBootstrapCDK || needToBootstrapSST) {
|
|
35
|
-
const spinner = createSpinner("
|
|
35
|
+
const spinner = createSpinner(cdkStatus.status === "bootstrap" || sstStatus.status === "bootstrap"
|
|
36
|
+
? "Deploying bootstrap stack, this only needs to happen once"
|
|
37
|
+
: "Updating bootstrap stack").start();
|
|
36
38
|
if (needToBootstrapCDK) {
|
|
37
39
|
await bootstrapCDK();
|
|
38
40
|
}
|
|
@@ -40,7 +42,7 @@ export const useBootstrap = Context.memo(async () => {
|
|
|
40
42
|
await bootstrapSST();
|
|
41
43
|
// fetch bootstrap status
|
|
42
44
|
sstStatus = await loadSSTStatus();
|
|
43
|
-
if (
|
|
45
|
+
if (sstStatus.status !== "ready")
|
|
44
46
|
throw new VisibleError("Failed to load bootstrap stack status");
|
|
45
47
|
}
|
|
46
48
|
spinner.succeed();
|
|
@@ -56,24 +58,25 @@ async function loadCDKStatus() {
|
|
|
56
58
|
const { Stacks: stacks } = await client.send(new DescribeStacksCommand({ StackName: stackName }));
|
|
57
59
|
// Check CDK bootstrap stack exists
|
|
58
60
|
if (!stacks || stacks.length === 0)
|
|
59
|
-
return
|
|
61
|
+
return { status: "bootstrap" };
|
|
60
62
|
// Check CDK bootstrap stack deployed successfully
|
|
61
63
|
if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
|
|
62
|
-
return
|
|
64
|
+
return { status: "bootstrap" };
|
|
63
65
|
}
|
|
64
66
|
// Check CDK bootstrap stack is up to date
|
|
65
67
|
// note: there is no a programmatical way to get the minimal required version
|
|
66
68
|
// of CDK bootstrap stack. We are going to hardcode it to 14 for now,
|
|
67
69
|
// which is the latest version as of CDK v2.62.2
|
|
68
70
|
const output = stacks[0].Outputs?.find((o) => o.OutputKey === "BootstrapVersion");
|
|
69
|
-
if (!output || parseInt(output.OutputValue) < 14)
|
|
70
|
-
return
|
|
71
|
-
|
|
71
|
+
if (!output || parseInt(output.OutputValue) < 14) {
|
|
72
|
+
return { status: "update" };
|
|
73
|
+
}
|
|
74
|
+
return { status: "ready" };
|
|
72
75
|
}
|
|
73
76
|
catch (e) {
|
|
74
77
|
if (e.name === "ValidationError" &&
|
|
75
78
|
e.message === `Stack with id ${stackName} does not exist`) {
|
|
76
|
-
return
|
|
79
|
+
return { status: "bootstrap" };
|
|
77
80
|
}
|
|
78
81
|
else {
|
|
79
82
|
throw e;
|
|
@@ -94,7 +97,7 @@ async function loadSSTStatus() {
|
|
|
94
97
|
catch (e) {
|
|
95
98
|
if (e.Code === "ValidationError" &&
|
|
96
99
|
e.message === `Stack with id ${stackName} does not exist`) {
|
|
97
|
-
return
|
|
100
|
+
return { status: "bootstrap" };
|
|
98
101
|
}
|
|
99
102
|
throw e;
|
|
100
103
|
}
|
|
@@ -110,7 +113,7 @@ async function loadSSTStatus() {
|
|
|
110
113
|
}
|
|
111
114
|
});
|
|
112
115
|
if (!version || !bucket) {
|
|
113
|
-
return
|
|
116
|
+
return { status: "bootstrap" };
|
|
114
117
|
}
|
|
115
118
|
// Need to update bootstrap stack:
|
|
116
119
|
// 1. If current MAJOR version < latest MAJOR version
|
|
@@ -126,9 +129,9 @@ async function loadSSTStatus() {
|
|
|
126
129
|
if (currentMajor < latestMajor ||
|
|
127
130
|
currentMajor > latestMajor ||
|
|
128
131
|
currentMinor < latestMinor) {
|
|
129
|
-
return
|
|
132
|
+
return { status: "update" };
|
|
130
133
|
}
|
|
131
|
-
return { version, bucket };
|
|
134
|
+
return { status: "ready", version, bucket };
|
|
132
135
|
}
|
|
133
136
|
export async function bootstrapSST() {
|
|
134
137
|
const { region, bootstrap, cdk } = useProject().config;
|
|
@@ -215,6 +218,11 @@ export async function bootstrapSST() {
|
|
|
215
218
|
},
|
|
216
219
|
});
|
|
217
220
|
rule.addTarget(new LambdaFunction(fn));
|
|
221
|
+
// Create permissions boundary
|
|
222
|
+
if (cdk?.customPermissionsBoundary) {
|
|
223
|
+
const boundaryPolicy = ManagedPolicy.fromManagedPolicyName(stack, "PermissionBoundaryPolicy", cdk.customPermissionsBoundary);
|
|
224
|
+
PermissionsBoundary.of(stack).apply(boundaryPolicy);
|
|
225
|
+
}
|
|
218
226
|
// Create stack outputs to store bootstrap stack info
|
|
219
227
|
new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
|
|
220
228
|
new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
|
package/cli/local/server.js
CHANGED
|
@@ -104,11 +104,38 @@ export async function useLocalServer(opts) {
|
|
|
104
104
|
const wss = new WebSocketServer({ noServer: true });
|
|
105
105
|
const wss2 = new WebSocketServer({ noServer: true });
|
|
106
106
|
const sockets = new Set();
|
|
107
|
+
let buffer = [
|
|
108
|
+
{
|
|
109
|
+
type: "cli.dev",
|
|
110
|
+
properties: {
|
|
111
|
+
stage: project.config.stage,
|
|
112
|
+
app: project.config.name,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
function publish(type, properties) {
|
|
117
|
+
const msg = {
|
|
118
|
+
type,
|
|
119
|
+
properties,
|
|
120
|
+
};
|
|
121
|
+
buffer.push(msg);
|
|
122
|
+
const json = JSON.stringify(msg);
|
|
123
|
+
[...sockets.values()].map((s) => s.send(json));
|
|
124
|
+
}
|
|
107
125
|
wss2.on("connection", (socket, req) => {
|
|
108
126
|
sockets.add(socket);
|
|
127
|
+
for (const msg of buffer) {
|
|
128
|
+
socket.send(JSON.stringify(msg));
|
|
129
|
+
}
|
|
109
130
|
socket.on("close", () => {
|
|
110
131
|
sockets.delete(socket);
|
|
111
132
|
});
|
|
133
|
+
socket.on("message", (data) => {
|
|
134
|
+
const parsed = JSON.parse(data.toString());
|
|
135
|
+
if (parsed.type === "log.cleared") {
|
|
136
|
+
buffer = buffer.filter((msg) => msg.properties?.functionID !== parsed.properties?.functionID);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
112
139
|
});
|
|
113
140
|
wss.on("connection", (socket, req) => {
|
|
114
141
|
if (req.headers.origin?.endsWith("localhost:3000"))
|
|
@@ -179,13 +206,6 @@ export async function useLocalServer(opts) {
|
|
|
179
206
|
cb(func);
|
|
180
207
|
});
|
|
181
208
|
}
|
|
182
|
-
function publish(type, properties) {
|
|
183
|
-
const msg = JSON.stringify({
|
|
184
|
-
type,
|
|
185
|
-
properties,
|
|
186
|
-
});
|
|
187
|
-
[...sockets.values()].map((s) => s.send(msg));
|
|
188
|
-
}
|
|
189
209
|
bus.subscribe("function.invoked", async (evt) => {
|
|
190
210
|
publish("function.invoked", evt.properties);
|
|
191
211
|
updateFunction(evt.properties.functionID, (draft) => {
|
package/constructs/BaseSite.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { IHostedZone } from "aws-cdk-lib/aws-route53";
|
|
2
2
|
import { ErrorResponse, DistributionProps, BehaviorOptions, IOrigin } from "aws-cdk-lib/aws-cloudfront";
|
|
3
3
|
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
4
|
+
export interface BaseSiteFileOptions {
|
|
5
|
+
exclude: string | string[];
|
|
6
|
+
include: string | string[];
|
|
7
|
+
cacheControl: string;
|
|
8
|
+
contentType?: string;
|
|
9
|
+
}
|
|
4
10
|
/**
|
|
5
11
|
* The customDomain for this website. SST supports domains that are hosted either on [Route 53](https://aws.amazon.com/route53/) or externally.
|
|
6
12
|
*
|
package/constructs/Function.d.ts
CHANGED
|
@@ -13,24 +13,14 @@ import { Size as CDKSize, Duration as CDKDuration } from "aws-cdk-lib/core";
|
|
|
13
13
|
declare const supportedRuntimes: {
|
|
14
14
|
container: CDKRuntime;
|
|
15
15
|
rust: CDKRuntime;
|
|
16
|
-
nodejs: CDKRuntime;
|
|
17
|
-
"nodejs4.3": CDKRuntime;
|
|
18
|
-
"nodejs6.10": CDKRuntime;
|
|
19
|
-
"nodejs8.10": CDKRuntime;
|
|
20
|
-
"nodejs10.x": CDKRuntime;
|
|
21
16
|
"nodejs12.x": CDKRuntime;
|
|
22
17
|
"nodejs14.x": CDKRuntime;
|
|
23
18
|
"nodejs16.x": CDKRuntime;
|
|
24
19
|
"nodejs18.x": CDKRuntime;
|
|
25
|
-
"python2.7": CDKRuntime;
|
|
26
|
-
"python3.6": CDKRuntime;
|
|
27
20
|
"python3.7": CDKRuntime;
|
|
28
21
|
"python3.8": CDKRuntime;
|
|
29
22
|
"python3.9": CDKRuntime;
|
|
30
23
|
"python3.10": CDKRuntime;
|
|
31
|
-
"dotnetcore1.0": CDKRuntime;
|
|
32
|
-
"dotnetcore2.0": CDKRuntime;
|
|
33
|
-
"dotnetcore2.1": CDKRuntime;
|
|
34
24
|
"dotnetcore3.1": CDKRuntime;
|
|
35
25
|
dotnet6: CDKRuntime;
|
|
36
26
|
java8: CDKRuntime;
|
|
@@ -66,6 +56,10 @@ export interface FunctionProps extends Omit<FunctionOptions, "functionName" | "m
|
|
|
66
56
|
*```
|
|
67
57
|
*/
|
|
68
58
|
copyFiles?: FunctionCopyFilesProps[];
|
|
59
|
+
/**
|
|
60
|
+
* Used to configure go function properties
|
|
61
|
+
*/
|
|
62
|
+
go?: GoProps;
|
|
69
63
|
/**
|
|
70
64
|
* Used to configure nodejs function properties
|
|
71
65
|
*/
|
|
@@ -458,6 +452,47 @@ export interface PythonProps {
|
|
|
458
452
|
*/
|
|
459
453
|
installCommands?: string[];
|
|
460
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Used to configure Go bundling options
|
|
457
|
+
*/
|
|
458
|
+
export interface GoProps {
|
|
459
|
+
/**
|
|
460
|
+
* The ldflags to use when building the Go module.
|
|
461
|
+
*
|
|
462
|
+
* @default ["-s", "-w"]
|
|
463
|
+
* @example
|
|
464
|
+
* ```js
|
|
465
|
+
* go: {
|
|
466
|
+
* ldFlags: ["-X main.version=1.0.0"],
|
|
467
|
+
* }
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
ldFlags?: string[];
|
|
471
|
+
/**
|
|
472
|
+
* The build tags to use when building the Go module.
|
|
473
|
+
*
|
|
474
|
+
* @default []
|
|
475
|
+
* @example
|
|
476
|
+
* ```js
|
|
477
|
+
* go: {
|
|
478
|
+
* buildTags: ["enterprise", "pro"],
|
|
479
|
+
* }
|
|
480
|
+
* ```
|
|
481
|
+
*/
|
|
482
|
+
buildTags?: string[];
|
|
483
|
+
/**
|
|
484
|
+
* Whether to enable CGO for the Go build.
|
|
485
|
+
*
|
|
486
|
+
* @default false
|
|
487
|
+
* @example
|
|
488
|
+
* ```js
|
|
489
|
+
* go: {
|
|
490
|
+
* cgoEnabled: true,
|
|
491
|
+
* }
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
494
|
+
cgoEnabled?: boolean;
|
|
495
|
+
}
|
|
461
496
|
/**
|
|
462
497
|
* Used to configure Java package build options
|
|
463
498
|
*/
|
package/constructs/Function.js
CHANGED
|
@@ -27,24 +27,14 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
|
27
27
|
const supportedRuntimes = {
|
|
28
28
|
container: CDKRuntime.FROM_IMAGE,
|
|
29
29
|
rust: CDKRuntime.PROVIDED_AL2,
|
|
30
|
-
nodejs: CDKRuntime.NODEJS,
|
|
31
|
-
"nodejs4.3": CDKRuntime.NODEJS_4_3,
|
|
32
|
-
"nodejs6.10": CDKRuntime.NODEJS_6_10,
|
|
33
|
-
"nodejs8.10": CDKRuntime.NODEJS_8_10,
|
|
34
|
-
"nodejs10.x": CDKRuntime.NODEJS_10_X,
|
|
35
30
|
"nodejs12.x": CDKRuntime.NODEJS_12_X,
|
|
36
31
|
"nodejs14.x": CDKRuntime.NODEJS_14_X,
|
|
37
32
|
"nodejs16.x": CDKRuntime.NODEJS_16_X,
|
|
38
33
|
"nodejs18.x": CDKRuntime.NODEJS_18_X,
|
|
39
|
-
"python2.7": CDKRuntime.PYTHON_2_7,
|
|
40
|
-
"python3.6": CDKRuntime.PYTHON_3_6,
|
|
41
34
|
"python3.7": CDKRuntime.PYTHON_3_7,
|
|
42
35
|
"python3.8": CDKRuntime.PYTHON_3_8,
|
|
43
36
|
"python3.9": CDKRuntime.PYTHON_3_9,
|
|
44
37
|
"python3.10": CDKRuntime.PYTHON_3_10,
|
|
45
|
-
"dotnetcore1.0": CDKRuntime.DOTNET_CORE_1,
|
|
46
|
-
"dotnetcore2.0": CDKRuntime.DOTNET_CORE_2,
|
|
47
|
-
"dotnetcore2.1": CDKRuntime.DOTNET_CORE_2_1,
|
|
48
38
|
"dotnetcore3.1": CDKRuntime.DOTNET_CORE_3_1,
|
|
49
39
|
dotnet6: CDKRuntime.DOTNET_6,
|
|
50
40
|
java8: CDKRuntime.JAVA_8,
|
package/constructs/RemixSite.js
CHANGED
|
@@ -72,9 +72,11 @@ export class RemixSite extends SsrSite {
|
|
|
72
72
|
// appropriate Lambda@Edge handler. We will utilise an internal asset
|
|
73
73
|
// template to create this wrapper within the "core server build" output
|
|
74
74
|
// directory.
|
|
75
|
+
// Ensure build directory exists
|
|
76
|
+
const buildPath = path.join(this.props.path, "build");
|
|
77
|
+
fs.mkdirSync(buildPath, { recursive: true });
|
|
75
78
|
// Copy the server lambda handler
|
|
76
|
-
|
|
77
|
-
fs.copyFileSync(path.resolve(__dirname, `../support/remix-site-function/${wrapperFile}`), handler);
|
|
79
|
+
fs.copyFileSync(path.resolve(__dirname, `../support/remix-site-function/${wrapperFile}`), path.join(buildPath, "server.js"));
|
|
78
80
|
// Copy the Remix polyfil to the server build directory
|
|
79
81
|
//
|
|
80
82
|
// Note: We need to ensure that the polyfills are injected above other code that
|
|
@@ -82,10 +84,10 @@ export class RemixSite extends SsrSite {
|
|
|
82
84
|
// doesn't appear to guarantee this, we therefore leverage ESBUild's
|
|
83
85
|
// `inject` option to ensure that the polyfills are injected at the top of
|
|
84
86
|
// the bundle.
|
|
85
|
-
const polyfillDest = path.join(
|
|
87
|
+
const polyfillDest = path.join(buildPath, "polyfill.js");
|
|
86
88
|
fs.copyFileSync(path.resolve(__dirname, "../support/remix-site-function/polyfill.js"), polyfillDest);
|
|
87
89
|
return {
|
|
88
|
-
handler: path.join(
|
|
90
|
+
handler: path.join(buildPath, "server.handler"),
|
|
89
91
|
esbuild: { inject: [polyfillDest] },
|
|
90
92
|
};
|
|
91
93
|
}
|
package/constructs/SsrSite.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { SSTConstruct } from "./Construct.js";
|
|
|
8
8
|
import { NodeJSProps } from "./Function.js";
|
|
9
9
|
import { SsrFunction } from "./SsrFunction.js";
|
|
10
10
|
import { EdgeFunction } from "./EdgeFunction.js";
|
|
11
|
-
import { BaseSiteDomainProps, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
|
|
11
|
+
import { BaseSiteFileOptions, BaseSiteDomainProps, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
|
|
12
12
|
import { Size } from "./util/size.js";
|
|
13
13
|
import { Duration } from "./util/duration.js";
|
|
14
14
|
import { Permissions } from "./util/permission.js";
|
|
@@ -27,6 +27,8 @@ export interface SsrSiteNodeJSProps extends NodeJSProps {
|
|
|
27
27
|
}
|
|
28
28
|
export interface SsrDomainProps extends BaseSiteDomainProps {
|
|
29
29
|
}
|
|
30
|
+
export interface SsrSiteFileOptions extends BaseSiteFileOptions {
|
|
31
|
+
}
|
|
30
32
|
export interface SsrSiteReplaceProps extends BaseSiteReplaceProps {
|
|
31
33
|
}
|
|
32
34
|
export interface SsrCdkDistributionProps extends BaseSiteCdkDistributionProps {
|
|
@@ -192,6 +194,60 @@ export interface SsrSiteProps {
|
|
|
192
194
|
responseHeadersPolicy?: IResponseHeadersPolicy;
|
|
193
195
|
server?: Pick<FunctionProps, "vpc" | "vpcSubnets" | "securityGroups" | "allowAllOutbound" | "allowPublicSubnet" | "architecture" | "logRetention">;
|
|
194
196
|
};
|
|
197
|
+
/**
|
|
198
|
+
* Pass in a list of file options to customize cache control and content type specific files.
|
|
199
|
+
*
|
|
200
|
+
* @default Versioned files cached for 1 year at the CDN and brower level. Unversioned files cached for 1 year at the CDN level, but not at the browser level.
|
|
201
|
+
* ```js
|
|
202
|
+
* [
|
|
203
|
+
* {
|
|
204
|
+
* exclude: "*",
|
|
205
|
+
* include: "{versioned_directory}/*",
|
|
206
|
+
* cacheControl: "public,max-age=31536000,immutable",
|
|
207
|
+
* },
|
|
208
|
+
* {
|
|
209
|
+
* exclude: "*",
|
|
210
|
+
* include: "[{non_versioned_file1}, {non_versioned_file2}, ...]",
|
|
211
|
+
* cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
|
|
212
|
+
* },
|
|
213
|
+
* {
|
|
214
|
+
* exclude: "*",
|
|
215
|
+
* include: "[{non_versioned_dir_1}/*, {non_versioned_dir_2}/*, ...]",
|
|
216
|
+
* cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
|
|
217
|
+
* },
|
|
218
|
+
* ]
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```js
|
|
223
|
+
* new AstroSite(stack, "Site", {
|
|
224
|
+
* fileOptions: [
|
|
225
|
+
* {
|
|
226
|
+
* exclude: "*",
|
|
227
|
+
* include: "{versioned_directory}/*.css",
|
|
228
|
+
* cacheControl: "public,max-age=31536000,immutable",
|
|
229
|
+
* contentType: "text/css; charset=UTF-8",
|
|
230
|
+
* },
|
|
231
|
+
* {
|
|
232
|
+
* exclude: "*",
|
|
233
|
+
* include: "[{versioned_directory}/*.js]",
|
|
234
|
+
* cacheControl: "public,max-age=31536000,immutable",
|
|
235
|
+
* },
|
|
236
|
+
* {
|
|
237
|
+
* exclude: "*",
|
|
238
|
+
* include: "[{non_versioned_file1}, {non_versioned_file2}, ...]",
|
|
239
|
+
* cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
|
|
240
|
+
* },
|
|
241
|
+
* {
|
|
242
|
+
* exclude: "*",
|
|
243
|
+
* include: "[{non_versioned_dir_1}/*, {non_versioned_dir_2}/*, ...]",
|
|
244
|
+
* cacheControl: "public,max-age=0,s-maxage=31536000,must-revalidate",
|
|
245
|
+
* },
|
|
246
|
+
* ]
|
|
247
|
+
* });
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
fileOptions?: SsrSiteFileOptions[];
|
|
195
251
|
}
|
|
196
252
|
type SsrSiteNormalizedProps = SsrSiteProps & {
|
|
197
253
|
path: Exclude<SsrSiteProps["path"], undefined>;
|
package/constructs/SsrSite.js
CHANGED
|
@@ -348,12 +348,14 @@ export class SsrSite extends Construct {
|
|
|
348
348
|
return assets;
|
|
349
349
|
}
|
|
350
350
|
createS3AssetFileOptions() {
|
|
351
|
+
if (this.props.fileOptions)
|
|
352
|
+
return this.props.fileOptions;
|
|
351
353
|
// Build file options
|
|
352
354
|
const fileOptions = [];
|
|
353
355
|
const clientPath = path.join(this.props.path, this.buildConfig.clientBuildOutputDir);
|
|
354
356
|
for (const item of fs.readdirSync(clientPath)) {
|
|
355
357
|
// Versioned files will be cached for 1 year (immutable) both at
|
|
356
|
-
// CDN and browser level.
|
|
358
|
+
// the CDN and browser level.
|
|
357
359
|
if (item === this.buildConfig.clientBuildVersionedSubDir) {
|
|
358
360
|
fileOptions.push({
|
|
359
361
|
exclude: "*",
|
|
@@ -425,15 +427,19 @@ export class SsrSite extends Construct {
|
|
|
425
427
|
ObjectKey: asset.s3ObjectKey,
|
|
426
428
|
})),
|
|
427
429
|
DestinationBucketName: this.bucket.bucketName,
|
|
428
|
-
FileOptions: (fileOptions || []).map(({ exclude, include, cacheControl }) => {
|
|
430
|
+
FileOptions: (fileOptions || []).map(({ exclude, include, cacheControl, contentType }) => {
|
|
431
|
+
if (typeof exclude === "string") {
|
|
432
|
+
exclude = [exclude];
|
|
433
|
+
}
|
|
434
|
+
if (typeof include === "string") {
|
|
435
|
+
include = [include];
|
|
436
|
+
}
|
|
429
437
|
return [
|
|
430
|
-
"--exclude",
|
|
431
|
-
|
|
432
|
-
"--
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
cacheControl,
|
|
436
|
-
];
|
|
438
|
+
...exclude.map((per) => ["--exclude", per]),
|
|
439
|
+
...include.map((per) => ["--include", per]),
|
|
440
|
+
["--cache-control", cacheControl],
|
|
441
|
+
contentType ? ["--content-type", contentType] : [],
|
|
442
|
+
].flat();
|
|
437
443
|
}),
|
|
438
444
|
ReplaceValues: this.getS3ContentReplaceValues(),
|
|
439
445
|
},
|
|
@@ -3,15 +3,9 @@ import { Bucket, BucketProps, IBucket } from "aws-cdk-lib/aws-s3";
|
|
|
3
3
|
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
4
4
|
import { IHostedZone } from "aws-cdk-lib/aws-route53";
|
|
5
5
|
import { Distribution, IDistribution } from "aws-cdk-lib/aws-cloudfront";
|
|
6
|
-
import { BaseSiteDomainProps, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
|
|
6
|
+
import { BaseSiteDomainProps, BaseSiteFileOptions, BaseSiteReplaceProps, BaseSiteCdkDistributionProps } from "./BaseSite.js";
|
|
7
7
|
import { SSTConstruct } from "./Construct.js";
|
|
8
8
|
import { FunctionBindingProps } from "./util/functionBinding.js";
|
|
9
|
-
export interface StaticSiteFileOptions {
|
|
10
|
-
exclude: string | string[];
|
|
11
|
-
include: string | string[];
|
|
12
|
-
cacheControl: string;
|
|
13
|
-
contentType?: string;
|
|
14
|
-
}
|
|
15
9
|
export interface StaticSiteProps {
|
|
16
10
|
/**
|
|
17
11
|
* Path to the directory where the website source is located.
|
|
@@ -77,7 +71,7 @@ export interface StaticSiteProps {
|
|
|
77
71
|
/**
|
|
78
72
|
* Pass in a list of file options to configure cache control for different files. Behind the scenes, the `StaticSite` construct uses a combination of the `s3 cp` and `s3 sync` commands to upload the website content to the S3 bucket. An `s3 cp` command is run for each file option block, and the options are passed in as the command options.
|
|
79
73
|
*
|
|
80
|
-
*
|
|
74
|
+
* @default No cache control for HTML files, and a 1 year cache control for JS/CSS files.
|
|
81
75
|
* ```js
|
|
82
76
|
* [
|
|
83
77
|
* {
|
|
@@ -274,6 +268,8 @@ export interface StaticSiteProps {
|
|
|
274
268
|
}
|
|
275
269
|
export interface StaticSiteDomainProps extends BaseSiteDomainProps {
|
|
276
270
|
}
|
|
271
|
+
export interface StaticSiteFileOptions extends BaseSiteFileOptions {
|
|
272
|
+
}
|
|
277
273
|
export interface StaticSiteReplaceProps extends BaseSiteReplaceProps {
|
|
278
274
|
}
|
|
279
275
|
export interface StaticSiteCdkDistributionProps extends BaseSiteCdkDistributionProps {
|
|
@@ -195,6 +195,9 @@ function permissionsToStatementsAndGrants(permissions) {
|
|
|
195
195
|
if (secret) {
|
|
196
196
|
statements.push(buildPolicyStatement(["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"], [secret.secretArn]));
|
|
197
197
|
}
|
|
198
|
+
if (secret?.encryptionKey) {
|
|
199
|
+
statements.push(buildPolicyStatement(["kms:Decrypt"], [secret.encryptionKey.keyArn]));
|
|
200
|
+
}
|
|
198
201
|
}
|
|
199
202
|
////////////////////////////////////
|
|
200
203
|
// Case: grant method
|
package/package.json
CHANGED
package/runtime/handlers/go.js
CHANGED
|
@@ -55,11 +55,20 @@ export const useGoHandler = Context.memo(async () => {
|
|
|
55
55
|
const project = await find(parsed.dir, "go.mod");
|
|
56
56
|
sources.set(input.functionID, project);
|
|
57
57
|
const src = path.relative(project, input.props.handler);
|
|
58
|
+
const ldFlags = input.props.go?.ldFlags || ["-s", "-w"];
|
|
59
|
+
const buildTags = input.props.go?.buildTags || [];
|
|
58
60
|
if (input.mode === "start") {
|
|
59
61
|
try {
|
|
60
62
|
const target = path.join(input.out, handlerName);
|
|
61
63
|
const srcPath = os.platform() === "win32" ? src.replaceAll("\\", "\\\\") : src;
|
|
62
|
-
const result = await execAsync(
|
|
64
|
+
const result = await execAsync([
|
|
65
|
+
"go",
|
|
66
|
+
"build",
|
|
67
|
+
...(ldFlags ? [`-ldflags "${ldFlags.join(" ")}"`] : []),
|
|
68
|
+
...(buildTags ? [`-t ${buildTags.join(" ")}`] : []),
|
|
69
|
+
`-o "${target}"`,
|
|
70
|
+
`./${srcPath}`,
|
|
71
|
+
].join(" "), {
|
|
63
72
|
cwd: project,
|
|
64
73
|
env: {
|
|
65
74
|
...process.env,
|
|
@@ -77,11 +86,18 @@ export const useGoHandler = Context.memo(async () => {
|
|
|
77
86
|
try {
|
|
78
87
|
const target = path.join(input.out, "bootstrap");
|
|
79
88
|
const srcPath = os.platform() === "win32" ? src.replaceAll("\\", "\\\\") : src;
|
|
80
|
-
await execAsync(
|
|
89
|
+
await execAsync([
|
|
90
|
+
"go",
|
|
91
|
+
"build",
|
|
92
|
+
...(ldFlags ? [`-ldflags "${ldFlags.join(" ")}"`] : []),
|
|
93
|
+
...(buildTags ? [`-t ${buildTags.join(" ")}`] : []),
|
|
94
|
+
`-o "${target}"`,
|
|
95
|
+
`./${srcPath}`,
|
|
96
|
+
].join(" "), {
|
|
81
97
|
cwd: project,
|
|
82
98
|
env: {
|
|
83
99
|
...process.env,
|
|
84
|
-
CGO_ENABLED: "0",
|
|
100
|
+
CGO_ENABLED: input.props.go?.cgoEnabled ? "1" : "0",
|
|
85
101
|
GOARCH: input.props.architecture === "arm_64" ? "arm64" : "amd64",
|
|
86
102
|
GOOS: "linux",
|
|
87
103
|
},
|
package/runtime/handlers/rust.js
CHANGED
|
@@ -3,7 +3,6 @@ import fs from "fs/promises";
|
|
|
3
3
|
import { useRuntimeHandlers } from "../handlers.js";
|
|
4
4
|
import { useRuntimeWorkers } from "../workers.js";
|
|
5
5
|
import { Context } from "../../context/context.js";
|
|
6
|
-
import { VisibleError } from "../../error.js";
|
|
7
6
|
import { exec, spawn } from "child_process";
|
|
8
7
|
import { promisify } from "util";
|
|
9
8
|
import { useRuntimeServerConfig } from "../server.js";
|
|
@@ -66,7 +65,7 @@ export const useRustHandler = Context.memo(async () => {
|
|
|
66
65
|
sources.set(input.functionID, project);
|
|
67
66
|
if (input.mode === "start") {
|
|
68
67
|
try {
|
|
69
|
-
await execAsync(
|
|
68
|
+
await execAsync(["cargo", "build", `--bin ${parsed.name}`].join(" "), {
|
|
70
69
|
cwd: project,
|
|
71
70
|
env: {
|
|
72
71
|
...process.env,
|
|
@@ -75,12 +74,22 @@ export const useRustHandler = Context.memo(async () => {
|
|
|
75
74
|
await fs.cp(path.join(project, `target/debug`, parsed.name), path.join(input.out, "handler"));
|
|
76
75
|
}
|
|
77
76
|
catch (ex) {
|
|
78
|
-
|
|
77
|
+
return {
|
|
78
|
+
type: "error",
|
|
79
|
+
errors: [String(ex)],
|
|
80
|
+
};
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
if (input.mode === "deploy") {
|
|
82
84
|
try {
|
|
83
|
-
await execAsync(
|
|
85
|
+
await execAsync([
|
|
86
|
+
"cargo",
|
|
87
|
+
"lambda",
|
|
88
|
+
"build",
|
|
89
|
+
"--release",
|
|
90
|
+
...(input.props.architecture === "arm_64" ? ["--arm64"] : []),
|
|
91
|
+
`--bin ${parsed.name}`,
|
|
92
|
+
].join(" "), {
|
|
84
93
|
cwd: project,
|
|
85
94
|
env: {
|
|
86
95
|
...process.env,
|
|
@@ -89,7 +98,10 @@ export const useRustHandler = Context.memo(async () => {
|
|
|
89
98
|
await fs.cp(path.join(project, `target/lambda/`, parsed.name, "bootstrap"), path.join(input.out, "bootstrap"));
|
|
90
99
|
}
|
|
91
100
|
catch (ex) {
|
|
92
|
-
|
|
101
|
+
return {
|
|
102
|
+
type: "error",
|
|
103
|
+
errors: [String(ex)],
|
|
104
|
+
};
|
|
93
105
|
}
|
|
94
106
|
}
|
|
95
107
|
return {
|
package/sst.mjs
CHANGED
|
@@ -5660,12 +5660,21 @@ var init_go = __esm({
|
|
|
5660
5660
|
const project = await find(parsed.dir, "go.mod");
|
|
5661
5661
|
sources.set(input.functionID, project);
|
|
5662
5662
|
const src = path11.relative(project, input.props.handler);
|
|
5663
|
+
const ldFlags = input.props.go?.ldFlags || ["-s", "-w"];
|
|
5664
|
+
const buildTags = input.props.go?.buildTags || [];
|
|
5663
5665
|
if (input.mode === "start") {
|
|
5664
5666
|
try {
|
|
5665
5667
|
const target = path11.join(input.out, handlerName);
|
|
5666
5668
|
const srcPath = os4.platform() === "win32" ? src.replaceAll("\\", "\\\\") : src;
|
|
5667
5669
|
const result = await execAsync(
|
|
5668
|
-
|
|
5670
|
+
[
|
|
5671
|
+
"go",
|
|
5672
|
+
"build",
|
|
5673
|
+
...ldFlags ? [`-ldflags "${ldFlags.join(" ")}"`] : [],
|
|
5674
|
+
...buildTags ? [`-t ${buildTags.join(" ")}`] : [],
|
|
5675
|
+
`-o "${target}"`,
|
|
5676
|
+
`./${srcPath}`
|
|
5677
|
+
].join(" "),
|
|
5669
5678
|
{
|
|
5670
5679
|
cwd: project,
|
|
5671
5680
|
env: {
|
|
@@ -5685,12 +5694,19 @@ var init_go = __esm({
|
|
|
5685
5694
|
const target = path11.join(input.out, "bootstrap");
|
|
5686
5695
|
const srcPath = os4.platform() === "win32" ? src.replaceAll("\\", "\\\\") : src;
|
|
5687
5696
|
await execAsync(
|
|
5688
|
-
|
|
5697
|
+
[
|
|
5698
|
+
"go",
|
|
5699
|
+
"build",
|
|
5700
|
+
...ldFlags ? [`-ldflags "${ldFlags.join(" ")}"`] : [],
|
|
5701
|
+
...buildTags ? [`-t ${buildTags.join(" ")}`] : [],
|
|
5702
|
+
`-o "${target}"`,
|
|
5703
|
+
`./${srcPath}`
|
|
5704
|
+
].join(" "),
|
|
5689
5705
|
{
|
|
5690
5706
|
cwd: project,
|
|
5691
5707
|
env: {
|
|
5692
5708
|
...process.env,
|
|
5693
|
-
CGO_ENABLED: "0",
|
|
5709
|
+
CGO_ENABLED: input.props.go?.cgoEnabled ? "1" : "0",
|
|
5694
5710
|
GOARCH: input.props.architecture === "arm_64" ? "arm64" : "amd64",
|
|
5695
5711
|
GOOS: "linux"
|
|
5696
5712
|
}
|
|
@@ -5993,7 +6009,6 @@ var init_rust = __esm({
|
|
|
5993
6009
|
init_handlers2();
|
|
5994
6010
|
init_workers();
|
|
5995
6011
|
init_context();
|
|
5996
|
-
init_error();
|
|
5997
6012
|
init_server();
|
|
5998
6013
|
init_fs();
|
|
5999
6014
|
execAsync2 = promisify2(exec4);
|
|
@@ -6054,34 +6069,53 @@ var init_rust = __esm({
|
|
|
6054
6069
|
sources.set(input.functionID, project);
|
|
6055
6070
|
if (input.mode === "start") {
|
|
6056
6071
|
try {
|
|
6057
|
-
await execAsync2(
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6072
|
+
await execAsync2(
|
|
6073
|
+
["cargo", "build", `--bin ${parsed.name}`].join(" "),
|
|
6074
|
+
{
|
|
6075
|
+
cwd: project,
|
|
6076
|
+
env: {
|
|
6077
|
+
...process.env
|
|
6078
|
+
}
|
|
6061
6079
|
}
|
|
6062
|
-
|
|
6080
|
+
);
|
|
6063
6081
|
await fs11.cp(
|
|
6064
6082
|
path12.join(project, `target/debug`, parsed.name),
|
|
6065
6083
|
path12.join(input.out, "handler")
|
|
6066
6084
|
);
|
|
6067
6085
|
} catch (ex) {
|
|
6068
|
-
|
|
6086
|
+
return {
|
|
6087
|
+
type: "error",
|
|
6088
|
+
errors: [String(ex)]
|
|
6089
|
+
};
|
|
6069
6090
|
}
|
|
6070
6091
|
}
|
|
6071
6092
|
if (input.mode === "deploy") {
|
|
6072
6093
|
try {
|
|
6073
|
-
await execAsync2(
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6094
|
+
await execAsync2(
|
|
6095
|
+
[
|
|
6096
|
+
"cargo",
|
|
6097
|
+
"lambda",
|
|
6098
|
+
"build",
|
|
6099
|
+
"--release",
|
|
6100
|
+
...input.props.architecture === "arm_64" ? ["--arm64"] : [],
|
|
6101
|
+
`--bin ${parsed.name}`
|
|
6102
|
+
].join(" "),
|
|
6103
|
+
{
|
|
6104
|
+
cwd: project,
|
|
6105
|
+
env: {
|
|
6106
|
+
...process.env
|
|
6107
|
+
}
|
|
6077
6108
|
}
|
|
6078
|
-
|
|
6109
|
+
);
|
|
6079
6110
|
await fs11.cp(
|
|
6080
6111
|
path12.join(project, `target/lambda/`, parsed.name, "bootstrap"),
|
|
6081
6112
|
path12.join(input.out, "bootstrap")
|
|
6082
6113
|
);
|
|
6083
6114
|
} catch (ex) {
|
|
6084
|
-
|
|
6115
|
+
return {
|
|
6116
|
+
type: "error",
|
|
6117
|
+
errors: [String(ex)]
|
|
6118
|
+
};
|
|
6085
6119
|
}
|
|
6086
6120
|
}
|
|
6087
6121
|
return {
|
|
@@ -6661,7 +6695,11 @@ import {
|
|
|
6661
6695
|
RemovalPolicy
|
|
6662
6696
|
} from "aws-cdk-lib/core";
|
|
6663
6697
|
import { Function, Runtime as Runtime2, Code } from "aws-cdk-lib/aws-lambda";
|
|
6664
|
-
import {
|
|
6698
|
+
import {
|
|
6699
|
+
ManagedPolicy,
|
|
6700
|
+
PermissionsBoundary,
|
|
6701
|
+
PolicyStatement
|
|
6702
|
+
} from "aws-cdk-lib/aws-iam";
|
|
6665
6703
|
import { Rule } from "aws-cdk-lib/aws-events";
|
|
6666
6704
|
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
|
|
6667
6705
|
import {
|
|
@@ -6678,19 +6716,20 @@ async function loadCDKStatus() {
|
|
|
6678
6716
|
new DescribeStacksCommand2({ StackName: stackName })
|
|
6679
6717
|
);
|
|
6680
6718
|
if (!stacks || stacks.length === 0)
|
|
6681
|
-
return
|
|
6719
|
+
return { status: "bootstrap" };
|
|
6682
6720
|
if (!["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
|
|
6683
|
-
return
|
|
6721
|
+
return { status: "bootstrap" };
|
|
6684
6722
|
}
|
|
6685
6723
|
const output = stacks[0].Outputs?.find(
|
|
6686
6724
|
(o) => o.OutputKey === "BootstrapVersion"
|
|
6687
6725
|
);
|
|
6688
|
-
if (!output || parseInt(output.OutputValue) < 14)
|
|
6689
|
-
return
|
|
6690
|
-
|
|
6726
|
+
if (!output || parseInt(output.OutputValue) < 14) {
|
|
6727
|
+
return { status: "update" };
|
|
6728
|
+
}
|
|
6729
|
+
return { status: "ready" };
|
|
6691
6730
|
} catch (e) {
|
|
6692
6731
|
if (e.name === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
|
|
6693
|
-
return
|
|
6732
|
+
return { status: "bootstrap" };
|
|
6694
6733
|
} else {
|
|
6695
6734
|
throw e;
|
|
6696
6735
|
}
|
|
@@ -6709,7 +6748,7 @@ async function loadSSTStatus() {
|
|
|
6709
6748
|
);
|
|
6710
6749
|
} catch (e) {
|
|
6711
6750
|
if (e.Code === "ValidationError" && e.message === `Stack with id ${stackName} does not exist`) {
|
|
6712
|
-
return
|
|
6751
|
+
return { status: "bootstrap" };
|
|
6713
6752
|
}
|
|
6714
6753
|
throw e;
|
|
6715
6754
|
}
|
|
@@ -6723,7 +6762,7 @@ async function loadSSTStatus() {
|
|
|
6723
6762
|
}
|
|
6724
6763
|
});
|
|
6725
6764
|
if (!version2 || !bucket) {
|
|
6726
|
-
return
|
|
6765
|
+
return { status: "bootstrap" };
|
|
6727
6766
|
}
|
|
6728
6767
|
const latestParts = LATEST_VERSION.split(".");
|
|
6729
6768
|
const latestMajor = parseInt(latestParts[0]);
|
|
@@ -6732,9 +6771,9 @@ async function loadSSTStatus() {
|
|
|
6732
6771
|
const currentMajor = parseInt(currentParts[0]);
|
|
6733
6772
|
const currentMinor = parseInt(currentParts[1] || "0");
|
|
6734
6773
|
if (currentMajor < latestMajor || currentMajor > latestMajor || currentMinor < latestMinor) {
|
|
6735
|
-
return
|
|
6774
|
+
return { status: "update" };
|
|
6736
6775
|
}
|
|
6737
|
-
return { version: version2, bucket };
|
|
6776
|
+
return { status: "ready", version: version2, bucket };
|
|
6738
6777
|
}
|
|
6739
6778
|
async function bootstrapSST() {
|
|
6740
6779
|
const { region, bootstrap: bootstrap2, cdk } = useProject().config;
|
|
@@ -6815,6 +6854,14 @@ async function bootstrapSST() {
|
|
|
6815
6854
|
}
|
|
6816
6855
|
});
|
|
6817
6856
|
rule.addTarget(new LambdaFunction(fn));
|
|
6857
|
+
if (cdk?.customPermissionsBoundary) {
|
|
6858
|
+
const boundaryPolicy = ManagedPolicy.fromManagedPolicyName(
|
|
6859
|
+
stack,
|
|
6860
|
+
"PermissionBoundaryPolicy",
|
|
6861
|
+
cdk.customPermissionsBoundary
|
|
6862
|
+
);
|
|
6863
|
+
PermissionsBoundary.of(stack).apply(boundaryPolicy);
|
|
6864
|
+
}
|
|
6818
6865
|
new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
|
|
6819
6866
|
new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
|
|
6820
6867
|
const asm = app.synth();
|
|
@@ -6904,11 +6951,11 @@ var init_bootstrap = __esm({
|
|
|
6904
6951
|
loadSSTStatus()
|
|
6905
6952
|
]);
|
|
6906
6953
|
Logger.debug("Loaded bootstrap status");
|
|
6907
|
-
const needToBootstrapCDK =
|
|
6908
|
-
const needToBootstrapSST =
|
|
6954
|
+
const needToBootstrapCDK = cdkStatus.status !== "ready";
|
|
6955
|
+
const needToBootstrapSST = sstStatus.status !== "ready";
|
|
6909
6956
|
if (needToBootstrapCDK || needToBootstrapSST) {
|
|
6910
6957
|
const spinner = createSpinner(
|
|
6911
|
-
"Deploying bootstrap stack, this only needs to happen once"
|
|
6958
|
+
cdkStatus.status === "bootstrap" || sstStatus.status === "bootstrap" ? "Deploying bootstrap stack, this only needs to happen once" : "Updating bootstrap stack"
|
|
6912
6959
|
).start();
|
|
6913
6960
|
if (needToBootstrapCDK) {
|
|
6914
6961
|
await bootstrapCDK();
|
|
@@ -6916,7 +6963,7 @@ var init_bootstrap = __esm({
|
|
|
6916
6963
|
if (needToBootstrapSST) {
|
|
6917
6964
|
await bootstrapSST();
|
|
6918
6965
|
sstStatus = await loadSSTStatus();
|
|
6919
|
-
if (
|
|
6966
|
+
if (sstStatus.status !== "ready")
|
|
6920
6967
|
throw new VisibleError("Failed to load bootstrap stack status");
|
|
6921
6968
|
}
|
|
6922
6969
|
spinner.succeed();
|
|
@@ -7085,11 +7132,40 @@ async function useLocalServer(opts) {
|
|
|
7085
7132
|
const wss = new WebSocketServer({ noServer: true });
|
|
7086
7133
|
const wss2 = new WebSocketServer({ noServer: true });
|
|
7087
7134
|
const sockets = /* @__PURE__ */ new Set();
|
|
7135
|
+
let buffer = [
|
|
7136
|
+
{
|
|
7137
|
+
type: "cli.dev",
|
|
7138
|
+
properties: {
|
|
7139
|
+
stage: project.config.stage,
|
|
7140
|
+
app: project.config.name
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
];
|
|
7144
|
+
function publish(type, properties) {
|
|
7145
|
+
const msg = {
|
|
7146
|
+
type,
|
|
7147
|
+
properties
|
|
7148
|
+
};
|
|
7149
|
+
buffer.push(msg);
|
|
7150
|
+
const json = JSON.stringify(msg);
|
|
7151
|
+
[...sockets.values()].map((s) => s.send(json));
|
|
7152
|
+
}
|
|
7088
7153
|
wss2.on("connection", (socket, req) => {
|
|
7089
7154
|
sockets.add(socket);
|
|
7155
|
+
for (const msg of buffer) {
|
|
7156
|
+
socket.send(JSON.stringify(msg));
|
|
7157
|
+
}
|
|
7090
7158
|
socket.on("close", () => {
|
|
7091
7159
|
sockets.delete(socket);
|
|
7092
7160
|
});
|
|
7161
|
+
socket.on("message", (data2) => {
|
|
7162
|
+
const parsed = JSON.parse(data2.toString());
|
|
7163
|
+
if (parsed.type === "log.cleared") {
|
|
7164
|
+
buffer = buffer.filter(
|
|
7165
|
+
(msg) => msg.properties?.functionID !== parsed.properties?.functionID
|
|
7166
|
+
);
|
|
7167
|
+
}
|
|
7168
|
+
});
|
|
7093
7169
|
});
|
|
7094
7170
|
wss.on("connection", (socket, req) => {
|
|
7095
7171
|
if (req.headers.origin?.endsWith("localhost:3000"))
|
|
@@ -7160,13 +7236,6 @@ async function useLocalServer(opts) {
|
|
|
7160
7236
|
cb(func);
|
|
7161
7237
|
});
|
|
7162
7238
|
}
|
|
7163
|
-
function publish(type, properties) {
|
|
7164
|
-
const msg = JSON.stringify({
|
|
7165
|
-
type,
|
|
7166
|
-
properties
|
|
7167
|
-
});
|
|
7168
|
-
[...sockets.values()].map((s) => s.send(msg));
|
|
7169
|
-
}
|
|
7170
7239
|
bus.subscribe("function.invoked", async (evt) => {
|
|
7171
7240
|
publish("function.invoked", evt.properties);
|
|
7172
7241
|
updateFunction(evt.properties.functionID, (draft) => {
|