# KV Storage

## Draft Community Group Report, 1 January 1970

This version:
  https://wicg.github.io/kv-storage/
Editor:
  Domenic Denicola (Google) d@domenic.me
Participate:
  GitHub WICG/kv-storage (new issue, open issues)
Commits:
  GitHub spec.bs commits

Copyright © 1970 the Contributors to the KV Storage Specification, published by the Web Platform Incubator Community Group under the W3C Community Contributor License Agreement (CLA). A human-readable summary is available.

## Abstract

This specification details a high level asynchronous key/value storage API, layered on top of IndexedDB, and as a spiritual successor to the original `localStorage`.

## Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

Not an active specification

Work on this specification is currently suspended, as no browser teams (including the Chromium project, which originated the proposal) are currently indicating interest in implementing it.

## 1. Introduction

This section is non-normative.

The `localStorage` API is widely used, and loved for its simplicity. However, its synchronous nature leads to terrible performance and cross-window synchronization issues.

This specification proposes a new API, called KV storage, which is intended to provide an analogously simple interface, while being asynchronous. Along the way, it embraces some additional goals:

- Layer on top of Indexed Database. This avoids introducing a new type of storage for user agents and web developers to manage, and allows an upgrade path to full IndexedDB usage if a web developer outgrows the KV storage interface. [INDEXEDDB-2]

- Modernize the API surface. Modern key/value stores in the platform, such as the `Cache` or `Headers` APIs, have aligned around the operation names given by JavaScript’s `Map`. We follow their example. As a bonus, this allows us to avoid the legacy named properties feature that the `Storage` interface uses.

- Support isolated storage areas. `localStorage` requires careful namespacing of keys to use robustly in a multi-actor environment. Popular libraries meant to replace it, like localForage, have included a way to create new storage areas beyond the default one.

A conversion of the HTML Standard’s `localStorage` example to use KV storage might look like the following:

    <p>
      You have viewed this page
      <span id="count">an untold number of</span>
      time(s).
    </p>
    <script type="module">
      (async () => {
        let pageLoadCount = await kvStorage.get("pageLoadCount") || 0;
        ++pageLoadCount;

        document.querySelector("#count").textContent = pageLoadCount;

        await kvStorage.set("pageLoadCount", pageLoadCount);
      })();
    </script>

As a side note, observe how, in contrast to the original example which performs up to five storage operations, our example only performs two. Also, it updates the UI as soon as possible, instead of delaying the UI update until we’ve set the new page load count.

The KV storage API design can take some credit for this, as by forcing us to explicitly state our `await` points, it makes it more obvious that we’re performing a potentially-expensive storage operation.

## 2. The `kvStorage` global

    partial interface WindowOrWorkerGlobalScope {
      [SecureContext] readonly attribute KVStorageArea kvStorage;
    };

`self . `kvStorage``

  Returns the default storage area. It is a pre-constructed instance of the `KVStorageArea` class, meant to be a convenience similar to `localStorage`.

  This property is only present in secure contexts, since persistent storage is a powerful feature.

Every `WindowOrWorkerGlobalScope` has an associated default KV Storage area, which is a `KVStorageArea` created in that realm with [[DatabaseName]] set to "`kv-storage:default`", [[DatabasePromise]] initially set to null, and [[BackingStoreObject]] initially set to null.

The `kvStorage` attribute’s getter must return this's default KV Storage area.

## 3. The `KVStorageArea` class

    [SecureContext, Exposed=(Window,Worker)]
    interface KVStorageArea {
      constructor(DOMString name);

      Promise<void> set(any key, any value);
      Promise<any> get(any key);
      Promise<void> delete(any key);
      Promise<void> clear();

      async iterable<any, any>;

      [SameObject] readonly attribute object backingStore;
    };

Each `KVStorageArea` instance must also contain the [[DatabaseName]], [[DatabasePromise]], and [[BackingStoreObject]] internal slots. The following is a non-normative summary of their meaning:

[[DatabaseName]]
  A string containing the name of the backing IndexedDB database.
[[DatabasePromise]]
  A promise for an `IDBDatabase` object, lazily initialized when performing any database operation.
[[BackingStoreObject]]
  The object returned by the `backingStore` getter, cached to ensure identity across gets.

### 3.1. constructor(name)

`storage = new `KVStorageArea`(name)`

  Creates a new `KVStorageArea` that provides an async key/value store view onto an IndexedDB database named ``kv-storage:${name}``.

  This does not actually open or create the database yet; that is done lazily when other methods are called. This means that all other methods can reject with database-related exceptions in failure cases.

1. Set this.[[DatabaseName]] to the concatenation of "`kv-storage:`" and name.

2. Set this.[[DatabasePromise]] to null.

3. Set this.[[BackingStoreObject]] to null.

### 3.2. set(key, value)

