-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
lib: throw from localStorage getter on missing storage path #60351
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
lib: throw from localStorage getter on missing storage path #60351
Conversation
|
Shouldn't this throw a SecurityError DOMException rather than a plain error?
https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage-dev |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #60351 +/- ##
==========================================
+ Coverage 88.05% 88.56% +0.50%
==========================================
Files 704 704
Lines 207857 207840 -17
Branches 39964 40054 +90
==========================================
+ Hits 183030 184073 +1043
+ Misses 16806 15798 -1008
+ Partials 8021 7969 -52
🚀 New features to boost your workflow:
|
I did go with this originally, but a) the security semantics don't really apply here (there's no origin check, for instance); b) throwing a native Error for an invalid execution environment is consistent with Node's other web implementations, eg..the global |
The spec reads as "throw a SecurityError if 'security semantics' or 'not configured to store data'" which makes it seem to me like we should still throw a SecurityError DOMException.
I think webstorage is special here, can crypto throw in browsers/the spec? |
|
I'll link the original DOMException-throwing commit (5e04491) for review alongside. If there's consensus to use this approach, then it's no problem to change it. |
JakobJingleheimer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🙌
test/parallel/test-webstorage.js
Outdated
| assert.match(cp.stderr, /Warning: `--localstorage-file` was provided without a valid path/); | ||
| assert.match( | ||
| cp.stderr, | ||
| /Error \[ERR_WEBSTORAGE_MISSING_STORAGE_PATH\]: Cannot initialize local storage without a `--localstorage-file` path/, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: matching against the whole error message is brittle. Better to match against only ERR_WEBSTORAGE_MISSING_STORAGE_PATH.
gurgunday
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lgtm
mcollina
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
|
The
notable-change
Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the Other Notable Changes section. |
KhafraDev
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be throwing a DOMException.
9dc2163 to
600eae6
Compare
|
Modified as per the blocking review. Note that this does diverge the behaviours of |
mcollina
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
|
Landed in 2fb3c7e |
PR-URL: #60351 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Notable changes: lib: * (SEMVER-MINOR) add options to util.deprecate (Rafael Gonzaga) #59982 * throw from localStorage getter on missing storage path (René) #60351 module: * (SEMVER-MINOR) mark type stripping as stable (Marco Ippolito) #60600 net: * (SEMVER-MINOR) increase network family autoselection timeout to 500ms (Rod Vagg) #60334 node-api: * (SEMVER-MINOR) add napi_create_object_with_properties (Miguel Marcondes Filho) #59953 v8: * (SEMVER-MINOR) adding total_allocated_bytes to HeapStatistics (Caio Lima) #60573 PR-URL: #60677
Notable changes: lib: * (SEMVER-MINOR) add options to util.deprecate (Rafael Gonzaga) #59982 * throw from localStorage getter on missing storage path (René) #60351 module: * (SEMVER-MINOR) mark type stripping as stable (Marco Ippolito) #60600 net: * (SEMVER-MINOR) increase network family autoselection timeout to 500ms (Rod Vagg) #60334 node-api: * (SEMVER-MINOR) add napi_create_object_with_properties (Miguel Marcondes Filho) #59953 v8: * (SEMVER-MINOR) adding total_allocated_bytes to HeapStatistics (Caio Lima) #60573 PR-URL: #60677
|
FWIW the spec's throwing on getter behavior breaks |
This isn't novel; the same occurs if eg. Node.js is built without crypto support. Global getters throwing errors is acceptable behaviour in the web spec, and implementations need to account for this. |
|
I see, thanks. FWIW, |
|
FWIW we resolved the issue by adding |
|
I agree that the current Node change is spec-complient: https://html.spec.whatwg.org/multipage/webstorage.html#the-localstorage-attribute
However, in practice, this is quite annoying in terms of DX, and requires us to gate our code everywhere to protect against localStorage throwing. Sure, we can implement such a function: function localStorageIsAvailable() {
try {
return typeof localStorage !== 'undefined';
} catch {
return false;
}
}But this is going to lead to unperformant code, creating expensive stacktraces for regular program control flow. It's unlikely that this code will only run once per node app and be memoized, considering all third-party apps needing localStorage access will have to write a similar function. We do have such code on Docusaurus, which was initially introduced for browser cases (in particular, when running within an iframes with certain browser settings): try {
return window[storageType];
} catch (err) {
logOnceBrowserStorageNotAvailableWarning(err as Error);
return null;
}It's already annoying that browsers can throw on getter access, and IMHO that choice is questionable and probably historical. It will probably be hard to find out why they made that choice decades ago, but here's a guess from someone working on web platform APIs, and suggesting this could be something to discuss in Winter TC (TC55)
https://bsky.app/profile/lukewarlow.dev/post/3m5ldcvizw22c For what it's worth, Deno doesn't throw:
By the way, it feels inconsistent with the spec to only throw for localStorage, and not for sessionStorage: https://html.spec.whatwg.org/multipage/webstorage.html#the-sessionstorage-attribute
|
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [node](https://nodejs.org) ([source](https://github.com/nodejs/node)) | minor | `25.1.0` -> `25.2.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>nodejs/node (node)</summary> ### [`v25.2.0`](https://github.com/nodejs/node/releases/tag/v25.2.0): 2025-11-11, Version 25.2.0 (Current), @​aduh95 [Compare Source](nodejs/node@v25.1.0...v25.2.0) ##### Notable Changes - \[[`a37c01e6a1`](nodejs/node@a37c01e6a1)] - **(SEMVER-MINOR)** **lib**: add options to util.deprecate (Rafael Gonzaga) [#​59982](nodejs/node#59982) - \[[`4fbb1ab101`](nodejs/node@4fbb1ab101)] - **lib**: throw from localStorage getter on missing storage path (René) [#​60351](nodejs/node#60351) - \[[`727560a96d`](nodejs/node@727560a96d)] - **(SEMVER-MINOR)** **module**: mark type stripping as stable (Marco Ippolito) [#​60600](nodejs/node#60600) - \[[`506b79e888`](nodejs/node@506b79e888)] - **(SEMVER-MINOR)** **net**: increase network family autoselection timeout to 500ms (Rod Vagg) [#​60334](nodejs/node#60334) - \[[`166c72ec02`](nodejs/node@166c72ec02)] - **(SEMVER-MINOR)** **node-api**: add napi\_create\_object\_with\_properties (Miguel Marcondes Filho) [#​59953](nodejs/node#59953) - \[[`399b340022`](nodejs/node@399b340022)] - **(SEMVER-MINOR)** **v8**: adding total\_allocated\_bytes to HeapStatistics (Caio Lima) [#​60573](nodejs/node#60573) ##### Commits - \[[`d5158a0a2d`](nodejs/node@d5158a0a2d)] - **benchmark**: focus on import.meta intialization in import-meta benchmark (Joyee Cheung) [#​60603](nodejs/node#60603) - \[[`26a5305fa9`](nodejs/node@26a5305fa9)] - **benchmark**: add per-suite setup option (Joyee Cheung) [#​60574](nodejs/node#60574) - \[[`4810e4b82d`](nodejs/node@4810e4b82d)] - **buffer**: speed up concat via TypedArray#set (Gürgün Dayıoğlu) [#​60399](nodejs/node#60399) - \[[`94a94a6b3a`](nodejs/node@94a94a6b3a)] - **console**: optimize single-string logging (Gürgün Dayıoğlu) [#​60422](nodejs/node#60422) - \[[`ad376c31db`](nodejs/node@ad376c31db)] - **crypto**: fix argument validation in crypto.timingSafeEqual fast path (Joyee Cheung) [#​60538](nodejs/node#60538) - \[[`dc38a45a55`](nodejs/node@dc38a45a55)] - **debugger**: fix event listener leak in the run command (Joyee Cheung) [#​60464](nodejs/node#60464) - \[[`a61e5d8e05`](nodejs/node@a61e5d8e05)] - **deps**: call OPENSSL\_free after ANS1\_STRING\_to\_UTF8 (Rafael Gonzaga) [#​60609](nodejs/node#60609) - \[[`51e5030afa`](nodejs/node@51e5030afa)] - **deps**: nghttp2: revert [`7784fa9`](nodejs/node@7784fa979d0b) (Antoine du Hamel) [#​59790](nodejs/node#59790) - \[[`eef838f499`](nodejs/node@eef838f499)] - **deps**: update nghttp2 to 1.67.1 (nodejs-github-bot) [#​59790](nodejs/node#59790) - \[[`13120a43d4`](nodejs/node@13120a43d4)] - **deps**: update simdjson to 4.1.0 (Node.js GitHub Bot) [#​60542](nodejs/node#60542) - \[[`6e1b23dab8`](nodejs/node@6e1b23dab8)] - **deps**: update corepack to 0.34.2 (Node.js GitHub Bot) [#​60550](nodejs/node#60550) - \[[`a02e05c486`](nodejs/node@a02e05c486)] - **deps**: update amaro to 1.1.5 (Node.js GitHub Bot) [#​60541](nodejs/node#60541) - \[[`b9ba3a7947`](nodejs/node@b9ba3a7947)] - **deps**: V8: backport [`fe81545`](nodejs/node@fe81545e6d14) (Caio Lima) [#​60429](nodejs/node#60429) - \[[`07bcd28494`](nodejs/node@07bcd28494)] - **deps**: V8: cherry-pick [`7ef6a00`](nodejs/node@7ef6a001762) (Xiao-Tao) [#​60259](nodejs/node#60259) - \[[`3e11658243`](nodejs/node@3e11658243)] - **doc**: update Collaborators list to reflect hybrist handle change (Antoine du Hamel) [#​60650](nodejs/node#60650) - \[[`b8e40e4d38`](nodejs/node@b8e40e4d38)] - **doc**: fix link in `--env-file=file` section (N. Bighetti) [#​60563](nodejs/node#60563) - \[[`9558c1c0df`](nodejs/node@9558c1c0df)] - **doc**: fix linter issues (Antoine du Hamel) [#​60636](nodejs/node#60636) - \[[`cdf70de563`](nodejs/node@cdf70de563)] - **doc**: add missing history entry for `sqlite.md` (Antoine du Hamel) [#​60607](nodejs/node#60607) - \[[`e3c5dcf1ea`](nodejs/node@e3c5dcf1ea)] - **doc**: correct values/references for buffer.kMaxLength (René) [#​60305](nodejs/node#60305) - \[[`a25d76c924`](nodejs/node@a25d76c924)] - **doc**: recommend events.once to manage 'close' event (Dan Fabulich) [#​60017](nodejs/node#60017) - \[[`795f32bf91`](nodejs/node@795f32bf91)] - **doc**: highlight module loading difference between import and require (Ajay A) [#​59815](nodejs/node#59815) - \[[`212775410b`](nodejs/node@212775410b)] - **doc**: add CJS code snippets in `sqlite.md` (Allon Murienik) [#​60395](nodejs/node#60395) - \[[`263c06096d`](nodejs/node@263c06096d)] - **doc**: fix typo in `process.unref` documentation (우혁) [#​59698](nodejs/node#59698) - \[[`356bdae408`](nodejs/node@356bdae408)] - **doc**: add some entries to `glossary.md` (Mohataseem Khan) [#​59277](nodejs/node#59277) - \[[`9632c398de`](nodejs/node@9632c398de)] - **doc**: improve agent.createConnection docs for http and https agents (JaeHo Jang) [#​58205](nodejs/node#58205) - \[[`f72880dbe3`](nodejs/node@f72880dbe3)] - **doc**: fix pseudo code in modules.md (chirsz) [#​57677](nodejs/node#57677) - \[[`a9c70cefe8`](nodejs/node@a9c70cefe8)] - **doc**: add missing variable in code snippet (Koushil Mankali) [#​55478](nodejs/node#55478) - \[[`2892d151d4`](nodejs/node@2892d151d4)] - **doc**: add missing word in `single-executable-applications.md` (Konstantin Tsabolov) [#​53864](nodejs/node#53864) - \[[`9c99ab6571`](nodejs/node@9c99ab6571)] - **doc**: fix typo in http.md (Michael Solomon) [#​59354](nodejs/node#59354) - \[[`3446cf375f`](nodejs/node@3446cf375f)] - **doc**: update devcontainer.json and add documentation (Joyee Cheung) [#​60472](nodejs/node#60472) - \[[`519c537875`](nodejs/node@519c537875)] - **doc**: add haramj as triager (Haram Jeong) [#​60348](nodejs/node#60348) - \[[`62889d7e99`](nodejs/node@62889d7e99)] - **doc**: clarify require(esm) description (dynst) [#​60520](nodejs/node#60520) - \[[`0b9ef68705`](nodejs/node@0b9ef68705)] - **doc**: instantiate resolver object (Donghoon Nam) [#​60476](nodejs/node#60476) - \[[`cd5c1ad29f`](nodejs/node@cd5c1ad29f)] - **doc**: correct module loading descriptions (Joyee Cheung) [#​60346](nodejs/node#60346) - \[[`74719dad7a`](nodejs/node@74719dad7a)] - **doc**: clarify Linux runtime requirements for >=25 (Joyee Cheung) [#​60484](nodejs/node#60484) - \[[`ca39540785`](nodejs/node@ca39540785)] - **doc**: clarify --use-system-ca support status (Joyee Cheung) [#​60340](nodejs/node#60340) - \[[`dbf204c714`](nodejs/node@dbf204c714)] - **doc,crypto**: link keygen to supported types (Filip Skokan) [#​60585](nodejs/node#60585) - \[[`3bcf86d56d`](nodejs/node@3bcf86d56d)] - **esm**: use sync loading/resolving on non-loader-hook thread (Joyee Cheung) [#​60380](nodejs/node#60380) - \[[`69b3d2c845`](nodejs/node@69b3d2c845)] - **http**: replace startsWith with strict equality (btea) [#​59394](nodejs/node#59394) - \[[`a38e2f5975`](nodejs/node@a38e2f5975)] - **http2**: add diagnostics channels for client stream request body (Darshan Sen) [#​60480](nodejs/node#60480) - \[[`c047e73a00`](nodejs/node@c047e73a00)] - **inspector**: inspect HTTP response body (Chengzhong Wu) [#​60572](nodejs/node#60572) - \[[`d2087bae92`](nodejs/node@d2087bae92)] - **inspector**: support inspecting HTTP/2 request and response bodies (Darshan Sen) [#​60483](nodejs/node#60483) - \[[`003121c475`](nodejs/node@003121c475)] - **inspector**: fix crash when receiving non json message (Shima Ryuhei) [#​60388](nodejs/node#60388) - \[[`a37c01e6a1`](nodejs/node@a37c01e6a1)] - **(SEMVER-MINOR)** **lib**: add options to util.deprecate (Rafael Gonzaga) [#​59982](nodejs/node#59982) - \[[`219d2e978d`](nodejs/node@219d2e978d)] - **lib**: replace global SharedArrayBuffer constructor with bound method (Renegade334) [#​60497](nodejs/node#60497) - \[[`4fbb1ab101`](nodejs/node@4fbb1ab101)] - **lib**: throw from localStorage getter on missing storage path (René) [#​60351](nodejs/node#60351) - \[[`ca8934f44d`](nodejs/node@ca8934f44d)] - **meta**: bump cachix/install-nix-action from 31.6.1 to 31.8.2 (dependabot\[bot]) [#​60534](nodejs/node#60534) - \[[`166490230a`](nodejs/node@166490230a)] - **meta**: bump github/codeql-action from 3.30.5 to 4.31.2 (dependabot\[bot]) [#​60533](nodejs/node#60533) - \[[`b722236a12`](nodejs/node@b722236a12)] - **meta**: bump actions/download-artifact from 5.0.0 to 6.0.0 (dependabot\[bot]) [#​60532](nodejs/node#60532) - \[[`3314b0bc60`](nodejs/node@3314b0bc60)] - **meta**: bump actions/upload-artifact from 4.6.2 to 5.0.0 (dependabot\[bot]) [#​60531](nodejs/node#60531) - \[[`d1d9891feb`](nodejs/node@d1d9891feb)] - **meta**: bump actions/github-script from 7.0.1 to 8.0.0 (dependabot\[bot]) [#​60530](nodejs/node#60530) - \[[`995596a34f`](nodejs/node@995596a34f)] - **meta**: bump actions/setup-node from 5.0.0 to 6.0.0 (dependabot\[bot]) [#​60529](nodejs/node#60529) - \[[`b60157a0fe`](nodejs/node@b60157a0fe)] - **meta**: bump actions/stale from 10.0.0 to 10.1.0 (dependabot\[bot]) [#​60528](nodejs/node#60528) - \[[`07fa6c9081`](nodejs/node@07fa6c9081)] - **meta**: call `create-release-post.yml` post release (Aviv Keller) [#​60366](nodejs/node#60366) - \[[`727560a96d`](nodejs/node@727560a96d)] - **(SEMVER-MINOR)** **module**: mark type stripping as stable (Marco Ippolito) [#​60600](nodejs/node#60600) - \[[`506b79e888`](nodejs/node@506b79e888)] - **(SEMVER-MINOR)** **net**: increase network family autoselection timeout to 500ms (Rod Vagg) [#​60334](nodejs/node#60334) - \[[`166c72ec02`](nodejs/node@166c72ec02)] - **(SEMVER-MINOR)** **node-api**: add napi\_create\_object\_with\_properties (Miguel Marcondes Filho) [#​59953](nodejs/node#59953) - \[[`6ab83cf979`](nodejs/node@6ab83cf979)] - **node-api**: use local files for instanceof test (Vladimir Morozov) [#​60190](nodejs/node#60190) - \[[`3671851879`](nodejs/node@3671851879)] - **perf\_hooks**: move non-standard performance properties to perf\_hooks (Chengzhong Wu) [#​60370](nodejs/node#60370) - \[[`6ddee4a7ed`](nodejs/node@6ddee4a7ed)] - **repl**: fix pasting after moving the cursor to the left (Ruben Bridgewater) [#​60470](nodejs/node#60470) - \[[`edc3033905`](nodejs/node@edc3033905)] - **sqlite,doc**: fix StatementSync section (Edy Silva) [#​60474](nodejs/node#60474) - \[[`e9b68e60d4`](nodejs/node@e9b68e60d4)] - **src**: move import.meta initializer to native land (Joyee Cheung) [#​60603](nodejs/node#60603) - \[[`0ebf839a4f`](nodejs/node@0ebf839a4f)] - **src**: use CP\_UTF8 for wide file names on win32 (Fedor Indutny) [#​60575](nodejs/node#60575) - \[[`a31ad37714`](nodejs/node@a31ad37714)] - **src**: show original file name in FileHandle GC close errors (Anna Henningsen) [#​60593](nodejs/node#60593) - \[[`a6c221324b`](nodejs/node@a6c221324b)] - **src**: avoid C strings in more C++ exception throws (Anna Henningsen) [#​60592](nodejs/node#60592) - \[[`fdff838ce3`](nodejs/node@fdff838ce3)] - **src**: add internal binding for constructing SharedArrayBuffers (Renegade334) [#​60497](nodejs/node#60497) - \[[`4385b0b65f`](nodejs/node@4385b0b65f)] - **src**: move `napi_addon_register_func` to `node_api_types.h` (Anna Henningsen) [#​60512](nodejs/node#60512) - \[[`de78da7887`](nodejs/node@de78da7887)] - **src**: move Node-API version detection to where it is used (Anna Henningsen) [#​60512](nodejs/node#60512) - \[[`b606d46c3f`](nodejs/node@b606d46c3f)] - **src**: remove unconditional NAPI\_EXPERIMENTAL in node.h (Chengzhong Wu) [#​60345](nodejs/node#60345) - \[[`5941341889`](nodejs/node@5941341889)] - **src**: clean up generic counter implementation (Anna Henningsen) [#​60447](nodejs/node#60447) - \[[`7015f30e62`](nodejs/node@7015f30e62)] - **src**: add enum handle for ToStringHelper + formatting (Burkov Egor) [#​56829](nodejs/node#56829) - \[[`39dfcbad6e`](nodejs/node@39dfcbad6e)] - **stream**: don't try to read more if reading (Robert Nagy) [#​60454](nodejs/node#60454) - \[[`ee333c9177`](nodejs/node@ee333c9177)] - **test**: deflake test-perf-hooks-timerify-histogram-sync (Joyee Cheung) [#​60639](nodejs/node#60639) - \[[`f0d81c91e7`](nodejs/node@f0d81c91e7)] - **test**: apply a delay to `watch-mode-kill-signal` tests (Joyee Cheung) [#​60610](nodejs/node#60610) - \[[`68791e2ccc`](nodejs/node@68791e2ccc)] - **test**: async iife in repl (Tony Gorez) [#​44878](nodejs/node#44878) - \[[`c4eb9c3383`](nodejs/node@c4eb9c3383)] - **test**: parallelize sea tests when there's enough disk space (Joyee Cheung) [#​60604](nodejs/node#60604) - \[[`be8c4172d9`](nodejs/node@be8c4172d9)] - **test**: only show overridden env in child process failures (Joyee Cheung) [#​60556](nodejs/node#60556) - \[[`8cae858f88`](nodejs/node@8cae858f88)] - **test**: ensure assertions are reached on more tests (Antoine du Hamel) [#​60498](nodejs/node#60498) - \[[`759d69331e`](nodejs/node@759d69331e)] - **test**: ensure assertions are reachable in `test/es-module` (Antoine du Hamel) [#​60501](nodejs/node#60501) - \[[`6aaf18c333`](nodejs/node@6aaf18c333)] - **test**: ensure assertions are reached on more tests (Antoine du Hamel) [#​60485](nodejs/node#60485) - \[[`bc41acf087`](nodejs/node@bc41acf087)] - **test**: ensure assertions are reached on more tests (Antoine du Hamel) [#​60500](nodejs/node#60500) - \[[`22fd621daf`](nodejs/node@22fd621daf)] - **test**: split test-perf-hooks-timerify (Joyee Cheung) [#​60568](nodejs/node#60568) - \[[`5efe4f722e`](nodejs/node@5efe4f722e)] - **test**: add more logs to test-esm-loader-hooks-inspect-wait (Joyee Cheung) [#​60466](nodejs/node#60466) - \[[`2a57268f34`](nodejs/node@2a57268f34)] - **test**: mark stringbytes-external-exceed-max tests as flaky on AIX (Joyee Cheung) [#​60565](nodejs/node#60565) - \[[`2c199f7f61`](nodejs/node@2c199f7f61)] - **test**: split test-esm-wasm.js (Joyee Cheung) [#​60491](nodejs/node#60491) - \[[`bc8f7db5bb`](nodejs/node@bc8f7db5bb)] - **test**: correct conditional secure heap flags test (Shelley Vohr) [#​60385](nodejs/node#60385) - \[[`3bf42a5dd3`](nodejs/node@3bf42a5dd3)] - **test**: spin longer on flaky platforms for test-worker-prof (Joyee Cheung) [#​60492](nodejs/node#60492) - \[[`eca6227e7e`](nodejs/node@eca6227e7e)] - **test**: ensure assertions are reachable in `test/internet` (Antoine du Hamel) [#​60513](nodejs/node#60513) - \[[`313983453b`](nodejs/node@313983453b)] - **test**: fix flaky test-watch-mode-kill-signal-\* (Joyee Cheung) [#​60443](nodejs/node#60443) - \[[`ccc26377b5`](nodejs/node@ccc26377b5)] - **test**: capture stack trace in debugger timeout errors (Joyee Cheung) [#​60457](nodejs/node#60457) - \[[`12e9213a24`](nodejs/node@12e9213a24)] - **test**: ensure assertions are reachable in `test/sequential` (Antoine du Hamel) [#​60412](nodejs/node#60412) - \[[`781a2661de`](nodejs/node@781a2661de)] - **test**: ensure assertions are reachable in more folders (Antoine du Hamel) [#​60411](nodejs/node#60411) - \[[`1e979e6eb7`](nodejs/node@1e979e6eb7)] - **test**: split test-runner-watch-mode (Joyee Cheung) [#​60391](nodejs/node#60391) - \[[`8c31cbb99b`](nodejs/node@8c31cbb99b)] - **test**: move test-runner-watch-mode helper into common (Joyee Cheung) [#​60391](nodejs/node#60391) - \[[`c94c6555cc`](nodejs/node@c94c6555cc)] - **test,crypto**: handle a few more BoringSSL tests (Shelley Vohr) [#​59030](nodejs/node#59030) - \[[`fd63c27444`](nodejs/node@fd63c27444)] - **test,crypto**: update x448 and ed448 expectation when on boringssl (Shelley Vohr) [#​60387](nodejs/node#60387) - \[[`bf0de92446`](nodejs/node@bf0de92446)] - **tls**: fix leak on invalid protocol method (Shelley Vohr) [#​60427](nodejs/node#60427) - \[[`7e8373b378`](nodejs/node@7e8373b378)] - **tools**: replace invalid expression in dependabot config (Riddhi) [#​60649](nodejs/node#60649) - \[[`ac08760547`](nodejs/node@ac08760547)] - **tools**: extract Nix dependency lists to separate files (Antoine du Hamel) [#​60495](nodejs/node#60495) - \[[`ae91a6cc3a`](nodejs/node@ae91a6cc3a)] - **tools**: only add test reporter args when node:test is used (Joyee Cheung) [#​60551](nodejs/node#60551) - \[[`97ed560222`](nodejs/node@97ed560222)] - **tools**: skip unaffected GHA jobs for changes in `test/internet` (Antoine du Hamel) [#​60517](nodejs/node#60517) - \[[`44ca97b404`](nodejs/node@44ca97b404)] - **tools**: fix update-icu script (Michaël Zasso) [#​60521](nodejs/node#60521) - \[[`07b0b5a5ba`](nodejs/node@07b0b5a5ba)] - **tools**: fix linter for semver-major release proposals (Antoine du Hamel) [#​60481](nodejs/node#60481) - \[[`97d74224c3`](nodejs/node@97d74224c3)] - **tools**: fix failing release-proposal linter for LTS transitions (Antoine du Hamel) [#​60465](nodejs/node#60465) - \[[`019af5bc27`](nodejs/node@019af5bc27)] - **tools**: skip running test-shared on deps changes (Antoine du Hamel) [#​60433](nodejs/node#60433) - \[[`3ec9764151`](nodejs/node@3ec9764151)] - **tools**: pin OpenSSL to 3.5.4 on test-shared workflow (Antoine du Hamel) [#​60428](nodejs/node#60428) - \[[`fe2d6d44d4`](nodejs/node@fe2d6d44d4)] - **tools**: remove undici from daily wpt.fyi job (Filip Skokan) [#​60444](nodejs/node#60444) - \[[`d09ba98398`](nodejs/node@d09ba98398)] - **tools**: document that nixpkgs updates should not be backported (Antoine du Hamel) [#​60431](nodejs/node#60431) - \[[`7fc99319e7`](nodejs/node@7fc99319e7)] - **tools**: do not use short hashes for deps versioning to avoid collision (Antoine du Hamel) [#​60407](nodejs/node#60407) - \[[`815edb0c3a`](nodejs/node@815edb0c3a)] - **tools,doc**: update JavaScript primitive types to match MDN Web Docs (JustApple) [#​60581](nodejs/node#60581) - \[[`6877139a2d`](nodejs/node@6877139a2d)] - **util**: fix stylize of special properties in inspect (Ge Gao) [#​60479](nodejs/node#60479) - \[[`399b340022`](nodejs/node@399b340022)] - **(SEMVER-MINOR)** **v8**: adding total\_allocated\_bytes to HeapStatistics (Caio Lima) [#​60573](nodejs/node#60573) - \[[`d64795b318`](nodejs/node@d64795b318)] - **watch**: fix interaction with multiple env files (Marco Ippolito) [#​60605](nodejs/node#60605) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNzMuMSIsInVwZGF0ZWRJblZlciI6IjQxLjE3My4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->



Fixes #60303.
The Storage specification states that the global
localStoragegetter should throw an exception if the storage environment cannot be obtained. Accordingly, a common way of testing for local storage capability in userland is along these lines:This tests both for the presence of the global and whether the getter succeeds, which also covers scenarios where the storage API is not exposed at all.
Node.js's flagged implementation of
localStoragealso used to follow this behaviour in v24 and earlier. If local storage could not be initialised due to the absence of the--localstorage-filecommand-line argument, the global getter would throw at the point of the variable being accessed. The above test therefore also worked well in v24: it would identify when the variable didn't exist, and would also detect when an accessor exception was thrown.When webstorage was enabled by default for v25 (#57666), this behaviour was changed: in the absence of
--localstorage-file, the global getter no longer throws, but instead returns an empty Proxy which returnsundefinedon all property access after emitting a warning. The motivation behind this change of approach was to avoid the test suite throwing during its global tests. However, a throw-on-access global getter already exists (crypto), and therefore there already exist mechanisms for getting around this.The behaviour as it stands is problematic. Exposing
localStorageas an empty object with no observable properties is an unexpected pattern, is inconsistent with the web, is non-compliant with the spec, and there is no longer a trivial and web-consistent way to observelocalStorageto work out whether or not it's actually available.I am therefore proposing, as an out-of-cycle breaking change, to revert to web-compatible behaviour and throw from the global getter if
localStoragecannot be initialised due to the missing command-line argument. Edit: just realised that webstorage wasn't stabilised, so this wouldn't need TSC approval to land.cc: @nodejs/web-standards