diff --git a/Cargo.lock b/Cargo.lock
index 81c15fbbd2..34ee5a81b9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -792,6 +792,7 @@ dependencies = [
"deno_ast",
"deno_bench_util",
"deno_broadcast_channel",
+ "deno_cache",
"deno_console",
"deno_core",
"deno_crypto",
@@ -1139,6 +1140,7 @@ version = "0.70.0"
dependencies = [
"atty",
"deno_broadcast_channel",
+ "deno_cache",
"deno_console",
"deno_core",
"deno_crypto",
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index f38a8e651d..f561272cd1 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -27,6 +27,7 @@ path = "./bench/lsp_bench_standalone.rs"
[build-dependencies]
deno_broadcast_channel = { version = "0.56.0", path = "../ext/broadcast_channel" }
deno_console = { version = "0.62.0", path = "../ext/console" }
+deno_cache = { version = "0.1.0", path = "../ext/cache" }
deno_core = { version = "0.144.0", path = "../core" }
deno_crypto = { version = "0.76.0", path = "../ext/crypto" }
deno_fetch = { version = "0.85.0", path = "../ext/fetch" }
diff --git a/cli/build.rs b/cli/build.rs
index 1a4eaa4254..0c3630d514 100644
--- a/cli/build.rs
+++ b/cli/build.rs
@@ -81,6 +81,7 @@ fn create_compiler_snapshot(
) {
// libs that are being provided by op crates.
let mut op_crate_libs = HashMap::new();
+ op_crate_libs.insert("deno.caches", deno_cache::get_declaration());
op_crate_libs.insert("deno.console", deno_console::get_declaration());
op_crate_libs.insert("deno.url", deno_url::get_declaration());
op_crate_libs.insert("deno.web", deno_web::get_declaration());
diff --git a/ext/cache/01_cache.js b/ext/cache/01_cache.js
index 0ea93c3c0d..83ac1cdfeb 100644
--- a/ext/cache/01_cache.js
+++ b/ext/cache/01_cache.js
@@ -3,105 +3,195 @@
///
((window) => {
- const core = window.Deno.core;
- const webidl = window.__bootstrap.webidl;
- const {
- SafeArrayIterator,
- Symbol,
- SymbolFor,
- ObjectDefineProperty,
- ObjectFromEntries,
- ObjectEntries,
- ReflectGet,
- ReflectHas,
- Proxy,
- } = window.__bootstrap.primordials;
+ function queryCache(requestQuery, options = {}, targetStorage = new Map()) {
+ const resultList = new Map();
+ // let storage = null;
+ // Ignore step 2-4;
+ for (const [request, response] of targetStorage.entries()) {
+ if (requestMatchesCatchedItem(requestQuery, request, response, options)) {
+ resultList.set(request, response);
+ }
+ }
+ return resultList;
+ }
- const _persistent = Symbol("[[persistent]]");
+ function requestMatchesCachedItem(
+ requestQuery,
+ request,
+ response = null,
+ options = {},
+ ) {
+ // Step 1.
+ if (options["ignoreMethod"] === false && request.method !== "GET") {
+ return false;
+ }
+
+ // Step 2.
+ let queryURL = requestQuery.url;
+ let cachedURL = request.url;
+ if (options["ignoreSearch"] === true) {
+ queryURL = "";
+ cachedURL = "";
+ }
+
+ // Step 5.
+ {
+ const a = new URL(queryURL);
+ const b = new URL(cachedURL);
+ if (
+ a.host !== b.host || a.pathname !== b.pathname || a.search !== b.search
+ ) {
+ // TODO(@satyarohith): think about exclude fragment flag
+ return false;
+ }
+ }
+
+ // Step 6.
+ if (
+ (response === null && options["ignoreVary"] === true) ||
+ !response.headers.has("Vary")
+ ) {
+ return true;
+ }
+
+ // Step 7.
+ const varyHeader = response.headers.get("Vary");
+ // TODO(@satyarohith): do the parsing of the vary header.
+ const fieldValues = varyHeader.split(",").map((field) => field.trim());
+ for (const fieldValue of fieldValues) {
+ if (
+ fieldValue === "*" ||
+ request.headers.get(fieldValue) !== requestQuery.headers.get(fieldValue)
+ ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
class CacheStorage {
#storage;
constructor() {
- webidl.illegalConstructor();
+ this.#storage = new Map();
+ return this;
}
- get length() {
- webidl.assertBranded(this, StoragePrototype);
- return core.opSync("op_webstorage_length", this[_persistent]);
+ // deno-lint-ignore require-await
+ async match(_request, _options) {
+ // TODO(@satyarohith): implement the algorithm.
+ return Promise.resolve(new Response("hello world"));
}
-
- key(index) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'key' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- index = webidl.converters["unsigned long"](index, {
- prefix,
- context: "Argument 1",
- });
-
- return core.opSync("op_webstorage_key", index, this[_persistent]);
+ // deno-lint-ignore require-await
+ async open(cacheName) {
+ if (!this.#storage.has(cacheName)) {
+ this.#storage.set(cacheName, new Cache(cacheName));
+ }
+ return Promise.resolve(this.#storage.get(cacheName));
}
-
- setItem(key, value) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'setItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
- value = webidl.converters.DOMString(value, {
- prefix,
- context: "Argument 2",
- });
-
- core.opSync("op_webstorage_set", key, value, this[_persistent]);
+ // deno-lint-ignore require-await
+ async has(cacheName) {
+ return Promise.resolve(this.#storage.has(cacheName));
}
-
- getItem(key) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'getItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
-
- return core.opSync("op_webstorage_get", key, this[_persistent]);
+ // deno-lint-ignore require-await
+ async delete(cacheName) {
+ return Promise.resolve(this.#storage.delete(cacheName));
}
-
- removeItem(key) {
- webidl.assertBranded(this, StoragePrototype);
- const prefix = "Failed to execute 'removeItem' on 'Storage'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
- key = webidl.converters.DOMString(key, {
- prefix,
- context: "Argument 1",
- });
-
- core.opSync("op_webstorage_remove", key, this[_persistent]);
- }
-
- clear() {
- webidl.assertBranded(this, StoragePrototype);
- core.opSync("op_webstorage_clear", this[_persistent]);
+ // deno-lint-ignore require-await
+ async keys() {
+ return Promise.resolve(Array.from(this.#storage.keys()));
}
}
- window.__bootstrap.webStorage = {
- localStorage() {
- if (!localStorage) {
- localStorage = createStorage(true);
+ class Cache {
+ #storage;
+ #name;
+ constructor(cacheName) {
+ this.#name = cacheName;
+ this.#storage = new Map();
+ return this;
+ }
+ // async match(request, options) {}
+
+ // deno-lint-ignore require-await
+ async matchAll(request, options = {}) {
+ let r = null;
+ // Step 2.
+ if (request instanceof Request) {
+ if (request.method !== "GET" && !options?.ignoreMethod) {
+ return Promise.resolve([]);
+ }
+ r = request;
+ } else if (request instanceof string) {
+ try {
+ r = new Request(request);
+ } catch (error) {
+ return Promise.reject(error);
+ }
}
- return localStorage;
- },
- sessionStorage() {
- if (!sessionStorage) {
- sessionStorage = createStorage(false);
+
+ // Step 5.
+ const responses = [];
+ // Step 5.2
+ if (r === null) {
+ for (const [_request, response] of this.#storage.entries()) {
+ responses.push(response);
+ }
+ // Step 5.3
+ } else {
+ const requestResponses = queryCache(r, options, this.#storage);
+ for (const response of requestResponses.values()) {
+ responses.push(response);
+ }
+ // Skip 5.4.
}
- return sessionStorage;
- },
- Storage,
+ // Step 5.5
+
+ return Promise.resolve(responses);
+ }
+
+ // deno-lint-ignore require-await
+ async add(request) {
+ const requests = [request];
+ return this.addAll(requests);
+ }
+
+ // async addAll(requests) {
+ // const responsePromises = [];
+ // const requestList = [];
+ // for (const request of requests) {
+ // if (
+ // request instanceof Request &&
+ // request.scheme !== "http" && request.scheme !== "https" ||
+ // request.method !== "GET"
+ // ) {
+ // return Promise.reject(new TypeError("type error"));
+ // }
+ // }
+ // }
+
+ // put(request, response) {
+ // let innerRequest = null;
+ // if (request instanceof Request) {
+ // innerRequest = request;
+ // } else {
+ // try {
+ // innerRequest = new Request(request);
+ // } catch (error) {
+ // throw Promise.reject(error);
+ // }
+ // }
+ // }
+
+ // async delete(request, options) {}
+ // deno-lint-ignore require-await
+ async keys() {
+ return Promise.resolve(Array.from(this.#storage.keys()));
+ }
+ }
+
+ window.__bootstrap.caches = {
+ CacheStorage,
};
})(this);
diff --git a/ext/cache/lib.deno_cache.d.ts b/ext/cache/lib.deno_cache.d.ts
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs
index bd1aacffff..68fc922550 100644
--- a/ext/cache/lib.rs
+++ b/ext/cache/lib.rs
@@ -14,5 +14,5 @@ pub fn init() -> Extension {
}
pub fn get_declaration() -> PathBuf {
- PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_console.d.ts")
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_cache.d.ts")
}
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index c123a912d6..c7c8774afa 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -23,6 +23,7 @@ path = "examples/hello_runtime.rs"
[build-dependencies]
deno_broadcast_channel = { version = "0.56.0", path = "../ext/broadcast_channel" }
+deno_cache = { version = "0.1.0", path = "../ext/cache" }
deno_console = { version = "0.62.0", path = "../ext/console" }
deno_core = { version = "0.144.0", path = "../core" }
deno_crypto = { version = "0.76.0", path = "../ext/crypto" }
@@ -46,6 +47,7 @@ winapi = "0.3.9"
[dependencies]
deno_broadcast_channel = { version = "0.56.0", path = "../ext/broadcast_channel" }
+deno_cache = { version = "0.1.0", path = "../ext/cache" }
deno_console = { version = "0.62.0", path = "../ext/console" }
deno_core = { version = "0.144.0", path = "../core" }
deno_crypto = { version = "0.76.0", path = "../ext/crypto" }
diff --git a/runtime/build.rs b/runtime/build.rs
index eea7a3602c..a15b2ec676 100644
--- a/runtime/build.rs
+++ b/runtime/build.rs
@@ -142,6 +142,7 @@ mod not_docs {
fn create_runtime_snapshot(snapshot_path: &Path, files: Vec) {
let extensions: Vec = vec![
deno_webidl::init(),
+ deno_cache::init(),
deno_console::init(),
deno_url::init(),
deno_tls::init(),
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index 3421528d20..b6d5f70914 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -49,6 +49,7 @@ delete Intl.v8BreakIterator;
const encoding = window.__bootstrap.encoding;
const colors = window.__bootstrap.colors;
const Console = window.__bootstrap.console.Console;
+ const CacheStorage = window.__bootstrap.caches.CacheStorage;
const inspectArgs = window.__bootstrap.console.inspectArgs;
const quoteString = window.__bootstrap.console.quoteString;
const compression = window.__bootstrap.compression;
@@ -466,6 +467,7 @@ delete Intl.v8BreakIterator;
btoa: util.writable(base64.btoa),
clearInterval: util.writable(timers.clearInterval),
clearTimeout: util.writable(timers.clearTimeout),
+ caches: util.nonEnumerable(new CacheStorage()),
console: util.nonEnumerable(
new Console((msg, level) => core.print(msg, level > 1)),
),
diff --git a/runtime/lib.rs b/runtime/lib.rs
index 543d3a0a21..50b1063ba6 100644
--- a/runtime/lib.rs
+++ b/runtime/lib.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
pub use deno_broadcast_channel;
+pub use deno_cache;
pub use deno_console;
pub use deno_core;
pub use deno_crypto;
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index 83ba380a6f..5f6c16a917 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -374,6 +374,7 @@ impl WebWorker {
let mut extensions: Vec = vec![
// Web APIs
deno_webidl::init(),
+ deno_cache::init(),
deno_console::init(),
deno_url::init(),
deno_web::init::(
diff --git a/runtime/worker.rs b/runtime/worker.rs
index 5100f42da1..770049f473 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -117,6 +117,7 @@ impl MainWorker {
let mut extensions: Vec = vec![
// Web APIs
deno_webidl::init(),
+ deno_cache::init(),
deno_console::init(),
deno_url::init(),
deno_web::init::(