-
Notifications
You must be signed in to change notification settings - Fork 303
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements cloudflare:compatibility-flags API
A simple built-in module and API for determining if a given compat flag is set. ``` import { compatFlags } from 'cloudflare:workers' console.log(compatFlags['url_standard']); // 'on' or 'off' console.log(compatFlags['url_original']); // 'on' or 'off' ```
- Loading branch information
Showing
8 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
161 changes: 161 additions & 0 deletions
161
0001-Implements-cloudflare-compatibility-flags-API.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
From fdac25bc6ad66aed94bf7e89e0f2afc1158c32d8 Mon Sep 17 00:00:00 2001 | ||
From: James M Snell <[email protected]> | ||
Date: Wed, 12 Jun 2024 12:52:43 -0700 | ||
Subject: [PATCH] Implements cloudflare:compatibility-flags API | ||
|
||
A simple built-in module and API for determining if a given compat | ||
flag is set. | ||
|
||
``` | ||
import { compatFlags } from 'cloudflare:workers' | ||
|
||
console.log(compatFlags['url_standard']); | ||
console.log(compatFlags['url_original']); | ||
``` | ||
--- | ||
src/cloudflare/workers.ts | 6 +++++ | ||
src/workerd/api/node/node.h | 22 ++++++++++++++++++ | ||
src/workerd/api/tests/compat-flags-test.js | 23 +++++++++++++++++++ | ||
.../api/tests/compat-flags-test.wd-test | 15 ++++++++++++ | ||
src/workerd/jsg/jsvalue.c++ | 5 ++++ | ||
src/workerd/jsg/jsvalue.h | 1 + | ||
6 files changed, 72 insertions(+) | ||
create mode 100644 src/workerd/api/tests/compat-flags-test.js | ||
create mode 100644 src/workerd/api/tests/compat-flags-test.wd-test | ||
|
||
diff --git a/src/cloudflare/workers.ts b/src/cloudflare/workers.ts | ||
index 2fd18587..9d30e321 100644 | ||
--- a/src/cloudflare/workers.ts | ||
+++ b/src/cloudflare/workers.ts | ||
@@ -11,3 +11,9 @@ export const WorkerEntrypoint = entrypoints.WorkerEntrypoint; | ||
export const DurableObject = entrypoints.DurableObject; | ||
export const RpcStub = entrypoints.RpcStub; | ||
export const RpcTarget = entrypoints.RpcTarget; | ||
+ | ||
+/* eslint-disable */ | ||
+import { default as flags } from 'workerd:compatibility-flags'; | ||
+export const compatFlags = (flags as any).compatFlags; | ||
+Object.freeze(compatFlags); | ||
+/* eslint-enable */ | ||
diff --git a/src/workerd/api/node/node.h b/src/workerd/api/node/node.h | ||
index d24b800c..39c7a39c 100644 | ||
--- a/src/workerd/api/node/node.h | ||
+++ b/src/workerd/api/node/node.h | ||
@@ -9,6 +9,7 @@ | ||
#include <workerd/jsg/modules.h> | ||
#include <capnp/dynamic.h> | ||
#include <node/node.capnp.h> | ||
+#include <workerd/io/compatibility-date.h> | ||
|
||
namespace workerd::api::node { | ||
|
||
@@ -17,7 +18,28 @@ namespace workerd::api::node { | ||
// built-ins | ||
class CompatibilityFlags : public jsg::Object { | ||
public: | ||
+ | ||
+ jsg::JsObject getCompatFlags(jsg::Lock& js, workerd::CompatibilityFlags::Reader flags) { | ||
+ auto obj = js.obj(); | ||
+ auto dynamic = capnp::toDynamic(flags); | ||
+ auto schema = dynamic.getSchema(); | ||
+ for (auto field : schema.getFields()) { | ||
+ bool value = dynamic.get(field).as<bool>(); | ||
+ for (auto annotation : field.getProto().getAnnotations()) { | ||
+ if (annotation.getId() == COMPAT_ENABLE_FLAG_ANNOTATION_ID) { | ||
+ obj.setReadOnly(js, annotation.getValue().getText(), js.boolean(value)); | ||
+ } | ||
+ else if (annotation.getId() == COMPAT_DISABLE_FLAG_ANNOTATION_ID) { | ||
+ obj.setReadOnly(js, annotation.getValue().getText(), js.boolean(!value)); | ||
+ } | ||
+ } | ||
+ } | ||
+ return obj; | ||
+ } | ||
+ | ||
JSG_RESOURCE_TYPE(CompatibilityFlags, workerd::CompatibilityFlags::Reader flags) { | ||
+ JSG_LAZY_READONLY_INSTANCE_PROPERTY(compatFlags, getCompatFlags); | ||
+ | ||
// Not your typical JSG_RESOURCE_TYPE definition.. here we are iterating | ||
// through all of the compatibility flags and registering each as read-only | ||
// literal values on the instance... | ||
diff --git a/src/workerd/api/tests/compat-flags-test.js b/src/workerd/api/tests/compat-flags-test.js | ||
new file mode 100644 | ||
index 00000000..f27bff8a | ||
--- /dev/null | ||
+++ b/src/workerd/api/tests/compat-flags-test.js | ||
@@ -0,0 +1,23 @@ | ||
+import { | ||
+ ok, | ||
+ throws, | ||
+} from 'node:assert'; | ||
+ | ||
+import { compatFlags } from 'cloudflare:workers'; | ||
+ | ||
+export const compatFlagsTest = { | ||
+ test() { | ||
+ throws(() => compatFlags.no_nodejs_compat_v2 = true); | ||
+ throws(() => compatFlags.not_a_real_compat_flag = true); | ||
+ ok(compatFlags['nodejs_compat_v2']); | ||
+ ok(!compatFlags['no_nodejs_compat_v2']); | ||
+ ok(compatFlags['url_standard']); | ||
+ ok(!compatFlags['url_original']); | ||
+ ok(!compatFlags['not-a-real-compat-flag']); | ||
+ const keys = Object.keys(compatFlags); | ||
+ ok(keys.includes('nodejs_compat_v2')); | ||
+ ok(keys.includes('url_standard')); | ||
+ ok(keys.includes('url_original')); | ||
+ ok(!keys.includes('not-a-real-compat-flag')); | ||
+ } | ||
+} | ||
diff --git a/src/workerd/api/tests/compat-flags-test.wd-test b/src/workerd/api/tests/compat-flags-test.wd-test | ||
new file mode 100644 | ||
index 00000000..38d8c5c1 | ||
--- /dev/null | ||
+++ b/src/workerd/api/tests/compat-flags-test.wd-test | ||
@@ -0,0 +1,15 @@ | ||
+using Workerd = import "/workerd/workerd.capnp"; | ||
+ | ||
+const unitTests :Workerd.Config = ( | ||
+ services = [ | ||
+ ( name = "compat-flags-test", | ||
+ worker = ( | ||
+ modules = [ | ||
+ (name = "worker", esModule = embed "compat-flags-test.js") | ||
+ ], | ||
+ compatibilityDate = "2023-01-15", | ||
+ compatibilityFlags = ["nodejs_compat_v2"], | ||
+ ) | ||
+ ), | ||
+ ], | ||
+); | ||
diff --git a/src/workerd/jsg/jsvalue.c++ b/src/workerd/jsg/jsvalue.c++ | ||
index 933fa28b..24cce4e7 100644 | ||
--- a/src/workerd/jsg/jsvalue.c++ | ||
+++ b/src/workerd/jsg/jsvalue.c++ | ||
@@ -58,6 +58,11 @@ void JsObject::set(Lock& js, kj::StringPtr name, const JsValue& value) { | ||
set(js, js.strIntern(name), value); | ||
} | ||
|
||
+void JsObject::setReadOnly(Lock& js, kj::StringPtr name, const JsValue& value) { | ||
+ v8::Local<v8::String> nameStr = js.strIntern(name); | ||
+ check(inner->DefineOwnProperty(js.v8Context(), nameStr, value, v8::ReadOnly)); | ||
+} | ||
+ | ||
JsValue JsObject::get(Lock& js, const JsValue& name) { | ||
return JsValue(check(inner->Get(js.v8Context(), name.inner))); | ||
} | ||
diff --git a/src/workerd/jsg/jsvalue.h b/src/workerd/jsg/jsvalue.h | ||
index ea4c9c30..343dcc07 100644 | ||
--- a/src/workerd/jsg/jsvalue.h | ||
+++ b/src/workerd/jsg/jsvalue.h | ||
@@ -329,6 +329,7 @@ public: | ||
|
||
void set(Lock& js, const JsValue& name, const JsValue& value); | ||
void set(Lock& js, kj::StringPtr name, const JsValue& value); | ||
+ void setReadOnly(Lock& js, kj::StringPtr name, const JsValue& value); | ||
JsValue get(Lock& js, const JsValue& name) KJ_WARN_UNUSED_RESULT; | ||
JsValue get(Lock& js, kj::StringPtr name) KJ_WARN_UNUSED_RESULT; | ||
|
||
-- | ||
2.34.1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { | ||
ok, | ||
strictEqual, | ||
throws, | ||
} from 'node:assert'; | ||
|
||
import { compatibilityFlags } from 'cloudflare:workers'; | ||
|
||
const kOn = 'on'; | ||
const kOff = 'off'; | ||
|
||
export const compatFlagsTest = { | ||
test() { | ||
throws(() => compatibilityFlags.no_nodejs_compat_v2 = "..."); | ||
throws(() => compatibilityFlags.not_a_real_compat_flag = "..."); | ||
throws(() => { delete compatibilityFlags['nodejs_compat_v2']; }); | ||
|
||
strictEqual(compatibilityFlags['nodejs_compat_v2'], kOn); | ||
strictEqual(compatibilityFlags['no_nodejs_compat_v2'], kOff); | ||
strictEqual(compatibilityFlags['url_standard'], kOn); | ||
strictEqual(compatibilityFlags['url_original'], kOff); | ||
|
||
// Since we are not specifying the experimental flag, experimental flags should | ||
// not be included in the output. | ||
strictEqual(compatibilityFlags['durable_object_rename'], undefined); | ||
strictEqual('durable_object_rename' in compatibilityFlags, false); | ||
|
||
// Importantly, if a flag does not exist, the value will be undefined. | ||
strictEqual(compatibilityFlags['not-a-real-compat-flag'], undefined); | ||
strictEqual('not-a-real-compat-flag' in compatibilityFlags, false); | ||
|
||
const keys = Object.keys(compatibilityFlags); | ||
ok(keys.includes('nodejs_compat_v2')); | ||
ok(keys.includes('url_standard')); | ||
ok(keys.includes('url_original')); | ||
ok(!keys.includes('not-a-real-compat-flag')); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Workerd = import "/workerd/workerd.capnp"; | ||
|
||
const unitTests :Workerd.Config = ( | ||
services = [ | ||
( name = "compat-flags-test", | ||
worker = ( | ||
modules = [ | ||
(name = "worker", esModule = embed "compat-flags-test.js") | ||
], | ||
compatibilityDate = "2023-01-15", | ||
compatibilityFlags = ["nodejs_compat_v2"], | ||
) | ||
), | ||
], | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters