sst 2.20.0 → 2.21.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.
@@ -1,11 +1,13 @@
1
+ import http from "http";
2
+ import { spawn } from "child_process";
1
3
  import { useRuntimeHandlers } from "../handlers.js";
2
4
  import { useRuntimeWorkers } from "../workers.js";
5
+ import { useRuntimeServerConfig } from "../server.js";
3
6
  import { Context } from "../../context/context.js";
4
7
  import { VisibleError } from "../../error.js";
5
- import { spawn } from "child_process";
6
- import { useRuntimeServerConfig } from "../server.js";
7
8
  import { isChild } from "../../util/fs.js";
8
9
  import { execAsync } from "../../util/process.js";
10
+ import { useFunctions } from "../../constructs/Function.js";
9
11
  export const useContainerHandler = Context.memo(async () => {
10
12
  const workers = await useRuntimeWorkers();
11
13
  const server = await useRuntimeServerConfig();
@@ -21,36 +23,9 @@ export const useContainerHandler = Context.memo(async () => {
21
23
  },
22
24
  canHandle: (input) => input.startsWith("container"),
23
25
  startWorker: async (input) => {
24
- const name = `sst-workerID-${input.workerID}-${Date.now()}`;
25
- const proc = spawn("docker", [
26
- "run",
27
- "--rm",
28
- "--network=host",
29
- `--name=${name}`,
30
- ...Object.entries({
31
- ...input.environment,
32
- IS_LOCAL: "true",
33
- AWS_LAMBDA_RUNTIME_API: `host.docker.internal:${server.port}/${input.workerID}`,
34
- })
35
- .map(([key, value]) => ["-e", `${key}=${value}`])
36
- .flat(),
37
- `sst-dev:${input.functionID}`,
38
- ], {
39
- env: {
40
- ...process.env,
41
- },
42
- cwd: input.out,
43
- });
44
- proc.on("exit", () => {
45
- workers.exited(input.workerID);
46
- });
47
- proc.stdout.on("data", (data) => {
48
- workers.stdout(input.workerID, data.toString());
49
- });
50
- proc.stderr.on("data", (data) => {
51
- workers.stdout(input.workerID, data.toString());
52
- });
53
- containers.set(input.workerID, name);
26
+ input.environment.SST_DEBUG_JOB
27
+ ? startJobWorker(input)
28
+ : startLambdaWorker(input);
54
29
  },
55
30
  stopWorker: async (workerID) => {
56
31
  const name = containers.get(workerID);
@@ -121,4 +96,155 @@ export const useContainerHandler = Context.memo(async () => {
121
96
  };
122
97
  },
123
98
  });
99
+ function dockerRun(input, opts, onExit) {
100
+ const name = `sst-workerID-${input.workerID}-${Date.now()}`;
101
+ const proc = spawn("docker", [
102
+ "run",
103
+ "--rm",
104
+ "--network=host",
105
+ `--name=${name}`,
106
+ ...Object.entries({
107
+ ...input.environment,
108
+ ...opts.envs,
109
+ IS_LOCAL: "true",
110
+ })
111
+ .map(([key, value]) => ["-e", `${key}=${value}`])
112
+ .flat(),
113
+ ...(opts.entrypoint !== undefined
114
+ ? ["--entrypoint", opts.entrypoint]
115
+ : []),
116
+ `sst-dev:${input.functionID}`,
117
+ ...(opts.cmd ?? []),
118
+ ], {
119
+ env: {
120
+ ...process.env,
121
+ },
122
+ cwd: input.out,
123
+ });
124
+ proc.on("exit", (code) => {
125
+ onExit(code);
126
+ });
127
+ proc.stdout.on("data", (data) => {
128
+ workers.stdout(input.workerID, data.toString());
129
+ });
130
+ proc.stderr.on("data", (data) => {
131
+ workers.stdout(input.workerID, data.toString());
132
+ });
133
+ containers.set(input.workerID, name);
134
+ }
135
+ function startLambdaWorker(input) {
136
+ dockerRun(input, {
137
+ envs: {
138
+ AWS_LAMBDA_RUNTIME_API: `host.docker.internal:${server.port}/${input.workerID}`,
139
+ },
140
+ }, () => {
141
+ workers.exited(input.workerID);
142
+ });
143
+ }
144
+ async function startJobWorker(input) {
145
+ // Job container is special:
146
+ // 1. Not capable of receiving the `event` payload
147
+ // - on `sst deploy`, the CodeBuild job is started with `SST_PAYLOAD` env var
148
+ // - on `sst dev`, set `SST_DEBUG_JOB` env var here
149
+ // 2. Worker exits at the end of the run.
150
+ const fn = useFunctions().fromID(input.functionID);
151
+ // Fetch request
152
+ const result = await init();
153
+ const awsRequestId = result.headers["lambda-runtime-aws-request-id"];
154
+ try {
155
+ dockerRun(input, {
156
+ entrypoint: "",
157
+ cmd: fn?.container?.docker.cmd,
158
+ envs: {
159
+ SST_PAYLOAD: result.body,
160
+ },
161
+ }, async (code) => {
162
+ code === 0 ? await success() : await error();
163
+ workers.exited(input.workerID);
164
+ });
165
+ }
166
+ catch (ex) {
167
+ await initError(ex);
168
+ workers.exited(input.workerID);
169
+ }
170
+ async function init() {
171
+ return await fetch({
172
+ path: `/runtime/invocation/next`,
173
+ method: "GET",
174
+ headers: {},
175
+ });
176
+ }
177
+ async function initError(ex) {
178
+ return await fetch({
179
+ path: `/runtime/init/error`,
180
+ method: "POST",
181
+ headers: {
182
+ "Content-Type": "application/json",
183
+ },
184
+ body: JSON.stringify({
185
+ errorType: "Error",
186
+ errorMessage: ex.message,
187
+ trace: ex.stack?.split("\n"),
188
+ }),
189
+ });
190
+ }
191
+ async function success() {
192
+ while (true) {
193
+ try {
194
+ await fetch({
195
+ path: `/runtime/invocation/${awsRequestId}/response`,
196
+ method: "POST",
197
+ headers: {
198
+ "Content-Type": "application/json",
199
+ },
200
+ body: JSON.stringify("Job completed successfully"),
201
+ });
202
+ break;
203
+ }
204
+ catch (ex) {
205
+ console.error(ex);
206
+ await new Promise((resolve) => setTimeout(resolve, 500));
207
+ }
208
+ }
209
+ }
210
+ async function error() {
211
+ return await fetch({
212
+ path: `/runtime/invocation/${awsRequestId}/error`,
213
+ method: "POST",
214
+ headers: {
215
+ "Content-Type": "application/json",
216
+ },
217
+ body: JSON.stringify({
218
+ errorType: "Error",
219
+ errorMessage: "Failed to run job",
220
+ trace: [],
221
+ }),
222
+ });
223
+ }
224
+ function fetch(req) {
225
+ return new Promise((resolve, reject) => {
226
+ const request = http.request(input.url + req.path, {
227
+ headers: req.headers,
228
+ method: req.method,
229
+ }, (res) => {
230
+ let body = "";
231
+ res.setEncoding("utf8");
232
+ res.on("data", (chunk) => {
233
+ body += chunk.toString();
234
+ });
235
+ res.on("end", () => {
236
+ resolve({
237
+ statusCode: res.statusCode,
238
+ headers: res.headers,
239
+ body,
240
+ });
241
+ });
242
+ });
243
+ request.on("error", reject);
244
+ if (req.body)
245
+ request.write(req.body);
246
+ request.end();
247
+ });
248
+ }
249
+ }
124
250
  });
