diff --git a/src/workerd/api/actor-state.c++ b/src/workerd/api/actor-state.c++ index 3052c90c99f..60ec4fa5ce7 100644 --- a/src/workerd/api/actor-state.c++ +++ b/src/workerd/api/actor-state.c++ @@ -826,9 +826,11 @@ kj::OneOf, kj::StringPtr> ActorState::getId() { } DurableObjectState::DurableObjectState(Worker::Actor::Id actorId, + jsg::JsRef exports, kj::Maybe> storage, kj::Maybe container) : id(kj::mv(actorId)), + exports(kj::mv(exports)), storage(kj::mv(storage)), container(container.map( [&](rpc::Container::Client& cap) { return jsg::alloc(kj::mv(cap)); })) {} diff --git a/src/workerd/api/actor-state.h b/src/workerd/api/actor-state.h index 3c21f7019be..0a8cdf28aa2 100644 --- a/src/workerd/api/actor-state.h +++ b/src/workerd/api/actor-state.h @@ -464,11 +464,16 @@ class WebSocketRequestResponsePair: public jsg::Object { class DurableObjectState: public jsg::Object { public: DurableObjectState(Worker::Actor::Id actorId, + jsg::JsRef exports, kj::Maybe> storage, kj::Maybe container); void waitUntil(kj::Promise promise); + jsg::JsValue getExports(jsg::Lock& js) { + return exports.getHandle(js); + } + kj::OneOf, kj::StringPtr> getId(); jsg::Optional> getStorage() { @@ -541,6 +546,11 @@ class DurableObjectState: public jsg::Object { JSG_RESOURCE_TYPE(DurableObjectState, CompatibilityFlags::Reader flags) { JSG_METHOD(waitUntil); + if (flags.getWorkerdExperimental()) { + // TODO(soon): Remove experimental gate as soon as we've wired up the control plane so that + // this works in production. + JSG_LAZY_INSTANCE_PROPERTY(exports, getExports); + } JSG_LAZY_INSTANCE_PROPERTY(id, getId); JSG_LAZY_INSTANCE_PROPERTY(storage, getStorage); JSG_LAZY_INSTANCE_PROPERTY(container, getContainer); @@ -581,6 +591,7 @@ class DurableObjectState: public jsg::Object { private: Worker::Actor::Id id; + jsg::JsRef exports; kj::Maybe> storage; kj::Maybe> container; diff --git a/src/workerd/io/worker.c++ b/src/workerd/io/worker.c++ index 739c0e95154..bf2983ab66e 100644 --- a/src/workerd/io/worker.c++ +++ b/src/workerd/io/worker.c++ @@ -3454,7 +3454,10 @@ void Worker::Actor::ensureConstructed(IoContext& context) { storage = impl->makeStorage(lock, worker->getIsolate().getApi(), *c); } auto handler = info.cls(lock, - jsg::alloc(cloneId(), kj::mv(storage), kj::mv(impl->container)), + jsg::alloc(cloneId(), + jsg::JsRef( + js, KJ_ASSERT_NONNULL(lock.getWorker().impl->ctxExports).addRef(js)), + kj::mv(storage), kj::mv(impl->container)), KJ_ASSERT_NONNULL(lock.getWorker().impl->env).addRef(js)); // HACK: We set handler.env to undefined because we already passed the real env into the diff --git a/src/workerd/server/server-test.c++ b/src/workerd/server/server-test.c++ index 6c73b6a3293..92ee1f5126b 100644 --- a/src/workerd/server/server-test.c++ +++ b/src/workerd/server/server-test.c++ @@ -4032,6 +4032,7 @@ KJ_TEST("Server: ctx.exports self-referential bindings") { ` await ctx.exports.AnotherEntrypoint.bar(321), ` await actor.baz(), ` await ctx.exports.default.corge(555), + ` await actor.grault(456), ` "UnconfiguredActor" in ctx.exports, // should be false ` ].join(", ")); ` }, @@ -4039,6 +4040,7 @@ KJ_TEST("Server: ctx.exports self-referential bindings") { `} `export class MyEntrypoint extends WorkerEntrypoint { ` foo(i) { return `foo: ${i}` } + ` grault(i) { return `grault: ${i}` } `} `export class AnotherEntrypoint extends WorkerEntrypoint { ` bar(i) { return `bar: ${i}` } @@ -4046,6 +4048,7 @@ KJ_TEST("Server: ctx.exports self-referential bindings") { `export class MyActor extends DurableObject { ` setValue(i) { this.value = i; } ` baz() { return `baz: ${this.value}` } + ` grault(i) { return this.ctx.exports.MyEntrypoint.grault(i); } `} `export class UnconfiguredActor extends DurableObject { ` qux(i) { return `qux: ${i}` } @@ -4078,7 +4081,7 @@ KJ_TEST("Server: ctx.exports self-referential bindings") { test.start(); auto conn = test.connect("test-addr"); - conn.httpGet200("/", "foo: 123, bar: 321, baz: 234, corge: 555, false"); + conn.httpGet200("/", "foo: 123, bar: 321, baz: 234, corge: 555, grault: 456, false"); } // =======================================================================================