`await storage.`set`(key, value)`

  Asynchronously stores the given value so that it can later be retrieved by the given key.

  Keys have to follow the same restrictions as IndexedDB keys: roughly, a key can be a number, string, array, `Date`, `ArrayBuffer`, `DataView`, typed array, or an array of these. Invalid keys will cause the returned promise to reject with a "`DataError`" `DOMException`.

  Values can be any value that can be structured-serialized for storage. Un-serializable values will cause a "`DataCloneError`" `DOMException`. The value undefined will cause the corresponding entry to be deleted.

  The returned promise will fulfill with undefined on success.

1. If key is not allowed as a key, return a promise rejected with a "`DataError`" `DOMException`.

2. Return the result of performing a database operation given this object, "`readwrite`", and the following steps operating on transaction and store:

   1. If value is undefined, then

      1. Perform the steps listed in the description of `IDBObjectStore`'s `delete()` method on store, given the argument key.

   2. Otherwise,

      1. Perform the steps listed in the description of `IDBObjectStore`'s `put()` method on store, given the arguments value and key.

   3. Let promise be a new promise in the relevant Realm of this.

   4. Add a simple event listener to transaction for "`complete`" that resolves promise with undefined.

   5. Add a simple event listener to transaction for "`error`" that rejects promise with transaction’s error.

   6. Add a simple event listener to transaction for "`abort`" that rejects promise with transaction’s error.

   7. Return promise.

### 3.3. get(key)

`value = await storage.`get`(key)`

  Asynchronously retrieves the value stored at the given key, or undefined if there is no value stored at key.

  Values retrieved will be structured-deserialized from their original form.

1. If key is not allowed as a key, return a promise rejected with a "`DataError`" `DOMException`.

2. Return the result of performing a database operation given this object, "`readonly`", and the following steps operating on transaction and store:

   1. Let request be the result of performing the steps listed in the description of `IDBObjectStore`'s `get()` method on store, given the argument key.

   2. Let promise be a new promise in the relevant Realm of this.

   3. Add a simple event listener to request for "`success`" that resolves promise with request’s result.

   4. Add a simple event listener to request for "`error`" that rejects promise with request’s error.

   5. Return promise.

### 3.4. delete(key)

`await storage.`delete`(key)`

  Asynchronously deletes the entry at the given key. This is equivalent to storage.`set`(key, undefined).

  The returned promise will fulfill with undefined on success.

1. If key is not allowed as a key, return a promise rejected with a "`DataError`" `DOMException`.

2. Return the result of performing a database operation given this object, "`readwrite`", and the following steps operating on transaction and store:

   1. Perform the steps listed in the description of `IDBObjectStore`'s `delete()` method on store, given the argument key.

   2. Let promise be a new promise in the relevant Realm of this.

   3. Add a simple event listener to transaction for "`complete`" that resolves promise with undefined.

   4. Add a simple event listener to transaction for "`error`" that rejects promise with transaction’s error.

   5. Add a simple event listener to transaction for "`abort`" that rejects promise with transaction’s error.

   6. Return promise.

### 3.5. clear()

`await storage.`clear`()`

  Asynchronously deletes all entries in this storage area.

  This is done by actually deleting the underlying IndexedDB database. As such, it always can be used as a fail-safe to get a clean slate, as shown below.

  The returned promise will fulfill with undefined on success.

1. Let realm be the relevant Realm of this.

2. If this.[[DatabasePromise]] is not null, return the result of reacting to this.[[DatabasePromise]] with fulfillment and rejection handlers that both perform the following steps:

   1. Set this.[[DatabasePromise]] to null.

   2. Return the result of deleting the database given this.[[DatabaseName]] and realm.

3. Otherwise, return the result of deleting the database given this.[[DatabaseName]] and realm.

To delete the database given a string name and a Realm realm:

1. Let promise be a new promise in realm.

2. Let request be the result of performing the steps listed in the description of `IDBFactory`'s `deleteDatabase()` method on the current `IDBFactory`, given the argument name.

3. If those steps threw an exception, catch the exception and reject promise with it.

4. Otherwise:

   1. Add a simple event listener to request for "`success`" that resolves promise with undefined.

   2. Add a simple event listener to request for "`error`" that rejects promise with request’s error.

5. Return promise.

This method can be used to recover from unexpected modifications to the backing store. For example,

    // This upgrade to version 100 breaks the "cats" storage area: since StorageAreas
    // assume a version of 1, "cats" can no longer be used with KV storage.
    const openRequest = indexedDB.open("kv-storage:cats", 100);
    openRequest.onsuccess = () => {
      openRequest.onsuccess.close();
    };

    (async () => {
      const area = new KVStorageArea("cats");

      // Due to the above upgrade, all other methods will reject:
      try {
        await area.set("fluffy", new Cat());
      } catch (e) {
        // This will be reached and output a "VersionError" DOMException
        console.error(e);
      }

      // But clear() will delete the database entirely:
      await area.clear();

      // Now we can use it again!
      await area.set("fluffy", new Cat());
      await area.set("tigger", new Cat());

      // Also, the version is back down to 1:
      console.assert(area.backingStore.version === 1);
    })();

