Skip to content
File

Blob: src/workerd/api/modules.h

cpp138 lines
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#pragma once
6 
7#include <workerd/api/base64.h>
8#include <workerd/api/filesystem.h>
9#include <workerd/api/messagechannel.h>
10#include <workerd/api/node/node.h>
11#include <workerd/api/pyodide/pyodide.h>
12#include <workerd/api/rtti.h>
13#include <workerd/api/sockets.h>
14#include <workerd/api/tracing.h>
15#include <workerd/api/unsafe.h>
16#include <workerd/api/workers-module.h>
17#include <workerd/jsg/modules-new.h>
18 
19#include <cloudflare/cloudflare.capnp.h>
20 
21namespace workerd::api {
22 
23// An object with a [Symbol.dispose]() method to remove patch to environment. Not exposed
24// publically, just used to implement Python's `patch_env()` context manager.
25// See src/pyodide/internal/envHelpers.ts
26class PythonPatchedEnv: public jsg::Object {
27 public:
28 PythonPatchedEnv(jsg::Lock& js, jsg::AsyncContextFrame::StorageKey& key, jsg::Value store) {
29 scope.emplace(js, key, kj::mv(store));
30 }
31 
32 void dispose() {
33 scope = kj::none;
34 }
35 
36 JSG_RESOURCE_TYPE(PythonPatchedEnv) {
37 JSG_DISPOSE(dispose);
38 }
39 
40 private:
41 kj::Maybe<jsg::AsyncContextFrame::StorageScope> scope;
42};
43 
44class EnvModule final: public jsg::Object {
45 public:
46 EnvModule() = default;
47 EnvModule(jsg::Lock&, const jsg::Url&) {}
48 
49 kj::Maybe<jsg::JsObject> getCurrentEnv(jsg::Lock& js);
50 kj::Maybe<jsg::JsObject> getCurrentExports(jsg::Lock& js);
51 
52 // Arranges to propagate the given newEnv in the async context.
53 jsg::JsRef<jsg::JsValue> withEnv(
54 jsg::Lock& js, jsg::Value newEnv, jsg::Function<jsg::JsRef<jsg::JsValue>()> fn);
55 
56 jsg::JsRef<jsg::JsValue> withExports(
57 jsg::Lock& js, jsg::Value newExports, jsg::Function<jsg::JsRef<jsg::JsValue>()> fn);
58 
59 jsg::JsRef<jsg::JsValue> withEnvAndExports(jsg::Lock& js,
60 jsg::Value newEnv,
61 jsg::Value newExports,
62 jsg::Function<jsg::JsRef<jsg::JsValue>()> fn);
63 
64 // Patch environment and return an object with a [Symbol.dispose]() method to restore it.
65 // Not exposed publically, just used to implement Python's `patch_env()` context manager.
66 // See src/pyodide/internal/envHelpers.ts
67 jsg::Ref<PythonPatchedEnv> pythonPatchEnv(jsg::Lock& js, jsg::Value newEnv);
68 
69 JSG_RESOURCE_TYPE(EnvModule) {
70 JSG_METHOD(getCurrentEnv);
71 JSG_METHOD(getCurrentExports);
72 JSG_METHOD(withEnv);
73 JSG_METHOD(withExports);
74 JSG_METHOD(withEnvAndExports);
75 JSG_METHOD(pythonPatchEnv);
76 }
77};
78 
79template <class Registry>
80void registerModules(Registry& registry, auto featureFlags) {
81 node::registerNodeJsCompatModules(registry, featureFlags);
82 registerUnsafeModules(registry, featureFlags);
83 if (featureFlags.getRttiApi()) {
84 registerRTTIModule(registry);
85 }
86 if (featureFlags.getUnsafeModule()) {
87 registerUnsafeModule(registry);
88 }
89 registerSocketsModule(registry, featureFlags);
90 registerBase64Module(registry, featureFlags);
91 registerMessageChannelModule(registry, featureFlags);
92 registry.addBuiltinBundle(CLOUDFLARE_BUNDLE);
93 registerWorkersModule(registry, featureFlags);
94 registerTracingModule(registry, featureFlags);
95 registry.template addBuiltinModule<EnvModule>(
96 "cloudflare-internal:env", workerd::jsg::ModuleRegistry::Type::INTERNAL);
97 registry.template addBuiltinModule<FileSystemModule>(
98 "cloudflare-internal:filesystem", workerd::jsg::ModuleRegistry::Type::INTERNAL);
99}
100 
101template <class TypeWrapper>
102void registerBuiltinModules(jsg::modules::ModuleRegistry::Builder& builder, auto featureFlags) {
103 builder.add(node::getInternalNodeJsCompatModuleBundle<TypeWrapper>(featureFlags));
104 builder.add(node::getExternalNodeJsCompatModuleBundle(featureFlags));
105 builder.add(getInternalSocketModuleBundle<TypeWrapper>(featureFlags));
106 builder.add(getInternalBase64ModuleBundle<TypeWrapper>(featureFlags));
107 builder.add(getInternalMessageChannelModuleBundle<TypeWrapper>(featureFlags));
108 builder.add(getInternalRpcModuleBundle<TypeWrapper>(featureFlags));
109 
110 builder.add(getInternalUnsafeModuleBundle<TypeWrapper>(featureFlags));
111 builder.add(getInternalTracingModuleBundle<TypeWrapper>(featureFlags));
112 if (featureFlags.getUnsafeModule()) {
113 builder.add(getExternalUnsafeModuleBundle<TypeWrapper>(featureFlags));
114 }
115 
116 if (featureFlags.getRttiApi()) {
117 builder.add(getExternalRttiModuleBundle<TypeWrapper>(featureFlags));
118 }
119 
120 {
121 jsg::modules::ModuleBundle::BuiltinBuilder builtinsBuilder(
122 jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN);
123 jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(builtinsBuilder, CLOUDFLARE_BUNDLE);
124 builder.add(builtinsBuilder.finish());
125 }
126 
127 {
128 jsg::modules::ModuleBundle::BuiltinBuilder builtinsBuilder(
129 jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY);
130 builtinsBuilder.addObject<EnvModule, TypeWrapper>("cloudflare-internal:env"_url);
131 builtinsBuilder.addObject<FileSystemModule, TypeWrapper>("cloudflare-internal:filesystem"_url);
132 jsg::modules::ModuleBundle::getBuiltInBundleFromCapnp(builtinsBuilder, CLOUDFLARE_BUNDLE);
133 builder.add(builtinsBuilder.finish());
134 }
135}
136 
137} // namespace workerd::api