@sst-community/sst 4.18.1 → 4.19.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.
@@ -0,0 +1,231 @@
1
+ import { type AwsOptions } from "./client.js";
2
+ /**
3
+ * The `microvm` client SDK is available through the following.
4
+ *
5
+ * @example
6
+ * ```js title="src/app.ts"
7
+ * import { microvm } from "sst/aws/microvm";
8
+ * ```
9
+ *
10
+ * If you are not using Node.js, you can use the AWS SDK instead, with the link data in
11
+ * `Resource`. For example, call
12
+ * [`RunMicrovm`](https://docs.aws.amazon.com/lambda/latest/microvm-api/API_RunMicrovm.html)
13
+ * with its `imageArn`, `imageVersion` and `executionRoleArn`.
14
+ */
15
+ export declare namespace microvm {
16
+ /**
17
+ * The link data for the MicroVM image.
18
+ *
19
+ * @example
20
+ * For example, let's say you have a MicroVM image.
21
+ *
22
+ * ```js title="sst.config.ts"
23
+ * new sst.aws.MicroVm("Sandbox", { image: { context: "./sandbox" } });
24
+ * ```
25
+ *
26
+ * `Resource.Sandbox` will have all the link data.
27
+ *
28
+ * ```js title="src/app.ts"
29
+ * import { Resource } from "sst";
30
+ *
31
+ * console.log(Resource.Sandbox);
32
+ * ```
33
+ */
34
+ export interface Resource {
35
+ /**
36
+ * The ARN of the MicroVM image.
37
+ */
38
+ imageArn?: string;
39
+ /**
40
+ * The version of the image that was deployed.
41
+ */
42
+ imageVersion?: string;
43
+ /**
44
+ * The ARN of the role MicroVMs run with.
45
+ */
46
+ executionRoleArn?: string;
47
+ /**
48
+ * The log group the MicroVMs' logs go to.
49
+ */
50
+ logGroup?: string;
51
+ /**
52
+ * The network connectors that let requests reach a MicroVM.
53
+ */
54
+ ingressNetworkConnectors?: string[];
55
+ /**
56
+ * The network connectors a MicroVM reaches the internet through.
57
+ */
58
+ egressNetworkConnectors?: string[];
59
+ /**
60
+ * The port the app in a MicroVM listens on.
61
+ */
62
+ port: number;
63
+ /**
64
+ * The longest a MicroVM can exist, in seconds.
65
+ */
66
+ duration?: number;
67
+ /**
68
+ * When an idle MicroVM is suspended, and then terminated.
69
+ */
70
+ idle?: IdlePolicy;
71
+ /**
72
+ * Set in `sst dev`, where the app runs on your machine.
73
+ */
74
+ dev?: {
75
+ url: string;
76
+ };
77
+ }
78
+ interface IdlePolicy {
79
+ autoResumeEnabled: boolean;
80
+ maxIdleDurationSeconds: number;
81
+ suspendedDurationSeconds: number;
82
+ }
83
+ type Duration = `${number} ${"second" | "seconds" | "minute" | "minutes" | "hour" | "hours"}`;
84
+ export interface Options {
85
+ /**
86
+ * Configure the options for the [aws4fetch](https://github.com/mhart/aws4fetch)
87
+ * [`AWSClient`](https://github.com/mhart/aws4fetch?tab=readme-ov-file#new-awsclientoptions) used internally by the SDK.
88
+ */
89
+ aws?: AwsOptions;
90
+ }
91
+ export interface RunOptions extends Options {
92
+ /**
93
+ * Overrides the component's `duration`: the longest this MicroVM can exist, running
94
+ * and suspended. Up to 8 hours.
95
+ */
96
+ duration?: Duration;
97
+ /**
98
+ * Overrides the component's `idle`. Pass `false` to keep this MicroVM running until
99
+ * its `duration` is up.
100
+ */
101
+ idle?: false | {
102
+ suspendAfter?: Duration;
103
+ terminateAfter?: Duration;
104
+ autoResume?: boolean;
105
+ };
106
+ /**
107
+ * How long `run` waits for the MicroVM to be running.
108
+ * @default `"1 minute"`
109
+ */
110
+ timeout?: Duration;
111
+ }
112
+ export interface FetchInit extends RequestInit {
113
+ /**
114
+ * The port to send the request to, if not the component's `port`.
115
+ */
116
+ port?: number;
117
+ }
118
+ export type State = "PENDING" | "RUNNING" | "SUSPENDING" | "SUSPENDED" | "TERMINATING" | "TERMINATED";
119
+ export interface DescribeResponse {
120
+ /**
121
+ * The ID of the MicroVM.
122
+ */
123
+ id: string;
124
+ /**
125
+ * The state of the MicroVM. AWS updates it eventually, so it can lag behind.
126
+ */
127
+ state: State;
128
+ /**
129
+ * Why the MicroVM is in this state.
130
+ */
131
+ stateReason?: string;
132
+ /**
133
+ * The URL of the MicroVM.
134
+ */
135
+ url: string;
136
+ /**
137
+ * The raw response from the AWS API.
138
+ */
139
+ response: any;
140
+ }
141
+ /**
142
+ * A running MicroVM, returned by `run` and `get`.
143
+ */
144
+ export interface MicroVm {
145
+ /**
146
+ * The ID of the MicroVM. Keep it to reach the same MicroVM later, with `get`.
147
+ */
148
+ id: string;
149
+ /**
150
+ * The URL of the MicroVM. A request to it needs a token from `token`, in the
151
+ * `X-aws-proxy-auth` header. `fetch` adds it for you.
152
+ */
153
+ url: string;
154
+ /**
155
+ * Sends a request to the app in the MicroVM. It works like `fetch`, with a path
156
+ * instead of a URL, and adds the token.
157
+ *
158
+ * ```js
159
+ * const res = await vm.fetch("/exec", {
160
+ * method: "POST",
161
+ * body: JSON.stringify({ code })
162
+ * });
163
+ * ```
164
+ */
165
+ fetch(path: string, init?: FetchInit): Promise<Response>;
166
+ /**
167
+ * A token for requests to a port of the MicroVM, valid for up to an hour. `fetch`
168
+ * refreshes it before it expires. Use this to let something else, like a browser,
169
+ * reach the MicroVM.
170
+ */
171
+ token(port?: number): Promise<string>;
172
+ /**
173
+ * Gets the MicroVM's state.
174
+ */
175
+ describe(): Promise<DescribeResponse>;
176
+ /**
177
+ * Suspends the MicroVM. Its memory and disk are kept, and you stop paying for compute.
178
+ */
179
+ suspend(): Promise<void>;
180
+ /**
181
+ * Resumes a suspended MicroVM.
182
+ */
183
+ resume(): Promise<void>;
184
+ /**
185
+ * Terminates the MicroVM.
186
+ */
187
+ terminate(): Promise<void>;
188
+ }
189
+ /**
190
+ * Runs a new MicroVM from the image, and waits until it's running.
191
+ *
192
+ * @example
193
+ *
194
+ * For example, let's say you have a MicroVM image.
195
+ *
196
+ * ```js title="sst.config.ts"
197
+ * new sst.aws.MicroVm("Sandbox", { image: { context: "./sandbox" } });
198
+ * ```
199
+ *
200
+ * Run a MicroVM from it, send it requests, and terminate it.
201
+ *
202
+ * ```js title="src/app.ts"
203
+ * import { Resource } from "sst";
204
+ * import { microvm } from "sst/aws/microvm";
205
+ *
206
+ * const vm = await microvm.run(Resource.Sandbox);
207
+ * const res = await vm.fetch("/hello");
208
+ * await vm.terminate();
209
+ * ```
210
+ *
211
+ * In `sst dev`, this doesn't start a MicroVM. The requests go to your app running on
212
+ * your machine, and `terminate` does nothing.
213
+ */
214
+ export function run(resource: Resource, options?: RunOptions): Promise<MicroVm>;
215
+ /**
216
+ * Gets a MicroVM that's already running, by its ID. Use this to reach the same MicroVM
217
+ * from a later request.
218
+ *
219
+ * ```js title="src/app.ts"
220
+ * const vm = await microvm.get(Resource.Sandbox, id);
221
+ * const res = await vm.fetch("/status");
222
+ * ```
223
+ */
224
+ export function get(resource: Resource, id: string, options?: Options): Promise<MicroVm>;
225
+ export class MicroVmError extends Error {
226
+ readonly response: Response;
227
+ readonly body: string;
228
+ constructor(response: Response, body: string);
229
+ }
230
+ export {};
231
+ }
@@ -0,0 +1,236 @@
1
+ import { awsFetch } from "./client.js";
2
+ /**
3
+ * The `microvm` client SDK is available through the following.
4
+ *
5
+ * @example
6
+ * ```js title="src/app.ts"
7
+ * import { microvm } from "sst/aws/microvm";
8
+ * ```
9
+ *
10
+ * If you are not using Node.js, you can use the AWS SDK instead, with the link data in
11
+ * `Resource`. For example, call
12
+ * [`RunMicrovm`](https://docs.aws.amazon.com/lambda/latest/microvm-api/API_RunMicrovm.html)
13
+ * with its `imageArn`, `imageVersion` and `executionRoleArn`.
14
+ */
15
+ export var microvm;
16
+ (function (microvm) {
17
+ const API = "/2025-09-09/microvms";
18
+ /**
19
+ * Runs a new MicroVM from the image, and waits until it's running.
20
+ *
21
+ * @example
22
+ *
23
+ * For example, let's say you have a MicroVM image.
24
+ *
25
+ * ```js title="sst.config.ts"
26
+ * new sst.aws.MicroVm("Sandbox", { image: { context: "./sandbox" } });
27
+ * ```
28
+ *
29
+ * Run a MicroVM from it, send it requests, and terminate it.
30
+ *
31
+ * ```js title="src/app.ts"
32
+ * import { Resource } from "sst";
33
+ * import { microvm } from "sst/aws/microvm";
34
+ *
35
+ * const vm = await microvm.run(Resource.Sandbox);
36
+ * const res = await vm.fetch("/hello");
37
+ * await vm.terminate();
38
+ * ```
39
+ *
40
+ * In `sst dev`, this doesn't start a MicroVM. The requests go to your app running on
41
+ * your machine, and `terminate` does nothing.
42
+ */
43
+ async function run(resource, options) {
44
+ if (resource.dev)
45
+ return local(resource);
46
+ const idle = options?.idle === false
47
+ ? undefined
48
+ : options?.idle
49
+ ? {
50
+ autoResumeEnabled: options.idle.autoResume ?? true,
51
+ maxIdleDurationSeconds: toSeconds(options.idle.suspendAfter ?? "15 minutes"),
52
+ suspendedDurationSeconds: toSeconds(options.idle.terminateAfter ?? "15 minutes"),
53
+ }
54
+ : resource.idle;
55
+ const res = await call(API, {
56
+ method: "POST",
57
+ headers: { "Content-Type": "application/json" },
58
+ body: JSON.stringify({
59
+ // Retries of this request start one MicroVM, not one each.
60
+ clientToken: crypto.randomUUID(),
61
+ imageIdentifier: resource.imageArn,
62
+ imageVersion: resource.imageVersion,
63
+ executionRoleArn: resource.executionRoleArn,
64
+ ingressNetworkConnectors: resource.ingressNetworkConnectors,
65
+ egressNetworkConnectors: resource.egressNetworkConnectors,
66
+ maximumDurationInSeconds: options?.duration
67
+ ? toSeconds(options.duration)
68
+ : resource.duration,
69
+ idlePolicy: idle,
70
+ logging: resource.logGroup
71
+ ? { cloudWatch: { logGroup: resource.logGroup } }
72
+ : undefined,
73
+ }),
74
+ }, options);
75
+ const data = (await res.json());
76
+ const vm = remote(resource, data.microvmId, data.endpoint, options);
77
+ const deadline = Date.now() + toSeconds(options?.timeout ?? "1 minute") * 1000;
78
+ try {
79
+ while (true) {
80
+ const { state, stateReason } = await vm.describe();
81
+ if (state === "RUNNING")
82
+ return vm;
83
+ if (state !== "PENDING")
84
+ throw new Error(`MicroVM ${vm.id} is ${state}${stateReason ? `: ${stateReason}` : ""}`);
85
+ if (Date.now() > deadline)
86
+ throw new Error(`MicroVM ${vm.id} didn't start in time`);
87
+ await new Promise((resolve) => setTimeout(resolve, 500));
88
+ }
89
+ }
90
+ catch (e) {
91
+ // Don't leave behind a MicroVM the caller never got.
92
+ await vm.terminate().catch(() => { });
93
+ throw e;
94
+ }
95
+ }
96
+ microvm.run = run;
97
+ /**
98
+ * Gets a MicroVM that's already running, by its ID. Use this to reach the same MicroVM
99
+ * from a later request.
100
+ *
101
+ * ```js title="src/app.ts"
102
+ * const vm = await microvm.get(Resource.Sandbox, id);
103
+ * const res = await vm.fetch("/status");
104
+ * ```
105
+ */
106
+ async function get(resource, id, options) {
107
+ if (resource.dev)
108
+ return local(resource, id);
109
+ const vm = remote(resource, id, undefined, options);
110
+ await vm.describe();
111
+ return vm;
112
+ }
113
+ microvm.get = get;
114
+ function remote(resource, id, endpoint, options) {
115
+ const tokens = new Map();
116
+ const refreshing = new Map();
117
+ async function token(port = resource.port) {
118
+ const cached = tokens.get(port);
119
+ // Refresh with 5 minutes to spare.
120
+ if (cached && cached.expires - Date.now() > 5 * 60 * 1000)
121
+ return cached.value;
122
+ // Requests made while a token is being created wait for it, instead of each
123
+ // creating one.
124
+ let pending = refreshing.get(port);
125
+ if (!pending) {
126
+ pending = createToken(port).finally(() => refreshing.delete(port));
127
+ refreshing.set(port, pending);
128
+ }
129
+ return pending;
130
+ }
131
+ async function createToken(port) {
132
+ const res = await call(`${API}/${id}/auth-token`, {
133
+ method: "POST",
134
+ headers: { "Content-Type": "application/json" },
135
+ body: JSON.stringify({
136
+ expirationInMinutes: 60,
137
+ allowedPorts: [{ port }],
138
+ }),
139
+ }, options);
140
+ const data = (await res.json());
141
+ const value = data.authToken["X-aws-proxy-auth"];
142
+ tokens.set(port, { value, expires: Date.now() + 60 * 60 * 1000 });
143
+ return value;
144
+ }
145
+ async function describe() {
146
+ const res = await call(`${API}/${id}`, { method: "GET" }, options);
147
+ const data = (await res.json());
148
+ endpoint = data.endpoint;
149
+ return {
150
+ id: data.microvmId,
151
+ state: data.state,
152
+ stateReason: data.stateReason,
153
+ url: `https://${data.endpoint}`,
154
+ response: data,
155
+ };
156
+ }
157
+ const vm = {
158
+ id,
159
+ get url() {
160
+ return `https://${endpoint}`;
161
+ },
162
+ async fetch(path, init) {
163
+ const { port, ...rest } = init ?? {};
164
+ const headers = new Headers(rest.headers);
165
+ headers.set("X-aws-proxy-auth", await token(port));
166
+ headers.set("X-aws-proxy-port", String(port ?? resource.port));
167
+ return fetch(`https://${endpoint}${path}`, { ...rest, headers });
168
+ },
169
+ token,
170
+ describe,
171
+ async suspend() {
172
+ await call(`${API}/${id}/suspend`, { method: "POST" }, options);
173
+ },
174
+ async resume() {
175
+ await call(`${API}/${id}/resume`, { method: "POST" }, options);
176
+ },
177
+ async terminate() {
178
+ await call(`${API}/${id}`, { method: "DELETE" }, options);
179
+ },
180
+ };
181
+ return vm;
182
+ }
183
+ // In `sst dev`, every MicroVM is the app running on your machine.
184
+ function local(resource, id) {
185
+ const url = resource.dev.url.replace(/\/$/, "");
186
+ const microvmId = id ?? `dev-${crypto.randomUUID()}`;
187
+ return {
188
+ id: microvmId,
189
+ url,
190
+ async fetch(path, init) {
191
+ const { port, ...rest } = init ?? {};
192
+ const target = port ? url.replace(/:\d+$/, `:${port}`) : url;
193
+ return fetch(`${target}${path}`, rest);
194
+ },
195
+ async token() {
196
+ return "";
197
+ },
198
+ async describe() {
199
+ return {
200
+ id: microvmId,
201
+ state: "RUNNING",
202
+ url,
203
+ response: {},
204
+ };
205
+ },
206
+ async suspend() { },
207
+ async resume() { },
208
+ async terminate() { },
209
+ };
210
+ }
211
+ async function call(path, init, options) {
212
+ const res = await awsFetch("lambda", path, init, options);
213
+ if (!res.ok)
214
+ throw new MicroVmError(res, await res.text());
215
+ return res;
216
+ }
217
+ function toSeconds(duration) {
218
+ const [count, unit] = duration.split(" ");
219
+ const value = parseFloat(count);
220
+ if (unit.startsWith("hour"))
221
+ return value * 3600;
222
+ if (unit.startsWith("minute"))
223
+ return value * 60;
224
+ return value;
225
+ }
226
+ class MicroVmError extends Error {
227
+ response;
228
+ body;
229
+ constructor(response, body) {
230
+ super(`MicroVM request failed with ${response.status}: ${body}`);
231
+ this.response = response;
232
+ this.body = body;
233
+ }
234
+ }
235
+ microvm.MicroVmError = MicroVmError;
236
+ })(microvm || (microvm = {}));
@@ -3,7 +3,10 @@ import { type AwsOptions } from "./client.js";
3
3
  /**
4
4
  * The `workflow` SDK is a thin wrapper around the
5
5
  * [`@aws/durable-execution-sdk-js`](https://www.npmjs.com/package/@aws/durable-execution-sdk-js)
6
- * package and the AWS Lambda durable execution APIs.
6
+ * package and the AWS Lambda durable execution APIs. `sst` depends on one
7
+ * version of that package, and the errors your workflow code catches, such as
8
+ * `StepError` or `CallbackError`, come from it, not from SST. When you update
9
+ * `sst`, check that package's release notes for changes to them.
7
10
  *
8
11
  * SST also adds a few helpers on top, including `ctx.stepWithRollback()`,
9
12
  * `ctx.rollbackAll()`, and `ctx.waitUntil()`.
@@ -3,7 +3,10 @@ import { awsFetch } from "./client.js";
3
3
  /**
4
4
  * The `workflow` SDK is a thin wrapper around the
5
5
  * [`@aws/durable-execution-sdk-js`](https://www.npmjs.com/package/@aws/durable-execution-sdk-js)
6
- * package and the AWS Lambda durable execution APIs.
6
+ * package and the AWS Lambda durable execution APIs. `sst` depends on one
7
+ * version of that package, and the errors your workflow code catches, such as
8
+ * `StepError` or `CallbackError`, come from it, not from SST. When you update
9
+ * `sst`, check that package's release notes for changes to them.
7
10
  *
8
11
  * SST also adds a few helpers on top, including `ctx.stepWithRollback()`,
9
12
  * `ctx.rollbackAll()`, and `ctx.waitUntil()`.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "@sst-community/sst",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
- "version": "4.18.1",
6
+ "version": "4.19.0",
7
7
  "main": "./dist/index.js",
8
8
  "repository": {
9
9
  "type": "git",
@@ -37,7 +37,7 @@
37
37
  "release": "./scripts/release.ts"
38
38
  },
39
39
  "devDependencies": {
40
- "@aws/durable-execution-sdk-js-testing": "^1.1.1",
40
+ "@aws/durable-execution-sdk-js-testing": "^1.3.0",
41
41
  "@tsconfig/node20": "20.1.4",
42
42
  "@types/aws-lambda": "^8.10.155",
43
43
  "@types/node": "22.10.0",
@@ -55,17 +55,17 @@
55
55
  "sst": "./bin/sst.mjs"
56
56
  },
57
57
  "optionalDependencies": {
58
- "@sst-community/sst-linux-x64": "4.18.1",
59
- "@sst-community/sst-linux-x86": "4.18.1",
60
- "@sst-community/sst-darwin-x64": "4.18.1",
61
- "@sst-community/sst-linux-arm64": "4.18.1",
62
- "@sst-community/sst-darwin-arm64": "4.18.1",
63
- "@sst-community/sst-win32-x86": "4.18.1",
64
- "@sst-community/sst-win32-x64": "4.18.1",
65
- "@sst-community/sst-win32-arm64": "4.18.1"
58
+ "@sst-community/sst-linux-x64": "4.19.0",
59
+ "@sst-community/sst-linux-x86": "4.19.0",
60
+ "@sst-community/sst-darwin-x64": "4.19.0",
61
+ "@sst-community/sst-linux-arm64": "4.19.0",
62
+ "@sst-community/sst-darwin-arm64": "4.19.0",
63
+ "@sst-community/sst-win32-x64": "4.19.0",
64
+ "@sst-community/sst-win32-arm64": "4.19.0",
65
+ "@sst-community/sst-win32-x86": "4.19.0"
66
66
  },
67
67
  "dependencies": {
68
- "@aws/durable-execution-sdk-js": "1.0.2",
68
+ "@aws/durable-execution-sdk-js": "2.6.0",
69
69
  "aws4fetch": "1.0.18",
70
70
  "jose": "5.2.3",
71
71
  "openid-client": "5.6.4"