From ad8e2d39f133238b43c69850ac646f6e9600912b Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sat, 25 Oct 2025 11:31:36 -0700 Subject: [PATCH 1/7] Mark transactions inactive during key serialization --- index.bs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/index.bs b/index.bs index 88bbfeb..8785f32 100644 --- a/index.bs +++ b/index.bs @@ -3010,13 +3010,25 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. If |key| was given, then: + 1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=]. + + 1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=]. + + NOTE: + The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction. + 1. Let |r| be the result of [=/converting a value to a key=] with |key|. Rethrow any exceptions. + 1. Set |transaction|'s [=transaction/state=] to [=transaction/active=]. + 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. + 1. Let |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. + 1. Let |key| be |r|. + 1. Let |targetRealm| be a user-agent defined [=ECMAScript/Realm=]. 1. Let |clone| be a [=clone=] of |value| in |targetRealm| during |transaction|. From d3854a0124cfa9d6036f5d938ab162e8461f88ed Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sat, 25 Oct 2025 11:47:15 -0700 Subject: [PATCH 2/7] Remove unnecessary whitespace change --- index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.bs b/index.bs index 8785f32..adc705d 100644 --- a/index.bs +++ b/index.bs @@ -3028,7 +3028,6 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. Let |key| be |r|. - 1. Let |targetRealm| be a user-agent defined [=ECMAScript/Realm=]. 1. Let |clone| be a [=clone=] of |value| in |targetRealm| during |transaction|. From 8d77e51f4fc1194786cfd544d56e1b8a5d3f7392 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sat, 25 Oct 2025 11:48:05 -0700 Subject: [PATCH 3/7] Remove mistaken duplicate line --- index.bs | 2 -- 1 file changed, 2 deletions(-) diff --git a/index.bs b/index.bs index adc705d..80438eb 100644 --- a/index.bs +++ b/index.bs @@ -3024,8 +3024,6 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. - 1. Let |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. - 1. Let |key| be |r|. 1. Let |targetRealm| be a user-agent defined [=ECMAScript/Realm=]. From 6ca912c618fc907ab0804802732a05b4225319c3 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 26 Oct 2025 19:41:18 -0700 Subject: [PATCH 4/7] Add IDBCursor continue/continuePrimaryKey --- index.bs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/index.bs b/index.bs index 80438eb..1aea906 100644 --- a/index.bs +++ b/index.bs @@ -3010,17 +3010,8 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. If |key| was given, then: - 1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=]. - - 1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=]. - - NOTE: - The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction. - - 1. Let |r| be the result of [=/converting a - value to a key=] with |key|. Rethrow any exceptions. - - 1. Set |transaction|'s [=transaction/state=] to [=transaction/active=]. + 1. Let |r| be the result of [=/convert a value to a key during a + transaction=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -4520,7 +4511,7 @@ The continue(|key|) method steps are: 1. If |key| is given, then: 1. Let |r| be the result of [=/converting a - value to a key=] with |key|. Rethrow any exceptions. + value to a key during a transaction=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -4579,14 +4570,14 @@ The continuePrimaryKey(|key|, |primaryKey|) meth [=exception/throw=] an "{{InvalidStateError}}" {{DOMException}}. 1. Let |r| be the result of [=/converting a value to - a key=] with |key|. Rethrow any exceptions. + a key during a transaction=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. 1. Let |key| be |r|. 1. Let |r| be the result of [=/converting a value - to a key=] with |primaryKey|. Rethrow any exceptions. + to a key during a transaction=] with |primaryKey| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -6630,6 +6621,26 @@ NOTE: For example, the value `[10, 20, null, 30, 20]` is converted to an [=array key=] with [=subkeys=] 10, 20, 30. +
+ +To convert a value to a key during a transaction with an ECMAScript value |input| and {{IDBTransaction}} +|transaction|, run the following steps. The result of these steps is a [=/key=], or "invalid value", or "invalid type", +or the steps may throw an exception. + +1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=]. + +1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=]. + + NOTE: + The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction. + +1. Let |r| be the result of [=/converting a value to a key=] with |input|. Rethrow any exceptions. + +1. Set |transaction|'s [=transaction/state=] to [=transaction/active=]. + +1. Return |r|. + +
# Privacy considerations # {#privacy} From ddf2e810b6dc8ffd328842f57374002960b917bc Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 26 Oct 2025 19:46:02 -0700 Subject: [PATCH 5/7] Fix wording --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 1aea906..3724174 100644 --- a/index.bs +++ b/index.bs @@ -3010,7 +3010,7 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. If |key| was given, then: - 1. Let |r| be the result of [=/convert a value to a key during a + 1. Let |r| be the result of [=/converting a value to a key during a transaction=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. From ba5d18bf6815f7d6a3a953bd17fa823d385305a0 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 9 Nov 2025 14:19:18 -0800 Subject: [PATCH 6/7] Refactor to prefer the with-transaction logic --- index.bs | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/index.bs b/index.bs index 3724174..acad60c 100644 --- a/index.bs +++ b/index.bs @@ -3010,8 +3010,7 @@ To add or put with |handle|, |value|, |key|, and |no-overwrite flag|, 1. If |key| was given, then: - 1. Let |r| be the result of [=/converting a value to a key during a - transaction=] with |key| and |transaction|. Rethrow any exceptions. + 1. Let |r| be the result of [=/converting a value to a key=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -4511,7 +4510,7 @@ The continue(|key|) method steps are: 1. If |key| is given, then: 1. Let |r| be the result of [=/converting a - value to a key during a transaction=] with |key| and |transaction|. Rethrow any exceptions. + value to a key=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -4570,14 +4569,14 @@ The continuePrimaryKey(|key|, |primaryKey|) meth [=exception/throw=] an "{{InvalidStateError}}" {{DOMException}}. 1. Let |r| be the result of [=/converting a value to - a key during a transaction=] with |key| and |transaction|. Rethrow any exceptions. + a key=] with |key| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. 1. Let |key| be |r|. 1. Let |r| be the result of [=/converting a value - to a key during a transaction=] with |primaryKey| and |transaction|. Rethrow any exceptions. + to a key=] with |primaryKey| and |transaction|. Rethrow any exceptions. 1. If |r| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -6481,8 +6480,8 @@ The steps return an ECMAScript value.
-To convert a value to a key with an ECMAScript value |input|, and an optional -[=/set=] |seen|, run the following steps. +To recursively convert a value to a key +with an ECMAScript value |input|, and an optional [=/set=] |seen|, run the following steps. The result of these steps is a [=/key=], or "invalid value", or "invalid type", or the steps may throw an exception. @@ -6549,7 +6548,7 @@ steps may throw an exception. 1. Let |entry| be [=ECMAScript/?=] [$Get$](|input|, |index|). 1. Let |key| be the result of - [=/converting a value to a key=] with arguments |entry| + [=/recursively converting a value to a key=] with arguments |entry| and |seen|. 1. [=ECMAScript/ReturnIfAbrupt=](|key|). @@ -6623,22 +6622,34 @@ NOTE:
-To convert a value to a key during a transaction with an ECMAScript value |input| and {{IDBTransaction}} +To convert a value to a key with an ECMAScript value |input| and optional {{IDBTransaction}} |transaction|, run the following steps. The result of these steps is a [=/key=], or "invalid value", or "invalid type", or the steps may throw an exception. -1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=]. +1. If |transaction| is given: -1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=]. + 1. [=/Assert=]: |transaction|'s [=transaction/state=] is [=transaction/active=]. + + 1. Set |transaction|'s [=transaction/state=] to [=transaction/inactive=]. + + NOTE: + The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction. + +1. Let |thrown| be null. + +1. Let |result| be null. + +1. [=Try=] the following step: + + 1. Let |result| be the result of [=/recursively converting a value to a key=] with |input|. - NOTE: - The [=/transaction=] is made [=transaction/inactive=] so that getters or other side effects triggered by the cloning operation are unable to make additional requests against the transaction. +1. If the above step threw, set |thrown| to the thrown error. -1. Let |r| be the result of [=/converting a value to a key=] with |input|. Rethrow any exceptions. +1. If |transaction| is given, set |transaction|'s [=transaction/state=] to [=transaction/active=]. -1. Set |transaction|'s [=transaction/state=] to [=transaction/active=]. +1. If |thrown| is not null, re-throw |thrown|. -1. Return |r|. +1. Return |result|.
From b82c2dbf47487a52677795089858fd5f66eba83f Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 9 Nov 2025 14:37:50 -0800 Subject: [PATCH 7/7] Refactor more related methods --- index.bs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/index.bs b/index.bs index acad60c..9e8452f 100644 --- a/index.bs +++ b/index.bs @@ -1359,7 +1359,7 @@ range=].
To convert a value to a key range with -|value| and optional |null disallowed flag|, run these steps: +|value|, {{IDBTransaction}} |transaction|, and optional |null disallowed flag|, run these steps: 1. If |value| is a [=/key range=], return |value|. @@ -1368,7 +1368,7 @@ To convert a value to a key range with [=unbounded key range=] otherwise. 1. Let |key| be the result of [=/converting - a value to a key=] with |value|. Rethrow any exceptions. + a value to a key=] with |value| and optionally passing |transaction|. Rethrow any exceptions. 1. If |key| is "invalid value" or "invalid type", [=exception/throw=] a "{{DataError}}" {{DOMException}}. @@ -1385,11 +1385,12 @@ NOTE:
- To determine when a value is a potentially valid key range with ECMAScript |value|, run these steps: + To determine when a value is a potentially valid key range with ECMAScript |value| and + {{IDBTransaction}} |transaction|, run these steps: 1. If |value| is a [=/key range=], return true. - 1. Let |key| be the result of [=/converting a value to a key=] with |value|. + 1. Let |key| be the result of [=/converting a value to a key=] with |value| and |transaction|. 1. If |key| is "invalid type" return false. @@ -3073,7 +3074,7 @@ The delete(|query|) method steps are: 1. If |transaction| is a [=transaction/read-only transaction=], [=exception/throw=] a "{{ReadOnlyError}}" {{DOMException}}. -1. Let |range| be the result of [=/converting a value to a key range=] with |query| and true. Rethrow any exceptions. +1. Let |range| be the result of [=/converting a value to a key range=] with |query|, |transaction|, and true. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=delete records from an object store=] with |store| and |range|. @@ -3188,7 +3189,7 @@ The get(|query|) method steps are: 1. If |transaction|'s [=transaction/state=] is not [=transaction/active=], then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. -1. Let |range| be the result of [=/converting a value to a key range=] with |query| and true. Rethrow any exceptions. +1. Let |range| be the result of [=/converting a value to a key range=] with |query|, |transaction|, and true. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=retrieve a value from an object store=] with [=ECMAScript/the current Realm record=], |store|, and |range|. @@ -3225,7 +3226,7 @@ The getKey(|query|) method steps are: 1. If |transaction|'s [=transaction/state=] is not [=transaction/active=], then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. -1. Let |range| be the result of [=/converting a value to a key range=] with |query| and true. Rethrow any exceptions. +1. Let |range| be the result of [=/converting a value to a key range=] with |query|, |transaction|, and true. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=retrieve a key from an object store=] with |store| and |range|. @@ -3306,7 +3307,7 @@ The count(|query|) method steps are: then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=count the records in a range=] with |store| and |range|. @@ -3364,7 +3365,7 @@ The openCursor(|query|, |direction|) method then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |cursor| be a new [=cursor=] with its @@ -3407,7 +3408,7 @@ The openKeyCursor(|query|, |direction|) met then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |cursor| be a new [=cursor=] with its @@ -3840,7 +3841,7 @@ The get(|query|) method steps are: 1. If |transaction|'s [=transaction/state=] is not [=transaction/active=], then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. -1. Let |range| be the result of [=/converting a value to a key range=] with |query| and true. Rethrow any exceptions. +1. Let |range| be the result of [=/converting a value to a key range=] with |query|, |transaction|, and true. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=retrieve a referenced value from an index=] with [=ECMAScript/the current Realm record=], |index|, and |range|. @@ -3877,7 +3878,7 @@ The getKey(|query|) method steps are: 1. If |transaction|'s [=transaction/state=] is not [=transaction/active=], then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. -1. Let |range| be the result of [=/converting a value to a key range=] with |query| and true. Rethrow any exceptions. +1. Let |range| be the result of [=/converting a value to a key range=] with |query|, |transaction|, and true. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=retrieve a value from an index=] with |index| and |range|. @@ -3958,7 +3959,7 @@ The count(|query|) method steps are: then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |operation| be an algorithm to run [=count the records in a range=] with |index| and |range|. @@ -4016,7 +4017,7 @@ The openCursor(|query|, |direction|) method steps then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |cursor| be a new [=cursor=] with its @@ -4059,7 +4060,7 @@ The openKeyCursor(|query|, |direction|) method st then [=exception/throw=] a "{{TransactionInactiveError}}" {{DOMException}}. 1. Let |range| be the result of - [=/converting a value to a key range=] with |query|. + [=/converting a value to a key range=] with |query| and |transaction|. Rethrow any exceptions. 1. Let |cursor| be a new [=cursor=] with its @@ -5630,15 +5631,15 @@ To create a [=request=] to retrieve multiple items from an [=object s 1. Let |direction| be a [=cursor/direction|cursor direction=]. -1. If running [=is a potentially valid key range=] with |queryOrOptions| is true, then: +1. If running [=is a potentially valid key range=] with |queryOrOptions| and |transaction| is true, then: - 1. Set |range| to the result of [=/converting a value to a key range=] with |queryOrOptions|. Rethrow any exceptions. + 1. Set |range| to the result of [=/converting a value to a key range=] with |queryOrOptions| and |transaction|. Rethrow any exceptions. 1. Set |direction| to "{{IDBCursorDirection/next}}". 1. Else: - 1. Set |range| to the result of [=/converting a value to a key range=] with |queryOrOptions|["{{IDBGetAllOptions/query}}"]. Rethrow any exceptions. + 1. Set |range| to the result of [=/converting a value to a key range=] with |queryOrOptions|["{{IDBGetAllOptions/query}}"] and |transaction|. Rethrow any exceptions. 1. Set |count| to |queryOrOptions|["{{IDBGetAllOptions/count}}"]. @@ -6606,14 +6607,14 @@ The result of these steps is a [=/key=], or "invalid value", or "invalid type", 1. Return a new [=array key=] with [=key/value=] set to |keys|. -1. Otherwise, return the result of [=/converting a +1. Otherwise, return the result of [=/recursively converting a value to a key=] with argument |input|. Rethrow any exceptions.
NOTE: - These steps are similar to those to [=convert a value to a key=] + These steps are similar to those to [=recursively convert a value to a key=] but if the top-level value is an {{Array}} then members which can not be converted to keys are ignored, and duplicates are removed. @@ -6647,7 +6648,7 @@ or the steps may throw an exception. 1. If |transaction| is given, set |transaction|'s [=transaction/state=] to [=transaction/active=]. -1. If |thrown| is not null, re-throw |thrown|. +1. If |thrown| is not null, rethrow |thrown|. 1. Return |result|.