Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a global Navigator object #39540

Closed
jimmywarting opened this issue Jul 27, 2021 · 24 comments
Closed

Add a global Navigator object #39540

jimmywarting opened this issue Jul 27, 2021 · 24 comments
Labels
feature request Issues that request new features to be added to Node.js. stale

Comments

@jimmywarting
Copy link

jimmywarting commented Jul 27, 2021

I think there is a bunch of interesting web related things on the navigator object itself that could fit into NodeJS and dose not require a UI.
Deno, Bun.js, Browser and all Worker threads has it. NodeJS is the only platform that lacks it

Things i find interesting to also have in a NodeJS environment is

  • geolocation
  • connection
  • hardwareConcurrency
  • platform
  • language
  • onLine
  • getBattery
  • getGamepads
  • vibrate
  • permissions
  • worker: implement Web Locks API #36502
  • usb
  • clipboard
  • storage + File System Access + estimates (whatwg/fs)
  • deviceMemory
  • presentation
  • bluetooth
  • userAgent

(not saying we should go ahead and implement all of this)
I think there should at least exist a global navigator object so ppl can at least polyfill missing features onto the global navigator

@targos targos added the feature request Issues that request new features to be added to Node.js. label Jul 27, 2021
@targos
Copy link
Member

targos commented Jul 27, 2021

I'm +1 on adding the navigator object, with APIs that make sense for Node.js.
We could start with relatively easy ones lik. hardwareConcurrency or platform

Mesteery added a commit to Mesteery/node that referenced this issue Jul 29, 2021
Mesteery added a commit to Mesteery/node that referenced this issue Jul 29, 2021
Mesteery added a commit to Mesteery/node that referenced this issue Jul 29, 2021
Add the Navigator object with the Device Memory API.

Refs: nodejs#39540
Refs: https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
Refs: https://w3c.github.io/device-memory

Co-authored-by: Voltrex <mohammadkeyvanzade94@gmail.com>
@tniessen
Copy link
Member

Refs: #39581 (comment)

The Navigator object is interesting because it brings together many APIs that can be useful, even in the context of Node.js

Navigator is defined by the HTML standard, not by the ECMAScript standard, and I am afraid most of its features are not necessarily meaningful in Node.js.

Navigator fields according to the current HTML standard:

  • NavigatorID: these values must be provided by each Node.js application and cannot be provided by Node.js itself. Some properties (e.g., userAgent) do not really make sense outside of web browsers as far as I can tell.
  • NavigatorLanguage: we could maybe use the system language here, but that is not necessarily the "user's preferred language." The user accessing the application might not be the same user that is running the Node.js process.
  • NavigatorOnLine: this does not seem to make sense for Node.js applications that might be connected to multiple networks through multiple network interfaces.
  • NavigatorContentUtils: this does not seem useful in Node.js.
  • NavigatorCookies: this does not seem to make sense in Node.js (neither true nor false is a meaningful value).
  • NavigatorPlugins: ouch
  • NavigatorConcurrentHardware: this is an indication at best and less useful than os.cpus().

Suggested extensions:

  • NavigatorDeviceMemory: this does not seem helpful, and the use cases covered by the "Introduction" section in the draft do not apply to Node.js. More precise APIs exist in Node.js.
  • NavigatorNetworkInformation: this seems to be pretty much useless for any server-side application because it is impossible for Node.js to tell what network interface the information should be referring to.
  • USB: this might actually maybe be a useful feature.
  • Geolocation: not sure if useful or how to implement this on a server.

Refs: #39581 (comment)

Navigator is defined by the HTML standard, not by the ECMAScript standard

I know.

NavigatorContentUtils: this does not seem useful in Node.js.
NavigatorCookies: this does not seem to make sense in Node.js (neither true nor false is a meaningful value).
NavigatorPlugins: ouch
NavigatorID: these values must be provided by each Node.js application and cannot be provided by Node.js itself. Some properties (e.g., userAgent) do not really make sense outside of web browsers as far as I can tell.
NavigatorLanguage: we could maybe use the system language here, but that is not necessarily the "user's preferred language." The user accessing the application might not be the same user that is running the Node.js process.

