Skip to content
File

Blob: src/workerd/server/workerd-api.c++

47.4 KB
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#include "workerd-api.h"
6 
7#include <workerd/api/actor-state.h>
8#include <workerd/api/actor.h>
9#include <workerd/api/analytics-engine.h>
10#include <workerd/api/base64.h>
11#include <workerd/api/cache.h>
12#include <workerd/api/capnp.h>
13#include <workerd/api/commonjs.h>
14#include <workerd/api/container.h>
15#include <workerd/api/crypto/impl.h>
16#include <workerd/api/encoding.h>
17#include <workerd/api/events.h>
18#include <workerd/api/eventsource.h>
19#include <workerd/api/export-loopback.h>
20#include <workerd/api/filesystem.h>
21#include <workerd/api/global-scope.h>
22#include <workerd/api/html-rewriter.h>
23#include <workerd/api/hyperdrive.h>
24#include <workerd/api/kv.h>
25#include <workerd/api/memory-cache.h>
26#include <workerd/api/modules.h>
27#include <workerd/api/node/node.h>
28#include <workerd/api/performance.h>
29#include <workerd/api/pyodide/pyodide.h>
30#include <workerd/api/pyodide/requirements.h>
31#include <workerd/api/queue.h>
32#include <workerd/api/r2.h>
33#include <workerd/api/scheduled.h>
34#include <workerd/api/sockets.h>
35#include <workerd/api/sql.h>
36#include <workerd/api/streams.h>
37#include <workerd/api/streams/standard.h>
38#include <workerd/api/sync-kv.h>
39#include <workerd/api/trace.h>
40#include <workerd/api/tracing.h>
41#include <workerd/api/unsafe.h>
42#include <workerd/api/url-standard.h>
43#include <workerd/api/urlpattern-standard.h>
44#include <workerd/api/urlpattern.h>
45#include <workerd/api/worker-loader.h>
46#include <workerd/api/worker-rpc.h>
47#include <workerd/api/workers-module.h>
48#include <workerd/io/compatibility-date.h>
49#include <workerd/io/promise-wrapper.h>
50#include <workerd/io/worker-modules.h>
51#include <workerd/jsg/jsg.h>
52#include <workerd/jsg/modules-new.h>
53#include <workerd/jsg/setup.h>
54#include <workerd/jsg/url.h>
55#include <workerd/jsg/util.h>
56#ifdef WORKERD_USE_TRANSPILER
57#include <workerd/rust/transpiler/lib.rs.h>
58#endif // defined(WORKERD_USE_TRANSPILER)
59#include <workerd/server/actor-id-impl.h>
60#include <workerd/server/fallback-service.h>
61#include <workerd/server/workerd-debug-port-client.h>
62#include <workerd/util/autogate.h>
63#include <workerd/util/thread-scopes.h>
64#include <workerd/util/use-perfetto-categories.h>
65 
66#include <kj-rs/kj-rs.h>
67#include <pyodide/generated/pyodide_extra.capnp.h>
68#include <pyodide/python-entrypoint.embed.h>
69 
70#include <kj/compat/gzip.h>
71#include <kj/compat/http.h>
72#include <kj/compat/tls.h>
73#include <kj/compat/url.h>
74 
75using namespace kj_rs;
76 
77namespace workerd::server {
78 
79using api::pyodide::PythonConfig;
80 
81namespace {
82JSG_DECLARE_ISOLATE_TYPE(JsgWorkerdIsolate,
83 // Declares the listing of host object types and structs that the jsg
84 // automatic type mapping will understand. Each of the various
85 // NNNN_ISOLATE_TYPES macros are defined in different header files
86 // (e.g. GLOBAL_SCOPE_ISOLATE_TYPES is defined in api/global-scope.h).
87 //
88 // Global scope types are defined first just by convention, the rest
89 // of the list is in alphabetical order for easier readability (the
90 // actual order of the items is unimportant), followed by additional
91 // types defined in worker.c++ or as part of jsg.
92 //
93 // When adding a new NNNN_ISOLATE_TYPES macro, remember to add it to
94 // src/workerd/api/rtti.c++ too (and tools/api-encoder.c++ for the
95 // time being), so it gets included in the TypeScript types.
96 EW_GLOBAL_SCOPE_ISOLATE_TYPES,
97 
98 EW_ACTOR_ISOLATE_TYPES,
99 EW_ACTOR_STATE_ISOLATE_TYPES,
100 EW_ANALYTICS_ENGINE_ISOLATE_TYPES,
101 EW_BASE64_ISOLATE_TYPES,
102 EW_BASICS_ISOLATE_TYPES,
103 EW_BLOB_ISOLATE_TYPES,
104 EW_CACHE_ISOLATE_TYPES,
105 EW_CAPNP_TYPES,
106 EW_CONTAINER_ISOLATE_TYPES,
107 EW_CJS_ISOLATE_TYPES,
108 EW_CRYPTO_ISOLATE_TYPES,
109 EW_ENCODING_ISOLATE_TYPES,
110 EW_EVENTS_ISOLATE_TYPES,
111 EW_FORMDATA_ISOLATE_TYPES,
112 EW_HTML_REWRITER_ISOLATE_TYPES,
113 EW_HTTP_ISOLATE_TYPES,
114 EW_SOCKETS_ISOLATE_TYPES,
115 EW_KV_ISOLATE_TYPES,
116 EW_PYODIDE_ISOLATE_TYPES,
117 EW_QUEUE_ISOLATE_TYPES,
118 EW_R2_PUBLIC_BETA_ISOLATE_TYPES,
119 EW_WORKER_RPC_ISOLATE_TYPES,
120 EW_SCHEDULED_ISOLATE_TYPES,
121 EW_STREAMS_ISOLATE_TYPES,
122 EW_TRACE_ISOLATE_TYPES,
123 EW_UNSAFE_ISOLATE_TYPES,
124 EW_MEMORY_CACHE_ISOLATE_TYPES,
125 EW_URL_ISOLATE_TYPES,
126 EW_URL_STANDARD_ISOLATE_TYPES,
127 EW_URLPATTERN_ISOLATE_TYPES,
128 EW_URLPATTERN_STANDARD_ISOLATE_TYPES,
129 EW_WEB_FILESYSTEM_ISOLATE_TYPE,
130 EW_FILESYSTEM_ISOLATE_TYPES,
131 EW_WEBSOCKET_ISOLATE_TYPES,
132 EW_SQL_ISOLATE_TYPES,
133 EW_SYNC_KV_ISOLATE_TYPES,
134 EW_NODE_ISOLATE_TYPES,
135 EW_RTTI_ISOLATE_TYPES,
136 EW_HYPERDRIVE_ISOLATE_TYPES,
137 EW_EVENTSOURCE_ISOLATE_TYPES,
138 EW_WORKER_LOADER_ISOLATE_TYPES,
139 EW_MESSAGECHANNEL_ISOLATE_TYPES,
140 EW_WORKERS_MODULE_ISOLATE_TYPES,
141 EW_EXPORT_LOOPBACK_ISOLATE_TYPES,
142 EW_PERFORMANCE_ISOLATE_TYPES,
143 EW_TRACING_ISOLATE_TYPES,
144 EW_WORKERD_DEBUG_PORT_CLIENT_ISOLATE_TYPES,
145 workerd::api::EnvModule,
146 workerd::api::PythonPatchedEnv,
147 
148 jsg::TypeWrapperExtension<PromiseWrapper>,
149 jsg::InjectConfiguration<CompatibilityFlags::Reader>,
150 Worker::Api::ErrorInterface);
151 
152static const PythonConfig defaultConfig{
153 .packageDiskCacheRoot = kj::none,
154 .pyodideDiskCacheRoot = kj::none,
155 .createSnapshot = false,
156 .createBaselineSnapshot = false,
157};
158 
159// An ActorStorage implementation which will always respond to reads as if the state is empty,
160// and will fail any writes.
161class EmptyReadOnlyActorStorageImpl final: public rpc::ActorStorage::Stage::Server {
162 public:
163 kj::Promise<void> get(GetContext context) override {
164 return kj::READY_NOW;
165 }
166 kj::Promise<void> getMultiple(GetMultipleContext context) override {
167 return context.getParams()
168 .getStream()
169 .endRequest(capnp::MessageSize{2, 0})
170 .sendIgnoringResult();
171 }
172 kj::Promise<void> list(ListContext context) override {
173 return context.getParams()
174 .getStream()
175 .endRequest(capnp::MessageSize{2, 0})
176 .sendIgnoringResult();
177 }
178 kj::Promise<void> getAlarm(GetAlarmContext context) override {
179 return kj::READY_NOW;
180 }
181 kj::Promise<void> txn(TxnContext context) override {
182 auto results = context.getResults(capnp::MessageSize{2, 1});
183 results.setTransaction(kj::heap<TransactionImpl>());
184 return kj::READY_NOW;
185 }
186 
187 private:
188 class TransactionImpl final: public rpc::ActorStorage::Stage::Transaction::Server {
189 protected:
190 kj::Promise<void> get(GetContext context) override {
191 return kj::READY_NOW;
192 }
193 kj::Promise<void> getMultiple(GetMultipleContext context) override {
194 return context.getParams()
195 .getStream()
196 .endRequest(capnp::MessageSize{2, 0})
197 .sendIgnoringResult();
198 }
199 kj::Promise<void> list(ListContext context) override {
200 return context.getParams()
201 .getStream()
202 .endRequest(capnp::MessageSize{2, 0})
203 .sendIgnoringResult();
204 }
205 kj::Promise<void> getAlarm(GetAlarmContext context) override {
206 return kj::READY_NOW;
207 }
208 kj::Promise<void> commit(CommitContext context) override {
209 return kj::READY_NOW;
210 }
211 };
212};
213 
214} // namespace
215 
216/**
217 * This function matches the implementation of `getPythonRequirements` in the internal repo. But it
218 * works on the workerd ModulesSource definition rather than the WorkerBundle.
219 */
220kj::Array<kj::String> getPythonRequirements(const Worker::Script::ModulesSource& source) {
221 kj::Vector<kj::String> requirements;
222 
223 for (auto& def: source.modules) {
224 KJ_SWITCH_ONEOF(def.content) {
225 KJ_CASE_ONEOF(content, Worker::Script::PythonRequirement) {
226 requirements.add(api::pyodide::canonicalizePythonPackageName(def.name));
227 }
228 KJ_CASE_ONEOF_DEFAULT {
229 break;
230 }
231 }
232 }
233 
234 return requirements.releaseAsArray();
235}
236 
237struct WorkerdApi::Impl final {
238 kj::Own<CompatibilityFlags::Reader> features;
239 capnp::List<config::Extension>::Reader extensions;
240 kj::Own<JsgIsolateObserver> observer;
241 JsgWorkerdIsolate jsgIsolate;
242 api::MemoryCacheProvider& memoryCacheProvider;
243 const PythonConfig& pythonConfig;
244 
245 class Configuration {
246 public:
247 Configuration(Impl& impl)
248 : features(*impl.features),
249 jsgConfig(jsg::JsgConfig{
250 .noSubstituteNull = features.getNoSubstituteNull(),
251 .unwrapCustomThenables = features.getUnwrapCustomThenables(),
252 .fetchIterableTypeSupport = features.getFetchIterableTypeSupport(),
253 .fetchIterableTypeSupportOverrideAdjustment =
254 features.getFetchIterableTypeSupportOverrideAdjustment(),
255 .fastApiEnabled = util::Autogate::isEnabled(util::AutogateKey::V8_FAST_API),
256 }) {}
257 operator const CompatibilityFlags::Reader() const {
258 return features;
259 }
260 operator const jsg::JsgConfig&() const {
261 return jsgConfig;
262 }
263 
264 private:
265 CompatibilityFlags::Reader& features;
266 jsg::JsgConfig jsgConfig;
267 };
268 
269 Impl(jsg::V8System& v8System,
270 CompatibilityFlags::Reader featuresParam,
271 capnp::List<config::Extension>::Reader extensionsParam,
272 v8::Isolate::CreateParams createParams,
273 v8::IsolateGroup group,
274 kj::Own<JsgIsolateObserver> observerParam,
275 api::MemoryCacheProvider& memoryCacheProvider,
276 const PythonConfig& pythonConfig = defaultConfig)
277 : features(capnp::clone(featuresParam)),
278 extensions(extensionsParam),
279 observer(kj::atomicAddRef(*observerParam)),
280 jsgIsolate(v8System,
281 group,
282 Configuration(*this),
283 kj::mv(observerParam),
284 jsg::defaultExternalStringAllocator(),
285 kj::mv(createParams)),
286 memoryCacheProvider(memoryCacheProvider),
287 pythonConfig(pythonConfig) {
288 jsgIsolate.runInLockScope([&](JsgWorkerdIsolate::Lock& lock) {
289 if (featuresParam.getNewModuleRegistry()) {
290 jsgIsolate.setUsingNewModuleRegistry();
291 }
292 
293 // Allows us to begin experimenting with eval/new fuction enabled in
294 // preparation for *possibly* enabling it by default in the future
295 // once v8 sandbox is fully enabled and rolled out.
296 if (featuresParam.getExperimentalAllowEvalAlways()) {
297 jsgIsolate.setAllowsAllowEval();
298 }
299 });
300 }
301};
302 
303WorkerdApi::WorkerdApi(jsg::V8System& v8System,
304 CompatibilityFlags::Reader features,
305 capnp::List<config::Extension>::Reader extensions,
306 v8::Isolate::CreateParams createParams,
307 v8::IsolateGroup group,
308 kj::Own<JsgIsolateObserver> observer,
309 api::MemoryCacheProvider& memoryCacheProvider,
310 const PythonConfig& pythonConfig)
311 : impl(kj::heap<Impl>(v8System,
312 features,
313 extensions,
314 kj::mv(createParams),
315 group,
316 kj::mv(observer),
317 memoryCacheProvider,
318 pythonConfig)) {}
319WorkerdApi::~WorkerdApi() noexcept(false) {}
320 
321kj::Own<jsg::Lock> WorkerdApi::lock(jsg::V8StackScope& stackScope) const {
322 return kj::heap<JsgWorkerdIsolate::Lock>(impl->jsgIsolate, stackScope);
323}
324CompatibilityFlags::Reader WorkerdApi::getFeatureFlags() const {
325 return *impl->features;
326}
327jsg::JsContext<api::ServiceWorkerGlobalScope> WorkerdApi::newContext(
328 jsg::Lock& lock, Worker::Api::NewContextOptions options) const {
329 jsg::NewContextOptions opts{
330 .newModuleRegistry = options.newModuleRegistry,
331 .schemaLoader = options.schemaLoader,
332 .enableWeakRef = getFeatureFlags().getJsWeakRef(),
333 };
334 return kj::downcast<JsgWorkerdIsolate::Lock>(lock).newContext<api::ServiceWorkerGlobalScope>(
335 kj::mv(opts));
336}
337jsg::Dict<NamedExport> WorkerdApi::unwrapExports(
338 jsg::Lock& lock, v8::Local<v8::Value> moduleNamespace) const {
339 return kj::downcast<JsgWorkerdIsolate::Lock>(lock).unwrap<jsg::Dict<NamedExport>>(
340 lock.v8Context(), moduleNamespace);
341}
342NamedExport WorkerdApi::unwrapExport(jsg::Lock& lock, v8::Local<v8::Value> exportVal) const {
343 return kj::downcast<JsgWorkerdIsolate::Lock>(lock).unwrap<NamedExport>(
344 lock.v8Context(), exportVal);
345}
346EntrypointClasses WorkerdApi::getEntrypointClasses(jsg::Lock& lock) const {
347 auto& typedLock = kj::downcast<JsgWorkerdIsolate::Lock>(lock);
348 
349 return {
350 .workerEntrypoint = typedLock.getConstructor<api::WorkerEntrypoint>(lock.v8Context()),
351 .durableObject = typedLock.getConstructor<api::DurableObjectBase>(lock.v8Context()),
352 .workflowEntrypoint = typedLock.getConstructor<api::WorkflowEntrypoint>(lock.v8Context()),
353 };
354}
355const jsg::TypeHandler<Worker::Api::ErrorInterface>& WorkerdApi::getErrorInterfaceTypeHandler(
356 jsg::Lock& lock) const {
357 return kj::downcast<JsgWorkerdIsolate::Lock>(lock).getTypeHandler<ErrorInterface>();
358}
359 
360const jsg::TypeHandler<api::QueueExportedHandler>& WorkerdApi::getQueueTypeHandler(
361 jsg::Lock& lock) const {
362 return kj::downcast<JsgWorkerdIsolate::Lock>(lock).getTypeHandler<api::QueueExportedHandler>();
363}
364 
365jsg::JsObject WorkerdApi::wrapExecutionContext(
366 jsg::Lock& lock, jsg::Ref<api::ExecutionContext> ref) const {
367 return jsg::JsObject(
368 kj::downcast<JsgWorkerdIsolate::Lock>(lock).wrap(lock.v8Context(), kj::mv(ref)));
369}
370 
371const jsg::IsolateObserver& WorkerdApi::getObserver() const {
372 return *impl->observer;
373}
374 
375void WorkerdApi::setIsolateObserver(IsolateObserver&) {};
376 
377Worker::Script::Source WorkerdApi::extractSource(kj::StringPtr name,
378 config::Worker::Reader conf,
379 CompatibilityFlags::Reader featureFlags,
380 Worker::ValidationErrorReporter& errorReporter) {
381 TRACE_EVENT("workerd", "WorkerdApi::extractSource()");
382 switch (conf.which()) {
383 case config::Worker::MODULES: {
384 auto modules = conf.getModules();
385 if (modules.size() == 0) {
386 errorReporter.addError(kj::str("Modules list cannot be empty."));
387 goto invalid;
388 }
389 
390 bool isPython = false;
391 auto moduleArray = KJ_MAP(module, modules) -> Worker::Script::Module {
392 if (module.isPythonModule()) {
393 isPython = true;
394 }
395 return readModuleConf(module, featureFlags, errorReporter);
396 };
397 
398 Worker::Script::ModulesSource result{
399 .mainModule = modules[0].getName(), .modules = kj::mv(moduleArray), .isPython = isPython};
400 
401 return result;
402 }
403 case config::Worker::SERVICE_WORKER_SCRIPT: {
404 uint wasmCount = 0;
405 for (auto binding: conf.getBindings()) {
406 if (binding.isWasmModule()) ++wasmCount;
407 }
408 
409 auto globals = kj::heapArrayBuilder<Worker::Script::Module>(wasmCount);
410 for (auto binding: conf.getBindings()) {
411 if (binding.isWasmModule()) {
412 globals.add(Worker::Script::Module{.name = binding.getName(),
413 .content = Worker::Script::WasmModule{.body = binding.getWasmModule()}});
414 }
415 }
416 
417 return Worker::Script::ScriptSource{
418 .mainScript = conf.getServiceWorkerScript(),
419 .mainScriptName = name,
420 .globals = globals.finish(),
421 };
422 }
423 case config::Worker::INHERIT:
424 // TODO(beta): Support inherit.
425 KJ_FAIL_ASSERT("inherit should have been handled earlier");
426 }
427 
428 errorReporter.addError(kj::str("Encountered unknown Worker code type. Was the "
429 "config compiled with a newer version of the schema?"));
430invalid:
431 return Worker::Script::ScriptSource{""_kj, name, nullptr};
432}
433 
434kj::Array<Worker::Script::CompiledGlobal> WorkerdApi::compileServiceWorkerGlobals(jsg::Lock& js,
435 const Worker::Script::ScriptSource& source,
436 const Worker::Isolate& isolate) const {
437 TRACE_EVENT("workerd", "WorkerdApi::compileScriptGlobals()");
438 const jsg::CompilationObserver& observer = *impl->observer;
439 return workerd::modules::legacy::compileServiceWorkerGlobals<JsgWorkerdIsolate>(
440 js, source, isolate, observer);
441}
442 
443namespace {
444kj::Maybe<jsg::ModuleRegistry::ModuleInfo> tryCompileLegacyModule(jsg::Lock& js,
445 kj::StringPtr name,
446 const Worker::Script::ModuleContent& content,
447 const jsg::CompilationObserver& observer,
448 CompatibilityFlags::Reader featureFlags) {
449 return modules::legacy::tryCompileLegacyModule<JsgWorkerdIsolate>(
450 js, name, content, observer, featureFlags);
451}
452} // namespace
453 
454// Part of the original module registry implementation.
455kj::Maybe<jsg::ModuleRegistry::ModuleInfo> WorkerdApi::tryCompileModule(jsg::Lock& js,
456 config::Worker::Module::Reader conf,
457 const jsg::CompilationObserver& observer,
458 CompatibilityFlags::Reader featureFlags) {
459 auto module = readModuleConf(conf, featureFlags);
460 return tryCompileLegacyModule(js, module.name, module.content, observer, featureFlags);
461}
462 
463Worker::Script::Module WorkerdApi::readModuleConf(config::Worker::Module::Reader conf,
464 CompatibilityFlags::Reader featureFlags,
465 kj::Maybe<Worker::ValidationErrorReporter&> errorReporter) {
466 return {.name = conf.getName(), .content = [&]() -> Worker::Script::ModuleContent {
467 switch (conf.which()) {
468 case config::Worker::Module::TEXT:
469 return Worker::Script::TextModule{conf.getText()};
470 case config::Worker::Module::DATA:
471 return Worker::Script::DataModule{conf.getData()};
472 case config::Worker::Module::WASM:
473 return Worker::Script::WasmModule{conf.getWasm()};
474 case config::Worker::Module::JSON:
475 return Worker::Script::JsonModule{conf.getJson()};
476 case config::Worker::Module::ES_MODULE:
477 // TODO(soon): Update this to also support full TS transform
478 // with a separate compat flag.
479#ifdef WORKERD_USE_TRANSPILER
480 if (featureFlags.getTypescriptStripTypes()) {
481 auto output = rust::transpiler::ts_strip(
482 // value comes from capnp so it is a valid utf-8
483 conf.getName().as<RustUncheckedUtf8>(), conf.getEsModule().asBytes().as<Rust>());
484 
485 if (output.success) {
486 return Worker::Script::EsModule{
487 .body = ::kj::from<Rust>(output.code), .ownBody = kj::mv(output.code)};
488 }
489 
490 auto description = kj::str("Error transpiling ", conf.getName(), " : ", output.error);
491 for (auto& diag: output.diagnostics) {
492 description = kj::str(description, "\n ", diag.message);
493 }
494 KJ_IF_SOME(reporter, errorReporter) {
495 reporter.addError(kj::mv(description));
496 return Worker::Script::TextModule{""};
497 } else {
498 KJ_FAIL_REQUIRE(description);
499 }
500 }
501#endif // defined(WORKERD_USE_TRANSPILER)
502 return Worker::Script::EsModule{static_cast<kj::StringPtr>(conf.getEsModule())};
503 case config::Worker::Module::COMMON_JS_MODULE: {
504 Worker::Script::CommonJsModule result{.body = conf.getCommonJsModule()};
505 if (conf.hasNamedExports()) {
506 result.namedExports = KJ_MAP(name, conf.getNamedExports()) -> kj::StringPtr { return name; };
507 }
508 return result;
509 }
510 case config::Worker::Module::PYTHON_MODULE:
511 return Worker::Script::PythonModule{conf.getPythonModule()};
512 case config::Worker::Module::PYTHON_REQUIREMENT:
513 return Worker::Script::PythonRequirement{};
514 case config::Worker::Module::OBSOLETE: {
515 // A non-supported or obsolete module type was configured
516 KJ_FAIL_REQUIRE("Worker bundle specified an unsupported module type");
517 }
518 }
519 
520 KJ_IF_SOME(e, errorReporter) {
521 e.addError(kj::str("Encountered unknown Worker.Module type. Was the "
522 "config compiled with a newer version of the schema?"));
523 return Worker::Script::TextModule{""};
524 } else {
525 KJ_FAIL_REQUIRE("unknown module type", (uint)conf.which());
526 }
527 }()};
528}
529 
530// Part of the original module registry implementation.
531void WorkerdApi::compileModules(jsg::Lock& lockParam,
532 const Worker::Script::ModulesSource& source,
533 const Worker::Isolate& isolate,
534 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts,
535 SpanParent parentSpan) const {
536 TRACE_EVENT("workerd", "WorkerdApi::compileModules()");
537 lockParam.withinHandleScope([&] {
538 auto modules = jsg::ModuleRegistryImpl<JsgWorkerdIsolate_TypeWrapper>::from(lockParam);
539 
540 using namespace workerd::api::pyodide;
541 auto featureFlags = getFeatureFlags();
542 
543 for (auto& module: source.modules) {
544 auto path = kj::Path::parse(module.name);
545 auto maybeInfo = tryCompileLegacyModule(
546 lockParam, module.name, module.content, modules->getObserver(), featureFlags);
547 KJ_IF_SOME(info, maybeInfo) {
548 modules->add(path, kj::mv(info));
549 }
550 }
551 
552 api::registerModules(*modules, featureFlags);
553 
554 if (source.isPython) {
555 modules::python::registerPythonWorkerdModules<JsgWorkerdIsolate>(
556 lockParam, *modules, featureFlags, kj::mv(artifacts), impl->pythonConfig, source);
557 }
558 
559 for (auto extension: impl->extensions) {
560 for (auto module: extension.getModules()) {
561 modules->addBuiltinModule(module.getName(), module.getEsModule().asArray(),
562 module.getInternal() ? jsg::ModuleRegistry::Type::INTERNAL
563 : jsg::ModuleRegistry::Type::BUILTIN);
564 }
565 }
566 });
567}
568 
569static v8::Local<v8::Value> createBindingValue(JsgWorkerdIsolate::Lock& lock,
570 const WorkerdApi::Global& global,
571 CompatibilityFlags::Reader featureFlags,
572 uint32_t ownerId,
573 api::MemoryCacheProvider& memoryCacheProvider) {
574 TRACE_EVENT("workerd", "WorkerdApi::createBindingValue()");
575 using Global = WorkerdApi::Global;
576 auto context = lock.v8Context();
577 
578 v8::Local<v8::Value> value;
579 
580 // When new binding types are created. If their value resolves to be a string
581 // or a JSON stringified/stringifiable value, then it should be added to
582 // process.env here as well, just like with Global::Json and kj::String
583 // entries.
584 //
585 // It is important to understand the process.env is fundamentally different
586 // from the existing bag of bindings. The keys and values on process.env are
587 // fundamentally a Record<string, string>, where any value set on process.env
588 // is coerced to a string. Having a separate object for process.env is the
589 // easiest approach as opposed to wrapping the bindings/env with a proxy that
590 // tries to abstract the details. If this ends up needing to change later then
591 // as long as the observable behavior remains the same we can do so without
592 // Yet Another Compat Flag.
593 
594 KJ_SWITCH_ONEOF(global.value) {
595 KJ_CASE_ONEOF(json, Global::Json) {
596 value = jsg::check(v8::JSON::Parse(context, lock.str(json.text)));
597 }
598 
599 KJ_CASE_ONEOF(pipeline, Global::Fetcher) {
600 value = lock.wrap(context,
601 lock.alloc<api::Fetcher>(pipeline.channel,
602 pipeline.requiresHost ? api::Fetcher::RequiresHostAndProtocol::YES
603 : api::Fetcher::RequiresHostAndProtocol::NO,
604 pipeline.isInHouse));
605 }
606 
607 KJ_CASE_ONEOF(loopback, Global::LoopbackServiceStub) {
608 value = lock.wrap(context, lock.alloc<api::LoopbackServiceStub>(loopback.channel));
609 }
610 
611 KJ_CASE_ONEOF(ns, Global::KvNamespace) {
612 value = lock.wrap(context,
613 lock.alloc<api::KvNamespace>(kj::str(ns.bindingName),
614 kj::Array<api::KvNamespace::AdditionalHeader>{}, ns.subrequestChannel));
615 }
616 
617 KJ_CASE_ONEOF(r2, Global::R2Bucket) {
618 value = lock.wrap(context,
619 lock.alloc<api::public_beta::R2Bucket>(
620 featureFlags, r2.subrequestChannel, kj::str(r2.bucket), kj::str(r2.bindingName)));
621 }
622 
623 KJ_CASE_ONEOF(ns, Global::QueueBinding) {
624 value = lock.wrap(context, lock.alloc<api::WorkerQueue>(ns.subrequestChannel));
625 }
626 
627 KJ_CASE_ONEOF(key, Global::CryptoKey) {
628 api::SubtleCrypto::ImportKeyData keyData;
629 KJ_SWITCH_ONEOF(key.keyData) {
630 KJ_CASE_ONEOF(data, kj::Array<byte>) {
631 keyData = kj::heapArray(data.asPtr());
632 }
633 KJ_CASE_ONEOF(json, Global::Json) {
634 v8::Local<v8::String> str = lock.wrap(context, kj::mv(json.text));
635 v8::Local<v8::Value> obj = jsg::check(v8::JSON::Parse(context, str));
636 keyData = lock.unwrap<api::SubtleCrypto::ImportKeyData>(context, obj);
637 }
638 }
639 
640 v8::Local<v8::String> algoStr = lock.wrap(context, kj::mv(key.algorithm.text));
641 v8::Local<v8::Value> algo = jsg::check(v8::JSON::Parse(context, algoStr));
642 auto importKeyAlgo =
643 lock.unwrap<kj::OneOf<kj::String, api::SubtleCrypto::ImportKeyAlgorithm>>(context, algo);
644 
645 jsg::Ref<api::CryptoKey> importedKey =
646 api::SubtleCrypto().importKeySync(lock, key.format, kj::mv(keyData),
647 api::interpretAlgorithmParam(kj::mv(importKeyAlgo)), key.extractable, key.usages);
648 
649 value = lock.wrap(context, kj::mv(importedKey));
650 }
651 
652 KJ_CASE_ONEOF(cache, Global::MemoryCache) {
653 value = lock.wrap(context,
654 lock.alloc<api::MemoryCache>(
655 api::SharedMemoryCache::Use(memoryCacheProvider.getInstance(cache.cacheId),
656 {
657 .maxKeys = cache.maxKeys,
658 .maxValueSize = cache.maxValueSize,
659 .maxTotalValueSize = cache.maxTotalValueSize,
660 })));
661 }
662 
663 KJ_CASE_ONEOF(ns, Global::EphemeralActorNamespace) {
664 value = lock.wrap(context, lock.alloc<api::ColoLocalActorNamespace>(ns.actorChannel));
665 }
666 KJ_CASE_ONEOF(ns, Global::LoopbackEphemeralActorNamespace) {
667 value = lock.wrap(context,
668 lock.alloc<api::LoopbackColoLocalActorNamespace>(
669 ns.actorChannel, lock.alloc<api::LoopbackDurableObjectClass>(ns.classChannel)));
670 }
671 
672 KJ_CASE_ONEOF(ns, Global::DurableActorNamespace) {
673 value = lock.wrap(context,
674 lock.alloc<api::DurableObjectNamespace>(
675 ns.actorChannel, kj::heap<ActorIdFactoryImpl>(ns.uniqueKey)));
676 }
677 KJ_CASE_ONEOF(ns, Global::LoopbackDurableActorNamespace) {
678 value = lock.wrap(context,
679 lock.alloc<api::LoopbackDurableObjectNamespace>(ns.actorChannel,
680 kj::heap<ActorIdFactoryImpl>(ns.uniqueKey),
681 lock.alloc<api::LoopbackDurableObjectClass>(ns.classChannel)));
682 }
683 
684 KJ_CASE_ONEOF(ae, Global::AnalyticsEngine) {
685 // Use subrequestChannel as logfwdrChannel
686 value = lock.wrap(context,
687 lock.alloc<api::AnalyticsEngine>(
688 ae.subrequestChannel, kj::str(ae.dataset), ae.version, ownerId));
689 }
690 
691 KJ_CASE_ONEOF(text, kj::String) {
692 value = lock.wrap(context, kj::mv(text));
693 }
694 
695 KJ_CASE_ONEOF(data, kj::Array<byte>) {
696 value = lock.wrap(context, kj::heapArray(data.asPtr()));
697 }
698 
699 KJ_CASE_ONEOF(wrapped, Global::Wrapped) {
700 auto moduleRegistry = jsg::ModuleRegistry::from(lock);
701 auto moduleName = kj::Path::parse(wrapped.moduleName);
702 
703 // wrapped bindings can be produced by internal modules only
704 KJ_IF_SOME(moduleInfo,
705 moduleRegistry->resolve(
706 lock, moduleName, kj::none, jsg::ModuleRegistry::ResolveOption::INTERNAL_ONLY)) {
707 // obtain the module
708 auto module = moduleInfo.module.getHandle(lock);
709 jsg::instantiateModule(lock, module);
710 
711 // build env object with inner bindings
712 auto env = v8::Object::New(lock.v8Isolate);
713 for (const auto& innerBinding: wrapped.innerBindings) {
714 lock.v8Set(env, innerBinding.name,
715 createBindingValue(lock, innerBinding, featureFlags, ownerId, memoryCacheProvider));
716 }
717 
718 // obtain exported function to call
719 auto moduleNs = jsg::check(module->GetModuleNamespace()->ToObject(context));
720 auto fn = lock.v8Get(moduleNs, wrapped.entrypoint);
721 KJ_ASSERT(fn->IsFunction(), "Entrypoint is not a function", wrapped.entrypoint);
722 
723 // invoke the function, its result will be binding value
724 v8::Local<v8::Value> arg = env.As<v8::Value>();
725 value = jsg::check(v8::Function::Cast(*fn)->Call(context, context->Global(), 1, &arg));
726 } else {
727 KJ_LOG(
728 ERROR, "wrapped binding module can't be resolved (internal modules only)", moduleName);
729 }
730 }
731 KJ_CASE_ONEOF(hyperdrive, Global::Hyperdrive) {
732 value = lock.wrap(context,
733 lock.alloc<api::Hyperdrive>(hyperdrive.subrequestChannel, kj::str(hyperdrive.database),
734 kj::str(hyperdrive.user), kj::str(hyperdrive.password), kj::str(hyperdrive.scheme)));
735 }
736 KJ_CASE_ONEOF(unsafe, Global::UnsafeEval) {
737 value = lock.wrap(context, lock.alloc<api::UnsafeEval>());
738 }
739 
740 KJ_CASE_ONEOF(actorClass, Global::ActorClass) {
741 value = lock.wrap(context, lock.alloc<api::DurableObjectClass>(actorClass.channel));
742 }
743 
744 KJ_CASE_ONEOF(actorClass, Global::LoopbackActorClass) {
745 value = lock.wrap(context, lock.alloc<api::LoopbackDurableObjectClass>(actorClass.channel));
746 }
747 
748 KJ_CASE_ONEOF(workerLoader, Global::WorkerLoader) {
749 value = lock.wrap(context,
750 lock.alloc<api::WorkerLoader>(
751 workerLoader.channel, CompatibilityDateValidation::CODE_VERSION));
752 }
753 
754 KJ_CASE_ONEOF(_, Global::WorkerdDebugPort) {
755 value = lock.wrap(context, lock.alloc<WorkerdDebugPortConnector>());
756 }
757 }
758 
759 return value;
760}
761 
762void WorkerdApi::compileGlobals(jsg::Lock& lockParam,
763 kj::ArrayPtr<const Global> globals,
764 v8::Local<v8::Object> target,
765 uint32_t ownerId) const {
766 TRACE_EVENT("workerd", "WorkerdApi::compileGlobals()");
767 auto& lock = kj::downcast<JsgWorkerdIsolate::Lock>(lockParam);
768 lockParam.withinHandleScope([&] {
769 auto& featureFlags = *impl->features;
770 
771 for (auto& global: globals) {
772 lockParam.withinHandleScope([&] {
773 // Don't use String's usual TypeHandler here because we want to intern the string.
774 auto value =
775 createBindingValue(lock, global, featureFlags, ownerId, impl->memoryCacheProvider);
776 KJ_ASSERT(!value.IsEmpty(), "global did not produce v8::Value");
777 lockParam.v8Set(target, global.name, value);
778 });
779 }
780 });
781}
782 
783void WorkerdApi::setModuleFallbackCallback(kj::Function<ModuleFallbackCallback>&& callback) const {
784 auto& isolateBase = const_cast<JsgWorkerdIsolate&>(impl->jsgIsolate);
785 isolateBase.setModuleFallbackCallback(kj::mv(callback));
786}
787 
788// =======================================================================================
789 
790WorkerdApi::Global WorkerdApi::Global::clone() const {
791 Global result;
792 result.name = kj::str(name);
793 
794 KJ_SWITCH_ONEOF(value) {
795 KJ_CASE_ONEOF(json, Global::Json) {
796 result.value = json.clone();
797 }
798 KJ_CASE_ONEOF(fetcher, Global::Fetcher) {
799 result.value = fetcher.clone();
800 }
801 KJ_CASE_ONEOF(loopback, Global::LoopbackServiceStub) {
802 result.value = loopback.clone();
803 }
804 KJ_CASE_ONEOF(kvNamespace, Global::KvNamespace) {
805 result.value = kvNamespace.clone();
806 }
807 KJ_CASE_ONEOF(r2Bucket, Global::R2Bucket) {
808 result.value = r2Bucket.clone();
809 }
810 KJ_CASE_ONEOF(queueBinding, Global::QueueBinding) {
811 result.value = queueBinding.clone();
812 }
813 KJ_CASE_ONEOF(key, Global::CryptoKey) {
814 result.value = key.clone();
815 }
816 KJ_CASE_ONEOF(cache, Global::MemoryCache) {
817 result.value = cache.clone();
818 }
819 KJ_CASE_ONEOF(ns, Global::EphemeralActorNamespace) {
820 result.value = ns.clone();
821 }
822 KJ_CASE_ONEOF(ns, Global::LoopbackEphemeralActorNamespace) {
823 result.value = ns.clone();
824 }
825 KJ_CASE_ONEOF(ns, Global::DurableActorNamespace) {
826 result.value = ns.clone();
827 }
828 KJ_CASE_ONEOF(ns, Global::LoopbackDurableActorNamespace) {
829 result.value = ns.clone();
830 }
831 KJ_CASE_ONEOF(ae, Global::AnalyticsEngine) {
832 result.value = ae.clone();
833 }
834 KJ_CASE_ONEOF(text, kj::String) {
835 result.value = kj::str(text);
836 }
837 KJ_CASE_ONEOF(data, kj::Array<byte>) {
838 result.value = kj::heapArray(data.asPtr());
839 }
840 KJ_CASE_ONEOF(wrapped, Global::Wrapped) {
841 result.value = wrapped.clone();
842 }
843 KJ_CASE_ONEOF(hyperdrive, Global::Hyperdrive) {
844 result.value = hyperdrive.clone();
845 }
846 KJ_CASE_ONEOF(unsafe, Global::UnsafeEval) {
847 result.value = Global::UnsafeEval{};
848 }
849 
850 KJ_CASE_ONEOF(actorClass, Global::ActorClass) {
851 result.value = actorClass.clone();
852 }
853 KJ_CASE_ONEOF(actorClass, Global::LoopbackActorClass) {
854 result.value = actorClass.clone();
855 }
856 KJ_CASE_ONEOF(workerLoader, Global::WorkerLoader) {
857 result.value = workerLoader.clone();
858 }
859 KJ_CASE_ONEOF(workerdDebugPort, Global::WorkerdDebugPort) {
860 result.value = workerdDebugPort.clone();
861 }
862 }
863 
864 return result;
865}
866 
867const WorkerdApi& WorkerdApi::from(const Worker::Api& api) {
868 return kj::downcast<const WorkerdApi>(api);
869}
870 
871// =======================================================================================
872 
873// TODO(soon): These are required for python workers but we don't support those yet
874// with the new module registry. Uncomment these when we do.
875// namespace {
876// static constexpr auto PYTHON_TAR_READER = "export default { }"_kj;
877 
878// static const auto metadataSpecifier = "pyodide-internal:runtime-generated/metadata"_url;
879// static const auto artifactsSpecifier = "pyodide-internal:artifacts"_url;
880// static const auto internalJaegerSpecifier = "pyodide-internal:internalJaeger"_url;
881// static const auto diskCacheSpecifier = "pyodide-internal:disk_cache"_url;
882// static const auto limiterSpecifier = "pyodide-internal:limiter"_url;
883// static const auto tarReaderSpecifier = "pyodide-internal:packages_tar_reader"_url;
884// } // namespace
885 
886kj::Arc<jsg::modules::ModuleRegistry> WorkerdApi::newWorkerdModuleRegistry(
887 const jsg::ResolveObserver& observer,
888 kj::Maybe<const Worker::Script::ModulesSource&> maybeSource,
889 const CompatibilityFlags::Reader& featureFlags,
890 const PythonConfig& pythonConfig,
891 const jsg::Url& bundleBase,
892 capnp::List<config::Extension>::Reader extensions,
893 kj::Maybe<kj::String> maybeFallbackService,
894 kj::Maybe<kj::Own<api::pyodide::ArtifactBundler_State>> artifacts) {
895 
896 return newWorkerModuleRegistry<JsgWorkerdIsolate_TypeWrapper>(observer, maybeSource, featureFlags,
897 bundleBase,
898 [&](jsg::modules::ModuleRegistry::Builder& builder, IsPythonWorker isPythonWorker) {
899 // TODO(later): The new module registry should eventually support python workers
900 // as well, but for now we forbid it. There are a number of nuances to python workers
901 // and modules that need to be worked out.
902 KJ_REQUIRE(!isPythonWorker, "Python workers are not supported with the new module registry");
903 // if (isPythonWorker) {
904 // using namespace api::pyodide;
905 
906 // // It's not possible to have a python worker without a source bundle.
907 // auto& source = KJ_ASSERT_NONNULL(maybeSource);
908 
909 // // To support python workers we create two modules bundles, one BUILTIN
910 // // and the other BUILTIN_ONLY. The BUILTIN bundle contains support modules
911 // // that need to be importable by the python worker bootstrap module (which
912 // // is added to the BUNDLE modules). The BUILTIN_ONLY bundle contains support
913 // // modules that are used by the BUILTIN modules and are not intended to be
914 // // accessible from the worker itself.
915 
916 // // Inject metadata that the entrypoint module will read.
917 // auto pythonRelease = KJ_ASSERT_NONNULL(getPythonSnapshotRelease(featureFlags));
918 // auto version = getPythonBundleName(pythonRelease);
919 // auto bundle = retrievePyodideBundle(pythonConfig, version);
920 
921 // // We end up adding modules from the bundle twice, once to get BUILTIN modules
922 // // and again to get the BUILTIN_ONLY modules. These end up in two different
923 // // module bundles.
924 // jsg::modules::ModuleBundle::BuiltinBuilder pyodideSdkBuilder;
925 
926 // // There are two bundles that are relevant here, PYODIDE_BUNDLE, which is
927 // // fixed and contains compiled-in modules, and the bundle that is fetched
928 // // that contains the more dynamic implementation details. We have to process
929 // // both.
930 // jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(pyodideSdkBuilder, PYODIDE_BUNDLE);
931 // jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(pyodideSdkBuilder, bundle);
932 // builder.add(pyodideSdkBuilder.finish());
933 
934 // jsg::modules::ModuleBundle::BuiltinBuilder pyodideBundleBuilder(
935 // jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY);
936 
937 // jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(pyodideBundleBuilder, PYODIDE_BUNDLE);
938 // jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(pyodideBundleBuilder, bundle);
939 
940 // pyodideBundleBuilder.addEsm(tarReaderSpecifier, PYTHON_TAR_READER);
941 
942 // api::pyodide::CreateBaselineSnapshot createBaselineSnapshot(
943 // pythonConfig.createBaselineSnapshot);
944 // api::pyodide::SnapshotToDisk snapshotToDisk(
945 // pythonConfig.createSnapshot || createBaselineSnapshot);
946 // auto maybeSnapshot = tryGetMetadataSnapshot(pythonConfig, snapshotToDisk);
947 // auto state = workerd::modules::python::createPyodideMetadataState(source,
948 // api::pyodide::IsWorkerd::YES, api::pyodide::IsTracing::NO, snapshotToDisk,
949 // createBaselineSnapshot, pythonRelease, kj::mv(maybeSnapshot), featureFlags);
950 
951 // pyodideBundleBuilder.addSynthetic(metadataSpecifier,
952 // jsg::modules::Module::newJsgObjectModuleHandler<api::pyodide::PyodideMetadataReader,
953 // JsgWorkerdIsolate_TypeWrapper>(
954 // [state = kj::mv(state)](
955 // jsg::Lock& js) mutable -> jsg::Ref<api::pyodide::PyodideMetadataReader> {
956 // // The ModuleRegistry may be shared across multiple isolates and workers.
957 // // We need to clone the PyodideMetadataReader::State for each instance
958 // // that is evaluated. Typically this is only once per python worker
959 // // but could be more in the future.
960 // return js.alloc<PyodideMetadataReader>(state->clone());
961 // }));
962 // // Inject artifact bundler.
963 // pyodideBundleBuilder.addSynthetic(artifactsSpecifier,
964 // jsg::modules::Module::newJsgObjectModuleHandler<ArtifactBundler,
965 // JsgWorkerdIsolate_TypeWrapper>(
966 // [](jsg::Lock& js) mutable -> jsg::Ref<ArtifactBundler> {
967 // return js.alloc<ArtifactBundler>(ArtifactBundler::makeDisabledBundler());
968 // }));
969 // // Inject jaeger internal tracer in a disabled state (we don't have a use for it in workerd)
970 // pyodideBundleBuilder.addSynthetic(internalJaegerSpecifier,
971 // jsg::modules::Module::newJsgObjectModuleHandler<DisabledInternalJaeger,
972 // JsgWorkerdIsolate_TypeWrapper>(
973 // [](jsg::Lock& js) mutable -> jsg::Ref<DisabledInternalJaeger> {
974 // return DisabledInternalJaeger::create(js);
975 // }));
976 // // Inject disk cache module
977 // pyodideBundleBuilder.addSynthetic(diskCacheSpecifier,
978 // jsg::modules::Module::newJsgObjectModuleHandler<DiskCache, JsgWorkerdIsolate_TypeWrapper>(
979 // [&packageDiskCacheRoot = pythonConfig.packageDiskCacheRoot](jsg::Lock& js) mutable
980 // -> jsg::Ref<DiskCache> { return js.alloc<DiskCache>(packageDiskCacheRoot); }));
981 // // Inject a (disabled) SimplePythonLimiter
982 // pyodideBundleBuilder.addSynthetic(limiterSpecifier,
983 // jsg::modules::Module::newJsgObjectModuleHandler<SimplePythonLimiter,
984 // JsgWorkerdIsolate_TypeWrapper>(
985 // [](jsg::Lock& js) mutable -> jsg::Ref<SimplePythonLimiter> {
986 // return SimplePythonLimiter::makeDisabled(js);
987 // }));
988 
989 // builder.add(pyodideBundleBuilder.finish());
990 // }
991 
992 // Handle extensions (extensions are a workerd-specific concept)
993 jsg::modules::ModuleBundle::BuiltinBuilder publicExtensionsBuilder(
994 jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN);
995 jsg::modules::ModuleBundle::BuiltinBuilder privateExtensionsBuilder(
996 jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY);
997 
998 for (auto extension: extensions) {
999 for (auto module: extension.getModules()) {
1000 KJ_IF_SOME(url, jsg::Url::tryParse(module.getName())) {
1001 if (module.getInternal()) {
1002 privateExtensionsBuilder.addEsm(url, module.getEsModule().asArray());
1003 } else {
1004 publicExtensionsBuilder.addEsm(url, module.getEsModule().asArray());
1005 }
1006 } else {
1007 KJ_LOG(WARNING, "Ignoring extension module with invalid name", module.getName());
1008 }
1009 }
1010 }
1011 
1012 builder.add(publicExtensionsBuilder.finish());
1013 builder.add(privateExtensionsBuilder.finish());
1014 
1015 // If we have a fallback service configured, add the fallback bundle.
1016 // The fallback bundle is used only in workerd local development mode.
1017 // If a module is not found in the static bundles, a registry that is
1018 // configured to use the fallback will send a request to the fallback
1019 // service to try resolving.
1020 KJ_IF_SOME(fallbackService, maybeFallbackService) {
1021 auto fallbackClient =
1022 kj::heap<workerd::fallback::FallbackServiceClient>(kj::str(fallbackService));
1023 
1024 // Map from the module resolution source to the fallback service import type.
1025 constexpr auto sourceToImportType = [](jsg::modules::ResolveContext::Source source) {
1026 switch (source) {
1027 case jsg::modules::ResolveContext::Source::STATIC_IMPORT:
1028 case jsg::modules::ResolveContext::Source::DYNAMIC_IMPORT:
1029 return workerd::fallback::ImportType::IMPORT;
1030 case jsg::modules::ResolveContext::Source::REQUIRE:
1031 return workerd::fallback::ImportType::REQUIRE;
1032 case jsg::modules::ResolveContext::Source::INTERNAL:
1033 return workerd::fallback::ImportType::INTERNAL;
1034 }
1035 KJ_UNREACHABLE;
1036 };
1037 
1038 builder.add(jsg::modules::ModuleBundle::newFallbackBundle(
1039 [client = kj::mv(fallbackClient), featureFlags, sourceToImportType](
1040 const jsg::modules::ResolveContext& context) mutable
1041 -> kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>> {
1042 auto normalizedSpecifier = kj::str(context.normalizedSpecifier.getHref());
1043 auto referrer = kj::str(context.referrerNormalizedSpecifier.getHref());
1044 KJ_IF_SOME(resolved,
1045 client->tryResolve(workerd::fallback::Version::V2, sourceToImportType(context.source),
1046 normalizedSpecifier, context.rawSpecifier.orDefault(nullptr), referrer,
1047 context.attributes)) {
1048 KJ_SWITCH_ONEOF(resolved) {
1049 KJ_CASE_ONEOF(str, kj::String) {
1050 // The fallback service returned an alternative specifier.
1051 // The resolution must start over with the new specifier.
1052 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(kj::mv(str));
1053 }
1054 KJ_CASE_ONEOF(def, kj::Own<server::config::Worker::Module::Reader>) {
1055 // The fallback service returned a module definition.
1056 // We need to convert that into a Module instance.
1057 auto mod = readModuleConf(*def, featureFlags, kj::none);
1058 KJ_IF_SOME(id, jsg::Url::tryParse(mod.name)) {
1059 // Note that unlike the regular case, the module content returned
1060 // by the fallback service is not guaranteed to be memory-resident.
1061 // We need to copy the content into a heap-allocated arrays and
1062 // make sure those stay alive while the Module is alive.
1063 KJ_SWITCH_ONEOF(mod.content) {
1064 KJ_CASE_ONEOF(content, Worker::Script::EsModule) {
1065 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1066 jsg::modules::Module::newEsm(kj::mv(id),
1067 jsg::modules::Module::Type::FALLBACK,
1068 kj::heapArray<const char>(content.body)));
1069 }
1070 KJ_CASE_ONEOF(content, Worker::Script::TextModule) {
1071 auto ownedData = kj::str(content.body);
1072 auto ptr = ownedData.asPtr();
1073 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1074 jsg::modules::Module::newSynthetic(kj::mv(id),
1075 jsg::modules::Module::Type::FALLBACK,
1076 jsg::modules::Module::newTextModuleHandler(ptr))
1077 .attach(kj::mv(ownedData)));
1078 }
1079 KJ_CASE_ONEOF(content, Worker::Script::DataModule) {
1080 auto ownedData = kj::heapArray<uint8_t>(content.body);
1081 auto ptr = ownedData.asPtr();
1082 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1083 jsg::modules::Module::newSynthetic(kj::mv(id),
1084 jsg::modules::Module::Type::FALLBACK,
1085 jsg::modules::Module::newDataModuleHandler(ptr))
1086 .attach(kj::mv(ownedData)));
1087 }
1088 KJ_CASE_ONEOF(content, Worker::Script::WasmModule) {
1089 auto ownedData = kj::heapArray<uint8_t>(content.body);
1090 auto ptr = ownedData.asPtr();
1091 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1092 jsg::modules::Module::newSynthetic(kj::mv(id),
1093 jsg::modules::Module::Type::FALLBACK,
1094 jsg::modules::Module::newWasmModuleHandler(ptr))
1095 .attach(kj::mv(ownedData)));
1096 }
1097 KJ_CASE_ONEOF(content, Worker::Script::JsonModule) {
1098 auto ownedData = kj::heapArray<const char>(content.body);
1099 auto ptr = ownedData.asPtr();
1100 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1101 jsg::modules::Module::newSynthetic(kj::mv(id),
1102 jsg::modules::Module::Type::FALLBACK,
1103 jsg::modules::Module::newJsonModuleHandler(ptr))
1104 .attach(kj::mv(ownedData)));
1105 }
1106 KJ_CASE_ONEOF(content, Worker::Script::CommonJsModule) {
1107 auto ownedData = kj::str(content.body);
1108 auto ptr = ownedData.asPtr();
1109 kj::ArrayPtr<const kj::StringPtr> named;
1110 KJ_IF_SOME(n, content.namedExports) {
1111 named = n;
1112 }
1113 return kj::Maybe<kj::OneOf<kj::String, kj::Own<jsg::modules::Module>>>(
1114 jsg::modules::Module::newSynthetic(kj::mv(id),
1115 jsg::modules::Module::Type::FALLBACK,
1116 jsg::modules::Module::newCjsStyleModuleHandler<
1117 api::CommonJsModuleContext, JsgWorkerdIsolate_TypeWrapper>(
1118 ptr, mod.name),
1119 KJ_MAP(name, named) {
1120 return kj::str(name);
1121 }).attach(kj::mv(ownedData)));
1122 }
1123 KJ_CASE_ONEOF(content, Worker::Script::PythonModule) {
1124 // Python modules are not supported.in fallback
1125 KJ_LOG(WARNING, "Fallback service returned a Python module");
1126 return kj::none;
1127 }
1128 KJ_CASE_ONEOF(content, Worker::Script::PythonRequirement) {
1129 // Python requirement modules are not supported.in fallback
1130 KJ_LOG(WARNING, "Fallback service returned a Python requirement");
1131 return kj::none;
1132 }
1133 KJ_CASE_ONEOF(content, Worker::Script::CapnpModule) {
1134 // Capnp modules are not supported.in fallback
1135 KJ_LOG(WARNING, "Fallback service returned a Capnp module");
1136 return kj::none;
1137 }
1138 }
1139 KJ_UNREACHABLE;
1140 }
1141 KJ_LOG(WARNING, "Fallback service returned an invalid id");
1142 return kj::none;
1143 }
1144 }
1145 }
1146 return kj::none;
1147 }));
1148 }
1149 }, jsg::modules::ModuleRegistry::Builder::Options::ALLOW_FALLBACK);
1150}
1151 
1152kj::Own<rpc::ActorStorage::Stage::Server> newEmptyReadOnlyActorStorage() {
1153 return kj::heap<EmptyReadOnlyActorStorageImpl>();
1154}
1155 
1156} // namespace workerd::server