Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ jobs:
run: |
nix-shell -I nixpkgs=./tools/nix/pkgs.nix -p 'nixfmt-tree' --run '
treefmt --quiet --ci
' || git --no-pager diff --exit-code
' && EXIT_CODE="$?" || EXIT_CODE="$?"
if [ "$EXIT_CODE" != "0" ]
then
git --no-pager diff || true
exit "$EXIT_CODE"
fi
lint-py:
if: github.event.pull_request.draft == false
Expand Down
8 changes: 8 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,14 @@ DataHandler.prototype.load = async function load(key) {
};
```

## Class: `QuotaExceededError`

<!-- YAML
added: REPLACEME
-->

The WHATWG {QuotaExceededError} class. Extends {DOMException}.

## Class: `ReadableByteStreamController`

<!-- YAML
Expand Down
2 changes: 1 addition & 1 deletion doc/api/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ added: v0.4.0
The `"main"` field defines the entry point of a package when imported by name
via a `node_modules` lookup. Its value is a path.

When a package has an [`"exports"`][] field, this will take precedence over the
The [`"exports"`][] field, if it exists, takes precedence over the
`"main"` field when importing the package by name.

It also defines the script that is used when the [package directory is loaded
Expand Down
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export default [
Float16Array: 'readonly',
FormData: 'readonly',
navigator: 'readonly',
QuotaExceededError: 'readonly',
ReadableStream: 'readonly',
ReadableStreamDefaultReader: 'readonly',
ReadableStreamBYOBReader: 'readonly',
Expand Down
6 changes: 5 additions & 1 deletion lib/eslint.config_partial.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const noRestrictedSyntax = [
message: "`btoa` supports only latin-1 charset, use Buffer.from(str).toString('base64') instead",
},
{
selector: 'NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])',
selector: 'NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError|QuotaExceededError)$/])',
message: "Use an error exported by 'internal/errors' instead.",
},
{
Expand Down Expand Up @@ -122,6 +122,10 @@ export default [
name: 'DOMException',
message: "Use lazy function `const { lazyDOMExceptionClass } = require('internal/util');` instead of the global.",
},
{
name: 'QuotaExceededError',
message: "Use `internalBinding('messaging').QuotaExceededError` instead of the global.",
},
{
name: 'ErrorEvent',
message: "Use `const { ErrorEvent } = require('internal/deps/undici/undici');` instead of the global.",
Expand Down
5 changes: 5 additions & 0 deletions lib/internal/bootstrap/web/exposed-wildcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ exposeInterface(globalThis, 'URL', URL);
exposeInterface(globalThis, 'URLSearchParams', URLSearchParams);
exposeLazyDOMExceptionProperty(globalThis);

// https://webidl.spec.whatwg.org/#quotaexceedederror
exposeLazyInterfaces(globalThis, 'internal/worker/clone_dom_exception', [
'QuotaExceededError',
]);

// https://dom.spec.whatwg.org/#interface-abortcontroller
// Lazy ones.
exposeLazyInterfaces(globalThis, 'internal/abort_controller', [
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/crypto/random.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,9 @@ function getRandomValues(data) {
'TypeMismatchError');
}
if (data.byteLength > 65536) {
throw lazyDOMException(
'The requested length exceeds 65,536 bytes',
'QuotaExceededError');
const { QuotaExceededError } = internalBinding('messaging');
throw new QuotaExceededError(
'The requested length exceeds 65,536 bytes');
}
randomFillSync(data, 0);
return data;
Expand Down
91 changes: 91 additions & 0 deletions lib/internal/per_context/domexception.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
const {
Error,
ErrorPrototype,
NumberIsFinite,
NumberIsNaN,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectSetPrototypeOf,
RangeError,
SafeMap,
SafeSet,
SafeWeakMap,
Expand Down Expand Up @@ -203,3 +206,91 @@ for (const { 0: name, 1: codeName, 2: value } of [
}

exports.DOMException = DOMException;

// https://webidl.spec.whatwg.org/#quotaexceedederror
class QuotaExceededError extends DOMException {
#quota;
#requested;

constructor(message = '', options = { __proto__: null }) {
super(message, 'QuotaExceededError');
this[transfer_mode_private_symbol] = kCloneable;

let quota = null;
let requested = null;

if (options !== null && options !== undefined) {
if ('quota' in options) {
quota = +options.quota;
if (!NumberIsFinite(quota)) {
// eslint-disable-next-line no-restricted-syntax
throw new TypeError(
`Cannot convert options.quota to a double: the value is ${NumberIsNaN(quota) ? 'NaN' : 'Infinity'}`,
);
}
if (quota < 0) {
// eslint-disable-next-line no-restricted-syntax
throw new RangeError('options.quota must not be negative');
}
}

if ('requested' in options) {
requested = +options.requested;
if (!NumberIsFinite(requested)) {
// eslint-disable-next-line no-restricted-syntax
throw new TypeError(
`Cannot convert options.requested to a double: the value is ${NumberIsNaN(requested) ? 'NaN' : 'Infinity'}`,
);
}
if (requested < 0) {
// eslint-disable-next-line no-restricted-syntax
throw new RangeError('options.requested must not be negative');
}
}
}

if (quota !== null && requested !== null && requested < quota) {
// eslint-disable-next-line no-restricted-syntax
throw new RangeError('options.requested must not be less than options.quota');
}

this.#quota = quota;
this.#requested = requested;
}

[messaging_clone_symbol]() {
const domExceptionClone = DOMExceptionPrototype[messaging_clone_symbol].call(this);
domExceptionClone.data.quota = this.#quota;
domExceptionClone.data.requested = this.#requested;
domExceptionClone.deserializeInfo = 'internal/worker/clone_dom_exception:QuotaExceededError';
return domExceptionClone;
}

[messaging_deserialize_symbol](data) {
DOMExceptionPrototype[messaging_deserialize_symbol].call(this, data);
this.#quota = data.quota;
this.#requested = data.requested;
}

get quota() {
if (!(#quota in this)) {
throwInvalidThisError(TypeError, 'QuotaExceededError');
}
return this.#quota;
}

get requested() {
if (!(#requested in this)) {
throwInvalidThisError(TypeError, 'QuotaExceededError');
}
return this.#requested;
}
}

ObjectDefineProperties(QuotaExceededError.prototype, {
[SymbolToStringTag]: { __proto__: null, configurable: true, value: 'QuotaExceededError' },
quota: { __proto__: null, enumerable: true, configurable: true },
requested: { __proto__: null, enumerable: true, configurable: true },
});

exports.QuotaExceededError = QuotaExceededError;
6 changes: 4 additions & 2 deletions lib/internal/worker/clone_dom_exception.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

// Delegate to the actual DOMException implementation.
// Delegate to the actual DOMException/QuotaExceededError implementation.
const messaging = internalBinding('messaging');
module.exports = {
DOMException: internalBinding('messaging').DOMException,
DOMException: messaging.DOMException,
QuotaExceededError: messaging.QuotaExceededError,
};
3 changes: 3 additions & 0 deletions node.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
}, { # POSIX
'defines': [ '__POSIX__' ],
}],
[ 'OS=="aix" or OS=="os400"', {
'cflags': [ '-mcpu=power9' ],
}],
[ 'node_enable_d8=="true"', {
'dependencies': [ 'tools/v8_gypfiles/d8.gyp:d8' ],
}],
Expand Down
15 changes: 15 additions & 0 deletions src/node_messaging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,21 @@ static void CreatePerContextProperties(Local<Object> target,
domexception)
.Check();
}
{
Local<Object> per_context_bindings;
Local<Value> quota_exceeded_error_val;
if (GetPerContextExports(context).ToLocal(&per_context_bindings) &&
per_context_bindings
->Get(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "QuotaExceededError"))
.ToLocal(&quota_exceeded_error_val)) {
target
->Set(context,
FIXED_ONE_BYTE_STRING(env->isolate(), "QuotaExceededError"),
quota_exceeded_error_val)
.Check();
}
}
}

static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
Expand Down
18 changes: 9 additions & 9 deletions src/node_webstorage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,23 @@ using v8::Value;

static void ThrowQuotaExceededException(Local<Context> context) {
Isolate* isolate = Isolate::GetCurrent();
auto dom_exception_str = FIXED_ONE_BYTE_STRING(isolate, "DOMException");
auto err_name = FIXED_ONE_BYTE_STRING(isolate, "QuotaExceededError");
auto quota_exceeded_str =
FIXED_ONE_BYTE_STRING(isolate, "QuotaExceededError");
auto err_message =
FIXED_ONE_BYTE_STRING(isolate, "Setting the value exceeded the quota");
Local<Object> per_context_bindings;
Local<Value> domexception_ctor_val;
Local<Value> quota_exceeded_ctor_val;
if (!GetPerContextExports(context).ToLocal(&per_context_bindings) ||
!per_context_bindings->Get(context, dom_exception_str)
.ToLocal(&domexception_ctor_val)) {
!per_context_bindings->Get(context, quota_exceeded_str)
.ToLocal(&quota_exceeded_ctor_val)) {
return;
}
CHECK(domexception_ctor_val->IsFunction());
Local<Function> domexception_ctor = domexception_ctor_val.As<Function>();
Local<Value> argv[] = {err_message, err_name};
CHECK(quota_exceeded_ctor_val->IsFunction());
Local<Function> quota_exceeded_ctor = quota_exceeded_ctor_val.As<Function>();
Local<Value> argv[] = {err_message};
Local<Value> exception;

if (!domexception_ctor->NewInstance(context, arraysize(argv), argv)
if (!quota_exceeded_ctor->NewInstance(context, arraysize(argv), argv)
.ToLocal(&exception)) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions test/common/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ intrinsics.add('console');

const webIdlExposedWildcard = new Set([
'DOMException',
'QuotaExceededError',
'TextEncoder',
'TextDecoder',
'AbortController',
Expand Down
Loading
Loading