Yes, I agree, and they are the ones I mean when I say they should not be implemented.

NavigatorDeviceMemory: this does not seem helpful, and the use cases covered by the "Introduction" section in the draft do not apply to Node.js. More precise APIs exist in Node.js.

Personally I find it interesting to have the RAM rounded to the nearest power of 2. But not having a lower bound of 0.25 and upper bound of 8 GiB as proposed in the specification.
And I don't think this information is imprecise. In my opinion it is not uncommon to need this rounded device memory.

NavigatorOnLine: this does not seem to make sense for Node.js applications that might be connected to multiple networks through multiple network interfaces.

Even though a Node.js application can be connected to multiple networks through multiple network interfaces, false can be returned if the application is completely disconnected.

Geolocation: not sure if useful or how to implement this on a server.

If the machine does not have GPS, the errorCallback can be called with the error https://www.w3.org/TR/geolocation/#dom-geolocationpositionerror-position_unavailable. It's true that it's hard to find a usecase for this one, but I think there's probably a useful purpose for this, for example a program that returns the current GPS location.

We can, not implement APIs that are not useful in Node.js, while having Navigator and some useful APIs.

I also think we should discuss this in the issue, and possibly get the author's opinion, right?


Personally I find it interesting to have the RAM rounded to the nearest power of 2. But not having a lower bound of 0.25 and upper bound of 8 GiB as proposed in the specification.
And I don't think this information is imprecise. In my opinion it is not uncommon to need this rounded device memory.

I am curious what a potential use case for this could be in Node.js. The use cases for browsers are outlined in the introductory section of the specification. But what about Node.js?

If I run one process on a machine with 256 MiB main memory (deviceMemory === 0.25) it surely has more resources available than each process when running a thousand processes on a machine with 128 GiB memory (deviceMemory === 128). Unless I put the single process under ulimit, in which case the device memory is even less meaningful.

(Also, the primary aspect of the spec appears to be the header field that is sent by the browser: This document defines a HTTP Client Hint header to surface device capability for memory i.e. device RAM, in order to enable web apps to customize content depending on device memory constraints.)

NavigatorOnLine: this does not seem to make sense for Node.js applications that might be connected to multiple networks through multiple network interfaces.

Even though a Node.js application can be connected to multiple networks through multiple network interfaces, false can be returned if the application is completely disconnected.

Interesting. So as long as the server has any network interfaces that aren't down (e.g., a virtual network switch connecting Docker containers on the same machine with no external networking capabilities), this property would be true? What use does this property have then?

Geolocation: not sure if useful or how to implement this on a server.

If the machine does not have GPS, the errorCallback can be called with the error https://www.w3.org/TR/geolocation/#dom-geolocationpositionerror-position_unavailable. It's true that it's hard to find a usecase for this one, but I think there's probably a useful purpose for this, for example a program that returns the current GPS location.

I think the more interesting question is: what if there are two GPS sensors, each returning different locations? That being said, some operating systems do provide geolocations even without GPS hardware, so we could implement this as "if provided by the operating system in an unambiguous manner, we'll just accept it, and if it isn't, we don't support it."


We can, not implement APIs that are not useful in Node.js, while having Navigator and some useful APIs.

We surely can add navigator and implement only APIs that make sense in the context of Node.js. However, I am afraid that it could become a slippery slope toward incorrect or meaningless additions. These APIs were, for the most part, not designed for environments other than web browsers.

@jimmywarting
Copy link
Author

jimmywarting commented Jul 31, 2021

The biggest reasons why i want to have a Navigator object is:

  • permissions: To request, revoke & query access to more powerful features and making NodeJS more secure
  • clipboard: just neat. Not so important... complex to get it right on windows, linux, mac, that's why it would be nice to have
  • storage + File System Access I quite like the File System Access. Being able to write cross platform code that utilize the file system in the same way is grate

I also worked with navigator.bluetooth (forgot to put it up on the list) and wanted to have it in nodejs before.

