little-durable-objects 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +49 -0
- package/dist/host/actorModule.d.ts +4 -0
- package/dist/host/actorModule.d.ts.map +1 -0
- package/dist/host/actorModule.js +54 -0
- package/dist/host/actorModule.js.map +1 -0
- package/dist/host/session.d.ts +20 -0
- package/dist/host/session.d.ts.map +1 -0
- package/dist/host/session.js +220 -0
- package/dist/host/session.js.map +1 -0
- package/dist/host/worker/entrypoint.d.ts +2 -0
- package/dist/host/worker/entrypoint.d.ts.map +1 -0
- package/dist/host/worker/entrypoint.js +26 -0
- package/dist/host/worker/entrypoint.js.map +1 -0
- package/dist/host/worker/runtime.d.ts +14 -0
- package/dist/host/worker/runtime.d.ts.map +1 -0
- package/dist/host/worker/runtime.js +77 -0
- package/dist/host/worker/runtime.js.map +1 -0
- package/dist/host/worker/supervisor.d.ts +21 -0
- package/dist/host/worker/supervisor.d.ts.map +1 -0
- package/dist/host/worker/supervisor.js +190 -0
- package/dist/host/worker/supervisor.js.map +1 -0
- package/dist/host.d.ts +2 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +2 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/modal.d.ts +29 -0
- package/dist/providers/modal.d.ts.map +1 -0
- package/dist/providers/modal.js +193 -0
- package/dist/providers/modal.js.map +1 -0
- package/dist/providers/modalCli.d.ts +3 -0
- package/dist/providers/modalCli.d.ts.map +1 -0
- package/dist/providers/modalCli.js +18 -0
- package/dist/providers/modalCli.js.map +1 -0
- package/dist/providers/types.d.ts +31 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/regions.d.ts +59 -0
- package/dist/regions.d.ts.map +1 -0
- package/dist/regions.js +46 -0
- package/dist/regions.js.map +1 -0
- package/dist/shared/actor.d.ts +28 -0
- package/dist/shared/actor.d.ts.map +1 -0
- package/dist/shared/actor.js +105 -0
- package/dist/shared/actor.js.map +1 -0
- package/dist/shared/errors.d.ts +25 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +48 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/invocationContext.d.ts +4 -0
- package/dist/shared/invocationContext.d.ts.map +1 -0
- package/dist/shared/invocationContext.js +10 -0
- package/dist/shared/invocationContext.js.map +1 -0
- package/dist/shared/types.d.ts +123 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +111 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/workflow/client.d.ts +23 -0
- package/dist/workflow/client.d.ts.map +1 -0
- package/dist/workflow/client.js +49 -0
- package/dist/workflow/client.js.map +1 -0
- package/dist/workflow/remoteClient.d.ts +26 -0
- package/dist/workflow/remoteClient.d.ts.map +1 -0
- package/dist/workflow/remoteClient.js +136 -0
- package/dist/workflow/remoteClient.js.map +1 -0
- package/package.json +82 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Terse
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# little-durable-objects
|
|
2
|
+
|
|
3
|
+
The package provides the typed `Actor` API, control-plane HTTP client, JavaScript host executor, region catalog, and provider contract. It also bundles the Modal command used by the Rust control plane.
|
|
4
|
+
|
|
5
|
+
Requires Node.js 20 or newer.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add little-durable-objects
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Workflow sandboxes receive one system-issued project JWT and use it only with the control plane:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Actor, configureDurableObjects } from "little-durable-objects"
|
|
15
|
+
|
|
16
|
+
configureDurableObjects({
|
|
17
|
+
token: process.env.DURABLE_OBJECT_TOKEN!,
|
|
18
|
+
namespaceId: process.env.DURABLE_OBJECT_NAMESPACE_ID!,
|
|
19
|
+
controlPlaneUrl: process.env.DURABLE_OBJECT_CONTROL_PLANE_URL!,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export class Counter extends Actor {
|
|
23
|
+
count = 0
|
|
24
|
+
|
|
25
|
+
async increment(): Promise<number> {
|
|
26
|
+
return ++this.count
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
await Counter.get("account-1").increment()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Calling `configureDurableObjects` is optional when these environment variables are already present:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
DURABLE_OBJECT_TOKEN
|
|
37
|
+
DURABLE_OBJECT_NAMESPACE_ID
|
|
38
|
+
DURABLE_OBJECT_CONTROL_PLANE_URL
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The control plane selects one sandbox provider globally. For Modal, set `DURABLE_OBJECT_SANDBOX_PROVIDER=modal`; optionally override its executable with `DURABLE_OBJECT_SANDBOX_COMMAND`.
|
|
42
|
+
|
|
43
|
+
The `little-durable-objects-modal` executable reads one JSON command from stdin, uses `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` through the Modal TypeScript SDK, and writes one JSON result to stdout. The Rust control plane invokes it locally; no provider HTTP server is required.
|
|
44
|
+
|
|
45
|
+
Actor hosts conventionally load `src/durable-objects.ts`. See the [runtime repository](https://github.com/TerseAI/little-durable-objects) for backend configuration, the REST admin API, authentication, and lifecycle behavior.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT © 2026 Terse
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actorModule.d.ts","sourceRoot":"","sources":["../../host/actorModule.ts"],"names":[],"mappings":"AAWA,iBAAe,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrF;AAED,iBAAe,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BvE;AAcD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { register } from "tsx/esm/api";
|
|
5
|
+
import { Actor, registerActorClass } from "../shared/actor.js";
|
|
6
|
+
import { ActorConfigurationError, ActorDefinitionError } from "../shared/errors.js";
|
|
7
|
+
const DEFAULT_ACTOR_ENTRYPOINT = "src/durable-objects.ts";
|
|
8
|
+
async function resolveActorEntrypoint(configured) {
|
|
9
|
+
const entrypointPath = path.resolve(configured ?? DEFAULT_ACTOR_ENTRYPOINT);
|
|
10
|
+
await requireFile(entrypointPath, configured === undefined ? `default actor entrypoint ${DEFAULT_ACTOR_ENTRYPOINT}` : `configured actor entrypoint ${configured}`);
|
|
11
|
+
return pathToFileURL(entrypointPath).href;
|
|
12
|
+
}
|
|
13
|
+
async function loadActorEntrypoint(moduleUrl) {
|
|
14
|
+
const unregister = register();
|
|
15
|
+
let actorModule;
|
|
16
|
+
try {
|
|
17
|
+
actorModule = (await import(moduleUrl));
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
await unregister();
|
|
21
|
+
}
|
|
22
|
+
const exports = Object.entries(actorModule);
|
|
23
|
+
if (exports.length === 0) {
|
|
24
|
+
throw new ActorDefinitionError(`actor entrypoint ${moduleUrl} has no named actor exports`);
|
|
25
|
+
}
|
|
26
|
+
const actorTypes = exports.map(([exportName, value]) => {
|
|
27
|
+
if (exportName === "default") {
|
|
28
|
+
throw new ActorDefinitionError("actor entrypoint must use named exports, not a default export");
|
|
29
|
+
}
|
|
30
|
+
if (typeof value !== "function" || value.prototype === undefined || Object.getPrototypeOf(value.prototype) !== Actor.prototype) {
|
|
31
|
+
throw new ActorDefinitionError(`actor entrypoint export ${exportName} must be a class that directly extends Actor`);
|
|
32
|
+
}
|
|
33
|
+
if (value.name !== exportName) {
|
|
34
|
+
throw new ActorDefinitionError(`actor entrypoint export ${exportName} must have the same class name`);
|
|
35
|
+
}
|
|
36
|
+
return registerActorClass(value).actorType;
|
|
37
|
+
});
|
|
38
|
+
actorTypes.sort();
|
|
39
|
+
return actorTypes;
|
|
40
|
+
}
|
|
41
|
+
async function requireFile(filePath, label) {
|
|
42
|
+
if (!(await isFile(filePath)))
|
|
43
|
+
throw new ActorConfigurationError(`${label} is not a file`);
|
|
44
|
+
}
|
|
45
|
+
async function isFile(filePath) {
|
|
46
|
+
try {
|
|
47
|
+
return (await stat(filePath)).isFile();
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export { loadActorEntrypoint, resolveActorEntrypoint };
|
|
54
|
+
//# sourceMappingURL=actorModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actorModule.js","sourceRoot":"","sources":["../../host/actorModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGtC,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAEnF,MAAM,wBAAwB,GAAG,wBAAwB,CAAA;AAEzD,KAAK,UAAU,sBAAsB,CAAC,UAA8B;IAChE,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,wBAAwB,CAAC,CAAA;IAC3E,MAAM,WAAW,CAAC,cAAc,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,4BAA4B,wBAAwB,EAAE,CAAC,CAAC,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAA;IAClK,OAAO,aAAa,CAAC,cAAc,CAAC,CAAC,IAAI,CAAA;AAC7C,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IAChD,MAAM,UAAU,GAAG,QAAQ,EAAE,CAAA;IAC7B,IAAI,WAAoC,CAAA;IACxC,IAAI,CAAC;QACD,WAAW,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAA4B,CAAA;IACtE,CAAC;YAAS,CAAC;QACP,MAAM,UAAU,EAAE,CAAA;IACtB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,oBAAoB,CAAC,oBAAoB,SAAS,6BAA6B,CAAC,CAAA;IAC9F,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,EAAE;QACnD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,oBAAoB,CAAC,+DAA+D,CAAC,CAAA;QACnG,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,UAAU,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC,SAAS,EAAE,CAAC;YAC7H,MAAM,IAAI,oBAAoB,CAAC,2BAA2B,UAAU,8CAA8C,CAAC,CAAA;QACvH,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,oBAAoB,CAAC,2BAA2B,UAAU,gCAAgC,CAAC,CAAA;QACzG,CAAC;QACD,OAAO,kBAAkB,CAAC,KAAmB,CAAC,CAAC,SAAS,CAAA;IAC5D,CAAC,CAAC,CAAA;IACF,UAAU,CAAC,IAAI,EAAE,CAAA;IACjB,OAAO,UAAU,CAAA;AACrB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,KAAa;IACtD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAAE,MAAM,IAAI,uBAAuB,CAAC,GAAG,KAAK,gBAAgB,CAAC,CAAA;AAC9F,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB;IAClC,IAAI,CAAC;QACD,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAA;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare class ActorSession {
|
|
2
|
+
private readonly settings;
|
|
3
|
+
private startup;
|
|
4
|
+
private connection;
|
|
5
|
+
constructor(settings?: ActorSessionSettings);
|
|
6
|
+
start(): Promise<void>;
|
|
7
|
+
waitUntilDisconnected(): Promise<void>;
|
|
8
|
+
private initialize;
|
|
9
|
+
}
|
|
10
|
+
declare class ActorSessionSettings {
|
|
11
|
+
readonly socketPath: string;
|
|
12
|
+
readonly actorEntrypoint: string | undefined;
|
|
13
|
+
readonly startupTimeoutMs: number;
|
|
14
|
+
readonly actorIdleTimeoutMs: number;
|
|
15
|
+
private constructor();
|
|
16
|
+
static fromEnvironment(environment: NodeJS.ProcessEnv): ActorSessionSettings;
|
|
17
|
+
}
|
|
18
|
+
declare function runActorHost(): Promise<never>;
|
|
19
|
+
export { ActorSession, ActorSessionSettings, runActorHost };
|
|
20
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../host/session.ts"],"names":[],"mappings":"AAqBA,cAAM,YAAY;IAIF,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAHrC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,UAAU,CAAoC;gBAEzB,QAAQ,uBAAoD;IAEzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;YAKxB,UAAU;CAU3B;AAED,cAAM,oBAAoB;IAElB,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM;IACjC,QAAQ,CAAC,kBAAkB,EAAE,MAAM;IAJvC,OAAO;IAOP,MAAM,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,GAAG,oBAAoB;CAU/E;AAED,iBAAe,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC,CAS5C;AAqKD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { createConnection } from "node:net";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { ActorConfigurationError, ActorProtocolError, ActorSessionError } from "../shared/errors.js";
|
|
5
|
+
import { parseActorSessionServerMessage } from "../shared/types.js";
|
|
6
|
+
import { loadActorEntrypoint, resolveActorEntrypoint } from "./actorModule.js";
|
|
7
|
+
import { ActorWorkerSupervisor } from "./worker/supervisor.js";
|
|
8
|
+
const DEFAULT_ACTOR_STARTUP_TIMEOUT_MS = 10_000;
|
|
9
|
+
const DEFAULT_ACTOR_IDLE_TIMEOUT_MS = 60_000;
|
|
10
|
+
const MAX_IDLE_TIMEOUT_MS = 86_400_000;
|
|
11
|
+
const MAX_MESSAGE_BYTES = 16 * 1024 * 1024;
|
|
12
|
+
const actorSessionSettingsSchema = z.object({
|
|
13
|
+
DURABLE_OBJECT_EXECUTOR_SOCKET: z.string().trim().min(1),
|
|
14
|
+
DURABLE_OBJECT_ENTRYPOINT: z.string().trim().min(1).optional()
|
|
15
|
+
});
|
|
16
|
+
class ActorSession {
|
|
17
|
+
settings;
|
|
18
|
+
startup;
|
|
19
|
+
connection;
|
|
20
|
+
constructor(settings = ActorSessionSettings.fromEnvironment(process.env)) {
|
|
21
|
+
this.settings = settings;
|
|
22
|
+
}
|
|
23
|
+
start() {
|
|
24
|
+
this.startup ??= this.initialize();
|
|
25
|
+
return this.startup;
|
|
26
|
+
}
|
|
27
|
+
waitUntilDisconnected() {
|
|
28
|
+
if (this.connection === undefined)
|
|
29
|
+
throw new ActorSessionError("actor session has not started");
|
|
30
|
+
return this.connection.closed();
|
|
31
|
+
}
|
|
32
|
+
async initialize() {
|
|
33
|
+
const actorEntrypointUrl = await resolveActorEntrypoint(this.settings.actorEntrypoint);
|
|
34
|
+
const actorTypes = await loadActorEntrypoint(actorEntrypointUrl);
|
|
35
|
+
const supervisor = new ActorWorkerSupervisor({
|
|
36
|
+
actorEntrypointUrl,
|
|
37
|
+
actorIdleTimeoutMs: this.settings.actorIdleTimeoutMs
|
|
38
|
+
});
|
|
39
|
+
const commandHandler = (command) => supervisor.handle(command);
|
|
40
|
+
this.connection = await ActorSessionConnection.open(this.settings.socketPath, actorTypes, commandHandler, this.settings.startupTimeoutMs);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class ActorSessionSettings {
|
|
44
|
+
socketPath;
|
|
45
|
+
actorEntrypoint;
|
|
46
|
+
startupTimeoutMs;
|
|
47
|
+
actorIdleTimeoutMs;
|
|
48
|
+
constructor(socketPath, actorEntrypoint, startupTimeoutMs, actorIdleTimeoutMs) {
|
|
49
|
+
this.socketPath = socketPath;
|
|
50
|
+
this.actorEntrypoint = actorEntrypoint;
|
|
51
|
+
this.startupTimeoutMs = startupTimeoutMs;
|
|
52
|
+
this.actorIdleTimeoutMs = actorIdleTimeoutMs;
|
|
53
|
+
}
|
|
54
|
+
static fromEnvironment(environment) {
|
|
55
|
+
const result = actorSessionSettingsSchema.safeParse(environment);
|
|
56
|
+
if (!result.success)
|
|
57
|
+
throw new ActorConfigurationError(`actor-host session settings are invalid: ${result.error.message}`);
|
|
58
|
+
return new ActorSessionSettings(result.data.DURABLE_OBJECT_EXECUTOR_SOCKET, result.data.DURABLE_OBJECT_ENTRYPOINT, parseStartupTimeout(environment.DURABLE_OBJECT_HOST_STARTUP_MS), parseActorIdleTimeout(environment.DURABLE_OBJECT_ACTOR_IDLE_TIMEOUT_MS));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function runActorHost() {
|
|
62
|
+
const session = new ActorSession();
|
|
63
|
+
await session.start();
|
|
64
|
+
const readyFile = process.env.DURABLE_OBJECT_HOST_READY_FILE;
|
|
65
|
+
if (readyFile)
|
|
66
|
+
await writeFile(readyFile, `${Date.now()}\n`, { mode: 0o600 });
|
|
67
|
+
await session.waitUntilDisconnected();
|
|
68
|
+
throw new ActorSessionError("Rust host disconnected from actor session");
|
|
69
|
+
}
|
|
70
|
+
class ActorSessionConnection {
|
|
71
|
+
socket;
|
|
72
|
+
commandHandler;
|
|
73
|
+
buffer = "";
|
|
74
|
+
attachedResolve;
|
|
75
|
+
attachedReject;
|
|
76
|
+
attachedPromise;
|
|
77
|
+
closedResolve;
|
|
78
|
+
closedPromise;
|
|
79
|
+
static async open(socketPath, actorTypes, commandHandler, timeoutMs) {
|
|
80
|
+
if (actorTypes.length === 0)
|
|
81
|
+
throw new ActorSessionError("the actor entrypoint does not export any actor classes");
|
|
82
|
+
const socket = await connectSocket(socketPath);
|
|
83
|
+
const connection = new ActorSessionConnection(socket, commandHandler);
|
|
84
|
+
connection.send({ type: "attach", protocol: 11, actor_types: actorTypes });
|
|
85
|
+
await connection.waitUntilAttached(timeoutMs);
|
|
86
|
+
return connection;
|
|
87
|
+
}
|
|
88
|
+
closed() {
|
|
89
|
+
return this.closedPromise;
|
|
90
|
+
}
|
|
91
|
+
constructor(socket, commandHandler) {
|
|
92
|
+
this.socket = socket;
|
|
93
|
+
this.commandHandler = commandHandler;
|
|
94
|
+
this.attachedPromise = new Promise((resolve, reject) => {
|
|
95
|
+
this.attachedResolve = resolve;
|
|
96
|
+
this.attachedReject = reject;
|
|
97
|
+
});
|
|
98
|
+
this.closedPromise = new Promise(resolve => {
|
|
99
|
+
this.closedResolve = resolve;
|
|
100
|
+
});
|
|
101
|
+
this.bindSocket();
|
|
102
|
+
}
|
|
103
|
+
waitUntilAttached(timeoutMs) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const timeout = setTimeout(() => {
|
|
106
|
+
const error = new ActorSessionError(`actor session attachment timed out after ${timeoutMs}ms`);
|
|
107
|
+
this.fail(error);
|
|
108
|
+
reject(error);
|
|
109
|
+
}, timeoutMs);
|
|
110
|
+
void this.attachedPromise.then(() => {
|
|
111
|
+
clearTimeout(timeout);
|
|
112
|
+
resolve();
|
|
113
|
+
}, error => {
|
|
114
|
+
clearTimeout(timeout);
|
|
115
|
+
reject(error);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
bindSocket() {
|
|
120
|
+
this.socket.setEncoding("utf8");
|
|
121
|
+
this.socket.on("data", (chunk) => this.acceptChunk(chunk));
|
|
122
|
+
this.socket.once("error", error => this.fail(error));
|
|
123
|
+
this.socket.once("close", () => this.close());
|
|
124
|
+
}
|
|
125
|
+
acceptChunk(chunk) {
|
|
126
|
+
this.buffer += chunk;
|
|
127
|
+
if (Buffer.byteLength(this.buffer) > MAX_MESSAGE_BYTES) {
|
|
128
|
+
this.fail(new ActorProtocolError("actor session message is too large"));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
let newline = this.buffer.indexOf("\n");
|
|
132
|
+
while (newline !== -1) {
|
|
133
|
+
const document = this.buffer.slice(0, newline);
|
|
134
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
135
|
+
void this.handle(document);
|
|
136
|
+
newline = this.buffer.indexOf("\n");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async handle(document) {
|
|
140
|
+
try {
|
|
141
|
+
const message = parseActorSessionServerMessage(document);
|
|
142
|
+
switch (message.type) {
|
|
143
|
+
case "attached":
|
|
144
|
+
this.attachedResolve?.();
|
|
145
|
+
this.attachedResolve = undefined;
|
|
146
|
+
this.attachedReject = undefined;
|
|
147
|
+
break;
|
|
148
|
+
case "command":
|
|
149
|
+
this.send({
|
|
150
|
+
type: "reply",
|
|
151
|
+
message_id: message.message_id,
|
|
152
|
+
reply: await this.commandHandler(message.command)
|
|
153
|
+
});
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
throw message;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
this.fail(sessionError(error));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
send(message) {
|
|
164
|
+
const document = `${JSON.stringify(message)}\n`;
|
|
165
|
+
if (Buffer.byteLength(document) > MAX_MESSAGE_BYTES)
|
|
166
|
+
throw new ActorSessionError("actor session message is too large");
|
|
167
|
+
this.socket.write(document);
|
|
168
|
+
}
|
|
169
|
+
fail(error) {
|
|
170
|
+
this.attachedReject?.(error);
|
|
171
|
+
this.attachedResolve = undefined;
|
|
172
|
+
this.attachedReject = undefined;
|
|
173
|
+
this.socket.destroy();
|
|
174
|
+
}
|
|
175
|
+
close() {
|
|
176
|
+
this.attachedReject?.(new ActorSessionError("Rust host disconnected from actor session"));
|
|
177
|
+
this.attachedResolve = undefined;
|
|
178
|
+
this.attachedReject = undefined;
|
|
179
|
+
this.closedResolve?.();
|
|
180
|
+
this.closedResolve = undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function connectSocket(socketPath) {
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
const socket = createConnection(socketPath);
|
|
186
|
+
const onError = (error) => {
|
|
187
|
+
socket.off("connect", onConnect);
|
|
188
|
+
socket.destroy();
|
|
189
|
+
reject(new ActorSessionError(`could not attach to Rust host at ${socketPath}`, { cause: error }));
|
|
190
|
+
};
|
|
191
|
+
const onConnect = () => {
|
|
192
|
+
socket.off("error", onError);
|
|
193
|
+
resolve(socket);
|
|
194
|
+
};
|
|
195
|
+
socket.once("error", onError);
|
|
196
|
+
socket.once("connect", onConnect);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function sessionError(error) {
|
|
200
|
+
return error instanceof Error ? error : new ActorSessionError(String(error));
|
|
201
|
+
}
|
|
202
|
+
function parseStartupTimeout(value) {
|
|
203
|
+
if (value === undefined)
|
|
204
|
+
return DEFAULT_ACTOR_STARTUP_TIMEOUT_MS;
|
|
205
|
+
const parsed = Number(value);
|
|
206
|
+
if (!Number.isInteger(parsed) || parsed <= 0)
|
|
207
|
+
throw new ActorConfigurationError("DURABLE_OBJECT_HOST_STARTUP_MS must be a positive integer");
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
function parseActorIdleTimeout(value) {
|
|
211
|
+
if (value === undefined)
|
|
212
|
+
return DEFAULT_ACTOR_IDLE_TIMEOUT_MS;
|
|
213
|
+
const parsed = Number(value);
|
|
214
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || parsed > MAX_IDLE_TIMEOUT_MS) {
|
|
215
|
+
throw new ActorConfigurationError(`DURABLE_OBJECT_ACTOR_IDLE_TIMEOUT_MS must be an integer between 1 and ${MAX_IDLE_TIMEOUT_MS}`);
|
|
216
|
+
}
|
|
217
|
+
return parsed;
|
|
218
|
+
}
|
|
219
|
+
export { ActorSession, ActorSessionSettings, runActorHost };
|
|
220
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../host/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../../../host/worker/entrypoint.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
2
|
+
import { findActorDefinition } from "../../shared/actor.js";
|
|
3
|
+
import { errorMessage, failedReply } from "../../shared/types.js";
|
|
4
|
+
import { loadActorEntrypoint } from "../actorModule.js";
|
|
5
|
+
import { ActorRuntime } from "./runtime.js";
|
|
6
|
+
const port = parentPort;
|
|
7
|
+
if (port === null)
|
|
8
|
+
throw new Error("actor Worker requires a parent message port");
|
|
9
|
+
const data = workerData;
|
|
10
|
+
try {
|
|
11
|
+
await loadActorEntrypoint(data.moduleUrl);
|
|
12
|
+
const definition = findActorDefinition(data.actorType);
|
|
13
|
+
if (definition === undefined)
|
|
14
|
+
throw new Error(`actor entrypoint ${data.moduleUrl} does not export ${data.actorType}`);
|
|
15
|
+
const runtime = new ActorRuntime(definition);
|
|
16
|
+
port.on("message", (message) => {
|
|
17
|
+
void runtime.handle(message.command).then(reply => post(reply), error => post(failedReply("actor_worker_failed", errorMessage(error))));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
post(failedReply("actor_worker_failed", errorMessage(error)));
|
|
22
|
+
}
|
|
23
|
+
function post(reply) {
|
|
24
|
+
port.postMessage(reply);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=entrypoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint.js","sourceRoot":"","sources":["../../../host/worker/entrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,MAAM,IAAI,GAAG,UAAU,CAAA;AACvB,IAAI,IAAI,KAAK,IAAI;IAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;AAEjF,MAAM,IAAI,GAAG,UAA6B,CAAA;AAC1C,IAAI,CAAC;IACD,MAAM,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACzC,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACtD,IAAI,UAAU,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,oBAAoB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IACrH,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAA;IAE5C,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAA2B,EAAE,EAAE;QAC/C,KAAK,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CACrC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EACpB,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CACzE,CAAA;IACL,CAAC,CAAC,CAAA;AACN,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACb,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,IAAI,CAAC,KAAyB;IACnC,IAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ActorDefinition } from "../../shared/actor.js";
|
|
2
|
+
import type { ActorExecutorReply, InvokeCommand } from "../../shared/types.js";
|
|
3
|
+
declare class ActorRuntime {
|
|
4
|
+
private readonly definition;
|
|
5
|
+
private readonly serializer;
|
|
6
|
+
private instance;
|
|
7
|
+
private identity;
|
|
8
|
+
constructor(definition: ActorDefinition);
|
|
9
|
+
handle(command: InvokeCommand): Promise<ActorExecutorReply>;
|
|
10
|
+
private invoke;
|
|
11
|
+
private createInstance;
|
|
12
|
+
}
|
|
13
|
+
export { ActorRuntime };
|
|
14
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../host/worker/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAK5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAyB,MAAM,uBAAuB,CAAA;AAErG,cAAM,YAAY;IAKF,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiC;IAC5D,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,QAAQ,CAA2B;gBAEd,UAAU,EAAE,eAAe;IAElD,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC;YAInD,MAAM;IAiCpB,OAAO,CAAC,cAAc;CAQzB;AA+BD,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { bindActorIdentity } from "../../shared/actor.js";
|
|
2
|
+
import { ActorProtocolError } from "../../shared/errors.js";
|
|
3
|
+
import { runInActorInvocation } from "../../shared/invocationContext.js";
|
|
4
|
+
import { JsonActorStateSerializer, errorMessage, failedReply } from "../../shared/types.js";
|
|
5
|
+
class ActorRuntime {
|
|
6
|
+
definition;
|
|
7
|
+
serializer = new JsonActorStateSerializer();
|
|
8
|
+
instance;
|
|
9
|
+
identity;
|
|
10
|
+
constructor(definition) {
|
|
11
|
+
this.definition = definition;
|
|
12
|
+
}
|
|
13
|
+
async handle(command) {
|
|
14
|
+
return this.invoke(command);
|
|
15
|
+
}
|
|
16
|
+
async invoke(command) {
|
|
17
|
+
const identity = identityFrom(command.actor);
|
|
18
|
+
if (identity.actorType !== this.definition.actorType) {
|
|
19
|
+
return failedReply("actor_type_not_found", `actor type ${identity.actorType} is not loaded in this customer process`);
|
|
20
|
+
}
|
|
21
|
+
if (this.identity !== undefined && identityKey(this.identity) !== identityKey(identity)) {
|
|
22
|
+
return failedReply("actor_identity_mismatch", "resident actor Worker received an invocation for a different actor");
|
|
23
|
+
}
|
|
24
|
+
const instance = this.instance ?? this.createInstance(identity, command.state);
|
|
25
|
+
if (!this.definition.methods.has(command.method)) {
|
|
26
|
+
return failedReply("method_not_found", `actor method ${this.definition.actorType}.${command.method} was not found`);
|
|
27
|
+
}
|
|
28
|
+
const method = Reflect.get(instance, command.method);
|
|
29
|
+
if (typeof method !== "function") {
|
|
30
|
+
return failedReply("method_not_callable", `actor method ${this.definition.actorType}.${command.method} is not callable`);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const rawResult = await runInActorInvocation(async () => Reflect.apply(method, instance, command.args));
|
|
34
|
+
const result = rawResult === undefined ? null : this.serializer.clone(rawResult, "actor result");
|
|
35
|
+
return {
|
|
36
|
+
type: "invoked",
|
|
37
|
+
result,
|
|
38
|
+
state: this.serializer.snapshot(instance)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
this.instance = undefined;
|
|
43
|
+
this.identity = undefined;
|
|
44
|
+
return failedReply("actor_method_failed", errorMessage(error));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
createInstance(identity, state) {
|
|
48
|
+
const instance = Reflect.construct(this.definition.actorClass, []);
|
|
49
|
+
bindActorIdentity(instance, identity.actorId);
|
|
50
|
+
if (state !== null)
|
|
51
|
+
this.serializer.hydrate(instance, persistedState(state));
|
|
52
|
+
this.identity = identity;
|
|
53
|
+
this.instance = instance;
|
|
54
|
+
return instance;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function persistedState(value) {
|
|
58
|
+
if (!isJsonObject(value)) {
|
|
59
|
+
throw new ActorProtocolError("persisted actor state must be a JSON object");
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
function isJsonObject(value) {
|
|
64
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65
|
+
}
|
|
66
|
+
function identityFrom(value) {
|
|
67
|
+
return {
|
|
68
|
+
namespaceId: value.namespace_id,
|
|
69
|
+
actorType: value.actor_type,
|
|
70
|
+
actorId: value.actor_id
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function identityKey(value) {
|
|
74
|
+
return `${value.namespaceId}\u001f${value.actorType}\u001f${value.actorId}`;
|
|
75
|
+
}
|
|
76
|
+
export { ActorRuntime };
|
|
77
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../host/worker/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ActorExecutorCommand, ActorExecutorReply } from "../../shared/types.js";
|
|
2
|
+
declare const DEFAULT_ACTOR_IDLE_TIMEOUT_MS = 60000;
|
|
3
|
+
declare const MAX_RESIDENT_ACTORS = 32;
|
|
4
|
+
declare class ActorWorkerSupervisor {
|
|
5
|
+
private readonly actorEntrypointUrl;
|
|
6
|
+
private readonly actorIdleTimeoutMs;
|
|
7
|
+
private readonly actors;
|
|
8
|
+
constructor(options: ActorWorkerSupervisorOptions);
|
|
9
|
+
handle(command: ActorExecutorCommand): Promise<ActorExecutorReply>;
|
|
10
|
+
private invoke;
|
|
11
|
+
private evict;
|
|
12
|
+
private makeRoomForActor;
|
|
13
|
+
private removeIfCurrent;
|
|
14
|
+
}
|
|
15
|
+
interface ActorWorkerSupervisorOptions {
|
|
16
|
+
readonly actorEntrypointUrl: string;
|
|
17
|
+
readonly actorIdleTimeoutMs?: number;
|
|
18
|
+
}
|
|
19
|
+
export { ActorWorkerSupervisor, DEFAULT_ACTOR_IDLE_TIMEOUT_MS, MAX_RESIDENT_ACTORS };
|
|
20
|
+
export type { ActorWorkerSupervisorOptions };
|
|
21
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../../host/worker/supervisor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAoE,MAAM,uBAAuB,CAAA;AAEvJ,QAAA,MAAM,6BAA6B,QAAS,CAAA;AAC5C,QAAA,MAAM,mBAAmB,KAAK,CAAA;AAE9B,cAAM,qBAAqB;IACvB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;gBAEpD,OAAO,EAAE,4BAA4B;IAQ3C,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAWxE,OAAO,CAAC,MAAM;IAsBd,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;CAK1B;AAyHD,UAAU,4BAA4B;IAClC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACvC;AASD,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,mBAAmB,EAAE,CAAA;AACpF,YAAY,EAAE,4BAA4B,EAAE,CAAA"}
|