@@ -19,7 +19,7 @@ interface BuildInput {
19
19
  out: string;
20
20
  props: FunctionProps;
21
21
  }
22
- interface StartWorkerInput {
22
+ export interface StartWorkerInput {
23
23
  url: string;
24
24
  workerID: string;
25
25
  functionID: string;
package/sst.mjs CHANGED
@@ -5718,16 +5718,18 @@ var container_exports = {};
5718
5718
  __export(container_exports, {
5719
5719
  useContainerHandler: () => useContainerHandler
5720
5720
  });
5721
+ import http from "http";
5721
5722
  import { spawn as spawn3 } from "child_process";
5723
+ import { useFunctions as useFunctions3 } from "../src/constructs/Function.js";
5722
5724
  var useContainerHandler;
5723
5725
  var init_container = __esm({
5724
5726
  "src/runtime/handlers/container.ts"() {
5725
5727
  "use strict";
5726
5728
  init_handlers2();
5727
5729
  init_workers();
5730
+ init_server();
5728
5731
  init_context();
5729
5732
  init_error();
5730
- init_server();
5731
5733
  init_fs();
5732
5734
  init_process();
5733
5735
  useContainerHandler = Context.memo(async () => {
@@ -5745,38 +5747,7 @@ var init_container = __esm({
5745
5747
  },
5746
5748
  canHandle: (input) => input.startsWith("container"),
5747
5749
  startWorker: async (input) => {
5748
- const name = `sst-workerID-${input.workerID}-${Date.now()}`;
5749
- const proc = spawn3(
5750
- "docker",
5751
- [
5752
- "run",
5753
- "--rm",
5754
- "--network=host",
5755
- `--name=${name}`,
5756
- ...Object.entries({
5757
- ...input.environment,
5758
- IS_LOCAL: "true",
5759
- AWS_LAMBDA_RUNTIME_API: `host.docker.internal:${server.port}/${input.workerID}`
5760
- }).map(([key, value]) => ["-e", `${key}=${value}`]).flat(),
5761
- `sst-dev:${input.functionID}`
5762
- ],
5763
- {
5764
- env: {
5765
- ...process.env
5766
- },
5767
- cwd: input.out
5768
- }
5769
- );
5770
- proc.on("exit", () => {
5771
- workers.exited(input.workerID);
5772
- });
5773
- proc.stdout.on("data", (data2) => {
5774
- workers.stdout(input.workerID, data2.toString());
5775
- });
5776
- proc.stderr.on("data", (data2) => {
5777
- workers.stdout(input.workerID, data2.toString());
5778
- });
5779
- containers.set(input.workerID, name);
5750
+ input.environment.SST_DEBUG_JOB ? startJobWorker(input) : startLambdaWorker(input);
5780
5751
  },
5781
5752
  stopWorker: async (workerID) => {
5782
5753
  const name = containers.get(workerID);
@@ -5845,6 +5816,161 @@ var init_container = __esm({
5845
5816
  };
5846
5817
  }
5847
5818
  });
5819
+ function dockerRun(input, opts, onExit) {
5820
+ const name = `sst-workerID-${input.workerID}-${Date.now()}`;
5821
+ const proc = spawn3(
5822
+ "docker",
5823
+ [
5824
+ "run",
5825
+ "--rm",
5826
+ "--network=host",
5827
+ `--name=${name}`,
5828
+ ...Object.entries({
5829
+ ...input.environment,
5830
+ ...opts.envs,
5831
+ IS_LOCAL: "true"
5832
+ }).map(([key, value]) => ["-e", `${key}=${value}`]).flat(),
5833
+ ...opts.entrypoint !== void 0 ? ["--entrypoint", opts.entrypoint] : [],
5834
+ `sst-dev:${input.functionID}`,
5835
+ ...opts.cmd ?? []
5836
+ ],
5837
+ {
5838
+ env: {
5839
+ ...process.env
5840
+ },
5841
+ cwd: input.out
5842
+ }
5843
+ );
5844
+ proc.on("exit", (code) => {
5845
+ onExit(code);
5846
+ });
5847
+ proc.stdout.on("data", (data2) => {
5848
+ workers.stdout(input.workerID, data2.toString());
5849
+ });
5850
+ proc.stderr.on("data", (data2) => {
5851
+ workers.stdout(input.workerID, data2.toString());
5852
+ });
5853
+ containers.set(input.workerID, name);
5854
+ }
5855
+ function startLambdaWorker(input) {
5856
+ dockerRun(
5857
+ input,
5858
+ {
5859
+ envs: {
5860
+ AWS_LAMBDA_RUNTIME_API: `host.docker.internal:${server.port}/${input.workerID}`
5861
+ }
5862
+ },
5863
+ () => {
5864
+ workers.exited(input.workerID);
5865
+ }
5866
+ );
5867
+ }
5868
+ async function startJobWorker(input) {
5869
+ const fn = useFunctions3().fromID(input.functionID);
5870
+ const result = await init();
5871
+ const awsRequestId = result.headers["lambda-runtime-aws-request-id"];
5872
+ try {
5873
+ dockerRun(
5874
+ input,
5875
+ {
5876
+ entrypoint: "",
5877
+ cmd: fn?.container?.docker.cmd,
5878
+ envs: {
5879
+ SST_PAYLOAD: result.body
5880
+ }
5881
+ },
5882
+ async (code) => {
5883
+ code === 0 ? await success() : await error3();
5884
+ workers.exited(input.workerID);
5885
+ }
5886
+ );
5887
+ } catch (ex) {
5888
+ await initError(ex);
5889
+ workers.exited(input.workerID);
5890
+ }
5891
+ async function init() {
5892
+ return await fetch({
5893
+ path: `/runtime/invocation/next`,
5894
+ method: "GET",
5895
+ headers: {}
5896
+ });
5897
+ }
5898
+ async function initError(ex) {
5899
+ return await fetch({
5900
+ path: `/runtime/init/error`,
5901
+ method: "POST",
5902
+ headers: {
5903
+ "Content-Type": "application/json"
5904
+ },
5905
+ body: JSON.stringify({
5906
+ errorType: "Error",
5907
+ errorMessage: ex.message,
5908
+ trace: ex.stack?.split("\n")
5909
+ })
5910
+ });
5911
+ }
5912
+ async function success() {
5913
+ while (true) {
5914
+ try {
5915
+ await fetch({
5916
+ path: `/runtime/invocation/${awsRequestId}/response`,
5917
+ method: "POST",
5918
+ headers: {
5919
+ "Content-Type": "application/json"
5920
+ },
5921
+ body: JSON.stringify("Job completed successfully")
5922
+ });
5923
+ break;
5924
+ } catch (ex) {
5925
+ console.error(ex);
5926
+ await new Promise((resolve2) => setTimeout(resolve2, 500));
5927
+ }
5928
+ }
5929
+ }
5930
+ async function error3() {
5931
+ return await fetch({
5932
+ path: `/runtime/invocation/${awsRequestId}/error`,
5933
+ method: "POST",
5934
+ headers: {
5935
+ "Content-Type": "application/json"
5936
+ },
5937
+ body: JSON.stringify({
5938
+ errorType: "Error",
5939
+ errorMessage: "Failed to run job",
5940
+ trace: []
5941
+ })
5942
+ });
5943
+ }
5944
+ function fetch(req) {
5945
+ return new Promise((resolve2, reject) => {
5946
+ const request = http.request(
5947
+ input.url + req.path,
5948
+ {
5949
+ headers: req.headers,
5950
+ method: req.method
5951
+ },
5952
+ (res) => {
5953
+ let body = "";
5954
+ res.setEncoding("utf8");
5955
+ res.on("data", (chunk) => {
5956
+ body += chunk.toString();
5957
+ });
5958
+ res.on("end", () => {
5959
+ resolve2({
5960
+ statusCode: res.statusCode,
5961
+ headers: res.headers,
5962
+ body
5963
+ });
5964
+ });
5965
+ }
5966
+ );
5967
+ request.on("error", reject);
5968
+ if (req.body)
5969
+ request.write(req.body);
5970
+ request.end();
5971
+ });
5972
+ }
5973
+ }
5848
5974
  });
5849
5975
  }
5850
5976
  });
@@ -6855,7 +6981,7 @@ import express2 from "express";
6855
6981
  import fs14 from "fs/promises";
6856
6982
  import { WebSocketServer } from "ws";
6857
6983
  import https3 from "https";
6858
- import http from "http";
6984
+ import http2 from "http";
6859
6985
  import { applyWSSHandler } from "@trpc/server/adapters/ws/dist/trpc-server-adapters-ws.cjs.js";
6860
6986
  import { optimise } from "dendriform-immer-patch-optimiser";
6861
6987
  import { sync } from "cross-spawn";
@@ -6951,7 +7077,7 @@ async function useLocalServer(opts) {
6951
7077
  rest
6952
7078
  );
6953
7079
  }
6954
- return http.createServer({}, rest);
7080
+ return http2.createServer({}, rest);
6955
7081
  })();
