From 75c69bc7f6ee9335b8df07775d226a3ba3a44b4d Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Mon, 7 Oct 2024 13:58:41 -0400 Subject: [PATCH 01/10] [spec] Update saved query to be async We fix our spec changes so that a query can be queued to reused if it is not the initial query but it is received before the initial query is resolved. Previously, only fully resolved queries were being treated as saved. --- spec.bs | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/spec.bs b/spec.bs index db8278f..bd359b9 100644 --- a/spec.bs +++ b/spec.bs @@ -338,12 +338,12 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. Let |moduleURLRecord| be |moduleMapKeyTuples|[0][0]. 1. Let |savedQueryName| be |options|["`savedQuery`"]. 1. If |savedQueryName| is a [=string=] that is not the empty string, then: - 1. Let |savedIndex| be the result of running [=get the index for a saved query=] on |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, and |savedQueryName|. - 1. If |savedIndex| is not null, then: - 1. If |savedIndex| is greater than |urlList|'s [=list/size=], return a [=promise rejected=] with a {{TypeError}}. + 1. Let |callbackTask| be the result of running [=obtain a callback to process the saved index result=], given |window|, |urlList|, and |promise|. + 1. Let |savedIndex| be the result of running [=get the index for a saved query=] on |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and |callbackTask|. + 1. If |savedIndex| is nonnegative, then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to run the steps of |callbackTask|, given |savedIndex|. + 1. If |savedIndex| is -1, then return |promise| and abort these steps. + - Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. - 1. Return a [=promise resolved=] with |savedIndex|. 1. Return |promise|, and immediately [=obtain a worklet agent=] given |window| and run the rest of these steps in that agent: 1. Let |operationMap| be |globalScope|'s [=SharedStorageWorkletGlobalScope/operation map=]. 1. If |operationMap| does not [=map/contain=] |operationName|, then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}, and abort these steps. @@ -360,12 +360,12 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes=
: If it was fulfilled with value |index|: - :: 1. If |index| is greater than |urlList|'s [=list/size=], then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}, and abort these steps. + :: 1. If |savedQueryName| is a [=string=] that is not the empty string, then run [=store the index for a saved query=] with |window|, |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and |index|. + 1. If |index| is greater than |urlList|'s [=list/size=], then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}, and abort these steps. Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with |index|. - 1. If |savedQueryName| is a [=string=] that is not the empty string, then run [=store the index for a saved query=] with |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and |index|. 1. Run |privateAggregationCompletionTask|. : If it was rejected: @@ -955,9 +955,18 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= :: a [=map=] of [=site=] to {{double}} : saved query map - :: a [=map=] of [=tuples=] ([=url/origin=] data origin, [=/URL=] worklet script URL, [=string=] operation name, [=string=] query name) to {{unsigned long}} + :: a [=map=] of [=tuples=] ([=url/origin=] data origin, [=/URL=] worklet script URL, [=string=] operation name, [=string=] query name) to [=saved query data=]
+ The saved query data is a [=struct=] with the following [=struct/items=]: + +
+ : index + :: a {{unsigned long}} + + : callbacks + :: a [=queue=] of [=tasks=]
+ #### Monkey patch for [=navigable/Traversable Navigables=] #### {#patch-trav-nav} @@ -982,20 +991,40 @@ navigables section, add the following: #### Saved queries #### {#saved-queries}
- To get the index for a saved query, given [=/navigable=] |navigable|, [=url/origin=] |origin|, [=/URL=] |moduleURLRecord|, [=string=] |operationName|, and [=string=] |savedQueryName|: + To get the index for a saved query, given [=/navigable=] |navigable|, [=url/origin=] |origin|, [=/URL=] |moduleURLRecord|, [=string=] |operationName|, [=string=] |savedQueryName|, and [=task=] |callbackTask|: 1. Let |topLevelTraversable| be the result of running [=get the top-level traversable=] for |navigable|. 1. [=Assert=] that |topLevelTraversable|'s [=page budget=] is not null. - 1. If |topLevelTraversable|'s [=page budget=]'s [=saved query map=] does not [=map/contain=] (|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|), then return null. - 1. Return |topLevelTraversable|'s [=page budget=]'s [=saved query map=][(|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|)]. + 1. If |topLevelTraversable|'s [=page budget=]'s [=saved query map=] does not [=map/contain=] (|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|), then: + 1. [=map/Set=] |topLevelTraversable|'s [=page budget=]'s [=saved query map=][(|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|)] to a new [=saved query data=] struct |queryData|. + 1. Set |queryData|'s [=saved query data/index=] value to -1. + 1. Return -2. + 1. Let |savedIndex| be |topLevelTraversable|'s [=page budget=]'s [=saved query map=][(|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|)]'s [=saved query data/index=]. + 1. If |savedIndex| is -1: + 1. [=queue/Enqueue=] |callbackTask| to |queryData|'s [=saved query data/callbacks=]. + 1. Return -1. + 1. Return |savedIndex|.
- To store the index for a saved query, given [=/navigable=] |navigable|, [=url/origin=] |origin|, [=/URL=] |moduleURLRecord|, [=string=] |operationName|, [=string=] |savedQueryName|, and {{unsigned long}} |index|: + To store the index for a saved query, given {{Window}} |window|, [=/navigable=] |navigable|, [=url/origin=] |origin|, [=/URL=] |moduleURLRecord|, [=string=] |operationName|, [=string=] |savedQueryName|, and {{unsigned long}} |index|: 1. Let |topLevelTraversable| be the result of running [=get the top-level traversable=] for |navigable|. 1. [=Assert=] that |topLevelTraversable|'s [=page budget=] is not null. - 1. [=map/Set=] |topLevelTraversable|'s [=page budget=]'s [=saved query map=][(|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|)] to |index|. + 1. Let |queryData| be |topLevelTraversable|'s [=page budget=]'s [=saved query map=][(|origin|, |moduleURLRecord|, |operationName|, |savedQueryName|)]. + 1. [=map/Set=] |queryData|'s [=saved query data/index=] to |index|. + 1. [=While=] |queryData|'s [=saved query data/callbacks=] is not empty: + 1. [=queue/Dequeue=] the next [=task=] |callbackTask| from |queryData|'s [=saved query data/callbacks=], and [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to run the steps of |callbackTask|, given |index|. +
+ +
+ To obtain a callback to process the saved index result, given {{Window}} |window|, [=/list=] of {{SharedStorageUrlWithMetadata}}s |urlList|, [=promise=] |promise|, perform the following steps. They return an algorithm. + + 1. Let |processIndexTask| be an algorithm to perform the following steps, given an {{unsigned long}} |index|: + 1. If |index| is greater than |urlList|'s [=list/size=], then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}. + Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. + 1. Otherwise, [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with |index|. + 1. Return |processIndexTask|.
#### Charging the [=Top-Level Traversable=] Entropy Budgets #### {#charge-top-trav-budgets} From 904917bca418cb3886591c80e93b9033a792ef94 Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Mon, 7 Oct 2024 14:10:32 -0400 Subject: [PATCH 02/10] fix type --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index bd359b9..85be1c5 100644 --- a/spec.bs +++ b/spec.bs @@ -962,7 +962,7 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes=
: index - :: a {{unsigned long}} + :: a {{long}} : callbacks :: a [=queue=] of [=tasks=]
From 62d7c49d90053cc287d00ddc7260e487df5e4f18 Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Tue, 8 Oct 2024 12:54:01 -0400 Subject: [PATCH 03/10] address comments --- spec.bs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 85be1c5..62757be 100644 --- a/spec.bs +++ b/spec.bs @@ -369,7 +369,8 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. Run |privateAggregationCompletionTask|. : If it was rejected: - :: 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}. + :: 1. If |savedQueryName| is a [=string=] that is not the empty string, then run [=store the index for a saved query=] with |window|, |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and 0. + 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}. Note: This indicates that either |operationCtor|'s run() method encounters an error (where |operationCtor| is the parameter in {{SharedStorageWorkletGlobalScope/register()}}), or the result |index| is a non-integer value, which violates the selectURL() protocol, and we don't know which url should be selected. 1. Run |privateAggregationCompletionTask|. @@ -1006,6 +1007,10 @@ navigables section, add the following: 1. Return |savedIndex|. + Note: The [=get the index for a saved query=] algorithm returns -2 to indicate that [=obtain a worklet agent|a worklet agent should be obtained=] and the index value is pending the result of the worklet agent's operation. + + Note: The [=get the index for a saved query=] algorithm returns -1 to indicate that a worklet agent was previously obtained and that the index is pending the result of the previous worklet agent's operation. We queue callbackTask to be run when the previous worklet agent's operation has completed. +
To store the index for a saved query, given {{Window}} |window|, [=/navigable=] |navigable|, [=url/origin=] |origin|, [=/URL=] |moduleURLRecord|, [=string=] |operationName|, [=string=] |savedQueryName|, and {{unsigned long}} |index|: From 1976227ec9b19ce77644f8f178062d45b1c9a81e Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Wed, 9 Oct 2024 14:25:36 -0400 Subject: [PATCH 04/10] abort and add notes --- spec.bs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 62757be..f258c06 100644 --- a/spec.bs +++ b/spec.bs @@ -340,10 +340,14 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. If |savedQueryName| is a [=string=] that is not the empty string, then: 1. Let |callbackTask| be the result of running [=obtain a callback to process the saved index result=], given |window|, |urlList|, and |promise|. 1. Let |savedIndex| be the result of running [=get the index for a saved query=] on |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and |callbackTask|. - 1. If |savedIndex| is nonnegative, then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to run the steps of |callbackTask|, given |savedIndex|. 1. If |savedIndex| is -1, then return |promise| and abort these steps. + Note: |callbackTask| is now stored to be run when a previously obtained worklet agent completes its operation to select the index for this query. When the steps of |callbackTask| are run, |promise| will be resolved. + 1. If |savedIndex| is nonnegative, then: + 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to run the steps of |callbackTask|, given |savedIndex|. + Note: Running the steps of |callbackTask| will resolve |promise|. + 1. Return |promise| and abort these steps. 1. Return |promise|, and immediately [=obtain a worklet agent=] given |window| and run the rest of these steps in that agent: 1. Let |operationMap| be |globalScope|'s [=SharedStorageWorkletGlobalScope/operation map=]. 1. If |operationMap| does not [=map/contain=] |operationName|, then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}, and abort these steps. From a27e7366c9af335ff7c8aa6538faefb564178bfe Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Wed, 9 Oct 2024 14:50:13 -0400 Subject: [PATCH 05/10] Fix budget charging --- spec.bs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/spec.bs b/spec.bs index f258c06..ed5a437 100644 --- a/spec.bs +++ b/spec.bs @@ -369,7 +369,7 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. - 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with |index|. + 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with a [=tuple=] (|index|, true). 1. Run |privateAggregationCompletionTask|. : If it was rejected: @@ -434,12 +434,14 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. If |options|["`resolveToConfig`"] is true, [=resolve=] |resultPromise| with |pendingConfig|. 1. Otherwise, [=resolve=] |resultPromise| with |urn|. 1. Let |indexPromise| be the result of running [=get the select-url result index=], given [=this=], |name|, |urlList|, |workletDataOrigin|, |navigable|, |options|, |preSpecifiedParams| and |aggregationCoordinator|. - 1. [=Upon fulfillment=] of |indexPromise| with |resultIndex|, perform the following steps: + 1. [=Upon fulfillment=] of |indexPromise| with (|resultIndex|, |shouldChargeTopLevelBudgets|), perform the following steps: 1. Let |site| be the result of running [=obtain a site=] with |document|'s [=Document/origin=]. 1. Let |remainingBudget| be the result of running [=determine remaining navigation budget=] with |environment| and |site|. 1. Let |pendingBits| be the logarithm base 2 of |urlList|'s [=list/size=]. - 1. let |pageBudgetResult| be the result of running [=charge shared storage top-level traversable budgets=] with |navigable|, |site|, and |pendingBits|. - 1. If |pageBudgetResult| is false, or if |pendingBits| is greather than |remainingBudget|, set |resultIndex| to the [=default selectURL index=]. + 1. If |shouldChargeTopLevelBudgets| is true: + 1. Let |pageBudgetResult| be the result of running [=charge shared storage top-level traversable budgets=] with |navigable|, |site|, and |pendingBits|. + 1. If |pageBudgetResult| is false, set |resultIndex| to the [=default selectURL index=]. + 1. If |pendingBits| is greather than |remainingBudget|, set |resultIndex| to the [=default selectURL index=]. 1. Let |finalConfig| be a new [=fenced frame config=]. 1. Set |finalConfig|'s [=fenced frame config/mapped url=] to |urlList|[|resultIndex|]. 1. Set |finalConfig|'s a "pending shared storage budget debit" field to |pendingBits|. @@ -1032,7 +1034,7 @@ navigables section, add the following: 1. Let |processIndexTask| be an algorithm to perform the following steps, given an {{unsigned long}} |index|: 1. If |index| is greater than |urlList|'s [=list/size=], then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}. Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. - 1. Otherwise, [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with |index|. + 1. Otherwise, [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with the [=tuple=] (|index|, false). 1. Return |processIndexTask|.
From 7790f679e2204d15a19fccba94587eef337b385f Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Wed, 9 Oct 2024 17:01:34 -0400 Subject: [PATCH 06/10] charge in rejection case --- spec.bs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec.bs b/spec.bs index ed5a437..fc965e2 100644 --- a/spec.bs +++ b/spec.bs @@ -329,8 +329,8 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. Let |promise| be a new [=promise=]. 1. Let |window| be |worklet|'s [=relevant settings object=]. 1. [=Assert=]: |window| is a {{Window}}. - 1. If |window|'s [=Window/browsing context=] is null, then return a [=promise rejected=] with a {{TypeError}}. - 1. If |window|'s [=associated document=] is not [=fully active=], return a [=promise rejected=] with a {{TypeError}}. + 1. If |window|'s [=Window/browsing context=] is null, then return the [=tuple=] of a ([=promise rejected=] with a {{TypeError}}, true) and abort these steps. + 1. If |window|'s [=associated document=] is not [=fully active=], return the [=tuple=] of a ([=promise rejected=] with a {{TypeError}}, true) and abort these steps. 1. [=Assert=]: |worklet|'s [=global scopes=]'s [=list/size=] is 1. 1. Let |globalScope| be |worklet|'s [=global scopes=][0]. 1. Let |moduleMapKeyTuples| be the result of running [=map/get the keys=] on |globalScope|'s [=relevant settings object=]'s [=module map=]. @@ -340,15 +340,15 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. If |savedQueryName| is a [=string=] that is not the empty string, then: 1. Let |callbackTask| be the result of running [=obtain a callback to process the saved index result=], given |window|, |urlList|, and |promise|. 1. Let |savedIndex| be the result of running [=get the index for a saved query=] on |navigable|, |workletDataOrigin|, |moduleURLRecord|, |operationName|, |savedQueryName|, and |callbackTask|. - 1. If |savedIndex| is -1, then return |promise| and abort these steps. + 1. If |savedIndex| is -1, then return the [=tuple=] (|promise|, false) and abort these steps. Note: |callbackTask| is now stored to be run when a previously obtained worklet agent completes its operation to select the index for this query. When the steps of |callbackTask| are run, |promise| will be resolved. 1. If |savedIndex| is nonnegative, then: 1. [=Queue a global task=] on the [=DOM manipulation task source=], given |window|, to run the steps of |callbackTask|, given |savedIndex|. Note: Running the steps of |callbackTask| will resolve |promise|. - 1. Return |promise| and abort these steps. - 1. Return |promise|, and immediately [=obtain a worklet agent=] given |window| and run the rest of these steps in that agent: + 1. Return the [=tuple=] (|promise|, false) and abort these steps. + 1. Return the [=tuple=] (|promise|, true), and immediately [=obtain a worklet agent=] given |window| and run the rest of these steps in that agent: 1. Let |operationMap| be |globalScope|'s [=SharedStorageWorkletGlobalScope/operation map=]. 1. If |operationMap| does not [=map/contain=] |operationName|, then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}, and abort these steps. @@ -433,8 +433,8 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. If [=this=]'s [=SharedStorageWorklet/has cross-origin data origin=] is false, return a [=promise rejected=] with a {{TypeError}}. 1. If |options|["`resolveToConfig`"] is true, [=resolve=] |resultPromise| with |pendingConfig|. 1. Otherwise, [=resolve=] |resultPromise| with |urn|. - 1. Let |indexPromise| be the result of running [=get the select-url result index=], given [=this=], |name|, |urlList|, |workletDataOrigin|, |navigable|, |options|, |preSpecifiedParams| and |aggregationCoordinator|. - 1. [=Upon fulfillment=] of |indexPromise| with (|resultIndex|, |shouldChargeTopLevelBudgets|), perform the following steps: + 1. Let (|indexPromise|, |shouldChargeTopLevelBudgets|) be the result of running [=get the select-url result index=], given [=this=], |name|, |urlList|, |workletDataOrigin|, |navigable|, |options|, |preSpecifiedParams| and |aggregationCoordinator|. + 1. [=Upon fulfillment=] of |indexPromise| with |resultIndex|, perform the following steps: 1. Let |site| be the result of running [=obtain a site=] with |document|'s [=Document/origin=]. 1. Let |remainingBudget| be the result of running [=determine remaining navigation budget=] with |environment| and |site|. 1. Let |pendingBits| be the logarithm base 2 of |urlList|'s [=list/size=]. @@ -451,6 +451,7 @@ Moreover, each {{SharedStorageWorklet}}'s [=global scopes|list of global scopes= 1. If |options|["`keepAlive`"] is false, run [=terminate a worklet global scope=] with [=this=]. 1. [=Upon rejection=] of |indexPromise|, perform the following steps: 1. Let |finalConfig| be a new [=fenced frame config=]. + 1. If |shouldChargeTopLevelBudgets| is true, run [=charge shared storage top-level traversable budgets=] with |navigable|, |site|, and |pendingBits|. 1. Set |finalConfig|'s [=fenced frame config/mapped url=] to |urlList|[[=default selectURL index=]]. 1. [=Finalize a pending config=] on |fencedFrameConfigMapping| with |urn| and |finalConfig|. 1. If |options|["`keepAlive`"] is false, run [=terminate a worklet global scope=] with [=this=]. @@ -1034,7 +1035,7 @@ navigables section, add the following: 1. Let |processIndexTask| be an algorithm to perform the following steps, given an {{unsigned long}} |index|: 1. If |index| is greater than |urlList|'s [=list/size=], then [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=reject=] |promise| with a {{TypeError}}. Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don't know which url should be selected. - 1. Otherwise, [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with the [=tuple=] (|index|, false). + 1. Otherwise, [=queue a global task=] on the [=DOM manipulation task source=], given |window|, to [=resolve=] |promise| with |index|. 1. Return |processIndexTask|. From 2316469ddf7f706ee4149d52fbafd36f7929564d Mon Sep 17 00:00:00 2001 From: Camillia Smith Barnes Date: Wed, 9 Oct 2024 18:24:09 -0400 Subject: [PATCH 07/10] use helper algo to fix rejection --- spec.bs | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/spec.bs b/spec.bs index fc965e2..2c39d10 100644 --- a/spec.bs +++ b/spec.bs @@ -174,6 +174,9 @@ spec: wikipedia-entropy; urlPrefix: https://en.wikipedia.org/wiki/Entropy_(infor spec: shared-storage-explainer; urlPrefix: https://github.com/WICG/shared-storage type:dfn text: legitimate use cases; url: example-scenarios +spec: UUID; urlPrefix: https://www.ietf.org/rfc/rfc4122.txt + type: dfn + text: urn uuid; url: urn-uuid