@capsulos/provider-lambda 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type LambdaMicrovmsClientConfig } from '@aws-sdk/client-lambda-microvms';
2
- import { type CapsuleHandle, type CapsuleInfo, type CapsuleSpec, type Connection, type Provider } from '@capsulos/sdk';
2
+ import { type CapsuleHandle, type CapsuleInfo, type CapsuleSpec, type Connection, type CreateOptions, type HeadersOptions, type Provider } from '@capsulos/sdk';
3
3
  export interface LambdaProviderOptions {
4
4
  region: string;
5
5
  /** AWS account id, used to build image ARNs from template names. */
@@ -26,14 +26,25 @@ export declare class LambdaProvider implements Provider {
26
26
  constructor(opts: LambdaProviderOptions);
27
27
  /** Templates are MicrovmImages; the API wants the full ARN (a plain name fails). */
28
28
  imageArn(template: string): string;
29
- create(spec: CapsuleSpec): Promise<CapsuleHandle>;
29
+ create(spec: CapsuleSpec, opts?: CreateOptions): Promise<CapsuleHandle>;
30
30
  get(id: string): Promise<CapsuleInfo | null>;
31
31
  /** All microVMs of one template (the API lists per image). */
32
32
  list(template?: string): Promise<CapsuleInfo[]>;
33
33
  terminate(id: string): Promise<void>;
34
34
  connect(id: string): Promise<Connection>;
35
+ /** A Connection from an endpoint already in hand (get() returns it): no extra GetMicrovm. */
36
+ connectionFor(id: string, endpoint: string): Connection;
35
37
  /** Headers to reach another port of the capsule through the same endpoint. */
36
- portHeaders(id: string, port: number): Promise<Record<string, string>>;
38
+ portHeaders(id: string, port: number, opts?: HeadersOptions): Promise<Record<string, string>>;
39
+ /** Forget the cached endpoint token: the next request mints a new one. */
40
+ invalidateToken(id: string): void;
41
+ private infoOf;
37
42
  private token;
43
+ /**
44
+ * Poll until the VM runs. A SUSPENDED VM (a clientToken that recovered an
45
+ * idle one) counts as alive: the first request auto-resumes it. Timeout and
46
+ * abort throw a CapsuleError that names the VM (capsuleId) for the caller
47
+ * to clean up; create() does that itself.
48
+ */
38
49
  private waitForRunning;
39
50
  }
package/dist/index.js CHANGED
@@ -8,7 +8,8 @@
8
8
  // - endpoint tokens expire after at most 60 min: cached in memory, re-minted
9
9
  // - other ports are addressed with the X-aws-proxy-port header
10
10
  // - the idle policy suspends and the first request auto-resumes (~0.8 s)
11
- // - clientToken is both idempotency and recovery (same token → same VM)
11
+ // - clientToken is both idempotency and recovery (same token → same VM);
12
+ // a recovered VM may be SUSPENDED, which create() accepts as alive
12
13
  import { LambdaMicrovmsClient, RunMicrovmCommand, GetMicrovmCommand, ListMicrovmsCommand, TerminateMicrovmCommand, CreateMicrovmAuthTokenCommand, } from '@aws-sdk/client-lambda-microvms';
13
14
  import { CapsuleError, } from '@capsulos/sdk';
14
15
  const CAPSULOD_PORT = 8080;
@@ -46,7 +47,7 @@ export class LambdaProvider {
46
47
  return template;
47
48
  return `arn:aws:lambda:${this.opts.region}:${this.opts.accountId}:microvm-image:${template}`;
48
49
  }
49
- async create(spec) {
50
+ async create(spec, opts = {}) {
50
51
  const ingress = this.opts.ingressConnectorArn ??
51
52
  `arn:aws:lambda:${this.opts.region}:aws:network-connector:aws-network-connector:ALL_INGRESS`;
52
53
  const res = await this.client.send(new RunMicrovmCommand({
@@ -70,21 +71,28 @@ export class LambdaProvider {
70
71
  }));
71
72
  if (!res.microvmId)
72
73
  throw new CapsuleError('RunMicrovm returned no microvmId');
73
- const info = await this.waitForRunning(res.microvmId);
74
- return { ...info, connection: await this.connect(res.microvmId) };
74
+ const id = res.microvmId;
75
+ let info;
76
+ try {
77
+ info = await this.waitForRunning(id, opts);
78
+ }
79
+ catch (err) {
80
+ // Never leave a VM running without an owner: the caller gets an error,
81
+ // not a capsule, so the VM goes too (the error still names it).
82
+ if (err instanceof CapsuleError && err.capsuleId === id) {
83
+ await this.terminate(id).catch(() => undefined);
84
+ throw new CapsuleError(`${err.message}; terminated it`, err.status, { capsuleId: id });
85
+ }
86
+ throw err;
87
+ }
88
+ if (!info.endpoint)
89
+ throw new CapsuleError(`microVM ${id} is ${info.state} but has no endpoint`, undefined, { capsuleId: id });
90
+ return { ...info, connection: this.connectionFor(id, info.endpoint) };
75
91
  }
76
92
  async get(id) {
77
93
  try {
78
94
  const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
79
- return {
80
- id,
81
- provider: this.name,
82
- state: toState(vm.state),
83
- template: vm.imageArn ?? null,
84
- createdAt: vm.startedAt ?? null,
85
- terminatedAt: vm.terminatedAt ?? null,
86
- stateReason: vm.stateReason ?? null,
87
- };
95
+ return this.infoOf(id, vm);
88
96
  }
89
97
  catch (err) {
90
98
  if (err instanceof Error && err.name === 'ResourceNotFoundException')
@@ -103,11 +111,13 @@ export class LambdaProvider {
103
111
  for (const item of page.items ?? []) {
104
112
  if (!item.microvmId)
105
113
  continue;
114
+ // The list item carries no endpoint, terminatedAt or stateReason: get() does.
106
115
  out.push({
107
116
  id: item.microvmId,
108
117
  provider: this.name,
109
118
  state: toState(item.state),
110
119
  template: item.imageArn ?? null,
120
+ templateVersion: item.imageVersion ?? null,
111
121
  createdAt: item.startedAt ?? null,
112
122
  });
113
123
  }
@@ -131,19 +141,41 @@ export class LambdaProvider {
131
141
  async connect(id) {
132
142
  const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
133
143
  if (!vm.endpoint)
134
- throw new CapsuleError(`microVM ${id} has no endpoint yet (state ${vm.state})`);
144
+ throw new CapsuleError(`microVM ${id} has no endpoint yet (state ${vm.state})`, undefined, { capsuleId: id });
145
+ return this.connectionFor(id, vm.endpoint);
146
+ }
147
+ /** A Connection from an endpoint already in hand (get() returns it): no extra GetMicrovm. */
148
+ connectionFor(id, endpoint) {
135
149
  return {
136
- baseUrl: `https://${vm.endpoint}`,
137
- headers: async () => ({ 'X-aws-proxy-auth': await this.token(id) }),
150
+ baseUrl: endpoint.startsWith('https://') ? endpoint : `https://${endpoint}`,
151
+ headers: async (opts) => ({ 'X-aws-proxy-auth': await this.token(id, opts?.fresh) }),
138
152
  };
139
153
  }
140
154
  /** Headers to reach another port of the capsule through the same endpoint. */
141
- async portHeaders(id, port) {
142
- return { 'X-aws-proxy-auth': await this.token(id), 'X-aws-proxy-port': String(port) };
155
+ async portHeaders(id, port, opts) {
156
+ return { 'X-aws-proxy-auth': await this.token(id, opts?.fresh), 'X-aws-proxy-port': String(port) };
143
157
  }
144
- async token(id) {
158
+ /** Forget the cached endpoint token: the next request mints a new one. */
159
+ invalidateToken(id) {
160
+ this.tokens.delete(id);
161
+ }
162
+ infoOf(id, vm) {
163
+ return {
164
+ id,
165
+ provider: this.name,
166
+ state: toState(vm.state),
167
+ template: vm.imageArn ?? null,
168
+ templateVersion: vm.imageVersion ?? null,
169
+ createdAt: vm.startedAt ?? null,
170
+ terminatedAt: vm.terminatedAt ?? null,
171
+ stateReason: vm.stateReason ?? null,
172
+ endpoint: vm.endpoint ? `https://${vm.endpoint}` : null,
173
+ maxDurationSeconds: vm.maximumDurationInSeconds ?? null,
174
+ };
175
+ }
176
+ async token(id, fresh = false) {
145
177
  const cached = this.tokens.get(id);
146
- if (cached && cached.expiresAt > Date.now())
178
+ if (cached && cached.expiresAt > Date.now() && !fresh)
147
179
  return cached.value;
148
180
  const ttl = Math.min(this.opts.tokenTtlMinutes ?? 60, 60);
149
181
  const ports = new Set([CAPSULOD_PORT, ...(this.opts.allowedPorts ?? [])]);
@@ -159,18 +191,27 @@ export class LambdaProvider {
159
191
  this.tokens.set(id, { value, expiresAt: Date.now() + (ttl - 5) * 60_000 });
160
192
  return value;
161
193
  }
162
- async waitForRunning(id, timeoutMs = 120_000) {
194
+ /**
195
+ * Poll until the VM runs. A SUSPENDED VM (a clientToken that recovered an
196
+ * idle one) counts as alive: the first request auto-resumes it. Timeout and
197
+ * abort throw a CapsuleError that names the VM (capsuleId) for the caller
198
+ * to clean up; create() does that itself.
199
+ */
200
+ async waitForRunning(id, opts = {}) {
201
+ const timeoutMs = opts.timeoutMs ?? 120_000;
163
202
  const t0 = Date.now();
164
203
  for (;;) {
165
- const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
166
- if (vm.state === 'RUNNING') {
167
- return { id, provider: this.name, state: 'running', template: vm.imageArn ?? null, createdAt: vm.startedAt ?? null };
168
- }
204
+ if (opts.signal?.aborted)
205
+ throw new CapsuleError(`creation of microVM ${id} aborted`, undefined, { capsuleId: id });
206
+ const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }), { abortSignal: opts.signal });
207
+ if (vm.state === 'RUNNING' || vm.state === 'SUSPENDED')
208
+ return this.infoOf(id, vm);
169
209
  if (vm.state === 'TERMINATED' || vm.state === 'TERMINATING') {
170
- throw new CapsuleError(`microVM ${id} died while starting: ${vm.stateReason ?? vm.state}`);
210
+ throw new CapsuleError(`microVM ${id} died while starting: ${vm.stateReason ?? vm.state}`, undefined, { capsuleId: id });
211
+ }
212
+ if (Date.now() - t0 > timeoutMs) {
213
+ throw new CapsuleError(`microVM ${id} did not run within ${timeoutMs}ms (state ${vm.state})`, undefined, { capsuleId: id });
171
214
  }
172
- if (Date.now() - t0 > timeoutMs)
173
- throw new CapsuleError(`timeout waiting for microVM ${id} to run`);
174
215
  await new Promise((r) => setTimeout(r, 400));
175
216
  }
176
217
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capsulos/provider-lambda",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "capsulos provider for AWS Lambda MicroVMs: capsules on your own AWS account.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@aws-sdk/client-lambda-microvms": "^3.1158.0",
47
- "@capsulos/sdk": "0.1.0"
47
+ "@capsulos/sdk": "0.1.1"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^22.20.1",
package/src/index.ts CHANGED
@@ -8,7 +8,8 @@
8
8
  // - endpoint tokens expire after at most 60 min: cached in memory, re-minted
9
9
  // - other ports are addressed with the X-aws-proxy-port header
10
10
  // - the idle policy suspends and the first request auto-resumes (~0.8 s)
11
- // - clientToken is both idempotency and recovery (same token → same VM)
11
+ // - clientToken is both idempotency and recovery (same token → same VM);
12
+ // a recovered VM may be SUSPENDED, which create() accepts as alive
12
13
  import {
13
14
  LambdaMicrovmsClient,
14
15
  RunMicrovmCommand,
@@ -25,6 +26,8 @@ import {
25
26
  type CapsuleSpec,
26
27
  type CapsuleState,
27
28
  type Connection,
29
+ type CreateOptions,
30
+ type HeadersOptions,
28
31
  type Provider,
29
32
  } from '@capsulos/sdk';
30
33
 
@@ -84,7 +87,7 @@ export class LambdaProvider implements Provider {
84
87
  return `arn:aws:lambda:${this.opts.region}:${this.opts.accountId}:microvm-image:${template}`;
85
88
  }
86
89
 
87
- async create(spec: CapsuleSpec): Promise<CapsuleHandle> {
90
+ async create(spec: CapsuleSpec, opts: CreateOptions = {}): Promise<CapsuleHandle> {
88
91
  const ingress =
89
92
  this.opts.ingressConnectorArn ??
90
93
  `arn:aws:lambda:${this.opts.region}:aws:network-connector:aws-network-connector:ALL_INGRESS`;
@@ -110,22 +113,27 @@ export class LambdaProvider implements Provider {
110
113
  }),
111
114
  );
112
115
  if (!res.microvmId) throw new CapsuleError('RunMicrovm returned no microvmId');
113
- const info = await this.waitForRunning(res.microvmId);
114
- return { ...info, connection: await this.connect(res.microvmId) };
116
+ const id = res.microvmId;
117
+ let info: CapsuleInfo;
118
+ try {
119
+ info = await this.waitForRunning(id, opts);
120
+ } catch (err) {
121
+ // Never leave a VM running without an owner: the caller gets an error,
122
+ // not a capsule, so the VM goes too (the error still names it).
123
+ if (err instanceof CapsuleError && err.capsuleId === id) {
124
+ await this.terminate(id).catch(() => undefined);
125
+ throw new CapsuleError(`${err.message}; terminated it`, err.status, { capsuleId: id });
126
+ }
127
+ throw err;
128
+ }
129
+ if (!info.endpoint) throw new CapsuleError(`microVM ${id} is ${info.state} but has no endpoint`, undefined, { capsuleId: id });
130
+ return { ...info, connection: this.connectionFor(id, info.endpoint) };
115
131
  }
116
132
 
117
133
  async get(id: string): Promise<CapsuleInfo | null> {
118
134
  try {
119
135
  const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
120
- return {
121
- id,
122
- provider: this.name,
123
- state: toState(vm.state),
124
- template: vm.imageArn ?? null,
125
- createdAt: vm.startedAt ?? null,
126
- terminatedAt: vm.terminatedAt ?? null,
127
- stateReason: vm.stateReason ?? null,
128
- };
136
+ return this.infoOf(id, vm);
129
137
  } catch (err) {
130
138
  if (err instanceof Error && err.name === 'ResourceNotFoundException') return null;
131
139
  throw err;
@@ -143,11 +151,13 @@ export class LambdaProvider implements Provider {
143
151
  );
144
152
  for (const item of page.items ?? []) {
145
153
  if (!item.microvmId) continue;
154
+ // The list item carries no endpoint, terminatedAt or stateReason: get() does.
146
155
  out.push({
147
156
  id: item.microvmId,
148
157
  provider: this.name,
149
158
  state: toState(item.state),
150
159
  template: item.imageArn ?? null,
160
+ templateVersion: item.imageVersion ?? null,
151
161
  createdAt: item.startedAt ?? null,
152
162
  });
153
163
  }
@@ -169,21 +179,46 @@ export class LambdaProvider implements Provider {
169
179
 
170
180
  async connect(id: string): Promise<Connection> {
171
181
  const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
172
- if (!vm.endpoint) throw new CapsuleError(`microVM ${id} has no endpoint yet (state ${vm.state})`);
182
+ if (!vm.endpoint) throw new CapsuleError(`microVM ${id} has no endpoint yet (state ${vm.state})`, undefined, { capsuleId: id });
183
+ return this.connectionFor(id, vm.endpoint);
184
+ }
185
+
186
+ /** A Connection from an endpoint already in hand (get() returns it): no extra GetMicrovm. */
187
+ connectionFor(id: string, endpoint: string): Connection {
173
188
  return {
174
- baseUrl: `https://${vm.endpoint}`,
175
- headers: async () => ({ 'X-aws-proxy-auth': await this.token(id) }),
189
+ baseUrl: endpoint.startsWith('https://') ? endpoint : `https://${endpoint}`,
190
+ headers: async (opts?: HeadersOptions) => ({ 'X-aws-proxy-auth': await this.token(id, opts?.fresh) }),
176
191
  };
177
192
  }
178
193
 
179
194
  /** Headers to reach another port of the capsule through the same endpoint. */
180
- async portHeaders(id: string, port: number): Promise<Record<string, string>> {
181
- return { 'X-aws-proxy-auth': await this.token(id), 'X-aws-proxy-port': String(port) };
195
+ async portHeaders(id: string, port: number, opts?: HeadersOptions): Promise<Record<string, string>> {
196
+ return { 'X-aws-proxy-auth': await this.token(id, opts?.fresh), 'X-aws-proxy-port': String(port) };
197
+ }
198
+
199
+ /** Forget the cached endpoint token: the next request mints a new one. */
200
+ invalidateToken(id: string): void {
201
+ this.tokens.delete(id);
202
+ }
203
+
204
+ private infoOf(id: string, vm: { state?: string; imageArn?: string; imageVersion?: string; startedAt?: Date; terminatedAt?: Date; stateReason?: string; endpoint?: string; maximumDurationInSeconds?: number }): CapsuleInfo {
205
+ return {
206
+ id,
207
+ provider: this.name,
208
+ state: toState(vm.state),
209
+ template: vm.imageArn ?? null,
210
+ templateVersion: vm.imageVersion ?? null,
211
+ createdAt: vm.startedAt ?? null,
212
+ terminatedAt: vm.terminatedAt ?? null,
213
+ stateReason: vm.stateReason ?? null,
214
+ endpoint: vm.endpoint ? `https://${vm.endpoint}` : null,
215
+ maxDurationSeconds: vm.maximumDurationInSeconds ?? null,
216
+ };
182
217
  }
183
218
 
184
- private async token(id: string): Promise<string> {
219
+ private async token(id: string, fresh = false): Promise<string> {
185
220
  const cached = this.tokens.get(id);
186
- if (cached && cached.expiresAt > Date.now()) return cached.value;
221
+ if (cached && cached.expiresAt > Date.now() && !fresh) return cached.value;
187
222
  const ttl = Math.min(this.opts.tokenTtlMinutes ?? 60, 60);
188
223
  const ports = new Set([CAPSULOD_PORT, ...(this.opts.allowedPorts ?? [])]);
189
224
  const res = await this.client.send(
@@ -200,17 +235,25 @@ export class LambdaProvider implements Provider {
200
235
  return value;
201
236
  }
202
237
 
203
- private async waitForRunning(id: string, timeoutMs = 120_000): Promise<CapsuleInfo> {
238
+ /**
239
+ * Poll until the VM runs. A SUSPENDED VM (a clientToken that recovered an
240
+ * idle one) counts as alive: the first request auto-resumes it. Timeout and
241
+ * abort throw a CapsuleError that names the VM (capsuleId) for the caller
242
+ * to clean up; create() does that itself.
243
+ */
244
+ private async waitForRunning(id: string, opts: CreateOptions = {}): Promise<CapsuleInfo> {
245
+ const timeoutMs = opts.timeoutMs ?? 120_000;
204
246
  const t0 = Date.now();
205
247
  for (;;) {
206
- const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }));
207
- if (vm.state === 'RUNNING') {
208
- return { id, provider: this.name, state: 'running', template: vm.imageArn ?? null, createdAt: vm.startedAt ?? null };
209
- }
248
+ if (opts.signal?.aborted) throw new CapsuleError(`creation of microVM ${id} aborted`, undefined, { capsuleId: id });
249
+ const vm = await this.client.send(new GetMicrovmCommand({ microvmIdentifier: id }), { abortSignal: opts.signal });
250
+ if (vm.state === 'RUNNING' || vm.state === 'SUSPENDED') return this.infoOf(id, vm);
210
251
  if (vm.state === 'TERMINATED' || vm.state === 'TERMINATING') {
211
- throw new CapsuleError(`microVM ${id} died while starting: ${vm.stateReason ?? vm.state}`);
252
+ throw new CapsuleError(`microVM ${id} died while starting: ${vm.stateReason ?? vm.state}`, undefined, { capsuleId: id });
253
+ }
254
+ if (Date.now() - t0 > timeoutMs) {
255
+ throw new CapsuleError(`microVM ${id} did not run within ${timeoutMs}ms (state ${vm.state})`, undefined, { capsuleId: id });
212
256
  }
213
- if (Date.now() - t0 > timeoutMs) throw new CapsuleError(`timeout waiting for microVM ${id} to run`);
214
257
  await new Promise((r) => setTimeout(r, 400));
215
258
  }
216
259
  }