sst 2.24.15 → 2.24.16

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.
@@ -12,6 +12,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
12
12
  const { useBus } = await import("../../bus.js");
13
13
  const { useWatcher } = await import("../../watcher.js");
14
14
  const { useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
15
+ const { exit, exitWithError, trackDevError, trackDevRunning } = await import("../program.js");
15
16
  const { Logger } = await import("../../logger.js");
16
17
  const { createSpinner } = await import("../spinner.js");
17
18
  const { bold, dim, yellow } = await import("colorette");
@@ -32,302 +33,318 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
32
33
  const { useIOT } = await import("../../iot.js");
33
34
  const { clear } = await import("../terminal.js");
34
35
  const { getCiInfo } = await import("../ci-info.js");
35
- if (args._[0] === "start") {
36
- console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
37
- }
38
- const project = useProject();
39
- const useFunctionLogger = Context.memo(async () => {
40
- const bus = useBus();
41
- const colors = ["#01cdfe", "#ff71ce", "#05ffa1", "#b967ff"];
42
- let index = 0;
43
- const pending = new Map();
44
- function prefix(requestID) {
45
- const exists = pending.get(requestID);
46
- if (exists) {
47
- return Colors.hex(exists.color)(Colors.prefix);
48
- }
49
- pending.set(requestID, {
50
- requestID,
51
- started: Date.now(),
52
- color: colors[index % colors.length],
53
- });
54
- index++;
55
- return prefix(requestID);
36
+ try {
37
+ if (args._[0] === "start") {
38
+ console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
56
39
  }
57
- function end(requestID) {
58
- // index--;
59
- // if (index < 0) index = colors.length - 1;
60
- pending.delete(requestID);
61
- }
62
- bus.subscribe("function.invoked", async (evt) => {
63
- Colors.line(prefix(evt.properties.requestID), Colors.dim.bold("Invoked"), Colors.dim(useFunctions().fromID(evt.properties.functionID)?.handler));
64
- });
65
- bus.subscribe("worker.stdout", async (evt) => {
66
- const info = useFunctions().fromID(evt.properties.functionID);
67
- prefix(evt.properties.requestID);
68
- const { started } = pending.get(evt.properties.requestID);
69
- for (let line of evt.properties.message.split("\n")) {
70
- // Remove prefix from container logs
71
- if (info?.runtime === "container") {
72
- // handle Node.js container logs
73
- // ie. 2023-07-05T00:13:42.448Z\td7330533-2429-4871-a632-ed29a1d32246\tINFO\tfoo!
74
- const parts = line.split("\t");
75
- if (parts.length >= 4 &&
76
- Date.parse(parts[0]) &&
77
- parts[1].length === 36) {
78
- line = parts.slice(3).join("\t");
79
- }
40
+ const project = useProject();
41
+ const useFunctionLogger = Context.memo(async () => {
42
+ const bus = useBus();
43
+ const colors = ["#01cdfe", "#ff71ce", "#05ffa1", "#b967ff"];
44
+ let index = 0;
45
+ const pending = new Map();
46
+ function prefix(requestID) {
47
+ const exists = pending.get(requestID);
48
+ if (exists) {
49
+ return Colors.hex(exists.color)(Colors.prefix);
80
50
  }
81
- Colors.line(prefix(evt.properties.requestID), Colors.dim(("+" + (Date.now() - started) + "ms").padEnd(7)), Colors.dim(line));
51
+ pending.set(requestID, {
52
+ requestID,
53
+ started: Date.now(),
54
+ color: colors[index % colors.length],
55
+ });
56
+ index++;
57
+ return prefix(requestID);
82
58
  }
83
- });
84
- bus.subscribe("function.build.started", async (evt) => {
85
- const info = useFunctions().fromID(evt.properties.functionID);
86
- if (!info)
87
- return;
88
- if (info.enableLiveDev === false)
89
- return;
90
- if (info.runtime !== "container")
91
- return;
92
- Colors.line(Colors.dim(Colors.prefix, "Building", info.handler, "container"));
93
- });
94
- bus.subscribe("function.build.success", async (evt) => {
95
- const info = useFunctions().fromID(evt.properties.functionID);
96
- if (!info)
97
- return;
98
- if (info.enableLiveDev === false)
99
- return;
100
- Colors.line(info.runtime === "container"
101
- ? Colors.dim(Colors.prefix, "Built", info.handler, "container")
102
- : Colors.dim(Colors.prefix, "Built", info.handler));
103
- });
104
- bus.subscribe("function.build.failed", async (evt) => {
105
- const info = useFunctions().fromID(evt.properties.functionID);
106
- if (!info)
107
- return;
108
- if (info.enableLiveDev === false)
109
- return;
110
- Colors.gap();
111
- Colors.line(Colors.danger("✖ "), "Build failed", info.handler);
112
- for (const line of evt.properties.errors) {
113
- Colors.line(" ", line);
59
+ function end(requestID) {
60
+ // index--;
61
+ // if (index < 0) index = colors.length - 1;
62
+ pending.delete(requestID);
114
63
  }
115
- Colors.gap();
116
- });
117
- bus.subscribe("function.success", async (evt) => {
118
- // stdout logs sometimes come in after
119
- const p = prefix(evt.properties.requestID);
120
- const req = pending.get(evt.properties.requestID);
121
- setTimeout(() => {
122
- Colors.line(p, Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
123
- end(evt.properties.requestID);
124
- }, 100);
125
- });
126
- bus.subscribe("function.error", async (evt) => {
127
- setTimeout(() => {
128
- Colors.line(prefix(evt.properties.requestID), Colors.danger.bold("Error:"), Colors.danger.bold(evt.properties.errorMessage));
129
- for (const line of evt.properties.trace || []) {
130
- // Skip double printing error message
131
- if (line.includes(evt.properties.errorMessage))
132
- continue;
133
- Colors.line(" ", `${dim(line)}`);
64
+ bus.subscribe("function.invoked", async (evt) => {
65
+ Colors.line(prefix(evt.properties.requestID), Colors.dim.bold("Invoked"), Colors.dim(useFunctions().fromID(evt.properties.functionID)?.handler));
66
+ });
67
+ bus.subscribe("worker.stdout", async (evt) => {
68
+ const info = useFunctions().fromID(evt.properties.functionID);
69
+ prefix(evt.properties.requestID);
70
+ const { started } = pending.get(evt.properties.requestID);
71
+ for (let line of evt.properties.message.split("\n")) {
72
+ // Remove prefix from container logs
73
+ if (info?.runtime === "container") {
74
+ // handle Node.js container logs
75
+ // ie. 2023-07-05T00:13:42.448Z\td7330533-2429-4871-a632-ed29a1d32246\tINFO\tfoo!
76
+ const parts = line.split("\t");
77
+ if (parts.length >= 4 &&
78
+ Date.parse(parts[0]) &&
79
+ parts[1].length === 36) {
80
+ line = parts.slice(3).join("\t");
81
+ }
82
+ }
83
+ Colors.line(prefix(evt.properties.requestID), Colors.dim(("+" + (Date.now() - started) + "ms").padEnd(7)), Colors.dim(line));
134
84
  }
135
- end(evt.properties.requestID);
136
- }, 100);
85
+ });
86
+ bus.subscribe("function.build.started", async (evt) => {
87
+ const info = useFunctions().fromID(evt.properties.functionID);
88
+ if (!info)
89
+ return;
90
+ if (info.enableLiveDev === false)
91
+ return;
92
+ if (info.runtime !== "container")
93
+ return;
94
+ Colors.line(Colors.dim(Colors.prefix, "Building", info.handler, "container"));
95
+ });
96
+ bus.subscribe("function.build.success", async (evt) => {
97
+ const info = useFunctions().fromID(evt.properties.functionID);
98
+ if (!info)
99
+ return;
100
+ if (info.enableLiveDev === false)
101
+ return;
102
+ Colors.line(info.runtime === "container"
103
+ ? Colors.dim(Colors.prefix, "Built", info.handler, "container")
104
+ : Colors.dim(Colors.prefix, "Built", info.handler));
105
+ });
106
+ bus.subscribe("function.build.failed", async (evt) => {
107
+ const info = useFunctions().fromID(evt.properties.functionID);
108
+ if (!info)
109
+ return;
110
+ if (info.enableLiveDev === false)
111
+ return;
112
+ Colors.gap();
113
+ Colors.line(Colors.danger("✖ "), "Build failed", info.handler);
114
+ for (const line of evt.properties.errors) {
115
+ Colors.line(" ", line);
116
+ }
117
+ Colors.gap();
118
+ });
119
+ bus.subscribe("function.success", async (evt) => {
120
+ // stdout logs sometimes come in after
121
+ const p = prefix(evt.properties.requestID);
122
+ const req = pending.get(evt.properties.requestID);
123
+ setTimeout(() => {
124
+ Colors.line(p, Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
125
+ end(evt.properties.requestID);
126
+ }, 100);
127
+ });
128
+ bus.subscribe("function.error", async (evt) => {
129
+ setTimeout(() => {
130
+ Colors.line(prefix(evt.properties.requestID), Colors.danger.bold("Error:"), Colors.danger.bold(evt.properties.errorMessage));
131
+ for (const line of evt.properties.trace || []) {
132
+ // Skip double printing error message
133
+ if (line.includes(evt.properties.errorMessage))
134
+ continue;
135
+ Colors.line(" ", `${dim(line)}`);
136
+ }
137
+ end(evt.properties.requestID);
138
+ }, 100);
139
+ });
137
140
  });
138
- });
139
- const useStackBuilder = Context.memo(async () => {
140
- const watcher = useWatcher();
141
- const scriptVersion = Date.now().toString();
142
- let lastDeployed;
143
- let isWorking = false;
144
- let isDirty = false;
145
- async function build() {
146
- if (isWorking) {
147
- isDirty = true;
148
- return;
149
- }
150
- isDirty = false;
151
- isWorking = true;
152
- Colors.gap();
153
- const spinner = createSpinner({
154
- color: "gray",
155
- text: lastDeployed ? ` Building...` : dim(` Checking for changes`),
156
- }).start();
157
- try {
158
- const [metafile, sstConfig] = await Stacks.load(project.paths.config);
159
- project.metafile = metafile;
160
- project.stacks = sstConfig.stacks;
161
- const assembly = await Stacks.synth({
162
- increaseTimeout: args["increase-timeout"],
163
- scriptVersion,
164
- fn: project.stacks,
165
- outDir: `.sst/cdk.out`,
166
- mode: "dev",
167
- });
168
- Logger.debug("Directory", assembly.directory);
169
- const next = await checksum(assembly.directory);
170
- Logger.debug("Checksum", "next", next, "old", lastDeployed);
171
- if (next === lastDeployed) {
172
- spinner.succeed(Colors.dim(" Built with no changes"));
173
- isWorking = false;
174
- if (isDirty)
175
- build();
141
+ const useStackBuilder = Context.memo(async () => {
142
+ const watcher = useWatcher();
143
+ const scriptVersion = Date.now().toString();
144
+ let lastDeployed;
145
+ let isWorking = false;
146
+ let isDirty = false;
147
+ async function build() {
148
+ if (isWorking) {
149
+ isDirty = true;
176
150
  return;
177
151
  }
178
- if (!lastDeployed) {
179
- spinner.stop();
180
- spinner.clear();
181
- Colors.mode("gap");
152
+ isDirty = false;
153
+ isWorking = true;
154
+ Colors.gap();
155
+ const spinner = createSpinner({
156
+ color: "gray",
157
+ text: lastDeployed
158
+ ? ` Building...`
159
+ : dim(` Checking for changes`),
160
+ }).start();
161
+ try {
162
+ const [metafile, sstConfig] = await Stacks.load(project.paths.config);
163
+ project.metafile = metafile;
164
+ project.stacks = sstConfig.stacks;
165
+ const assembly = await Stacks.synth({
166
+ increaseTimeout: args["increase-timeout"],
167
+ scriptVersion,
168
+ fn: project.stacks,
169
+ outDir: `.sst/cdk.out`,
170
+ mode: "dev",
171
+ });
172
+ Logger.debug("Directory", assembly.directory);
173
+ const next = await checksum(assembly.directory);
174
+ Logger.debug("Checksum", "next", next, "old", lastDeployed);
175
+ if (next === lastDeployed) {
176
+ spinner.succeed(Colors.dim(" Built with no changes"));
177
+ isWorking = false;
178
+ if (isDirty)
179
+ build();
180
+ return;
181
+ }
182
+ if (!lastDeployed) {
183
+ spinner.stop();
184
+ spinner.clear();
185
+ Colors.mode("gap");
186
+ }
187
+ else {
188
+ spinner.succeed(Colors.dim(` Built`));
189
+ Colors.gap();
190
+ }
191
+ deploy(assembly);
182
192
  }
183
- else {
184
- spinner.succeed(Colors.dim(` Built`));
193
+ catch (ex) {
194
+ isWorking = false;
195
+ spinner.fail();
196
+ Colors.line(ex.stack
197
+ .split("\n")
198
+ .map((line) => " " + line)
199
+ .join("\n"));
185
200
  Colors.gap();
201
+ if (!lastDeployed) {
202
+ trackDevError(ex);
203
+ }
186
204
  }
187
- deploy(assembly);
188
205
  }
189
- catch (ex) {
206
+ async function deploy(assembly) {
207
+ const nextChecksum = await checksum(assembly.directory);
208
+ const component = render(React.createElement(DeploymentUI, { assembly: assembly }));
209
+ const results = await Stacks.deployMany(assembly.stacks);
210
+ component.clear();
211
+ component.unmount();
212
+ printDeploymentResults(assembly, results);
213
+ // Run after initial deploy
214
+ if (!lastDeployed) {
215
+ await saveAppMetadata({ mode: "dev" });
216
+ // Check failed stacks
217
+ const failed = Object.values(results).find((result) => Stacks.isFailed(result.status));
218
+ failed
219
+ ? trackDevError(new Error(`CloudFormation status ${failed.status}`))
220
+ : trackDevRunning();
221
+ // print start frontend commands
222
+ useSites()
223
+ .all.filter(({ props }) => props.dev?.deploy !== true)
224
+ .forEach(({ type, props }) => {
225
+ const framework = type === "AstroSite"
226
+ ? "Astro"
227
+ : type === "NextjsSite"
228
+ ? "Next.js"
229
+ : type === "RemixSite"
230
+ ? "Remix"
231
+ : type === "SolidStartSite"
232
+ ? "SolidStart"
233
+ : type === "SvelteKitSite"
234
+ ? "SvelteKit"
235
+ : undefined;
236
+ if (framework) {
237
+ const cdCmd = path.resolve(props.path) === process.cwd()
238
+ ? ""
239
+ : `cd ${props.path} && `;
240
+ Colors.line(Colors.primary(`➜ `), Colors.bold(`Start ${framework}:`), `${cdCmd}npm run dev`);
241
+ Colors.gap();
242
+ }
243
+ });
244
+ }
245
+ lastDeployed = nextChecksum;
246
+ // Write outputs.json
247
+ fs.writeFile(project.config.outputs ||
248
+ path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
190
249
  isWorking = false;
191
- spinner.fail();
192
- Colors.line(ex.stack
193
- .split("\n")
194
- .map((line) => " " + line)
195
- .join("\n"));
196
- Colors.gap();
250
+ if (isDirty)
251
+ build();
197
252
  }
198
- }
199
- async function deploy(assembly) {
200
- const nextChecksum = await checksum(assembly.directory);
201
- const component = render(React.createElement(DeploymentUI, { assembly: assembly }));
202
- const results = await Stacks.deployMany(assembly.stacks);
203
- component.clear();
204
- component.unmount();
205
- printDeploymentResults(assembly, results);
206
- // Run after initial deploy
207
- if (!lastDeployed) {
208
- await saveAppMetadata({ mode: "dev" });
209
- // print start frontend commands
210
- useSites()
211
- .all.filter(({ props }) => props.dev?.deploy !== true)
212
- .forEach(({ type, props }) => {
213
- const framework = type === "AstroSite"
214
- ? "Astro"
215
- : type === "NextjsSite"
216
- ? "Next.js"
217
- : type === "RemixSite"
218
- ? "Remix"
219
- : type === "SolidStartSite"
220
- ? "SolidStart"
221
- : type === "SvelteKitSite"
222
- ? "SvelteKit"
223
- : undefined;
224
- if (framework) {
225
- const cdCmd = path.resolve(props.path) === process.cwd()
226
- ? ""
227
- : `cd ${props.path} && `;
228
- Colors.line(Colors.primary(`➜ `), Colors.bold(`Start ${framework}:`), `${cdCmd}npm run dev`);
229
- Colors.gap();
230
- }
231
- });
253
+ async function checksum(cdkOutPath) {
254
+ const manifestPath = path.join(cdkOutPath, "manifest.json");
255
+ const cdkManifest = JSON.parse(await fs.readFile(manifestPath).then((x) => x.toString()));
256
+ const checksumData = await Promise.all(Object.keys(cdkManifest.artifacts)
257
+ .filter((key) => cdkManifest.artifacts[key].type ===
258
+ "aws:cloudformation:stack")
259
+ .map(async (key) => {
260
+ const { templateFile } = cdkManifest.artifacts[key].properties;
261
+ const templatePath = path.join(cdkOutPath, templateFile);
262
+ const templateContent = await fs.readFile(templatePath);
263
+ return templateContent;
264
+ })).then((x) => x.join("\n"));
265
+ const hash = crypto
266
+ .createHash("sha256")
267
+ .update(checksumData)
268
+ .digest("hex");
269
+ return hash;
232
270
  }
233
- lastDeployed = nextChecksum;
234
- // Write outputs.json
235
- fs.writeFile(project.config.outputs ||
236
- path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
237
- isWorking = false;
238
- if (isDirty)
271
+ watcher.subscribe("file.changed", async (evt) => {
272
+ if (!project.metafile)
273
+ return;
274
+ if (!project.metafile.inputs[evt.properties.relative.split(path.sep).join(path.posix.sep)])
275
+ return;
239
276
  build();
240
- }
241
- async function checksum(cdkOutPath) {
242
- const manifestPath = path.join(cdkOutPath, "manifest.json");
243
- const cdkManifest = JSON.parse(await fs.readFile(manifestPath).then((x) => x.toString()));
244
- const checksumData = await Promise.all(Object.keys(cdkManifest.artifacts)
245
- .filter((key) => cdkManifest.artifacts[key].type === "aws:cloudformation:stack")
246
- .map(async (key) => {
247
- const { templateFile } = cdkManifest.artifacts[key].properties;
248
- const templatePath = path.join(cdkOutPath, templateFile);
249
- const templateContent = await fs.readFile(templatePath);
250
- return templateContent;
251
- })).then((x) => x.join("\n"));
252
- const hash = crypto
253
- .createHash("sha256")
254
- .update(checksumData)
255
- .digest("hex");
256
- return hash;
257
- }
258
- watcher.subscribe("file.changed", async (evt) => {
259
- if (!project.metafile)
260
- return;
261
- if (!project.metafile.inputs[evt.properties.relative.split(path.sep).join(path.posix.sep)])
262
- return;
263
- build();
264
- });
265
- await build();
266
- });
267
- const useDisconnector = Context.memo(async () => {
268
- const bus = useBus();
269
- const iot = await useIOT();
270
- bus.subscribe("cli.dev", async (evt) => {
271
- const topic = `${iot.prefix}/events`;
272
- iot.publish(topic, "cli.dev", evt.properties);
273
- });
274
- bus.publish("cli.dev", {
275
- stage: project.config.stage,
276
- app: project.config.name,
277
- });
278
- bus.subscribe("cli.dev", async (evt) => {
279
- if (evt.properties.stage !== project.config.stage)
280
- return;
281
- if (evt.properties.app !== project.config.name)
282
- return;
283
- Colors.gap();
284
- Colors.line(Colors.danger(`➜ `), "Another `sst dev` session has been started for this stage. Exiting...");
285
- process.exit(0);
286
- });
287
- });
288
- const [appMetadata] = await Promise.all([
289
- useAppMetadata(),
290
- useLocalServer({
291
- key: "",
292
- cert: "",
293
- live: true,
294
- }),
295
- ]);
296
- async function promptChangeMode() {
297
- const readline = await import("readline");
298
- const rl = readline.createInterface({
299
- input: process.stdin,
300
- output: process.stdout,
277
+ });
278
+ await build();
301
279
  });
302
- return new Promise((resolve) => {
303
- console.log("");
304
- rl.question(`You have previously deployed the stage "${project.config.stage}" in production. It is recommended that you use a different stage for development. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to run this stage in dev mode? [y/N] `, async (input) => {
305
- rl.close();
306
- resolve(input.trim() === "y");
280
+ const useDisconnector = Context.memo(async () => {
281
+ const bus = useBus();
282
+ const iot = await useIOT();
283
+ bus.subscribe("cli.dev", async (evt) => {
284
+ const topic = `${iot.prefix}/events`;
285
+ iot.publish(topic, "cli.dev", evt.properties);
286
+ });
287
+ bus.publish("cli.dev", {
288
+ stage: project.config.stage,
289
+ app: project.config.name,
290
+ });
291
+ bus.subscribe("cli.dev", async (evt) => {
292
+ if (evt.properties.stage !== project.config.stage)
293
+ return;
294
+ if (evt.properties.app !== project.config.name)
295
+ return;
296
+ Colors.gap();
297
+ Colors.line(Colors.danger(`➜ `), "Another `sst dev` session has been started for this stage. Exiting...");
298
+ await exit();
307
299
  });
308
300
  });
309
- }
310
- // Check app mode changed
311
- if (!project.config.advanced?.disableAppModeCheck &&
312
- !getCiInfo().isCI &&
313
- appMetadata &&
314
- appMetadata.mode !== "dev") {
315
- if (!(await promptChangeMode())) {
316
- process.exit(0);
301
+ const [appMetadata] = await Promise.all([
302
+ useAppMetadata(),
303
+ useLocalServer({
304
+ key: "",
305
+ cert: "",
306
+ live: true,
307
+ }),
308
+ ]);
309
+ async function promptChangeMode() {
310
+ const readline = await import("readline");
311
+ const rl = readline.createInterface({
312
+ input: process.stdin,
313
+ output: process.stdout,
314
+ });
315
+ return new Promise((resolve) => {
316
+ console.log("");
317
+ rl.question(`You have previously deployed the stage "${project.config.stage}" in production. It is recommended that you use a different stage for development. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to run this stage in dev mode? [y/N] `, async (input) => {
318
+ rl.close();
319
+ resolve(input.trim() === "y");
320
+ });
321
+ });
322
+ }
323
+ // Check app mode changed
324
+ if (!project.config.advanced?.disableAppModeCheck &&
325
+ !getCiInfo().isCI &&
326
+ appMetadata &&
327
+ appMetadata.mode !== "dev") {
328
+ if (!(await promptChangeMode())) {
329
+ await exit();
330
+ }
317
331
  }
332
+ clear();
333
+ await printHeader({ console: true, hint: "ready!" });
334
+ await useStackBuilder();
335
+ await Promise.all([
336
+ useDisconnector(),
337
+ useRuntimeWorkers(),
338
+ useIOTBridge(),
339
+ useRuntimeServer(),
340
+ usePothosBuilder(),
341
+ useMetadata(),
342
+ useKyselyTypeGenerator(),
343
+ useRDSWarmer(),
344
+ useFunctionLogger(),
345
+ ]);
346
+ }
347
+ catch (e) {
348
+ await exitWithError(e);
318
349
  }
319
- clear();
320
- await printHeader({ console: true, hint: "ready!" });
321
- await useStackBuilder();
322
- await Promise.all([
323
- useDisconnector(),
324
- useRuntimeWorkers(),
325
- useIOTBridge(),
326
- useRuntimeServer(),
327
- usePothosBuilder(),
328
- useMetadata(),
329
- useKyselyTypeGenerator(),
330
- useRDSWarmer(),
331
- useFunctionLogger(),
332
- ]);
333
350
  });