@lunora/container 1.0.0-alpha.2 → 1.0.0-alpha.21
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/LICENSE.md +26 -0
- package/README.md +99 -1
- package/dist/bridge.d.mts +51 -35
- package/dist/bridge.d.ts +51 -35
- package/dist/bridge.mjs +1 -76
- package/dist/do/index.d.mts +580 -45
- package/dist/do/index.d.ts +580 -45
- package/dist/do/index.mjs +1 -138
- package/dist/index.d.mts +235 -114
- package/dist/index.d.ts +235 -114
- package/dist/index.mjs +1 -2
- package/dist/otel.d.mts +161 -0
- package/dist/otel.d.ts +161 -0
- package/dist/otel.mjs +1 -0
- package/dist/packem_shared/ContainerProxy-BsQAwSNX.mjs +27 -0
- package/dist/packem_shared/containerBindingName-DP2NqQV-.mjs +1 -0
- package/dist/packem_shared/createContainerContext-Df9Ev-Fp.mjs +1 -0
- package/dist/packem_shared/jurisdiction-BKRNOTip.mjs +1 -0
- package/dist/packem_shared/jurisdiction.d-8oUUvrew.d.mts +281 -0
- package/dist/packem_shared/jurisdiction.d-8oUUvrew.d.ts +281 -0
- package/package.json +7 -3
- package/dist/packem_shared/containerBindingName-BGdSdFNA.mjs +0 -116
- package/dist/packem_shared/createContainerContext-CTpyUQ4J.mjs +0 -133
- package/dist/packem_shared/types.d-D2l2SYol.d.mts +0 -140
- package/dist/packem_shared/types.d-D2l2SYol.d.ts +0 -140
package/dist/do/index.d.ts
CHANGED
|
@@ -1,63 +1,598 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
2
|
+
import { a as ContainerDefinition, D as DurableObjectJurisdiction } from "../packem_shared/jurisdiction.d-8oUUvrew.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
type DurableObjectJurisdiction = "eu" | "fedramp" | "us";
|
|
4
|
+
* ContainerStartOptions as they come from worker types
|
|
5
|
+
*/
|
|
6
|
+
type ContainerStartOptions = NonNullable<Parameters<NonNullable<DurableObject['ctx']['container']>['start']>[0]>;
|
|
9
7
|
/**
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
* Options for container configuration
|
|
9
|
+
*/
|
|
10
|
+
interface ContainerOptions {
|
|
11
|
+
/** Optional ID for the container */
|
|
12
|
+
id?: string;
|
|
13
|
+
/** Default port number to connect to (defaults to container.defaultPort) */
|
|
14
|
+
defaultPort?: number;
|
|
15
|
+
/** How long to keep the container alive without activity */
|
|
16
|
+
sleepAfter?: string | number;
|
|
17
|
+
/** Environment variables to pass to the container */
|
|
18
|
+
envVars?: Record<string, string>;
|
|
19
|
+
/** Custom entrypoint to override container default */
|
|
20
|
+
entrypoint?: string[];
|
|
21
|
+
/** Whether to enable internet access for the container */
|
|
22
|
+
enableInternet?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Options for starting a container with specific configuration
|
|
26
|
+
*/
|
|
27
|
+
interface ContainerStartConfigOptions {
|
|
28
|
+
/** Environment variables to pass to the container */
|
|
29
|
+
envVars?: Record<string, string>;
|
|
30
|
+
/** Custom entrypoint to override container default */
|
|
31
|
+
entrypoint?: string[];
|
|
32
|
+
/** Whether to enable internet access for the container */
|
|
33
|
+
enableInternet?: boolean;
|
|
34
|
+
/** Key-value metadata labels attached to the container for metrics/observability */
|
|
35
|
+
labels?: Record<string, string>;
|
|
36
|
+
}
|
|
37
|
+
interface StartAndWaitForPortsOptions {
|
|
38
|
+
startOptions?: ContainerStartConfigOptions;
|
|
39
|
+
ports?: number | number[];
|
|
40
|
+
cancellationOptions?: CancellationOptions;
|
|
41
|
+
}
|
|
42
|
+
/** cancellationOptions for startAndWaitForPorts() */
|
|
43
|
+
interface CancellationOptions {
|
|
44
|
+
/** abort signal, use to abort startAndWaitForPorts manually. */
|
|
45
|
+
abort?: AbortSignal;
|
|
46
|
+
/** max time to get container instance and start it (application inside may not be ready), in milliseconds */
|
|
47
|
+
instanceGetTimeoutMS?: number;
|
|
48
|
+
/** max time to wait for application to be listening at all specified ports, in milliseconds. */
|
|
49
|
+
portReadyTimeoutMS?: number;
|
|
50
|
+
/** time to wait between polling, in milliseconds */
|
|
51
|
+
waitInterval?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Options for waitForPort()
|
|
55
|
+
*/
|
|
56
|
+
interface WaitOptions {
|
|
57
|
+
/** The port number to check for readiness */
|
|
58
|
+
portToCheck: number;
|
|
59
|
+
/** Optional AbortSignal, use this to abort waiting for ports */
|
|
60
|
+
signal?: AbortSignal;
|
|
61
|
+
/** Number of attempts to wait for port to be ready */
|
|
62
|
+
retries?: number;
|
|
63
|
+
/** Time to wait in between polling port for readiness, in milliseconds */
|
|
64
|
+
waitInterval?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Represents a scheduled task within a Container
|
|
68
|
+
* @template T Type of the payload data
|
|
69
|
+
*/
|
|
70
|
+
type Schedule<T = string> = {
|
|
71
|
+
/** Unique identifier for the schedule */
|
|
72
|
+
taskId: string;
|
|
73
|
+
/** Name of the method to be called */
|
|
74
|
+
callback: string;
|
|
75
|
+
/** Data to be passed to the callback */
|
|
76
|
+
payload: T;
|
|
77
|
+
} & ({
|
|
78
|
+
/** Type of schedule for one-time execution at a specific time */
|
|
79
|
+
type: 'scheduled';
|
|
80
|
+
/** Timestamp when the task should execute */
|
|
81
|
+
time: number;
|
|
82
|
+
} | {
|
|
83
|
+
/** Type of schedule for delayed execution */
|
|
84
|
+
type: 'delayed';
|
|
85
|
+
/** Timestamp when the task should execute */
|
|
86
|
+
time: number;
|
|
87
|
+
/** Number of seconds to delay execution */
|
|
88
|
+
delayInSeconds: number;
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Params sent to `onStop` method when the container stops
|
|
92
|
+
*/
|
|
93
|
+
type StopParams = {
|
|
94
|
+
exitCode: number;
|
|
95
|
+
reason: 'exit' | 'runtime_signal';
|
|
96
|
+
};
|
|
97
|
+
type State = {
|
|
98
|
+
lastChange: number;
|
|
99
|
+
} & ({
|
|
100
|
+
status: 'running' | 'stopping' | 'stopped' | 'healthy';
|
|
101
|
+
} | {
|
|
102
|
+
status: 'stopped_with_code';
|
|
103
|
+
exitCode?: number;
|
|
104
|
+
});
|
|
105
|
+
type OutboundHandlerContext<Params = unknown> = {
|
|
106
|
+
containerId: string;
|
|
107
|
+
className: string;
|
|
108
|
+
} & ([Params] extends [undefined] ? {
|
|
109
|
+
params?: undefined;
|
|
110
|
+
} : undefined extends Params ? {
|
|
111
|
+
params?: Params;
|
|
112
|
+
} : {
|
|
113
|
+
params: Params;
|
|
114
|
+
});
|
|
115
|
+
type OutboundParamsArg<Params> = [Params] extends [undefined] ? [] : undefined extends Params ? [params?: Params] : [params: Params];
|
|
116
|
+
type OutboundHandler<E = Cloudflare.Env, P = unknown> = {
|
|
117
|
+
bivarianceHack(req: Request, env: E, ctx: OutboundHandlerContext<P>): Promise<Response> | Response;
|
|
118
|
+
}['bivarianceHack'];
|
|
119
|
+
type OutboundHandlerParams = Record<string, unknown>;
|
|
120
|
+
type OutboundHandlerParamsOf<THandler> = THandler extends ((req: Request, env: unknown, ctx: OutboundHandlerContext<infer Params>) => Promise<Response> | Response) ? Params : never;
|
|
121
|
+
declare function outboundParams<THandler extends OutboundHandler<unknown, unknown>>(_handler: THandler, params: OutboundHandlerParamsOf<THandler>): OutboundHandlerParamsOf<THandler>;
|
|
122
|
+
type OutboundHandlers<ParamsByMethod extends OutboundHandlerParams, E = Cloudflare.Env> = { [Method in keyof ParamsByMethod]?: OutboundHandler<E, ParamsByMethod[Method]>; };
|
|
123
|
+
type OutboundHandlerOverride<Params = unknown> = {
|
|
124
|
+
method: string;
|
|
125
|
+
} & ([Params] extends [undefined] ? {
|
|
126
|
+
params?: undefined;
|
|
127
|
+
} : undefined extends Params ? {
|
|
128
|
+
params?: Params;
|
|
129
|
+
} : {
|
|
130
|
+
params: Params;
|
|
131
|
+
});
|
|
132
|
+
type OutboundByHostOverrides = Record<string, OutboundHandlerOverride>;
|
|
133
|
+
type OutboundByHostOverrideInput<Params = unknown> = Record<string, string | OutboundHandlerOverride<Params>>;
|
|
134
|
+
type Signal = 'SIGKILL' | 'SIGINT' | 'SIGTERM';
|
|
135
|
+
type SignalInteger = number;
|
|
136
|
+
type ContainerProxyOptions = {
|
|
137
|
+
enableInternet?: boolean;
|
|
138
|
+
containerId: string;
|
|
139
|
+
className: string;
|
|
140
|
+
outboundByHostOverrides?: OutboundByHostOverrides;
|
|
141
|
+
outboundHandlerOverride?: OutboundHandlerOverride;
|
|
142
|
+
allowedHosts?: string[];
|
|
143
|
+
deniedHosts?: string[];
|
|
144
|
+
interceptAll?: boolean;
|
|
145
|
+
};
|
|
146
|
+
declare class ContainerProxy extends WorkerEntrypoint<Cloudflare.Env, ContainerProxyOptions> {
|
|
147
|
+
fetch(request: Request): Promise<Response>;
|
|
148
|
+
}
|
|
149
|
+
declare class Container<Env = Cloudflare.Env> extends DurableObject<Env> {
|
|
150
|
+
static get outboundByHost(): Record<string, OutboundHandler> | undefined;
|
|
151
|
+
static set outboundByHost(handlers: Record<string, OutboundHandler>);
|
|
152
|
+
static get outboundHandlers(): Record<string, OutboundHandler> | undefined;
|
|
153
|
+
static set outboundHandlers(handlers: Record<string, OutboundHandler>);
|
|
154
|
+
static get outbound(): OutboundHandler | undefined;
|
|
155
|
+
static set outbound(handler: OutboundHandler);
|
|
156
|
+
static get outboundProxies(): Record<string, OutboundHandler> | undefined;
|
|
157
|
+
static set outboundProxies(handlers: Record<string, OutboundHandler>);
|
|
158
|
+
static get outboundProxy(): OutboundHandler | undefined;
|
|
159
|
+
static set outboundProxy(handler: OutboundHandler);
|
|
160
|
+
defaultPort?: number;
|
|
161
|
+
requiredPorts?: number[];
|
|
162
|
+
sleepAfter: string | number;
|
|
163
|
+
envVars: ContainerStartOptions['env'];
|
|
164
|
+
entrypoint: ContainerStartOptions['entrypoint'];
|
|
165
|
+
enableInternet: ContainerStartOptions['enableInternet'];
|
|
166
|
+
labels: ContainerStartOptions['labels'];
|
|
167
|
+
interceptHttps: boolean;
|
|
168
|
+
allowedHosts?: string[];
|
|
169
|
+
deniedHosts?: string[];
|
|
170
|
+
pingEndpoint: string;
|
|
171
|
+
applyOutboundInterceptionPromise: Promise<void>;
|
|
172
|
+
usingInterception: boolean;
|
|
173
|
+
constructor(ctx: DurableObject['ctx'], env: Env, options?: ContainerOptions);
|
|
174
|
+
/**
|
|
175
|
+
* Gets the current state of the container
|
|
176
|
+
* @returns Promise<State>
|
|
177
|
+
*/
|
|
178
|
+
getState(): Promise<State>;
|
|
179
|
+
/**
|
|
180
|
+
* Set the catch-all outbound handler to a named method from `outboundHandlers`.
|
|
181
|
+
* Overrides the default `outbound` at runtime via ContainerProxy props.
|
|
182
|
+
*
|
|
183
|
+
* @param methodName - Name of a method defined in `static outboundHandlers`
|
|
184
|
+
* @param params - Optional params passed to the handler as `ctx.params`
|
|
185
|
+
* @throws Error if the method name is not found in `outboundHandlers`
|
|
186
|
+
*/
|
|
187
|
+
setOutboundHandler<Params = unknown>(methodName: string, ...paramsArg: OutboundParamsArg<Params>): Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* Add or override a hostname-specific outbound handler at runtime,
|
|
190
|
+
* referencing a named method from `outboundHandlers`.
|
|
191
|
+
* Overrides any matching entry in `static outboundByHost` for this hostname.
|
|
192
|
+
*
|
|
193
|
+
* @param hostname - The hostname or ip:port to intercept (e.g. `'google.com'`)
|
|
194
|
+
* @param methodName - Name of a method defined in `static outboundHandlers`
|
|
195
|
+
* @param params - Optional params passed to the handler as `ctx.params`
|
|
196
|
+
* @throws Error if the method name is not found in `outboundHandlers`
|
|
197
|
+
*/
|
|
198
|
+
setOutboundByHost<Params = unknown>(hostname: string, methodName: string, ...paramsArg: OutboundParamsArg<Params>): Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* Remove a runtime hostname override added via `setOutboundByHost`.
|
|
201
|
+
* The default handler from `static outboundByHost` (if any) will be used again.
|
|
202
|
+
*
|
|
203
|
+
* @param hostname - The hostname or ip:port to stop overriding
|
|
204
|
+
*/
|
|
205
|
+
removeOutboundByHost(hostname: string): Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* Replace all runtime hostname overrides at once.
|
|
208
|
+
* Each value may be either a method name or an object with `method` and `params`.
|
|
209
|
+
*
|
|
210
|
+
* @param handlers - Record mapping hostnames to handler configs in `outboundHandlers`
|
|
211
|
+
* @throws Error if any method name is not found in `outboundHandlers`
|
|
212
|
+
*/
|
|
213
|
+
setOutboundByHosts<Params = unknown>(handlers: OutboundByHostOverrideInput<Params>): Promise<void>;
|
|
214
|
+
/**
|
|
215
|
+
* Replace all allowed hosts at runtime.
|
|
216
|
+
* Allowed hosts get internet access even when `enableInternet` is false.
|
|
217
|
+
*
|
|
218
|
+
* @param hosts - Array of hostnames to allow (e.g. `['api.stripe.com', 'example.com']`)
|
|
219
|
+
*/
|
|
220
|
+
setAllowedHosts(hosts: string[]): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Replace all denied hosts at runtime.
|
|
223
|
+
* Denied hosts are blocked unconditionally, even when `enableInternet` is true
|
|
224
|
+
* or a catch-all outbound handler is set.
|
|
225
|
+
*
|
|
226
|
+
* @param hosts - Array of hostnames to deny (e.g. `['evil.com', 'blocked.org']`)
|
|
227
|
+
*/
|
|
228
|
+
setDeniedHosts(hosts: string[]): Promise<void>;
|
|
229
|
+
/**
|
|
230
|
+
* Add a single hostname to the allowed hosts list at runtime.
|
|
231
|
+
*
|
|
232
|
+
* @param hostname - The hostname to allow (e.g. `'api.stripe.com'`)
|
|
233
|
+
*/
|
|
234
|
+
allowHost(hostname: string): Promise<void>;
|
|
235
|
+
/**
|
|
236
|
+
* Add a single hostname to the denied hosts list at runtime.
|
|
237
|
+
*
|
|
238
|
+
* @param hostname - The hostname to deny (e.g. `'evil.com'`)
|
|
239
|
+
*/
|
|
240
|
+
denyHost(hostname: string): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Remove a hostname from the allowed hosts list.
|
|
243
|
+
*
|
|
244
|
+
* @param hostname - The hostname to remove from the allow list
|
|
245
|
+
*/
|
|
246
|
+
removeAllowedHost(hostname: string): Promise<void>;
|
|
247
|
+
/**
|
|
248
|
+
* Remove a hostname from the denied hosts list.
|
|
249
|
+
*
|
|
250
|
+
* @param hostname - The hostname to remove from the deny list
|
|
251
|
+
*/
|
|
252
|
+
removeDeniedHost(hostname: string): Promise<void>;
|
|
253
|
+
/**
|
|
254
|
+
* Start the container if it's not running and set up monitoring and lifecycle hooks,
|
|
255
|
+
* without waiting for ports to be ready.
|
|
256
|
+
*
|
|
257
|
+
* It will automatically retry if the container fails to start, using the specified waitOptions
|
|
258
|
+
*
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* await this.start({
|
|
262
|
+
* envVars: { DEBUG: 'true', NODE_ENV: 'development' },
|
|
263
|
+
* entrypoint: ['npm', 'run', 'dev'],
|
|
264
|
+
* enableInternet: false,
|
|
265
|
+
* labels: { tenant: 'acme', env: 'prod' },
|
|
266
|
+
* });
|
|
267
|
+
*
|
|
268
|
+
* @param startOptions - Override `envVars`, `entrypoint`, `enableInternet` and `labels` on a per-instance basis
|
|
269
|
+
* @param waitOptions - Optional wait configuration with abort signal for cancellation. Default ~8s timeout.
|
|
270
|
+
* @returns A promise that resolves when the container start command has been issued
|
|
271
|
+
* @throws Error if no container context is available or if all start attempts fail
|
|
272
|
+
*/
|
|
273
|
+
start(startOptions?: ContainerStartConfigOptions, waitOptions?: WaitOptions): Promise<void>;
|
|
274
|
+
/**
|
|
275
|
+
* Start the container and wait for ports to be available.
|
|
276
|
+
*
|
|
277
|
+
* For each specified port, it polls until the port is available or `cancellationOptions.portReadyTimeoutMS` is reached.
|
|
278
|
+
*
|
|
279
|
+
* @param ports - The ports to wait for (if undefined, uses requiredPorts or defaultPort)
|
|
280
|
+
* @param cancellationOptions - Options to configure timeouts, polling intereva, and abort signal
|
|
281
|
+
* @param startOptions Override configuration on a per-instance basis for env vars, entrypoint command, internet access, and labels
|
|
282
|
+
* @returns A promise that resolves when the container has been started and the ports are listening
|
|
283
|
+
* @throws Error if port checks fail after the specified timeout or if the container fails to start.
|
|
284
|
+
*/
|
|
285
|
+
startAndWaitForPorts(args: StartAndWaitForPortsOptions): Promise<void>;
|
|
286
|
+
startAndWaitForPorts(ports?: number | number[], cancellationOptions?: CancellationOptions, startOptions?: ContainerStartConfigOptions): Promise<void>;
|
|
287
|
+
startAndWaitForPorts(portsOrArgs?: number | number[] | StartAndWaitForPortsOptions, cancellationOptions?: CancellationOptions, startOptions?: ContainerStartConfigOptions): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
*
|
|
290
|
+
* Waits for a specified port to be ready
|
|
291
|
+
*
|
|
292
|
+
* Returns the number of tries used to get the port, or throws if it couldn't get the port within the specified retry limits.
|
|
293
|
+
*
|
|
294
|
+
* @param waitOptions -
|
|
295
|
+
* - `portToCheck`: The port number to check
|
|
296
|
+
* - `abort`: Optional AbortSignal to cancel waiting
|
|
297
|
+
* - `retries`: Number of retries before giving up (default: TRIES_TO_GET_PORTS)
|
|
298
|
+
* - `waitInterval`: Interval between retries in milliseconds (default: INSTANCE_POLL_INTERVAL_MS)
|
|
299
|
+
*/
|
|
300
|
+
waitForPort(waitOptions: WaitOptions): Promise<number>;
|
|
301
|
+
/**
|
|
302
|
+
* Send a signal to the container.
|
|
303
|
+
* @param signal - The signal to send to the container (default: 15 for SIGTERM)
|
|
304
|
+
*/
|
|
305
|
+
stop(signal?: Signal | SignalInteger): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* Destroys the container with a SIGKILL. Triggers onStop.
|
|
308
|
+
*/
|
|
309
|
+
destroy(): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Lifecycle method called when container starts successfully
|
|
312
|
+
* Override this method in subclasses to handle container start events
|
|
313
|
+
*/
|
|
314
|
+
onStart(): void | Promise<void>;
|
|
315
|
+
/**
|
|
316
|
+
* Lifecycle method called when container shuts down
|
|
317
|
+
* Override this method in subclasses to handle Container stopped events
|
|
318
|
+
* @param params - Object containing exitCode and reason for the stop
|
|
319
|
+
*/
|
|
320
|
+
onStop(params: StopParams): void | Promise<void>;
|
|
321
|
+
/**
|
|
322
|
+
* Lifecycle method called when the container is running, and the activity timeout
|
|
323
|
+
* expiration (set by `sleepAfter`) has been reached.
|
|
324
|
+
*
|
|
325
|
+
* If you want to shutdown the container, you should call this.stop() here
|
|
326
|
+
*
|
|
327
|
+
* By default, this method calls `this.stop()`
|
|
328
|
+
*/
|
|
329
|
+
onActivityExpired(): Promise<void>;
|
|
330
|
+
/**
|
|
331
|
+
* Error handler for container errors
|
|
332
|
+
* Override this method in subclasses to handle container errors
|
|
333
|
+
* @param error - The error that occurred
|
|
334
|
+
* @returns Can return any value or throw the error
|
|
335
|
+
*/
|
|
336
|
+
onError(error: unknown): unknown;
|
|
337
|
+
/**
|
|
338
|
+
* Renew the container's activity timeout
|
|
339
|
+
*
|
|
340
|
+
* Call this method whenever there is activity on the container
|
|
341
|
+
*/
|
|
342
|
+
renewActivityTimeout(): void;
|
|
343
|
+
/**
|
|
344
|
+
* Decrement the inflight request counter.
|
|
345
|
+
* When the counter transitions to 0, renew the activity timeout so the
|
|
346
|
+
* inactivity window starts fresh from the moment the last request completes.
|
|
347
|
+
*/
|
|
348
|
+
private decrementInflight;
|
|
349
|
+
/**
|
|
350
|
+
* Schedule a task to be executed in the future.
|
|
351
|
+
*
|
|
352
|
+
* We strongly recommend using this instead of the `alarm` handler.
|
|
353
|
+
*
|
|
354
|
+
* @template T Type of the payload data
|
|
355
|
+
* @param when When to execute the task (Date object or number of seconds delay)
|
|
356
|
+
* @param callback Name of the method to call
|
|
357
|
+
* @param payload Data to pass to the callback
|
|
358
|
+
* @returns Schedule object representing the scheduled task
|
|
359
|
+
*/
|
|
360
|
+
schedule<T = string>(when: Date | number, callback: string, payload?: T): Promise<Schedule<T>>;
|
|
361
|
+
/**
|
|
362
|
+
* Send a request to the container (HTTP or WebSocket) using standard fetch API signature
|
|
363
|
+
*
|
|
364
|
+
* This method handles HTTP requests to the container.
|
|
365
|
+
*
|
|
366
|
+
* WebSocket requests done outside the DO won't work until https://github.com/cloudflare/workerd/issues/2319 is addressed.
|
|
367
|
+
* Until then, please use `switchPort` + `fetch()`.
|
|
368
|
+
*
|
|
369
|
+
* Method supports multiple signatures to match standard fetch API:
|
|
370
|
+
* - containerFetch(request: Request, port?: number)
|
|
371
|
+
* - containerFetch(url: string | URL, init?: RequestInit, port?: number)
|
|
372
|
+
*
|
|
373
|
+
* Starts the container if not already running, and waits for the target port to be ready.
|
|
374
|
+
*
|
|
375
|
+
* @returns A Response from the container
|
|
376
|
+
*/
|
|
377
|
+
containerFetch(requestOrUrl: Request | string | URL, portOrInit?: number | RequestInit, portParam?: number): Promise<Response>;
|
|
378
|
+
/**
|
|
379
|
+
*
|
|
380
|
+
* Fetch handler on the Container class.
|
|
381
|
+
* By default this forwards all requests to the container by calling `containerFetch`.
|
|
382
|
+
* Use `switchPort` to specify which port on the container to target, or this will use `defaultPort`.
|
|
383
|
+
* @param request The request to handle
|
|
384
|
+
*/
|
|
385
|
+
fetch(request: Request): Promise<Response>;
|
|
386
|
+
private container;
|
|
387
|
+
private onStopCalled;
|
|
388
|
+
private state;
|
|
389
|
+
private monitor;
|
|
390
|
+
private startInFlight;
|
|
391
|
+
private monitoredPromise;
|
|
392
|
+
private sleepAfterMs;
|
|
393
|
+
private inflightRequests;
|
|
394
|
+
private outboundByHostOverrides;
|
|
395
|
+
private outboundHandlerOverride?;
|
|
396
|
+
private allowedHostsOverride?;
|
|
397
|
+
private deniedHostsOverride?;
|
|
398
|
+
private hasInterceptAllRegistration;
|
|
399
|
+
/**
|
|
400
|
+
* Validates that a method name exists in the outboundHandlers registry for this class.
|
|
401
|
+
* @throws Error if the method name is not found
|
|
402
|
+
*/
|
|
403
|
+
private validateOutboundHandlerMethodName;
|
|
404
|
+
private get effectiveAllowedHosts();
|
|
405
|
+
private get effectiveDeniedHosts();
|
|
406
|
+
private getOutboundConfiguration;
|
|
407
|
+
private persistOutboundConfiguration;
|
|
408
|
+
private restoreOutboundConfiguration;
|
|
409
|
+
/**
|
|
410
|
+
* Returns true if a catch-all outbound HTTP interception is needed.
|
|
411
|
+
* This is the case when a static `outbound` handler or a runtime
|
|
412
|
+
* `outboundHandlerOverride` (catch-all) is configured.
|
|
413
|
+
* When false, we only intercept specific hosts to avoid overhead.
|
|
414
|
+
*/
|
|
415
|
+
private needsCatchAllInterception;
|
|
416
|
+
private hasMutableOutboundConfiguration;
|
|
417
|
+
private shouldInterceptAllOutbound;
|
|
418
|
+
private getStaticOutboundByHostKeys;
|
|
419
|
+
/**
|
|
420
|
+
* Collects all hostnames that need per-host outbound interception.
|
|
421
|
+
* This path is only used for the narrow optimized case where outbound
|
|
422
|
+
* handling is static and host-specific.
|
|
423
|
+
*/
|
|
424
|
+
private getHostsToIntercept;
|
|
425
|
+
private refreshOutboundInterception;
|
|
426
|
+
/**
|
|
427
|
+
* Applies (or re-applies) outbound HTTP interception with the current
|
|
428
|
+
* default registries + runtime overrides passed through ContainerProxy props.
|
|
429
|
+
*
|
|
430
|
+
* Uses per-host interception only for static host-specific outbound handlers.
|
|
431
|
+
* As soon as the config needs to evaluate all hosts (catch-all outbound,
|
|
432
|
+
* allow/deny lists, or runtime-mutated outbound config), we promote the
|
|
433
|
+
* container to intercept-all and keep it there until the instance restarts.
|
|
434
|
+
*
|
|
435
|
+
* When `interceptHttps` is enabled, also applies HTTPS interception:
|
|
436
|
+
* - Intercept-all mode: `interceptOutboundHttps('*', ...)` for all HTTPS traffic
|
|
437
|
+
* - Per-host mode: `interceptOutboundHttps(host, ...)` for each known host
|
|
438
|
+
*/
|
|
439
|
+
private applyOutboundInterception;
|
|
440
|
+
/**
|
|
441
|
+
* Execute SQL queries against the Container's database
|
|
442
|
+
*/
|
|
443
|
+
private sql;
|
|
444
|
+
private requestAndPortFromContainerFetchArgs;
|
|
445
|
+
/**
|
|
446
|
+
*
|
|
447
|
+
* The method prioritizes port sources in this order:
|
|
448
|
+
* 1. Ports specified directly in the method call
|
|
449
|
+
* 2. `requiredPorts` class property (if set)
|
|
450
|
+
* 3. `defaultPort` (if neither of the above is specified)
|
|
451
|
+
* 4. Falls back to port 33 if none of the above are set
|
|
452
|
+
*/
|
|
453
|
+
private getPortsToCheck;
|
|
454
|
+
/**
|
|
455
|
+
* Tries to start a container if it's not already running
|
|
456
|
+
* Returns the number of tries used
|
|
457
|
+
*/
|
|
458
|
+
private startContainerIfNotRunning;
|
|
459
|
+
private doStartContainer;
|
|
460
|
+
private setupMonitorCallbacks;
|
|
461
|
+
deleteSchedules(name: string): void;
|
|
462
|
+
/**
|
|
463
|
+
* Method called when an alarm fires
|
|
464
|
+
* Executes any scheduled tasks that are due
|
|
465
|
+
*/
|
|
466
|
+
alarm(alarmProps?: AlarmInvocationInfo): Promise<void>;
|
|
467
|
+
timeout?: ReturnType<typeof setTimeout>;
|
|
468
|
+
resolve?: () => void;
|
|
469
|
+
private syncPendingStoppedEvents;
|
|
470
|
+
private callOnStop;
|
|
471
|
+
/**
|
|
472
|
+
* Schedule the next alarm based on upcoming tasks
|
|
473
|
+
*/
|
|
474
|
+
scheduleNextAlarm(ms?: number): Promise<void>;
|
|
475
|
+
listSchedules<T = string>(name: string): Promise<Schedule<T>[]>;
|
|
476
|
+
private toSchedule;
|
|
477
|
+
/**
|
|
478
|
+
* Get a scheduled task by ID
|
|
479
|
+
* @template T Type of the payload data
|
|
480
|
+
* @param id ID of the scheduled task
|
|
481
|
+
* @returns The Schedule object or undefined if not found
|
|
482
|
+
*/
|
|
483
|
+
getSchedule<T = string>(id: string): Promise<Schedule<T> | undefined>;
|
|
484
|
+
private isActivityExpired;
|
|
485
|
+
}
|
|
17
486
|
type DurableObjectContext = ConstructorParameters<typeof Container>[0];
|
|
18
487
|
/**
|
|
19
|
-
* Base class for the generated Container DO classes. Applies a
|
|
20
|
-
* `defineContainer` definition onto `@cloudflare/containers`' `Container`:
|
|
21
|
-
* port, sleep timeout, internet access, and the container environment (static
|
|
22
|
-
* `env` merged with the declared Worker secrets — a declared-but-unset secret
|
|
23
|
-
* fails fast here rather than starting a container without its credential).
|
|
24
|
-
*
|
|
25
|
-
* Generated subclasses stay one line of behavior:
|
|
26
|
-
*
|
|
27
|
-
* ```ts
|
|
28
|
-
* export class TranscoderContainer extends LunoraContainer {
|
|
29
|
-
* constructor(ctx: DurableObjectState, env: Env) {
|
|
30
|
-
* super(ctx, env, transcoder, "transcoder");
|
|
31
|
-
* }
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
|
|
488
|
+
* Base class for the generated Container DO classes. Applies a
|
|
489
|
+
* `defineContainer` definition onto `@cloudflare/containers`' `Container`:
|
|
490
|
+
* port, sleep timeout, internet access, and the container environment (static
|
|
491
|
+
* `env` merged with the declared Worker secrets — a declared-but-unset secret
|
|
492
|
+
* fails fast here rather than starting a container without its credential).
|
|
493
|
+
*
|
|
494
|
+
* Generated subclasses stay one line of behavior:
|
|
495
|
+
*
|
|
496
|
+
* ```ts
|
|
497
|
+
* export class TranscoderContainer extends LunoraContainer {
|
|
498
|
+
* constructor(ctx: DurableObjectState, env: Env) {
|
|
499
|
+
* super(ctx, env, transcoder, "transcoder");
|
|
500
|
+
* }
|
|
501
|
+
* }
|
|
502
|
+
* ```
|
|
503
|
+
* @experimental
|
|
504
|
+
*/
|
|
35
505
|
declare class LunoraContainer<Env = unknown> extends Container<Env> {
|
|
36
506
|
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
507
|
+
* Data-residency jurisdiction the app's DOs are pinned to (codegen passes the
|
|
508
|
+
* schema's `.jurisdiction("…")`). Used to pin the best-effort lifecycle report
|
|
509
|
+
* to the same region as the root shard. `undefined` ⇒ un-pinned.
|
|
510
|
+
*/
|
|
41
511
|
private readonly lunoraJurisdiction?;
|
|
42
512
|
/** The `lunora/containers.ts` export name, for lifecycle log correlation. */
|
|
43
513
|
private readonly lunoraName;
|
|
514
|
+
/** Default port the readiness probes target when a check omits its own `port`. */
|
|
515
|
+
private readonly lunoraDefaultPort?;
|
|
516
|
+
/** Hard-cap lifetime in whole seconds (from the `hardTimeout` config), or `undefined`. */
|
|
517
|
+
private readonly lunoraHardTimeoutSeconds?;
|
|
518
|
+
/** Declarative readiness probes that gate request proxying (from the `readyOn` config). */
|
|
519
|
+
private readonly lunoraReadyOn;
|
|
520
|
+
/** Map of container env-var name → Worker Secrets Store binding name (from the `secretsStore` config). */
|
|
521
|
+
private readonly lunoraSecretsStore?;
|
|
522
|
+
/** Memoised Secrets Store resolution: run once, then merged into `envVars` before the first start. */
|
|
523
|
+
private lunoraSecretsStoreResolved?;
|
|
44
524
|
constructor(context: DurableObjectContext, env: Env, definition: ContainerDefinition, exportName?: string, jurisdiction?: DurableObjectJurisdiction);
|
|
525
|
+
/**
|
|
526
|
+
* Proxy entry for every `ctx.containers.<name>` fetch. Resolves the
|
|
527
|
+
* `secretsStore` bindings into `envVars` before delegating, so the values
|
|
528
|
+
* are present when the base implicitly starts the container for this
|
|
529
|
+
* request — a no-op when `secretsStore` is unset.
|
|
530
|
+
*/
|
|
531
|
+
override containerFetch(...args: Parameters<Container<Env>["containerFetch"]>): Promise<Response>;
|
|
532
|
+
/**
|
|
533
|
+
* Explicit start (`ctx.containers.<name>.get(id).start()`). Resolves the
|
|
534
|
+
* `secretsStore` bindings into `envVars` first, mirroring
|
|
535
|
+
* {@link containerFetch}. A per-instance `start({ envVars })` replaces the
|
|
536
|
+
* env set wholesale (base behavior), so the injected values only apply to a
|
|
537
|
+
* bare `start()` — same as the static `env`/`secrets`. When the caller
|
|
538
|
+
* supplies its own `envVars` we skip resolution entirely: those values would
|
|
539
|
+
* be discarded anyway, so a missing/unreadable binding shouldn't fail a start
|
|
540
|
+
* that never uses them.
|
|
541
|
+
*/
|
|
542
|
+
override start(...args: Parameters<Container<Env>["start"]>): Promise<void>;
|
|
543
|
+
override onActivityExpired(): Promise<void>;
|
|
45
544
|
override onError(error: unknown): unknown;
|
|
46
545
|
override onStart(): Promise<void>;
|
|
546
|
+
/**
|
|
547
|
+
* Hook run when the container's `hardTimeout` elapses (dispatched by the base
|
|
548
|
+
* scheduler via the run-generation-stamped schedule armed in
|
|
549
|
+
* {@link onStart}). Default: stop the instance. Override to drain/checkpoint
|
|
550
|
+
* first. A stale schedule from a previous run, or an already-stopped
|
|
551
|
+
* instance, is ignored (upstream cloudflare/containers#85).
|
|
552
|
+
*/
|
|
553
|
+
onHardTimeoutExpired(payload?: {
|
|
554
|
+
generation?: number;
|
|
555
|
+
}): Promise<void>;
|
|
47
556
|
override onStop(parameters: StopParams): Promise<void>;
|
|
48
557
|
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
558
|
+
* Arm the hard-timeout kill via the base scheduler (so it integrates with
|
|
559
|
+
* the container's own alarm machinery instead of fighting it). Bumps the run
|
|
560
|
+
* generation and stamps the schedule with it, so {@link onHardTimeoutExpired}
|
|
561
|
+
* can tell a fresh schedule from a stale one. No-op without a `hardTimeout`.
|
|
562
|
+
*/
|
|
563
|
+
private armHardTimeout;
|
|
564
|
+
/**
|
|
565
|
+
* Resolve the `secretsStore` bindings (async `.get()`) once and merge the
|
|
566
|
+
* values into `envVars`, so they're present when the base starts the
|
|
567
|
+
* container. Memoised on the first call — every later start reuses the
|
|
568
|
+
* resolved promise. A missing binding or a non-string value fails fast (the
|
|
569
|
+
* start surfaces the error), the same fail-closed stance the static
|
|
570
|
+
* `secrets` resolution takes for a missing Worker secret. No-op without
|
|
571
|
+
* `secretsStore`.
|
|
572
|
+
*/
|
|
573
|
+
private resolveSecretsStoreEnv;
|
|
574
|
+
/**
|
|
575
|
+
* Block until every `readyOn` probe responds with its expected status, or
|
|
576
|
+
* throw once the readiness budget is spent. Probes run in parallel and hit
|
|
577
|
+
* the container's TCP port directly (NOT `containerFetch`, which would
|
|
578
|
+
* recurse back into the start path). No-op without `readyOn`.
|
|
579
|
+
*/
|
|
580
|
+
private awaitContainerReadiness;
|
|
581
|
+
/** Poll one readiness probe until it returns its expected status or the shared deadline passes. */
|
|
582
|
+
private awaitReadinessCheck;
|
|
583
|
+
/**
|
|
584
|
+
* Best-effort push of `envelope` into the root ShardDO's log buffer so it
|
|
585
|
+
* also appears in the Studio Logs panel (the terminal already has it via
|
|
586
|
+
* `emitContainerLifecycle`). Fire-and-forget and fully swallowed: a missing
|
|
587
|
+
* `SHARD` binding, a missing admin token, or a fetch failure NEVER throws
|
|
588
|
+
* out of a lifecycle hook — the `console` path stays the source of truth.
|
|
589
|
+
*/
|
|
55
590
|
private surfaceInStudioLogs;
|
|
56
591
|
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
592
|
+
* Per-instance correlation id: the Durable Object id, which Cloudflare also
|
|
593
|
+
* injects into the container as `CLOUDFLARE_DURABLE_OBJECT_ID`. Read
|
|
594
|
+
* defensively — the id shape varies and isn't worth crashing a hook over.
|
|
595
|
+
*/
|
|
61
596
|
private instanceId;
|
|
62
597
|
}
|
|
63
|
-
export { LunoraContainer
|
|
598
|
+
export { ContainerProxy, LunoraContainer, type OutboundHandler, type OutboundHandlerContext, type OutboundHandlerParams, type OutboundHandlerParamsOf, type OutboundHandlers, outboundParams };
|