@lunora/container 1.0.0-alpha.30 → 1.0.0-alpha.32
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/bridge.d.mts +0 -6
- package/dist/bridge.d.ts +0 -6
- package/dist/bridge.mjs +1 -1
- package/dist/do/index.d.mts +1 -2
- package/dist/do/index.d.ts +1 -2
- package/dist/do/index.mjs +1 -1
- package/dist/index.d.mts +222 -23
- package/dist/index.d.ts +222 -23
- package/dist/index.mjs +1 -1
- package/dist/otel.d.mts +0 -7
- package/dist/otel.d.ts +0 -7
- package/dist/otel.mjs +1 -1
- package/dist/packem_shared/CONTAINER_EXEC_PATH-bHAyYUZk.mjs +1 -0
- package/dist/packem_shared/{ContainerProxy-BsQAwSNX.mjs → ContainerProxy-fTW_pXWY.mjs} +5 -5
- package/dist/packem_shared/{containerBindingName-CP4v-2Cw.mjs → containerBindingName-D01FopQt.mjs} +1 -1
- package/dist/packem_shared/createContainerContext-LXvczcU0.mjs +1 -0
- package/dist/packem_shared/exec-BjOpQOTW.mjs +1 -0
- package/dist/packem_shared/jurisdiction-DtE9s70w.mjs +1 -0
- package/dist/packem_shared/{jurisdiction.d-DeQ3rtYK.d.mts → jurisdiction.d-KcQu2ZT_.d.mts} +1 -13
- package/dist/packem_shared/{jurisdiction.d-DeQ3rtYK.d.ts → jurisdiction.d-KcQu2ZT_.d.ts} +1 -13
- package/package.json +2 -2
- package/dist/packem_shared/createContainerContext-BXarJmWd.mjs +0 -1
- package/dist/packem_shared/jurisdiction-BKRNOTip.mjs +0 -1
package/dist/bridge.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
2
|
/**
|
|
3
3
|
* A `fetch` implementation — defaults to the runtime global.
|
|
4
|
-
* @experimental
|
|
5
4
|
*/
|
|
6
5
|
type FetchLike = (input: string, init: {
|
|
7
6
|
body: string;
|
|
@@ -15,7 +14,6 @@ type FetchLike = (input: string, init: {
|
|
|
15
14
|
}>;
|
|
16
15
|
/**
|
|
17
16
|
* `ContainerBridgeOptions` is part of the experimental `@lunora/container` API and may change without a major version bump.
|
|
18
|
-
* @experimental
|
|
19
17
|
*/
|
|
20
18
|
interface ContainerBridgeOptions {
|
|
21
19
|
/**
|
|
@@ -35,7 +33,6 @@ interface ContainerBridgeOptions {
|
|
|
35
33
|
}
|
|
36
34
|
/**
|
|
37
35
|
* Thrown when a Lunora function returns an error envelope. A `LunoraError` subclass carrying the wire `code`.
|
|
38
|
-
* @experimental
|
|
39
36
|
*/
|
|
40
37
|
declare class ContainerBridgeError extends LunoraError {
|
|
41
38
|
constructor(code: string, message: string);
|
|
@@ -46,7 +43,6 @@ declare class ContainerBridgeError extends LunoraError {
|
|
|
46
43
|
* imported) so the bridge stays dependency-free and its `.d.ts` is
|
|
47
44
|
* self-contained; the `__lunoraPhantom` shape matches, so a real `api.x.y`
|
|
48
45
|
* reference is assignable and its arg/return types are inferable.
|
|
49
|
-
* @experimental
|
|
50
46
|
*/
|
|
51
47
|
interface BridgeFunctionReference<Args = unknown, Result = unknown> {
|
|
52
48
|
readonly __lunoraPhantom?: {
|
|
@@ -69,7 +65,6 @@ type ResultOfReference<Reference> = Reference extends {
|
|
|
69
65
|
} ? Result : never;
|
|
70
66
|
/**
|
|
71
67
|
* `ContainerBridge` is part of the experimental `@lunora/container` API and may change without a major version bump.
|
|
72
|
-
* @experimental
|
|
73
68
|
*/
|
|
74
69
|
interface ContainerBridge {
|
|
75
70
|
/** Call an `action` by `namespace:fn` path. Alias of {@link ContainerBridge.call} for intent. */
|
|
@@ -100,7 +95,6 @@ interface ContainerBridge {
|
|
|
100
95
|
* `query`/`mutation`/`action` are intent-revealing aliases of one `call` — the
|
|
101
96
|
* wire is identical and the server dispatches by the function's registered
|
|
102
97
|
* kind, so a query path called via `.mutation(...)` still runs as a query.
|
|
103
|
-
* @experimental
|
|
104
98
|
*/
|
|
105
99
|
declare const createContainerBridge: (options: ContainerBridgeOptions) => ContainerBridge;
|
|
106
100
|
export { type BridgeFunctionReference, type ContainerBridge, ContainerBridgeError, type ContainerBridgeOptions, type FetchLike, createContainerBridge };
|
package/dist/bridge.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
2
|
/**
|
|
3
3
|
* A `fetch` implementation — defaults to the runtime global.
|
|
4
|
-
* @experimental
|
|
5
4
|
*/
|
|
6
5
|
type FetchLike = (input: string, init: {
|
|
7
6
|
body: string;
|
|
@@ -15,7 +14,6 @@ type FetchLike = (input: string, init: {
|
|
|
15
14
|
}>;
|
|
16
15
|
/**
|
|
17
16
|
* `ContainerBridgeOptions` is part of the experimental `@lunora/container` API and may change without a major version bump.
|
|
18
|
-
* @experimental
|
|
19
17
|
*/
|
|
20
18
|
interface ContainerBridgeOptions {
|
|
21
19
|
/**
|
|
@@ -35,7 +33,6 @@ interface ContainerBridgeOptions {
|
|
|
35
33
|
}
|
|
36
34
|
/**
|
|
37
35
|
* Thrown when a Lunora function returns an error envelope. A `LunoraError` subclass carrying the wire `code`.
|
|
38
|
-
* @experimental
|
|
39
36
|
*/
|
|
40
37
|
declare class ContainerBridgeError extends LunoraError {
|
|
41
38
|
constructor(code: string, message: string);
|
|
@@ -46,7 +43,6 @@ declare class ContainerBridgeError extends LunoraError {
|
|
|
46
43
|
* imported) so the bridge stays dependency-free and its `.d.ts` is
|
|
47
44
|
* self-contained; the `__lunoraPhantom` shape matches, so a real `api.x.y`
|
|
48
45
|
* reference is assignable and its arg/return types are inferable.
|
|
49
|
-
* @experimental
|
|
50
46
|
*/
|
|
51
47
|
interface BridgeFunctionReference<Args = unknown, Result = unknown> {
|
|
52
48
|
readonly __lunoraPhantom?: {
|
|
@@ -69,7 +65,6 @@ type ResultOfReference<Reference> = Reference extends {
|
|
|
69
65
|
} ? Result : never;
|
|
70
66
|
/**
|
|
71
67
|
* `ContainerBridge` is part of the experimental `@lunora/container` API and may change without a major version bump.
|
|
72
|
-
* @experimental
|
|
73
68
|
*/
|
|
74
69
|
interface ContainerBridge {
|
|
75
70
|
/** Call an `action` by `namespace:fn` path. Alias of {@link ContainerBridge.call} for intent. */
|
|
@@ -100,7 +95,6 @@ interface ContainerBridge {
|
|
|
100
95
|
* `query`/`mutation`/`action` are intent-revealing aliases of one `call` — the
|
|
101
96
|
* wire is identical and the server dispatches by the function's registered
|
|
102
97
|
* kind, so a query path called via `.mutation(...)` still runs as a query.
|
|
103
|
-
* @experimental
|
|
104
98
|
*/
|
|
105
99
|
declare const createContainerBridge: (options: ContainerBridgeOptions) => ContainerBridge;
|
|
106
100
|
export { type BridgeFunctionReference, type ContainerBridge, ContainerBridgeError, type ContainerBridgeOptions, type FetchLike, createContainerBridge };
|
package/dist/bridge.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraError as
|
|
1
|
+
import{LunoraError as u}from"@lunora/errors";const h="/_lunora/rpc";class w extends u{constructor(r,e){super(r,e,{name:"ContainerBridgeError"})}}const p=(t,r)=>{let e=t;for(;e.endsWith("/");)e=e.slice(0,-1);return`${e}${r}`},g=(t,r)=>new Error(`createContainerBridge: request to "${t}" failed (status ${String(r.status)}${r.statusText?` ${r.statusText}`:""})`),m=async(t,r)=>{try{return await t.json()}catch{throw t.ok?new u("INTERNAL",`createContainerBridge: request to "${r}" returned a non-JSON response (status ${String(t.status)})`):g(r,t)}},B=t=>{if(typeof t.baseUrl!="string"||t.baseUrl.length===0)throw new TypeError("createContainerBridge: `baseUrl` must be a non-empty Worker URL (e.g. https://my-app.workers.dev) — is the URL env var set?");const r=t.fetch??globalThis.fetch,e=async(n,i={},c)=>{if(typeof r!="function")throw new TypeError("createContainerBridge: no `fetch` available — pass `fetch` in options for this runtime.");const d={"content-type":"application/json"};t.token!==void 0&&(d.authorization=`Bearer ${t.token}`);const s=await r(p(t.baseUrl,h),{body:JSON.stringify({args:i,functionPath:n,shardKey:c}),headers:d,method:"POST"}),o=await m(s,n);if(typeof o=="object"&&o!==null&&"error"in o){const{error:a}=o;if(typeof a=="object"&&a!==null){const{code:f,message:y}=a;if(typeof f=="string"&&typeof y=="string")throw new w(f,y)}let l;try{l=JSON.stringify(a)}catch{l=String(a)}throw new u("INTERNAL",`createContainerBridge: request to "${n}" returned a malformed error envelope (status ${String(s.status)}): ${l}`)}if(!s.ok)throw g(n,s);return o.result};return{action:e,call:e,mutation:e,query:e,run:async(n,i,c)=>e(n.__lunoraRef,i,c)}};export{w as ContainerBridgeError,B as createContainerBridge};
|
package/dist/do/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { C as ContainerDefinition, D as DurableObjectJurisdiction } from "../packem_shared/jurisdiction.d-KcQu2ZT_.mjs";
|
|
1
2
|
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
2
|
-
import { a as ContainerDefinition, D as DurableObjectJurisdiction } from "../packem_shared/jurisdiction.d-DeQ3rtYK.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* ContainerStartOptions as they come from worker types
|
|
5
5
|
*/
|
|
@@ -500,7 +500,6 @@ type DurableObjectContext = ConstructorParameters<typeof Container>[0];
|
|
|
500
500
|
* }
|
|
501
501
|
* }
|
|
502
502
|
* ```
|
|
503
|
-
* @experimental
|
|
504
503
|
*/
|
|
505
504
|
declare class LunoraContainer<Env = unknown> extends Container<Env> {
|
|
506
505
|
/**
|
package/dist/do/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { C as ContainerDefinition, D as DurableObjectJurisdiction } from "../packem_shared/jurisdiction.d-KcQu2ZT_.js";
|
|
1
2
|
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
2
|
-
import { a as ContainerDefinition, D as DurableObjectJurisdiction } from "../packem_shared/jurisdiction.d-DeQ3rtYK.js";
|
|
3
3
|
/**
|
|
4
4
|
* ContainerStartOptions as they come from worker types
|
|
5
5
|
*/
|
|
@@ -500,7 +500,6 @@ type DurableObjectContext = ConstructorParameters<typeof Container>[0];
|
|
|
500
500
|
* }
|
|
501
501
|
* }
|
|
502
502
|
* ```
|
|
503
|
-
* @experimental
|
|
504
503
|
*/
|
|
505
504
|
declare class LunoraContainer<Env = unknown> extends Container<Env> {
|
|
506
505
|
/**
|
package/dist/do/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{LunoraError as u}from"@lunora/errors";import{resolveContainerEnvVars as m,parseDurationSeconds as y}from"../packem_shared/containerBindingName-D01FopQt.mjs";import{a as g}from"../packem_shared/jurisdiction-DtE9s70w.mjs";import{Container as f}from"../packem_shared/ContainerProxy-fTW_pXWY.mjs";import{ContainerProxy as b,outboundParams as x}from"../packem_shared/ContainerProxy-fTW_pXWY.mjs";const w="lunora",E=(s,t,r,e)=>({container:s,event:r,instance:t,level:r==="error"?"error":"info",message:e,source:w,ts:Date.now(),type:"container"}),i=(s,t,r,e)=>{const o=E(s,t,r,e),n=JSON.stringify(o);return r==="error"?console.error(n):console.log(n),o},N="__lunora_admin__:recordContainerEvent",d="__root__",R=s=>{if(s===null||typeof s!="object")return!1;const t=s;return typeof t.get=="function"&&typeof t.idFromName=="function"},_=(s,t)=>{const r=g(s,t);return typeof r.getByName=="function"?r.getByName(d):r.get(r.idFromName(d))},T=async(s,t,r)=>{try{const e=s??{},o=e.SHARD;if(!R(o))return;const n=typeof e.LUNORA_ADMIN_TOKEN=="string"?e.LUNORA_ADMIN_TOKEN:void 0;if(!n||n.length===0)return;const a=new Request("https://shard.internal/rpc",{body:JSON.stringify({args:{event:t},functionPath:N}),headers:{authorization:`Bearer ${n}`,"content-type":"application/json"},method:"POST"});await _(o,r).fetch(a)}catch{}},p=500,S=3e4,h="__lunoraHardTimeoutGeneration";class L extends f{lunoraJurisdiction;lunoraName;lunoraDefaultPort;lunoraHardTimeoutSeconds;lunoraReadyOn;lunoraSecretsStore;lunoraSecretsStoreResolved;constructor(t,r,e,o,n){super(t,r,{defaultPort:e.defaultPort,entrypoint:e.entrypoint?[...e.entrypoint]:void 0,envVars:m(e,r,o),sleepAfter:e.sleepAfter}),e.enableInternet!==void 0&&(this.enableInternet=e.enableInternet),e.requiredPorts!==void 0&&(this.requiredPorts=[...e.requiredPorts]),e.interceptHttps!==void 0&&(this.interceptHttps=e.interceptHttps),e.allowedHosts!==void 0&&(this.allowedHosts=[...e.allowedHosts]),e.deniedHosts!==void 0&&(this.deniedHosts=[...e.deniedHosts]),e.pingEndpoint!==void 0&&(this.pingEndpoint=e.pingEndpoint),e.labels!==void 0&&(this.labels={...e.labels}),this.lunoraName=o??"container",this.lunoraJurisdiction=n,this.lunoraDefaultPort=e.defaultPort,this.lunoraReadyOn=e.readyOn?[...e.readyOn]:[],this.lunoraHardTimeoutSeconds=e.hardTimeout===void 0?void 0:y(e.hardTimeout),this.lunoraSecretsStore=e.secretsStore}async containerFetch(...t){return await this.resolveSecretsStoreEnv(),super.containerFetch(...t)}async start(...t){const[r]=t;return r?.envVars===void 0&&await this.resolveSecretsStoreEnv(),super.start(...t)}async onActivityExpired(){const t=i(this.lunoraName,this.instanceId(),"sleep");this.surfaceInStudioLogs(t),await super.onActivityExpired()}onError(t){const r=i(this.lunoraName,this.instanceId(),"error",t instanceof Error?t.message:String(t));return this.surfaceInStudioLogs(r),super.onError(t)}async onStart(){const t=i(this.lunoraName,this.instanceId(),"start");this.surfaceInStudioLogs(t),await super.onStart(),await this.armHardTimeout(),await this.awaitContainerReadiness()}async onHardTimeoutExpired(t){const r=await this.ctx.storage.get(h);if(t?.generation!==void 0&&t.generation!==r||this.ctx.container?.running!==!0)return;const e=i(this.lunoraName,this.instanceId(),"stop","hard timeout reached");this.surfaceInStudioLogs(e),await this.stop()}async onStop(t){const r=i(this.lunoraName,this.instanceId(),"stop",`${t.reason} (exit ${String(t.exitCode)})`);this.surfaceInStudioLogs(r),await super.onStop(t)}async armHardTimeout(){if(this.lunoraHardTimeoutSeconds===void 0)return;const t=(await this.ctx.storage.get(h)??0)+1;await this.ctx.storage.put(h,t),await this.schedule(this.lunoraHardTimeoutSeconds,"onHardTimeoutExpired",{generation:t})}async resolveSecretsStoreEnv(){const t=this.lunoraSecretsStore;t!==void 0&&(this.lunoraSecretsStoreResolved??=(async()=>{const r=this.env,e={};for(const[o,n]of Object.entries(t)){const a=r[n];if(a===void 0||typeof a.get!="function")throw new u("INTERNAL",`container "${this.lunoraName}": secretsStore env "${o}" points at binding "${n}", which is not a Secrets Store binding on the Worker env. Add a \`secrets_store_secrets\` entry binding "${n}".`);const c=await a.get();if(typeof c!="string")throw new TypeError(`container "${this.lunoraName}": Secrets Store binding "${n}" (env "${o}") did not resolve to a string value.`);e[o]=c}this.envVars={...this.envVars,...e}})().catch(r=>{throw this.lunoraSecretsStoreResolved=void 0,r}),await this.lunoraSecretsStoreResolved)}async awaitContainerReadiness(){if(this.lunoraReadyOn.length===0)return;const{container:t}=this.ctx;if(t===void 0)return;const r=Date.now()+S;await Promise.all(this.lunoraReadyOn.map(async e=>this.awaitReadinessCheck(t,e,r)))}async awaitReadinessCheck(t,r,e){const o=r.port??this.lunoraDefaultPort;if(o===void 0)throw new u("INTERNAL",`container "${this.lunoraName}": readyOn check "${r.path}" has no port — set the check's \`port\` or the container \`defaultPort\`.`);const n=r.status??200,a=r.path.startsWith("/")?r.path:`/${r.path}`,c=t.getTcpPort(o);for(;;){const v=Math.max(p,e-Date.now());try{if((await c.fetch(`http://container${a}`,{signal:AbortSignal.timeout(v)})).status===n)return}catch{}if(Date.now()>=e)throw new u("INTERNAL",`container "${this.lunoraName}": readiness check "${r.path}" (port ${String(o)}) did not return ${String(n)} within ${String(S)}ms`);await new Promise(l=>{setTimeout(l,p)})}}surfaceInStudioLogs(t){T(this.env,t,this.lunoraJurisdiction).catch(()=>{})}instanceId(){try{const{id:t}=this.ctx;return typeof t?.toString=="function"?t.toString():"unknown"}catch{return"unknown"}}}export{b as ContainerProxy,L as LunoraContainer,x as outboundParams};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,74 @@
|
|
|
1
|
-
import { D as DurableObjectJurisdiction,
|
|
2
|
-
export type { B as BuildImageSource, c as ContainerInstanceType, d as ContainerReadinessCheck, e as ContainerRollout, f as CustomContainerInstanceType, g as NamedContainerInstanceType, R as RegistryImageSource } from "./packem_shared/jurisdiction.d-
|
|
1
|
+
import { D as DurableObjectJurisdiction, a as ContainerConfig, C as ContainerDefinition, b as ContainerImageSource, N as NormalizedContainerImage } from "./packem_shared/jurisdiction.d-KcQu2ZT_.mjs";
|
|
2
|
+
export type { B as BuildImageSource, c as ContainerInstanceType, d as ContainerReadinessCheck, e as ContainerRollout, f as CustomContainerInstanceType, g as NamedContainerInstanceType, R as RegistryImageSource } from "./packem_shared/jurisdiction.d-KcQu2ZT_.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Per-call options for `ContainerHandle.exec`.
|
|
5
|
+
*/
|
|
6
|
+
interface ContainerExecOptions {
|
|
7
|
+
/** Arguments passed to `command`, unshelled — the container must not concatenate them into a shell string. */
|
|
8
|
+
args?: ReadonlyArray<string>;
|
|
9
|
+
/** Working directory for the command, relative to the container's own root. */
|
|
10
|
+
cwd?: string;
|
|
11
|
+
/** Extra environment for this command only, merged over the container's env. */
|
|
12
|
+
env?: Readonly<Record<string, string>>;
|
|
13
|
+
/**
|
|
14
|
+
* Cap on the response body, in bytes. The whole `{code,stdout,stderr}`
|
|
15
|
+
* document has to be held in memory to be parsed, and a build box or job
|
|
16
|
+
* runner routinely writes tens of megabytes — a single unbounded `exec`
|
|
17
|
+
* that returns more than the isolate's memory limit kills the isolate and
|
|
18
|
+
* every other in-flight request sharing it, not just this call. So a
|
|
19
|
+
* runner that overruns the cap fails the call loudly rather than taking
|
|
20
|
+
* the shard down with it; raise this (or have the runner cap its own
|
|
21
|
+
* output) when a command legitimately produces more.
|
|
22
|
+
*
|
|
23
|
+
* Default {@link DEFAULT_EXEC_MAX_OUTPUT_BYTES} (1MB).
|
|
24
|
+
*/
|
|
25
|
+
maxOutputBytes?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Abort the call. Composed with {@link ContainerExecOptions.timeoutMs} when
|
|
28
|
+
* both are given — whichever fires first wins.
|
|
29
|
+
*/
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
/**
|
|
32
|
+
* Give up after this many ms. Covers the whole call — the request *and*
|
|
33
|
+
* reading the response body, since `fetch` resolves on headers and a
|
|
34
|
+
* runner that answers `200` and then stalls mid-body would otherwise sit
|
|
35
|
+
* past the deadline. Sent to the container as well, so a well-behaved
|
|
36
|
+
* runner can kill the process rather than leak it when the caller walks
|
|
37
|
+
* away.
|
|
38
|
+
*/
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The outcome of a `ContainerHandle.exec` call.
|
|
43
|
+
*
|
|
44
|
+
* A non-zero `code` is **not** an error: a command that ran and failed is a
|
|
45
|
+
* result, and the caller decides what to do with it. Only a failure to *run*
|
|
46
|
+
* the command — transport, a non-2xx from the runner, an unparseable body —
|
|
47
|
+
* throws.
|
|
48
|
+
*/
|
|
49
|
+
interface ContainerExecResult {
|
|
50
|
+
/** Process exit code. Non-zero means the command ran and failed. */
|
|
51
|
+
code: number;
|
|
52
|
+
/** Everything the command wrote to stderr. */
|
|
53
|
+
stderr: string;
|
|
54
|
+
/** Everything the command wrote to stdout. */
|
|
55
|
+
stdout: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The route `ContainerHandle.exec` POSTs to. Namespaced under
|
|
59
|
+
* `/__lunora/` so it cannot collide with an application route the container
|
|
60
|
+
* already serves — the previous ad-hoc convention was a bare `/exec`, which an
|
|
61
|
+
* app could plausibly own for its own purposes.
|
|
62
|
+
*
|
|
63
|
+
* Exported because it is a *contract*, not an implementation detail: a
|
|
64
|
+
* container image has to serve exactly this route, and `@lunora/agent`'s
|
|
65
|
+
* human-in-the-loop gate has to recognise it. Both had it hard-coded as a
|
|
66
|
+
* second literal, which drifts silently — and on the gate's side, drift
|
|
67
|
+
* un-gates model-chosen command execution.
|
|
68
|
+
*/
|
|
69
|
+
declare const CONTAINER_EXEC_PATH = "/__lunora/exec";
|
|
3
70
|
/**
|
|
4
71
|
* Options for explicitly starting an instance (mirrors `@cloudflare/containers`).
|
|
5
|
-
* @experimental
|
|
6
72
|
*/
|
|
7
73
|
interface ContainerStartOptions {
|
|
8
74
|
/** Override outbound internet access for this start. */
|
|
@@ -16,7 +82,6 @@ interface ContainerStartOptions {
|
|
|
16
82
|
}
|
|
17
83
|
/**
|
|
18
84
|
* A container instance's runtime state, as returned by `getState()`. Structural — the platform adds fields over time.
|
|
19
|
-
* @experimental
|
|
20
85
|
*/
|
|
21
86
|
interface ContainerInstanceState {
|
|
22
87
|
[key: string]: unknown;
|
|
@@ -44,7 +109,6 @@ interface ContainerStubLike {
|
|
|
44
109
|
}
|
|
45
110
|
/**
|
|
46
111
|
* What the client needs from a Durable Object namespace binding.
|
|
47
|
-
* @experimental
|
|
48
112
|
*/
|
|
49
113
|
interface ContainerNamespaceLike {
|
|
50
114
|
get: (id: unknown) => ContainerStubLike;
|
|
@@ -57,9 +121,24 @@ interface ContainerNamespaceLike {
|
|
|
57
121
|
}
|
|
58
122
|
/**
|
|
59
123
|
* A handle on one container instance (one Durable Object).
|
|
60
|
-
* @experimental
|
|
61
124
|
*/
|
|
62
125
|
interface ContainerHandle {
|
|
126
|
+
/**
|
|
127
|
+
* Run a command inside the container and return its exit code and output.
|
|
128
|
+
*
|
|
129
|
+
* A container is an HTTP server, so there is no platform-level exec to call:
|
|
130
|
+
* the command is POSTed to `/__lunora/exec` and the container app
|
|
131
|
+
* serves that route. What this method adds over hand-rolling that fetch is
|
|
132
|
+
* the **contract** — a pinned path, a typed request and response, and the
|
|
133
|
+
* distinction between "the command failed" (a `code`) and "the command could
|
|
134
|
+
* not be run" (a throw). Before it existed every caller invented its own
|
|
135
|
+
* `/exec` convention and read the raw body back as if it were output, which
|
|
136
|
+
* silently turned a runner's 500 into a successful-looking result.
|
|
137
|
+
*
|
|
138
|
+
* The container side must accept `{ args, command, cwd, env, timeoutMs }`
|
|
139
|
+
* and answer `{ code, stdout, stderr }` as JSON.
|
|
140
|
+
*/
|
|
141
|
+
exec: (command: string, options?: ContainerExecOptions) => Promise<ContainerExecResult>;
|
|
63
142
|
/**
|
|
64
143
|
* Send an HTTP (or WebSocket-upgrade) request to the container. A path
|
|
65
144
|
* string (`"/transcode"`) is resolved against a synthetic origin; a full
|
|
@@ -82,7 +161,6 @@ interface ContainerHandle {
|
|
|
82
161
|
* game, a job runner per id) often needs to tear down or inspect the instance
|
|
83
162
|
* rather than wait for `sleepAfter`, so these wrap the container DO's
|
|
84
163
|
* `start`/`stop`/`destroy`/`getState`.
|
|
85
|
-
* @experimental
|
|
86
164
|
*/
|
|
87
165
|
interface ContainerInstanceHandle extends ContainerHandle {
|
|
88
166
|
/** Stop and discard the instance (its ephemeral disk is lost). */
|
|
@@ -117,7 +195,6 @@ interface ContainerInstanceHandle extends ContainerHandle {
|
|
|
117
195
|
* Each maps to the corresponding `@cloudflare/containers` `Container` RPC, so
|
|
118
196
|
* an app can tighten or relax a single instance's allowed/denied hosts after
|
|
119
197
|
* start without redeploying.
|
|
120
|
-
* @experimental
|
|
121
198
|
*/
|
|
122
199
|
interface ContainerEgressControls {
|
|
123
200
|
/** Add one hostname (or glob) to the allow-list. */
|
|
@@ -135,7 +212,6 @@ interface ContainerEgressControls {
|
|
|
135
212
|
}
|
|
136
213
|
/**
|
|
137
214
|
* The per-definition accessor exposed as `ctx.containers.<exportName>`.
|
|
138
|
-
* @experimental
|
|
139
215
|
*/
|
|
140
216
|
interface ContainerAccessor {
|
|
141
217
|
/**
|
|
@@ -178,7 +254,6 @@ interface ContainerAccessor {
|
|
|
178
254
|
}
|
|
179
255
|
/**
|
|
180
256
|
* Tuning for a pooled, retrying container handle. See {@link ContainerAccessor.pool}.
|
|
181
|
-
* @experimental
|
|
182
257
|
*/
|
|
183
258
|
interface PoolOptions {
|
|
184
259
|
/** Total attempts before giving up (each on a freshly-picked instance). Default 3. */
|
|
@@ -195,6 +270,10 @@ interface PoolOptions {
|
|
|
195
270
|
* Whether a *returned* response should be retried on another instance.
|
|
196
271
|
* Defaults to retrying any `5xx`. A thrown error (network/start failure) is
|
|
197
272
|
* always retried regardless of this predicate.
|
|
273
|
+
*
|
|
274
|
+
* Applies to `fetch` only. `exec` retries on the cold-start transients
|
|
275
|
+
* alone, because its caller never chose the request and a command that
|
|
276
|
+
* already ran must not be re-run just because the runner failed afterwards.
|
|
198
277
|
*/
|
|
199
278
|
retryOn?: (response: Response) => boolean;
|
|
200
279
|
/** Pool size to spread picks across. Defaults to the definition's `maxInstances`, else 3. */
|
|
@@ -205,7 +284,6 @@ interface PoolOptions {
|
|
|
205
284
|
* only on the platform's provisioning transients (no-instance / not-listening /
|
|
206
285
|
* rate-limited — see {@link isColdStartTransient}), which is why it's safe by
|
|
207
286
|
* default: those responses mean the request never reached the container.
|
|
208
|
-
* @experimental
|
|
209
287
|
*/
|
|
210
288
|
interface InstanceRetryOptions {
|
|
211
289
|
/**
|
|
@@ -221,7 +299,6 @@ interface InstanceRetryOptions {
|
|
|
221
299
|
}
|
|
222
300
|
/**
|
|
223
301
|
* Wiring info for one definition, emitted by codegen into the generated DO.
|
|
224
|
-
* @experimental
|
|
225
302
|
*/
|
|
226
303
|
interface ContainerBindingSpec {
|
|
227
304
|
/** Durable Object binding name, e.g. `CONTAINER_TRANSCODER`. */
|
|
@@ -240,12 +317,10 @@ interface ContainerBindingSpec {
|
|
|
240
317
|
* `traceparent` (the inbound RPC's W3C trace context, forwarded by the runtime
|
|
241
318
|
* and read off the request by the DO) is stamped onto every outbound container
|
|
242
319
|
* `fetch`, so the container's own spans stitch under the Worker's trace.
|
|
243
|
-
* @experimental
|
|
244
320
|
*/
|
|
245
321
|
declare const createContainerContext: (env: Record<string, unknown>, specs: ReadonlyArray<ContainerBindingSpec>, jurisdiction?: DurableObjectJurisdiction, traceparent?: string) => Record<string, ContainerAccessor>;
|
|
246
322
|
/**
|
|
247
323
|
* A test handler: receives the request plus the targeted instance name.
|
|
248
|
-
* @experimental
|
|
249
324
|
*/
|
|
250
325
|
type ContainerTestHandler = (request: Request, instance: {
|
|
251
326
|
name: string;
|
|
@@ -260,7 +335,6 @@ type ContainerTestHandler = (request: Request, instance: {
|
|
|
260
335
|
* transcoder: (request) => new Response("ok"),
|
|
261
336
|
* });
|
|
262
337
|
* ```
|
|
263
|
-
* @experimental
|
|
264
338
|
*/
|
|
265
339
|
declare const createContainerTestContext: (handlers: Record<string, ContainerTestHandler>) => Record<string, ContainerAccessor>;
|
|
266
340
|
/**
|
|
@@ -272,7 +346,6 @@ declare const createContainerTestContext: (handlers: Record<string, ContainerTes
|
|
|
272
346
|
* `Dockerfile.dev` also counts) is used as-is with its directory as the build
|
|
273
347
|
* context; any other path is treated as the build-context directory and the
|
|
274
348
|
* Dockerfile is expected at `<dir>/Dockerfile`.
|
|
275
|
-
* @experimental
|
|
276
349
|
*/
|
|
277
350
|
declare const normalizeContainerImage: (image: ContainerImageSource) => NormalizedContainerImage;
|
|
278
351
|
/**
|
|
@@ -280,7 +353,6 @@ declare const normalizeContainerImage: (image: ContainerImageSource) => Normaliz
|
|
|
280
353
|
* `transcoder` → `TranscoderContainer`. wrangler's `containers[].class_name`
|
|
281
354
|
* and the Durable Object binding's `class_name` both reference it, so codegen
|
|
282
355
|
* and the config layer MUST derive it identically — always via this helper.
|
|
283
|
-
* @experimental
|
|
284
356
|
*/
|
|
285
357
|
declare const containerClassName: (exportName: string) => string;
|
|
286
358
|
/**
|
|
@@ -288,7 +360,6 @@ declare const containerClassName: (exportName: string) => string;
|
|
|
288
360
|
* `CONTAINER_TRANSCODER`, `imageResizer` → `CONTAINER_IMAGE_RESIZER`. The
|
|
289
361
|
* `CONTAINER_` prefix namespaces these away from `SHARD`/`SESSION`/`SCHEDULER`
|
|
290
362
|
* so a container export can never collide with the built-in bindings.
|
|
291
|
-
* @experimental
|
|
292
363
|
*/
|
|
293
364
|
declare const containerBindingName: (exportName: string) => string;
|
|
294
365
|
/**
|
|
@@ -297,17 +368,14 @@ declare const containerBindingName: (exportName: string) => string;
|
|
|
297
368
|
* it as the wrangler `containers[].image`, and `lunora deploy` builds that tag
|
|
298
369
|
* with Railpack and `wrangler containers push`es it before deploying — so all
|
|
299
370
|
* three derive the tag from this one helper and can never disagree.
|
|
300
|
-
* @experimental
|
|
301
371
|
*/
|
|
302
372
|
declare const containerBuildTag: (exportName: string) => string;
|
|
303
373
|
/**
|
|
304
374
|
* `defineContainer` is part of the experimental `@lunora/container` API and may change without a major version bump.
|
|
305
|
-
* @experimental
|
|
306
375
|
*/
|
|
307
376
|
declare const defineContainer: (config: ContainerConfig) => ContainerDefinition;
|
|
308
377
|
/**
|
|
309
378
|
* True when a value is a `defineContainer` result (the runtime brand check).
|
|
310
|
-
* @experimental
|
|
311
379
|
*/
|
|
312
380
|
declare const isContainerDefinition: (value: unknown) => value is ContainerDefinition;
|
|
313
381
|
/**
|
|
@@ -315,7 +383,138 @@ declare const isContainerDefinition: (value: unknown) => value is ContainerDefin
|
|
|
315
383
|
* plus every declared secret resolved from the Worker `env`. A declared secret
|
|
316
384
|
* missing from the Worker env fails fast — starting the container without a
|
|
317
385
|
* credential it was promised yields far worse errors downstream.
|
|
318
|
-
* @experimental
|
|
319
386
|
*/
|
|
320
387
|
declare const resolveContainerEnvVariables: (definition: ContainerDefinition, workerEnv: Record<string, unknown>, exportName?: string) => Record<string, string>;
|
|
321
|
-
export {
|
|
388
|
+
export { CONTAINER_EXEC_PATH,
|
|
389
|
+
/**
|
|
390
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
391
|
+
*
|
|
392
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
393
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
394
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
395
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
396
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
397
|
+
* behind the `@lunora/container/do` subpath.
|
|
398
|
+
*/
|
|
399
|
+
type ContainerAccessor,
|
|
400
|
+
/**
|
|
401
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
402
|
+
*
|
|
403
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
404
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
405
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
406
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
407
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
408
|
+
* behind the `@lunora/container/do` subpath.
|
|
409
|
+
*/
|
|
410
|
+
type ContainerBindingSpec, type ContainerConfig, type ContainerDefinition,
|
|
411
|
+
/**
|
|
412
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
413
|
+
*
|
|
414
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
415
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
416
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
417
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
418
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
419
|
+
* behind the `@lunora/container/do` subpath.
|
|
420
|
+
*/
|
|
421
|
+
type ContainerEgressControls, type ContainerExecOptions, type ContainerExecResult,
|
|
422
|
+
/**
|
|
423
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
424
|
+
*
|
|
425
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
426
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
427
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
428
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
429
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
430
|
+
* behind the `@lunora/container/do` subpath.
|
|
431
|
+
*/
|
|
432
|
+
type ContainerHandle, type ContainerImageSource,
|
|
433
|
+
/**
|
|
434
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
435
|
+
*
|
|
436
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
437
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
438
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
439
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
440
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
441
|
+
* behind the `@lunora/container/do` subpath.
|
|
442
|
+
*/
|
|
443
|
+
type ContainerInstanceHandle,
|
|
444
|
+
/**
|
|
445
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
446
|
+
*
|
|
447
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
448
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
449
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
450
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
451
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
452
|
+
* behind the `@lunora/container/do` subpath.
|
|
453
|
+
*/
|
|
454
|
+
type ContainerInstanceState,
|
|
455
|
+
/**
|
|
456
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
457
|
+
*
|
|
458
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
459
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
460
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
461
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
462
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
463
|
+
* behind the `@lunora/container/do` subpath.
|
|
464
|
+
*/
|
|
465
|
+
type ContainerNamespaceLike,
|
|
466
|
+
/**
|
|
467
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
468
|
+
*
|
|
469
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
470
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
471
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
472
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
473
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
474
|
+
* behind the `@lunora/container/do` subpath.
|
|
475
|
+
*/
|
|
476
|
+
type ContainerStartOptions,
|
|
477
|
+
/**
|
|
478
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
479
|
+
*
|
|
480
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
481
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
482
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
483
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
484
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
485
|
+
* behind the `@lunora/container/do` subpath.
|
|
486
|
+
*/
|
|
487
|
+
type ContainerTestHandler,
|
|
488
|
+
/**
|
|
489
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
490
|
+
*
|
|
491
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
492
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
493
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
494
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
495
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
496
|
+
* behind the `@lunora/container/do` subpath.
|
|
497
|
+
*/
|
|
498
|
+
type DurableObjectJurisdiction,
|
|
499
|
+
/**
|
|
500
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
501
|
+
*
|
|
502
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
503
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
504
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
505
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
506
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
507
|
+
* behind the `@lunora/container/do` subpath.
|
|
508
|
+
*/
|
|
509
|
+
type InstanceRetryOptions, type NormalizedContainerImage,
|
|
510
|
+
/**
|
|
511
|
+
* `@lunora/container` — Cloudflare Containers for Lunora.
|
|
512
|
+
*
|
|
513
|
+
* This root export is Node-safe (no Cloudflare runtime imports): the
|
|
514
|
+
* `defineContainer` authoring surface, the naming/normalization helpers
|
|
515
|
+
* codegen and `@lunora/config` share, the `ctx.containers` client wiring, and
|
|
516
|
+
* a Docker-free test double. The workerd-only `LunoraContainer` base class
|
|
517
|
+
* (which pulls in `@cloudflare/containers` → `cloudflare:workers`) lives
|
|
518
|
+
* behind the `@lunora/container/do` subpath.
|
|
519
|
+
*/
|
|
520
|
+
type PoolOptions, containerBindingName, containerBuildTag, containerClassName, createContainerContext, createContainerTestContext, defineContainer, isContainerDefinition, normalizeContainerImage, resolveContainerEnvVariables as resolveContainerEnvVars };
|