### 3.6. Iteration

The `KVStorageArea` interface supports asynchronous iteration.

`for await (const key of storage.`keys()`) { ... }`

  Retrieves an async iterator containing the keys of all entries in this storage area.

  Keys will be yielded in ascending order; roughly, segregated by type, and then sorted within each type. They will be key round-tripped from their original form.

`for await (const value of storage.`values()`) { ... }`

  Retrieves an async iterator containing the values of all entries in this storage area.

  Values will be yielded in the same order as for `keys()`. They will be structured-deserialized from their original form.

`for await (const [key, value] of storage.`entries()`) { ... }`
`for await (const [key, value] of storage) { ... }`

  Retrieves an async iterator containing two-element `[key, value]` arrays, each of which corresponds to an entry in this storage area.

  Entries will be yielded in the same order as for `keys()`. Each key and value will be key round-tripped and structured-deserialized from its original form, respectively.

All of these iterators provide live views onto the storage area: modifications made to entries sorted after the last-returned one will be reflected in the iteration.

The asynchronous iterator initialization steps for `KVStorageArea`, given storageArea and asyncIterator, are:

1. Set asyncIterator’s last key to not yet started.

To get the next iteration result, given the storageArea and asyncIterator:

1. Return the result of performing a database operation given storageArea, "`readonly`", and the following steps operating on transaction and store:

   1. Let range be the result of getting the range for asyncIterator’s last key.

   2. Let keyRequest be the result of performing the steps listed in the description of `IDBObjectStore`'s `getKey()` method on store, given the argument range.

   3. Let valueRequest be the result of performing the steps listed in the description of `IDBObjectStore`'s `get()` method on store, given the argument range.

      Note: The iterator returned from `keys()` discards the value. Implementations could avoid constructing valueRequest in that case.

   4. Let promise be a new promise in the relevant Realm of asyncIterator.

   5. Add a simple event listener to valueRequest for "`success`" that performs the following steps:

      1. Let key be keyRequest’s result.

      2. If key is undefined, then:

         1. Resolve promise with undefined.

      3. Otherwise:

         1. Let value be valueRequest’s result.

         2. Resolve promise with (key, value, key).

         3. Set asyncIterator’s last key to key.

   6. Add a simple event listener to keyRequest for "`error`" that rejects promise with keyRequest’s error.

   7. Add a simple event listener to valueRequest for "`error`" that rejects promise with valueRequest’s error.

   8. Return promise.

To illustrate the live nature of the async iterators, consider the following:

    await kvStorage.set(10, "value 10");
    await kvStorage.set(20, "value 20");
    await kvStorage.set(30, "value 30");

    const keysSeen = [];
    for await (const key of kvStorage.keys()) {
      if (key === 20) {
        await kvStorage.set(15, "value 15");
        await kvStorage.delete(20);
        await kvStorage.set(25, "value 25");
      }
      keysSeen.push(key);
    }

    console.log(keysSeen);   // logs 10, 20, 25, 30

That is, calling `keys()` does not create a snapshot as of the time it was called; it returns a live asynchronous iterator, that lazily retrieves the next key after the last-seen one.

Assuming you knew that that you only stored JSON-compatible types in the `KVStorageArea` storage, you could use the following code to send all locally-stored entries to a server:

    const entries = [];
    for await (const entry of kvStorage.entries()) {
      entries.push(entry);
    }

    fetch("/storage-receiver", {
      method: "POST",
      body: entries,
      headers: {
        "Content-Type": "application/json"
      }
    });

### 3.7. backingStore

`{ database, store, version } = storage.`backingStore``

  Returns an object containing all of the information necessary to manually interface with the IndexedDB backing store that underlies this storage area:

  - database will be a string equal to "`kv-storage:`" concatenated with the database name passed to the constructor. (For the default storage area, it will be "`kv-storage:default`".)

  - store will be the string "`store`".

  - version will be the number 1.

  It is good practice to use the `backingStore` property to retrieve this information, instead of memorizing the above factoids.

1. If this.[[BackingStoreObject]] is null, then:

   1. Let backingStoreObject be ObjectCreate(`%ObjectPrototype%`).

   2. Perform CreateDataProperty(backingStoreObject, "`database`", this.[[DatabaseName]]).

   3. Perform CreateDataProperty(backingStoreObject, "`store`", "`store`").

   4. Perform CreateDataProperty(backingStoreObject, "`version`", 1).

   5. Perform SetIntegrityLevel(backingStoreObject, "`frozen`").

   6. Set this.[[BackingStoreObject]] to backingStoreObject.

