diff --git a/review-drafts/2022-02.bs b/review-drafts/2022-02.bs new file mode 100644 index 0000000..4cdc6c7 --- /dev/null +++ b/review-drafts/2022-02.bs @@ -0,0 +1,743 @@ +
+Group: WHATWG +Date: 2022-02-23 +H1: Storage +Shortname: storage +Text Macro: TWITTER storagestandard +Text Macro: LATESTRD 2022-02 +Abstract: The Storage Standard defines an API for persistent storage and quota estimates, as well as the platform storage architecture. +Translation: ja https://triple-underscore.github.io/storage-ja.html ++ +
+urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT + text: agent; url: #sec-agents; type: dfn + text: agent cluster; url: #sec-agent-clusters; type: dfn ++ + + +
Over the years the web has grown various APIs that can be used for storage, e.g., IndexedDB,
+localStorage
, and showNotification()
. The Storage Standard consolidates
+these APIs by defining:
+
+
Traditionally, as the user runs out of storage space on their device, the data stored with these +APIs gets lost without the user being able to intervene. However, persistent buckets cannot be +cleared without consent by the user. This thus brings data guarantees users have enjoyed on native +platforms to the web. + +
A simple way to make storage persistent is through invoking the {{persist()}} method. It + simultaneously requests the end user for permission and changes the storage to be persistent once + granted:
+ +
+navigator.storage.persist().then(persisted => {
+ if (persisted) {
+ /* … */
+ }
+});
+
+
+ To not show user-agent-driven dialogs to the end user unannounced slightly more involved code + can be written:
+ +
+Promise.all([
+ navigator.storage.persisted(),
+ navigator.permissions.query({name: "persistent-storage"})
+]).then(([persisted, permission]) => {
+ if (!persisted && permission.state == "granted") {
+ navigator.storage.persist().then( /* … */ );
+ } else if (!persisted && permission.state == "prompt") {
+ showPersistentStorageExplanation();
+ }
+});
+
+
+ The {{estimate()}} method can be used to determine whether there is enough space left to + store content for an application: + +
+function retrieveNextChunk(nextChunkInfo) {
+ return navigator.storage.estimate().then(info => {
+ if (info.quota - info.usage > nextChunkInfo.size) {
+ return fetch(nextChunkInfo.url);
+ } else {
+ throw new Error("insufficient space to store next chunk");
+ }
+ }).then( /* … */ );
+}
+
+
+This specification depends on the Infra Standard. [[!INFRA]] + +
This specification uses terminology from the HTML, IDL, and Permissions Standards. +[[!HTML]] [[!WEBIDL]] [[!PERMISSIONS]] + + + +
A user agent has various kinds of semi-persistent state: + +
End-user credentials, such as username and passwords submitted through HTML forms +
Permissions for various features, such as geolocation +
HTTP cache, cookies, authentication entries, TLS client certificates +
localStorage
,
+ sessionStorage
, application caches, notifications, etc.
+This standard primarily concerns itself with storage. + + + +
Standards defining local or session storage APIs will define a storage endpoint and +register it by changing this standard. They will invoke +either the obtain a local storage bottle map or the +obtain a session storage bottle map algorithm, which will give them: + +
Failure, which might mean the API has to throw or otherwise indicate there is no storage + available for that environment settings object. + +
A storage proxy map that operates analogously to a map, which can be + used to store data in a manner that suits the API. This standard takes care of isolating that data + from other APIs, storage keys, and storage types. +
If you are defining a standard for such an API, consider filing an issue against this +standard for assistance and review. + +
To isolate this data this standard defines a storage shed which segments +storage shelves by a storage key. A storage shelf in turn consists of a +storage bucket and will likely consist of multiple storage buckets in the future to +allow for different storage policies. And lastly, a storage bucket consists of +storage bottles, one for each storage endpoint. + + +
A storage endpoint is a local or +session storage API that uses the infrastructure defined by this standard, most notably +storage bottles, to keep track of its storage needs. + +
A storage endpoint has an identifier, which is a +storage identifier. + +
A storage endpoint also has types, which is a +set of storage types. + +
A storage endpoint also has a quota, which is null or a +number representing a recommended quota (in bytes) for each +storage bottle corresponding to this storage endpoint. + +
A storage identifier is an ASCII string. + +
A storage type is "local
" or "session
".
+
+
The registered storage endpoints are a set of storage endpoints +defined by the following table: + + +
Identifier + | Type + | Quota + |
---|---|---|
"caches "
+ | « "local " »
+ | null + |
"indexedDB "
+ | « "local " »
+ | null + |
"localStorage "
+ | « "local " »
+ | 5 × 220 (i.e., 5 mebibytes) + |
"serviceWorkerRegistrations "
+ | « "local " »
+ | null + |
"sessionStorage "
+ | « "session " »
+ | 5 × 220 (i.e., 5 mebibytes) + |
As mentioned, standards can use these storage identifiers with +obtain a local storage bottle map and obtain a session storage bottle map. It is +anticipated that some APIs will be applicable to both storage types going forward. + + + +
A storage key is a tuple consisting of an origin +(an origin). [[!HTML]] + +
This is expected to change; see +Client-Side Storage Partitioning. + +
To obtain a storage key, given an environment settings object +environment, run these steps: + +
Let key be the result of running + obtain a storage key for non-storage purposes with environment. + +
If key's origin is an opaque origin, then return + failure. + +
If the user has disabled storage, then return failure. + +
Return key. +
To obtain a storage key for non-storage purposes, given an environment +settings object environment, run these steps: + +
+ +To determine whether a storage key A +equals storage key B, run these +steps: + +
If A's origin is not same origin with + B's origin, then return false. + +
Return true. +
A storage shed is a map of storage keys to storage shelves. +It is initially empty. + +
A user agent holds a storage shed, which is a +storage shed. A user agent's storage shed holds all +local storage data. + +
A browsing session holds a storage shed, which is +a storage shed. A browsing session's +storage shed holds all session storage data. + +
To legacy-clone a browsing session storage shed, given a +browsing session A and a browsing session B, run +these steps: + +
For each key → shelf of A's + storage shed: + +
Let newShelf be the result of running create a storage shelf with
+ "session
".
+
+
Set newShelf's bucket map["default
"]'s
+ bottle map["sessionStorage
"]'s map to a
+ clone of shelf's bucket map["default
"]'s
+ bottle map["sessionStorage
"]'s map.
+
+
Set B's storage shed[key] to + newShelf. +
This is considered legacy as the benefits, if any, do not outweigh the +implementation complexity. And therefore it will not be expanded or used outside of +HTML. [[HTML]] + + +
A storage shelf exists for +each storage key within a storage shed. It holds a bucket map, +which is a map of strings to storage buckets. + +
For now "default
" is the only key that exists in a
+bucket map. See issue #2. It is
+given a value when a storage shelf is
+obtained for the first time.
+
+
To obtain a storage shelf, given a storage shed shed, an +environment settings object environment, and a storage type +type, run these steps: + +
Let key be the result of running obtain a storage key with + environment. + +
If key is failure, then return failure. + +
If shed[key] does not exist, then set + shed[key] to the result of running create a storage shelf with + type. + +
Return shed[key]. +
To obtain a local storage shelf, given an environment settings object
+environment, return the result of running obtain a storage shelf with the user
+agent's storage shed, environment, and "local
".
+
+
To create a storage shelf, given a storage type type, run these +steps: + +
Let shelf be a new storage shelf. + +
Set shelf's bucket map["default
"] to the result of running
+ create a storage bucket with type.
+
+
Return shelf. +
A storage bucket is a place for storage endpoints to store data. + +
A storage bucket has a bottle map of storage identifiers to +storage bottles. + +
A local storage bucket is a storage bucket for +local storage APIs. + +
A local storage bucket has a
+mode, which is
+"best-effort
" or "persistent
". It is initially "best-effort
".
+
+
A session storage bucket is a storage bucket for session storage APIs. + +
To create a storage bucket, given a storage type type, run these +steps: + +
Let bucket be null. + +
If type is "local
", then set bucket to a new
+ local storage bucket.
+
+
Otherwise: + +
Assert: type is "session
".
+
+
Set bucket to a new session storage bucket. +
For each endpoint of registered storage endpoints whose + types contain type, set bucket's + bottle map[endpoint's identifier] to a new + storage bottle whose quota is endpoint's + quota. + +
Return bucket. +
A storage bottle is a part of a storage bucket carved out for a single
+storage endpoint. A storage bottle has a map, which is
+initially an empty map. A storage bottle also has a
+proxy map reference set, which is initially an empty
+set. A storage bottle also has a quota, which is
+null or a number representing a conservative estimate of the total amount of bytes it can hold. Null
+indicates the lack of a limit. It is still bound by the storage quota of its
+encompassing storage shelf.
+
+ A storage bottle's map is where the actual data meant to be
+stored lives. User agents are expected to store this data, and make it available across agent
+and even agent cluster boundaries, in an implementation-defined manner, so that this
+standard and standards using this standard can access the contents.
+
+ To obtain a storage bottle map, given a storage type type,
+environment settings object environment, and storage identifier
+identifier, run these steps: Let shed be null.
+
+ If type is " Otherwise:
+
+ Assert: type is " Set shed to environment's
+ browsing session's
+ storage shed.
+ Let shelf be the result of running obtain a storage shelf, with
+ shed, environment, and type.
+
+ If shelf is failure, then return failure.
+
+ Let bucket be shelf's bucket map[" Let bottle be bucket's bottle map[identifier].
+
+ Let proxyMap be a new storage proxy map whose
+ backing map is bottle's map.
+
+ Append proxyMap to bottle's
+ proxy map reference set.
+
+ Return proxyMap.
+ To obtain a local storage bottle map, given an
+environment settings object environment and storage identifier
+identifier, return the result of running obtain a storage bottle map with
+" To obtain a session storage bottle map, given an
+environment settings object environment and storage identifier
+identifier, return the result of running obtain a storage bottle map with
+" A storage proxy map is equivalent to a map, except that all operations
+are instead performed on its backing map.
+
+ This allows for the backing map to be replaced. This
+is needed for issue #4 and potentially the
+Storage Access API.
+
+
+
+ A local storage bucket can only have its mode change to
+" When granted to an origin, the persistence permission can be used to
+protect storage from the user agent's clearing policies. The user agent cannot clear storage marked
+as persistent without involvement from the origin or user. This makes it particularly
+useful for resources the user needs to have available while offline or resources the user creates
+locally.
+
+ The " " If the result of getting the current permission state with
+ " Let shelf be the result of running obtain a local storage shelf with
+ current settings object.
+
+ Set shelf's bucket map[" The storage usage of a storage shelf is an implementation-defined
+rough estimate of the amount of bytes used by it.
+
+ This cannot be an exact amount as user agents might, and are encouraged to, use
+deduplication, compression, and other techniques that obscure exactly how much bytes a
+storage shelf uses.
+
+ The storage quota of a storage shelf is an
+implementation-defined conservative estimate of the total amount of bytes it can hold. This
+amount should be less than the total storage space on the device. It must not be a function of the
+available storage space on the device.
+
+ User agents are strongly encouraged to consider navigation frequency, recency of visits,
+ bookmarking, and permission for " Directly or indirectly revealing available storage space can lead to fingerprinting and leaking
+ information outside the scope of the origin involved.
+ Whenever a storage bucket is cleared by the user agent, it must be cleared in its
+entirety. User agents should avoid clearing storage buckets while script that is able to
+access them is running, unless instructed otherwise by the user.
+
+ If removal of storage buckets leaves the encompassing storage shelf's
+bucket map empty, then remove that
+storage shelf and corresponding storage key from the encompassing
+storage shed.
+
+
+ A user agent that comes under storage pressure should clear network state and
+local storage buckets whose mode is
+" If a user agent continues to be under storage pressure, then the user agent should inform the
+user and offer a way to clear the remaining local storage buckets, i.e., those whose
+mode is " Session storage buckets must be cleared as browsing sessions are closed.
+
+ If the user agent allows for revival of browsing sessions, e.g.,
+through reopening browsing sessions or continued use of them after restarting the user
+agent, then clearing necessarily involves a more complex set of heuristics.
+
+
+ User agents should offer users the ability to clear network state and storage for individual
+websites. User agents should not distinguish between network state and storage in their user
+interface. This ensures network state cannot be used to revive storage and reduces the number of
+concepts users need to be mindful of.
+
+
+ Credentials should be separated as they contain data the user might not be able to revive, such
+as an autogenerated password. Permissions are best separated too to avoid inconveniencing the user.
+
+
+
+ Each environment settings object has an associated {{StorageManager}} object. [[!HTML]]
+
+ The The Let promise be a new promise.
+
+ Let shelf be the result of running obtain a local storage shelf with
+ this's relevant settings object.
+
+ If shelf is failure, then reject promise with a {{TypeError}}.
+
+ Otherwise, run these steps in parallel:
+
+ Let persisted be true if shelf's
+ bucket map[" It will be false when there's an internal error.
+
+ Queue a task to resolve promise with persisted.
+ Return promise.
+ The Let promise be a new promise.
+
+ Let shelf be the result of running obtain a local storage shelf with
+ this's relevant settings object.
+
+ If shelf is failure, then reject promise with a {{TypeError}}.
+
+ Otherwise, run these steps in parallel:
+
+ Let permission be the result of requesting permission to use
+ " User agents are encouraged to not let the user answer this question twice for
+ the same origin around the same time and this algorithm is not equipped to handle
+ such a scenario.
+
+ Let bucket be shelf's bucket map[" Let persisted be true if bucket's
+ mode is " It will be false when there's an internal error.
+
+ If persisted is false and permission is "{{PermissionState/granted}}",
+ then:
+
+ Set bucket's mode to
+ " If there was no internal error, then set persisted to true.
+ Queue a task to resolve promise with persisted.
+ Return promise.
+ The Let promise be a new promise.
+
+ Let shelf be the result of running obtain a local storage shelf with
+ this's relevant settings object.
+
+ If shelf is failure, then reject promise with a {{TypeError}}.
+
+ Otherwise, run these steps in parallel:
+
+ Let usage be storage usage for shelf.
+
+ Let quota be storage quota for shelf.
+
+ Let dictionary be a new {{StorageEstimate}} dictionary whose {{usage}} member
+ is usage and {{quota}} member is quota.
+
+ If there was an internal error while obtaining usage and quota, then
+ queue a task to reject promise with a {{TypeError}}.
+
+ Internal errors are supposed to be extremely rare and indicate some kind of
+ low-level platform or hardware fault. However, at the scale of the web with the diversity of
+ implementation and platforms, the unexpected does occur.
+
+ Otherwise, queue a task to resolve promise with dictionary.
+ Return promise.
+ With that, many thanks to
+Adrian Bateman,
+Aislinn Grigas,
+Alex Russell,
+Ali Alabbas,
+Andrew Sutherland,
+Andrew Williams,
+Ben Kelly,
+Ben Turner,
+Dale Harvey,
+David Grogan,
+Domenic Denicola,
+fantasai,
+Jake Archibald,
+Jeffrey Yasskin,
+Jesse Mykolyn,
+Jinho Bang,
+Jonas Sicking,
+Joshua Bell,
+Kenji Baheux,
+Kinuko Yasuda,
+Luke Wagner,
+Michael Nordman,
+Mike Taylor,
+Mounir Lamouri,
+Shachar Zohar,
+黃強 (Shawn Huang),
+簡冠庭 (Timothy Guan-tin Chien), and
+Victor Costan
+for being awesome!
+
+ This standard is written by Anne van Kesteren
+(Mozilla,
+annevk@annevk.nl).
diff --git a/storage.bs b/storage.bs
index 484bced..8fa9536 100644
--- a/storage.bs
+++ b/storage.bs
@@ -3,7 +3,7 @@ Group: WHATWG
H1: Storage
Shortname: storage
Text Macro: TWITTER storagestandard
-Text Macro: LATESTRD 2021-08
+Text Macro: LATESTRD 2022-02
Abstract: The Storage Standard defines an API for persistent storage and quota estimates, as well as the platform storage architecture.
Translation: ja https://triple-underscore.github.io/storage-ja.html
+
+
+
+
+local
", then set shed to the user agent's
+ storage shed.
+
+
+
+
+ session
".
+
+ default
"].
+
+ local
", environment, and identifier.
+
+session
", environment, and identifier.
+
+
+Storage proxy maps
+
+Persistence permission
+
+persistent
" if the user (or user agent on behalf of the user) has granted permission
+to use the "persistent-storage
" powerful feature.
+
+persistent-storage
" powerful feature's permission-related algorithms,
+and types are defaulted, except for:
+
+
+
+
+
+
+persistent-storage
"'s permission state must have the same value for all
+ environment settings objects with a given origin.
+
+
+
+persistent-storage
" is "{{PermissionState/granted}}", then return.
+
+ default
"]'s
+ mode to "best-effort
".
+ Usage and quota
+
+persistent-storage
" when
+ determining quotas.
+
+ Management
+
+Storage pressure
+
+best-effort
", ideally prioritizing removal in a manner that least impacts the user.
+
+persistent
".
+
+User interface guidelines
+
+API
+
+
+[SecureContext]
+interface mixin NavigatorStorage {
+ [SameObject] readonly attribute StorageManager storage;
+};
+Navigator includes NavigatorStorage;
+WorkerNavigator includes NavigatorStorage;
+
+
+storage
getter steps are to return
+this's relevant settings object's {{StorageManager}} object.
+
+
+[SecureContext,
+ Exposed=(Window,Worker)]
+interface StorageManager {
+ Promise<boolean> persisted();
+ [Exposed=Window] Promise<boolean> persist();
+
+ Promise<StorageEstimate> estimate();
+};
+
+dictionary StorageEstimate {
+ unsigned long long usage;
+ unsigned long long quota;
+};
+
+
+persisted()
method steps are:
+
+
+
+
+
+
+
+ default
"]'s mode is
+ "persistent
"; otherwise false.
+
+ persist()
method steps are:
+
+
+
+
+
+
+
+ persistent-storage
".
+
+ default
"].
+
+ persistent
"; otherwise false.
+
+
+
+
+ persistent
".
+
+ estimate()
method steps are:
+
+
+
+
+
+
+
+
+
+ Acknowledgments
+
+