6956
7082
  const wss = new WebSocketServer({ server });
6957
7083
  wss.on("connection", (socket, req) => {
@@ -8210,7 +8336,7 @@ var dev = (program2) => program2.command(
8210
8336
  const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
8211
8337
  const fs19 = await import("fs/promises");
8212
8338
  const crypto2 = await import("crypto");
8213
- const { useFunctions: useFunctions3 } = await import("../src/constructs/Function.js");
8339
+ const { useFunctions: useFunctions4 } = await import("../src/constructs/Function.js");
8214
8340
  const { useSites } = await import("../src/constructs/SsrSite.js");
8215
8341
  const { usePothosBuilder: usePothosBuilder2 } = await Promise.resolve().then(() => (init_pothos2(), pothos_exports2));
8216
8342
  const { useKyselyTypeGenerator: useKyselyTypeGenerator2 } = await Promise.resolve().then(() => (init_kysely(), kysely_exports));
@@ -8255,12 +8381,12 @@ var dev = (program2) => program2.command(
8255
8381
  prefix(evt.properties.requestID),
8256
8382
  Colors2.dim.bold("Invoked"),
8257
8383
  Colors2.dim(
8258
- useFunctions3().fromID(evt.properties.functionID)?.handler
8384
+ useFunctions4().fromID(evt.properties.functionID)?.handler
8259
8385
  )
8260
8386
  );
8261
8387
  });
8262
8388
  bus.subscribe("worker.stdout", async (evt) => {
8263
- const info = useFunctions3().fromID(evt.properties.functionID);
8389
+ const info = useFunctions4().fromID(evt.properties.functionID);
8264
8390
  prefix(evt.properties.requestID);
8265
8391
  const { started } = pending.get(evt.properties.requestID);
8266
8392
  for (let line of evt.properties.message.split("\n")) {
@@ -8278,7 +8404,7 @@ var dev = (program2) => program2.command(
8278
8404
  }
8279
8405
  });
8280
8406
  bus.subscribe("function.build.started", async (evt) => {
8281
- const info = useFunctions3().fromID(evt.properties.functionID);
8407
+ const info = useFunctions4().fromID(evt.properties.functionID);
8282
8408
  if (!info)
8283
8409
  return;
8284
8410
  if (info.enableLiveDev === false)
@@ -8290,7 +8416,7 @@ var dev = (program2) => program2.command(
8290
8416
  );
8291
8417
  });
8292
8418
  bus.subscribe("function.build.success", async (evt) => {
8293
- const info = useFunctions3().fromID(evt.properties.functionID);
8419
+ const info = useFunctions4().fromID(evt.properties.functionID);
8294
8420
  if (!info)
8295
8421
  return;
8296
8422
  if (info.enableLiveDev === false)
@@ -8300,7 +8426,7 @@ var dev = (program2) => program2.command(
8300
8426
  );
8301
8427
  });
8302
8428
  bus.subscribe("function.build.failed", async (evt) => {
8303
- const info = useFunctions3().fromID(evt.properties.functionID);
8429
+ const info = useFunctions4().fromID(evt.properties.functionID);
8304
8430
  if (!info)
8305
8431
  return;
8306
8432
  if (info.enableLiveDev === false)