I think the more interesting question is: what if there are two GPS sensors, each returning different locations? That being said, some operating systems do provide geolocations even without GPS hardware, so we could implement this as "if provided by the operating system in an unambiguous manner, we'll just accept it, and if it isn't, we don't support it."

I kind of investigated how Google dose geolocation without gps using ip and wifi access points / mac addresses at some point and thought about impl it as a npm module at some point in my life
https://developers.google.com/maps/documentation/geolocation/overview

Geolocation: not sure if useful or how to implement this on a server.

There are ppl building Drones with NodeJS. NodeJS is more than just a server 😉

...Language would be useful with localization and Intl

@jasnell
Copy link
Member

jasnell commented Jul 31, 2021

There are ppl building Drones with NodeJS. NodeJS is more than just a server

Yes, and that's good but by itself is not enough to justify adding to core. The parts of the web platform API that we have adopted so far are bits that a) already overlap with existing core functions or b) are generally usable in all use cases, server or otherwise. Much of the navigator api is very specific to individual types of use cases that do not necessarily meet both of those criteria. I don't think anyone here is saying no outright, that would be silly, but we do need to be selective and deliberate.

@tniessen
Copy link
Member

tniessen commented Jul 31, 2021

permissions: To request, revoke & query access to more powerful features and making NodeJS more secure

I believe @addaleax or @jasnell did some work around permission-based security models for Node.js. One of the main problems is that any permission system would make it entirely impossible to use native addons in Node.js because we cannot reasonably restrict their permissions. Also, how would we determine if a permission was granted or not? We surely cannot implement "prompt", and we cannot rely on the file system, so the only option might be command-line arguments (similar to how deno does it) or environment variables. In my experience, it is much easier and more reliable to use operating system features, e.g., file permissions and iptables, to control access for server processes.

storage

I don't think Node.js implements any of the "storage endpoints" that would be affected by navigator.storage, but this is the first time I am looking at it, so I might be misunderstanding the purpose of the API.

File System Access

The draft does seem to require these three functions to have any use:

window.showOpenFilePicker
window.showSaveFilePicker
window.showDirectoryPicker

I don't see how any of these could be implemented in Node.js.

There are ppl building Drones with NodeJS. NodeJS is more than just a server

Regardless of whether it is a good idea to build flying objects based on software that relies on dynamic memory allocations and crashes when it runs out of memory and that is incredibly difficult to statically analyze, I am not saying that there are no applications that won't benefit from geolocation. But are those few applications worth adding geolocation to Node.js core?

@jimmywarting
Copy link
Author

jimmywarting commented Jul 31, 2021

The draft does seem to require these three functions to have any use: showOpenFilePicker, showSaveFilePicker, showDirectoryPicker

Not really, you could take advantage of the sandboxed filesystem and use it without dialogs.
I know Deno was looking into adapting File system to co-exist with other api's

This API would live in parallel with the existing low-level file system API provided by Deno.open, Deno.write, Deno.read, Deno.readDir, ...

Writing to a file:

import fs from 'node:fs'
const fileHandle = await fs.getFileHandle("/tmp/foo.txt"); // Returns FileSystemFileHandle 
const writable = await fileHandle.createWritable();
const writer = writable.getWriter();
await writer.write(new TextEncoder().encode("Hello World"));
await writer.close();

Also directory listing

const directoryHandle = await fs.getDirectoryHandle("/etc"); // Returns FileSystemDirectoryHandle 
for await (let [name, handle] of directoryHandle) {
  // ...
}

https://wicg.github.io/file-system-access/

Or maybe we have a directoryHandle corresponding to the cwd or a complete secure sandboxed directory

const fileHandle = await navigator.storage.getDirectory();

I know there have been talks about getting a blob backed up by the file system and i hope it will land so we can upload large file with FormData, creating objectURLs for worker threads and transfering files with very little cost. This would be the most "correct" way to obtain a File from the filesystem.

With my File System Adapter I created a way to obtain a a Handle by doing something like

const handle = await getOriginPrivateDirectory(nodeAdapter, './public')

@jimmywarting
Copy link
Author

jimmywarting commented Jul 31, 2021

Deno has a permission api on it's Deno namespace... https://deno.land/manual/runtime/permission_apis with some degree of cli prompts