2. Return this.[[BackingStoreObject]].

Consider a checklist application, which tracks the Pokémon a user has collected. It might use a `KVStorageArea` storage like so:

    bulbasaur.onchange = () => kvStorage.set("bulbasaur", bulbasaur.checked);
    ivysaur.onchange = () => kvStorage.set("ivysaur", ivysaur.checked);
    venusaur.onchange = () => kvStorage.set("venusaur", venusaur.checked);
    // ...

(Hopefully the developer quickly realizes that the above will be hard to maintain, and refactors the code into a loop. But in the meantime, their repetitive code makes for a good example, so let’s take advantage of that.)

The developer now realizes they want to add an evolution feature, e.g. for when the user transforms their Bulbasaur into an Ivysaur. They might first implement this like so:

    bulbasaurEvolve.onclick = async () => {
      await kvStorage.set("bulbasaur", false);
      await kvStorage.set("ivysaur", true);
    };

However, our developer starts getting bug reports from their users: if the users happen to open up the checklist app in a second tab while they’re evolving in the first tab, the second tab will sometimes see that their Bulbasaur has disappeared, without ever turning into an Ivysaur! A Pokémon has gone missing!

The solution here is to step beyond the comfort zone of KV storage, and start using the full power of IndexedDB: in particular, its transactions feature. The `backingStore` getter is the gateway to this world:

    const { database, store, version } = kvStorage.backingStore;
    const request = indexedDB.open(database, version);
    request.onsuccess = () => {
      const db = request.result;

      bulbasaurEvolve.onclick = () => {
        const transaction = db.transaction(store, "readwrite");
        const store = transaction.objectStore(store);

        store.put("bulbasaur", false);
        store.put("ivysaur", true);

        db.close();
      };
    };

Satisfied with their web app’s Pokémon integrity, our developer is now happy and fulfilled. (At least, until they realize that none of their code has error handling.)

## 4. Supporting operations and concepts

To add a simple event listener, given an `EventTarget` target, an event type string type, and a set of steps steps:

1. Let jsCallback be a new JavaScript function object, created in the current realm, that performs the steps given by steps. Other properties of the function (such as its `name` and `length` properties, or [[Prototype]]) are unobservable, and can be chosen arbitrarily.

2. Let idlCallback be the result of converting jsCallback to an `EventListener`.

3. Perform the steps listed in the description of `EventTarget`'s `addEventListener()` method on target given the arguments type and idlCallback.

The current `IDBFactory` is the `IDBFactory` instance returned by the following steps:

1. Assert: the current global object includes `WindowOrWorkerGlobalScope`.

2. Return the result of performing the steps listed in the description of the getter for `WindowOrWorkerGlobalScope`'s `indexedDB` attribute on the current global object.

To perform a database operation given a `KVStorageArea` area, a mode string mode, and a set of steps steps that operate on an `IDBTransaction` transaction and an `IDBObjectStore` store:

1. Assert: area.[[DatabaseName]] is a string (and in particular is not null).

2. If area.[[DatabasePromise]] is null, initialize the database promise for area.

3. Return the result of reacting to area.[[DatabasePromise]] with a fulfillment handler that performs the following steps, given database:

   1. Let transaction be the result of performing the steps listed in the description of `IDBDatabase`'s `transaction()` method on database, given the arguments "`store`" and mode.

   2. Let store be the result of performing the steps listed in the description of `IDBTransaction`'s `objectStore()` method on transaction, given the argument "`store`".

   3. Return the result of performing steps, passing along transaction and store.

To initialize the database promise for a `KVStorageArea` area:

1. Set area.[[DatabasePromise]] to a new promise in the relevant Realm of area.

2. If the current global object does not include `WindowOrWorkerGlobalScope`, reject area.[[DatabasePromise]] with a `TypeError`, and return.

3. Let request be the result of performing the steps listed in the description of `IDBFactory`'s `open()` method on the current `IDBFactory`, given the arguments area.[[DatabaseName]] and 1.

4. If those steps threw an exception, catch the exception, reject area.[[DatabasePromise]] with it, and return.

5. Add a simple event listener to request for "`success`" that performs the following steps:

   1. Let database be request’s result.

   2. Check the database schema for database. If the result is false, reject area.[[DatabasePromise]] with an "`InvalidStateError`" `DOMException` and abort these steps.

   3. Add a simple event listener to database for "`close`" that sets area.[[DatabasePromise]] to null.

      This means that if the database is closed abnormally, future invocations of perform a database operation will attempt to reopen it.

   4. Add a simple event listener to database for "`versionchange`" that performs the steps listed in the description of `IDBDatabase`'s `close()` method on database, and then sets area.[[DatabasePromise]] to null.

      This allows attempts to upgrade the underlying database, or to delete it (e.g. via the `clear()` method), to succeed. Without this, if two `KVStorageArea` instances were both open referencing the same underlying database, `clear()` would hang, as it only closes the connection maintained by the `KVStorageArea` it is invoked on.

   5. Resolve promise with database.

