Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 0fd23dc

Browse files
committed
Add support for navigator.userAgent, closes #209
1 parent 75abe07 commit 0fd23dc

File tree

6 files changed

+38
-0
lines changed

6 files changed

+38
-0
lines changed

packages/core/src/plugins/core.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
DOMException,
4343
FetchEvent,
4444
FixedLengthStream,
45+
Navigator,
4546
Request,
4647
Response,
4748
ScheduledEvent,
@@ -365,6 +366,12 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
365366
CompatResponse = proxyStringFormDataFiles(CompatResponse);
366367
}
367368

369+
// Only include `navigator` if `global_navigator` compatibility flag is set
370+
const compatGlobals: Context = {};
371+
if (ctx.compat.isEnabled("global_navigator")) {
372+
compatGlobals.navigator = new Navigator();
373+
}
374+
368375
// Try to parse upstream URL if set
369376
try {
370377
this.upstreamURL =
@@ -449,6 +456,8 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
449456
// Approximate with serialize/deserialize if not there.
450457
structuredClone: globalThis.structuredClone ?? structuredCloneBuffer,
451458

459+
...compatGlobals,
460+
452461
// The types below would be included automatically, but it's not possible
453462
// to create instances of them without using their constructors and they
454463
// may be returned from Miniflare's realm (e.g. ArrayBuffer responses,

packages/core/src/standards/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ export type {
4343
} from "./http";
4444
export { FixedLengthStream } from "./streams";
4545
export type { ArrayBufferViewConstructor } from "./streams";
46+
export * from "./navigator";
4647
export * from "./timers";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export class Navigator {
2+
readonly userAgent = "Cloudflare-Workers";
3+
}

packages/core/test/plugins/core.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,17 @@ test("CorePlugin: setup: Response parses files in FormData as File objects only
497497
resFormData = await res.formData();
498498
t.true(resFormData.get("file") instanceof File);
499499
});
500+
test("CorePlugin: setup: includes navigator only if compatibility flag enabled", async (t) => {
501+
let plugin = new CorePlugin(ctx);
502+
let globals = (await plugin.setup()).globals;
503+
t.is(globals?.navigator, undefined);
504+
505+
const compat = new Compatibility(undefined, ["global_navigator"]);
506+
plugin = new CorePlugin({ log, compat, rootPath });
507+
globals = (await plugin.setup()).globals;
508+
t.is(globals?.navigator.userAgent, "Cloudflare-Workers");
509+
});
510+
500511
test("CorePlugin: setup: structuredClone: creates deep-copy of value", async (t) => {
501512
const plugin = new CorePlugin(ctx);
502513
const { globals } = await plugin.setup();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Navigator } from "@miniflare/core";
2+
import test from "ava";
3+
4+
test("Navigator: userAgent is Cloudflare-Workers", (t) => {
5+
const navigator = new Navigator();
6+
t.is(navigator.userAgent, "Cloudflare-Workers");
7+
});

packages/shared/src/compat.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ export interface CompatibilityFeature {
1111
// will get a type error if they try to use an unsupported flag via the API,
1212
// and they won't be logged in the "Enabled Compatibility Flags" section.
1313
export type CompatibilityEnableFlag =
14+
| "global_navigator"
1415
| "durable_object_fetch_requires_full_url"
1516
| "fetch_refuses_unknown_protocols"
1617
| "formdata_parser_supports_files"
1718
| "html_rewriter_treats_esi_include_as_void_tag";
1819
export type CompatibilityDisableFlag =
20+
| "no_global_navigator"
1921
| "durable_object_fetch_allows_relative_url"
2022
| "fetch_treats_unknown_protocols_as_http"
2123
| "formdata_parser_converts_files_to_strings";
@@ -24,6 +26,11 @@ export type CompatibilityFlag =
2426
| CompatibilityDisableFlag;
2527

2628
const FEATURES: CompatibilityFeature[] = [
29+
{
30+
defaultAsOf: "2022-03-21",
31+
enableFlag: "global_navigator",
32+
disableFlag: "no_global_navigator",
33+
},
2734
{
2835
defaultAsOf: "2021-11-10",
2936
enableFlag: "durable_object_fetch_requires_full_url",

0 commit comments

Comments
 (0)