@tniessen
Copy link
Member

I know Deno was looking into adapting File system to co-exist with other api's

import fs from 'node:fs'
const fileHandle = await fs.getFileHandle("/tmp/foo.txt"); // Returns FileSystemFileHandle

Oh sure, we can always do that, but then the code isn't really runtime-agnostic because it requires APIs specific to a certain runtime to retrieve file handles.

Deno has a permission api on it's Deno namespace

We could implement something like that, but, when enabled, it would make it impossible for applications to use the child_process APIs and any native addons. (Similarly, in Deno, --allow-run and --allow-plugin essentially remove any security guarantees.)

@tniessen
Copy link
Member

tniessen commented Aug 4, 2021

I believe @addaleax or @jasnell did some work around permission-based security models for Node.js.

Found it: #22112

@jimmywarting
Copy link
Author

Oh, btw browser has something new on drag and drop'ed files & folders DataTransferItem.prototype.getAsFileSystemHandle to get things as a whatwg/fs handle

@nissy-dev
Copy link
Contributor

nissy-dev commented May 23, 2022

Recently, WinterCG was launched to promote runtimes supporting an unified API regardless of the runtime they are using: be it browsers, servers, embedded applications, or edge runtimes. The WinterCG's Minimum Common Web Platform API proposal includes navigator.userAgent

Cloudflare Workers and Deno also has a navigator.userAgent API. If this API is implemented, Node.js improve compatibility with them and web.

If you are interested in implementing it, I would like to work on it! How do you think?

ref #43155

@tniessen
Copy link
Member

I'm still somewhat concerned that there might be code that checks if (globalThis.navigator) to see if it's running in a, well, navigator ("the client" as the HTML spec puts it).

That being said, once the proposal matures and if this doesn't turn into a slippery slide that leads to other navigator properties being added that make little sense in non-browsers, I probably wouldn't be opposed to adding it at some point in the future.

@fahdi
Copy link

fahdi commented Jun 29, 2022

@tniessen Was it ever added?

@sosoba
Copy link
Contributor

sosoba commented Jul 11, 2022

You can set up global object with custom library via API https://nodejs.org/dist/latest-v16.x/docs/api/esm.html#globalpreload

@github-actions
Copy link
Contributor

github-actions bot commented Jan 8, 2023

There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.

For more information on how the project manages feature requests, please consult the feature request management document.

@github-actions github-actions bot added the stale label Jan 8, 2023
@dnalborczyk
Copy link
Contributor

example of current values for globalThis.navigator.userAgent:

Cloudflare Workers: Cloudflare-Workers
Deno: Deno/1.29.2
Bun: Bun/0.4.0

@muzuiget
Copy link

muzuiget commented Jun 2, 2023

bun currently implements:

Navigator {
  userAgent: "Bun/0.6.6",
  hardwareConcurrency: 4
}

@jimmywarting
Copy link
Author

how do you feel about navigator.userAgentData?
Note that it's an experimental technology. and behind a unofficial draft spec.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-UA

@tniessen
Copy link
Member

For anyone else who missed this (like I did), globalThis.navigator has been added in #47769. There are already multiple PRs attempting to add properties that, in my opinion, do not benefit Node.js, so here we go...

@zm-cttae
Copy link

Could someone kindly add navigator.platform so we can have a cross-platform OS targeting method?

@TheSainEyereg
Copy link

Seems like this changes already broke some libraries e.g. pdf.js which now thinks that navigator has "platform" property

IMG_20231019_180922_239.jpg

IMG_20231019_180936_868.jpg

In NodeJS 20.5.0 all works fine

@zm-cttae
Copy link

Noting here also that Process.platform and Navigator.platform are different e.g. Navigator value is capitalised

Copy link
Contributor

There has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the never-stale Mark issue so that it is never considered stale label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.

@github-actions github-actions bot added the stale label Apr 17, 2024
Copy link
Contributor

There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment.

For more information on how the project manages feature requests, please consult the feature request management document.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. stale
Projects
Status: In Progress
Development

Successfully merging a pull request may close this issue.