6. Add a simple event listener to request for "`error`" that rejects promise with request’s error.

7. Add a simple event listener to request for "`upgradeneeded`" that performs the following steps:

   1. Let database be request’s result.

   2. Perform the steps listed in the description of `IDBDatabase`'s `createObjectStore()` method on database, given the arguments "`store`".

   3. If these steps throw an exception, catch the exception and reject area.[[DatabasePromise]] with it.

To check the database schema for an `IDBDatabase` database:

1. Let objectStores be database’s connection's object store set.

2. If objectStores’s size is not 1, return false.

3. Let store be objectStores[0].

4. If store’s name is not "`store`", return false.

5. If store has a key generator, return false.

6. If store has a key path, return false.

7. If any indexes reference store, return false.

8. Return true.

Check the database schema only needs to be called in the initial setup algorithm, initialize the database promise, since once the database connection has been opened, the schema cannot change.

A value value is allowed as a key if the following steps return true:

1. If Type(value) is Number or String, return true.

2. If IsArray(value) is true, return true.

3. If value has a [[DateValue]] internal slot, return true.

4. If value has a [[ViewedArrayBuffer]] internal slot, return true.

5. If value has an [[ArrayBufferByteLength]] internal slot, return true.

6. Return false.

A value being allowed as a key means that it can at least plausibly be used as a key in the IndexedDB APIs. In particular, the values which are allowed as a key are a subset of those for which IndexedDB’s convert a value to a key algorithm will succeed.

Most notably, using the allowed as a key predicate ensures that `IDBKeyRange` objects, or any other special object that is accepted as a query in future IndexedDB specification revisions, will be disallowed. Only straightforward key values are accepted by the KV storage API.

Key round-tripping refers to the way in which JavaScript values are processed by first being passed through IndexedDB’s convert a value to a key operation, then converted back through its convert a key to a value operation. Keys returned by the `keys()` or `entries()` methods will have gone through this process.

Notably, any typed arrays or `DataView`s will have been "unwrapped", and returned back as just `ArrayBuffer`s containing the same bytes. Also, similar to the structured-serialization/deserialization process, any "expando" properties or other modifications will not be preserved by key round-tripping.

For primitive string or number values, there’s no need to worry about key round-tripping; the values are indistinguishable.

To get the range for a key key:

1. If key is not yet started, then return the result of performing the steps listed in the description of the `IDBKeyRange.lowerBound()` static method, given the argument −Infinity.

   The intent here is to get an unbounded key range, but this is the closest thing we can get that is representable as an `IDBKeyRange` object. It works equivalently for our purposes, but will behave incorrectly if Indexed DB ever adds keys that sort below −Infinity. See some discussion on potential future improvements.

2. Otherwise, return the result of performing the steps listed listed in the description of the `IDBKeyRange.lowerBound()` static method, given the arguments key and true.

The special value not yet started can be taken to be any JavaScript value that is not equal to any other program-accessible JavaScript value (but is equal to itself). It is used exclusively as an argument to the get the range for a key algorithm.

A newly created object or symbol, e.g. `const nys = {}` or `const nys = Symbol()`, would satisfy this definition.

## Acknowledgments

The editor would like to thank Andrew Sutherland, Kenneth Rohde Christiansen, Jacob Rask, Jake Archibald, Jan Varga, Joshua Bell, Ms2ger, and Victor Costan for their contributions to this specification.

## Conformance

This specification depends on the Infra Standard. [INFRA]

## Index

### Terms defined by this specification

- add a simple event listener, in §4
- allowed as a key, in §4
- backingStore, in §3.6
- [[BackingStoreObject]], in §3
- check the database schema, in §4
- clear(), in §3.4
- constructor(name), in §3
- current IDBFactory, in §4
- [[DatabaseName]], in §3
- [[DatabasePromise]], in §3
- default KV Storage area, in §2
- delete(key), in §3.3
- delete the database, in §3.5
- deleting the database, in §3.5
- entries(), in §3.6
- get(key), in §3.2
- get the range for a key, in §4
- getting the range for, in §4
- getting the range for a key, in §4
- initialize the database promise, in §4
- key round-trip, in §4
- keys(), in §3.6
- kvStorage, in §2
- KVStorageArea, in §2
- KVStorageArea(name), in §3
- last key, in §3.6
- not yet started, in §4
- perform a database operation, in §4
- performing a database operation, in §4
- set(key, value), in §3.1
- values(), in §3.6

https://dom.spec.whatwg.org/#callbackdef-eventlistener Referenced in:

- 4. Supporting operations and concepts

https://dom.spec.whatwg.org/#eventtarget Referenced in:

- 4. Supporting operations and concepts (2)

https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener Referenced in:

- 4. Supporting operations and concepts

https://tc39.github.io/ecma262/#sec-properties-of-the-object-prototype-object Referenced in:

- 3.7. backingStore

https://tc39.github.io/ecma262/#sec-createdataproperty Referenced in:

- 3.7. backingStore (2) (3)

https://tc39.github.io/ecma262/#sec-date-objects Referenced in:

- 3.2. set(key, value)

https://tc39.github.io/ecma262/#sec-isarray Referenced in:

- 4. Supporting operations and concepts

https://tc39.github.io/ecma262/#sec-map-objects Referenced in:

- 1. Introduction

https://tc39.github.io/ecma262/#sec-objectcreate Referenced in:

- 3.7. backingStore

https://tc39.github.io/ecma262/#sec-setintegritylevel Referenced in:

- 3.7. backingStore

https://tc39.github.io/ecma262/#sec-ecmascript-data-types-and-values Referenced in:

- 4. Supporting operations and concepts

https://tc39.github.io/ecma262/#current-realm Referenced in:

- 4. Supporting operations and concepts

https://tc39.github.io/ecma262/#realm-record Referenced in:

- 3.5. clear()

https://tc39.github.io/ecma262/#sec-typedarray-objects Referenced in:

- 3.2. set(key, value)
- 4. Supporting operations and concepts

https://fetch.spec.whatwg.org/#headers Referenced in:

- 1. Introduction

https://html.spec.whatwg.org/multipage/webstorage.html#storage-2 Referenced in:

- 1. Introduction

https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize Referenced in:

- 3.3. get(key)
- 3.6. Iteration (2)
- 4. Supporting operations and concepts

https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeforstorage Referenced in:

- 3.2. set(key, value)
- 4. Supporting operations and concepts

https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope Referenced in:

- 2. The kvStorage global (2)
- 4. Supporting operations and concepts (2) (3)

https://html.spec.whatwg.org/multipage/webappapis.html#current-global-object Referenced in:

- 4. Supporting operations and concepts (2) (3)

https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage Referenced in:

- Unnumbered Section
- 1. Introduction (2)
- 2. The kvStorage global

https://html.spec.whatwg.org/multipage/webappapis.html#concept-relevant-realm Referenced in:

- 3.2. set(key, value)
- 3.3. get(key)
- 3.4. delete(key)
- 3.5. clear()
- 3.6. Iteration
- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#idbdatabase Referenced in:

- 3. The KVStorageArea class
- 4. Supporting operations and concepts (2) (3) (4)

https://w3c.github.io/IndexedDB/#idbfactory Referenced in:

- 3.5. clear()
- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#idbkeyrange Referenced in:

- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#idbobjectstore Referenced in:

- 3.2. set(key, value) (2)
- 3.3. get(key)
- 3.4. delete(key)
- 3.6. Iteration (2)
- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#idbtransaction Referenced in:

- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#greater-than Referenced in:

- 3.6. Iteration

https://w3c.github.io/IndexedDB/#close-a-database-connection Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbdatabase-close Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#connection Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#convert-a-key-to-a-value Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#convert-a-value-to-a-key Referenced in:

- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbobjectstore-delete Referenced in:

- 3.2. set(key, value)
- 3.4. delete(key)

https://w3c.github.io/IndexedDB/#dom-idbfactory-deletedatabase Referenced in:

- 3.5. clear()

https://w3c.github.io/IndexedDB/#transaction-error Referenced in:

- 3.2. set(key, value) (2)
- 3.4. delete(key) (2)

https://w3c.github.io/IndexedDB/#dom-idbobjectstore-get Referenced in:

- 3.3. get(key)
- 3.6. Iteration

https://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey Referenced in:

- 3.6. Iteration

https://w3c.github.io/IndexedDB/#index-concept Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-windoworworkerglobalscope-indexeddb Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#key-generator Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#object-store-key-path Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbkeyrange-lowerbound Referenced in:

- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#dom-idbkeyrange-lowerbound Referenced in:

- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#object-store-name Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#connection-object-store-set Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbfactory-open Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#dom-idbobjectstore-put Referenced in:

- 3.2. set(key, value)

https://w3c.github.io/IndexedDB/#request-result Referenced in:

- 3.3. get(key)
- 3.6. Iteration (2)
- 4. Supporting operations and concepts (2)

https://w3c.github.io/IndexedDB/#transaction-concept Referenced in:

- 3.7. backingStore

https://w3c.github.io/IndexedDB/#dom-idbdatabase-transaction Referenced in:

- 4. Supporting operations and concepts

https://w3c.github.io/IndexedDB/#unbounded-key-range Referenced in:

- 4. Supporting operations and concepts

https://infra.spec.whatwg.org/#list-size Referenced in:

- 4. Supporting operations and concepts

https://www.w3.org/2001/tag/doc/promises-guide/#a-new-promise Referenced in:

- 3.2. set(key, value)
- 3.3. get(key)
- 3.4. delete(key)
- 3.5. clear()
- 3.6. Iteration
- 4. Supporting operations and concepts

https://www.w3.org/2001/tag/doc/promises-guide/#a-promise-rejected-with Referenced in:

- 3.2. set(key, value)
- 3.3. get(key)
- 3.4. delete(key)

https://www.w3.org/2001/tag/doc/promises-guide/#reject-promise Referenced in:

- 3.2. set(key, value) (2)
- 3.3. get(key)
- 3.4. delete(key) (2)
- 3.5. clear() (2)
- 3.6. Iteration (2)
- 4. Supporting operations and concepts (2) (3) (4) (5)

https://w3c.github.io/webappsec-secure-contexts/#secure-contexts Referenced in:

- 2. The kvStorage global

https://w3c.github.io/ServiceWorker/#cache Referenced in:

- 1. Introduction

https://heycam.github.io/webidl/#idl-ArrayBuffer Referenced in:

- 3.2. set(key, value)
- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#idl-DOMException Referenced in:

- 3.2. set(key, value) (2) (3)
- 3.3. get(key)
- 3.4. delete(key)
- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#idl-DOMString Referenced in:

- 3. The KVStorageArea class

https://heycam.github.io/webidl/#datacloneerror Referenced in:

- 3.2. set(key, value)

https://heycam.github.io/webidl/#dataerror Referenced in:

- 3.2. set(key, value) (2)
- 3.3. get(key)
- 3.4. delete(key)

https://heycam.github.io/webidl/#idl-DataView Referenced in:

- 3.2. set(key, value)
- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#Exposed Referenced in:

- 3. The KVStorageArea class

https://heycam.github.io/webidl/#invalidstateerror Referenced in:

- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#SameObject Referenced in:

- 3. The KVStorageArea class

https://heycam.github.io/webidl/#SecureContext Referenced in:

- 2. The kvStorage global
- 3. The KVStorageArea class

https://heycam.github.io/webidl/#exceptiondef-typeerror Referenced in:

- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#dfn-convert-ecmascript-to-idl-value Referenced in:

- 4. Supporting operations and concepts

https://heycam.github.io/webidl/#include Referenced in:

- 4. Supporting operations and concepts (2)

https://heycam.github.io/webidl/#idl-named-properties Referenced in:

- 1. Introduction

https://heycam.github.io/webidl/#idl-object Referenced in:

- 3. The KVStorageArea class

https://heycam.github.io/webidl/#this Referenced in:

- 2. The kvStorage global

### Terms defined by reference

- [DOM] defines the following terms:
  - EventListener
  - EventTarget
  - addEventListener(type, callback)
- [ECMASCRIPT] defines the following terms:
  - %ObjectPrototype%
  - CreateDataProperty
  - Date
  - IsArray
  - Map
  - ObjectCreate
  - SetIntegrityLevel
  - Type
  - current realm
  - realm
  - typed array
- [FETCH] defines the following terms:
  - Headers
- [HTML] defines the following terms:
  - Storage
  - StructuredDeserialize
  - StructuredSerializeForStorage
  - WindowOrWorkerGlobalScope
  - current global object
  - localStorage
  - relevant realm
- [INDEXEDDB-2] defines the following terms:
  - IDBDatabase
  - IDBFactory
  - IDBKeyRange
  - IDBObjectStore
  - IDBTransaction
  - ascending
  - close a database connection
  - close()
  - connection
  - convert a key to a value
  - convert a value to a key
  - createObjectStore(name)
  - delete(query)
  - deleteDatabase(name)
  - error (for transaction)
  - get(query)
  - getKey(query)
  - index
  - indexedDB
  - key generator
  - key path
  - lowerBound(lower)
  - lowerBound(lower, open)
  - name
  - object store set
  - objectStore(name)
  - open(name)
  - put(value)
  - result
  - transaction
  - transaction(storeNames)
  - unbounded key range
- [INFRA] defines the following terms:
  - size
- [promises-guide] defines the following terms:
  - a new promise
  - a promise rejected with
  - reject
- [secure-contexts] defines the following terms:
  - secure contexts
- [service-workers-1] defines the following terms:
  - Cache
- [WebIDL] defines the following terms:
  - ArrayBuffer
  - DOMException
  - DOMString
  - DataCloneError
  - DataError
  - DataView
  - Exposed
  - InvalidStateError
  - SameObject
  - SecureContext
  - TypeError
  - converted to an idl value
  - include
  - named properties
  - object
  - this

## References

### Normative References

[DOM]
  Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
  ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/
[HTML]
  Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INDEXEDDB-2]
  Ali Alabbas; Joshua Bell. Indexed Database API 2.0. URL: https://w3c.github.io/IndexedDB/
[INFRA]
  Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PROMISES-GUIDE]
  Domenic Denicola. Writing Promise-Using Specifications. 9 November 2018. TAG Finding. URL: https://www.w3.org/2001/tag/doc/promises-guide
[WebIDL]
  Boris Zbarsky. Web IDL. URL: https://heycam.github.io/webidl/

### Informative References

[FETCH]
  Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[SECURE-CONTEXTS]
  Mike West. Secure Contexts. URL: https://w3c.github.io/webappsec-secure-contexts/
[SERVICE-WORKERS-1]
  Alex Russell; et al. Service Workers 1. URL: https://w3c.github.io/ServiceWorker/

## IDL Index

    partial interface WindowOrWorkerGlobalScope {
      [SecureContext] readonly attribute KVStorageArea kvStorage;
    };

    [SecureContext, Exposed=(Window,Worker)]
    interface KVStorageArea {
      constructor(DOMString name);

      Promise<void> set(any key, any value);
      Promise<any> get(any key);
      Promise<void> delete(any key);
      Promise<void> clear();

      async iterable<any, any>;

      [SameObject] readonly attribute object backingStore;
    };

#default-kv-storage-area Referenced in:

- 2. The kvStorage global

#dom-windoworworkerglobalscope-kvstorage Referenced in:

- 2. The kvStorage global (2) (3)

#KVStorageArea Referenced in:

- 2. The kvStorage global (2) (3)
- 3. The KVStorageArea class (2)
- 3.1. constructor(name)
- 3.6. Iteration (2) (3)
- 3.7. backingStore
- 4. Supporting operations and concepts (2) (3) (4)

#databasename Referenced in:

- 2. The kvStorage global
- 3. The KVStorageArea class
- 3.1. constructor(name)
- 3.5. clear() (2)
- 3.7. backingStore
- 4. Supporting operations and concepts (2)

#databasepromise Referenced in:

- 2. The kvStorage global
- 3. The KVStorageArea class
- 3.1. constructor(name)
- 3.5. clear() (2) (3)
- 4. Supporting operations and concepts (2) (3) (4) (5) (6) (7) (8) (9)

#backingstoreobject Referenced in:

- 2. The kvStorage global
- 3. The KVStorageArea class
- 3.1. constructor(name)
- 3.7. backingStore (2) (3)

#KVStorageArea-constructor Referenced in:

- 3. The KVStorageArea class
- 3.1. constructor(name)

#KVStorageArea-set Referenced in:

- 3. The KVStorageArea class
- 3.2. set(key, value)
- 3.4. delete(key)

#KVStorageArea-get Referenced in:

- 3. The KVStorageArea class
- 3.3. get(key)

#KVStorageArea-delete Referenced in:

- 3. The KVStorageArea class
- 3.4. delete(key)

#KVStorageArea-clear Referenced in:

- 3. The KVStorageArea class
- 3.5. clear()
- 4. Supporting operations and concepts (2)

#deleting-the-database Referenced in:

- 3.5. clear() (2)

#dom-kvstoragearea-keys Referenced in:

- 3.6. Iteration (2) (3) (4)
- 4. Supporting operations and concepts

#dom-kvstoragearea-entries Referenced in:

- 4. Supporting operations and concepts

#kvstorageareaasynciterator-last-key Referenced in:

- 3.6. Iteration (2)

#KVStorageArea-backingstore Referenced in:

- 3. The KVStorageArea class (2)
- 3.7. backingStore (2) (3)

#add-a-simple-event-listener Referenced in:

- 3.2. set(key, value) (2) (3)
- 3.3. get(key) (2)
- 3.4. delete(key) (2) (3)
- 3.5. clear() (2)
- 3.6. Iteration (2) (3)
- 4. Supporting operations and concepts (2) (3) (4) (5)

#current-idbfactory Referenced in:

- 3.5. clear()
- 4. Supporting operations and concepts

#performing-a-database-operation Referenced in:

- 3. The KVStorageArea class
- 3.2. set(key, value)
- 3.3. get(key)
- 3.4. delete(key)
- 3.6. Iteration
- 4. Supporting operations and concepts

#initialize-the-database-promise Referenced in:

- 4. Supporting operations and concepts (2)

#check-the-database-schema Referenced in:

- 4. Supporting operations and concepts (2)

#allowed-as-a-key Referenced in:

- 3.2. set(key, value)
- 3.3. get(key)
- 3.4. delete(key)
- 4. Supporting operations and concepts (2) (3)

#key-round-trip Referenced in:

- 3.6. Iteration (2)
- 4. Supporting operations and concepts (2)

#get-the-range-for-a-key Referenced in:

- 3.6. Iteration
- 4. Supporting operations and concepts

#not-yet-started Referenced in:

- 3.6. Iteration
- 4. Supporting operations and concepts