feat: experimental Cross-Origin Storage cache backend#1549
feat: experimental Cross-Origin Storage cache backend#1549nico-martin wants to merge 5 commits intomainfrom
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
|
I'm very excited about this PR! Thanks a lot 🤗! Here's some feedback and general thoughts:
|
|
Thank you very much for your answers!
I think you're mainly concerned with the
Not sure if I get that right. So if I want to calculate the hash from the blob, I still need to download the whole file. So I would still have to download the whole file before I can evaluate if it's already stored in the COS. And then when I store the hash and the URL, then I would still store that in let's say the local storage, which means the URL->Hash Map is stored per origin so each origin first has to download the file before it knows if it can use the COS. Or have I misunderstood something? |
Just to be sure I understand how you envision this at the current stage: developers who would opt in would not be expected to release apps in the wild with this flag set, as people without the extension would effectively not have a cached experience? If so, I'd hope to convince you to rethink this as progressive enhancement from the start. This shouldn't be thought of as its own Transformers.js caching backend, but as a thing to try first before falling back to Cache API before falling back to network. This way developers can see the immediate benefit more clearly. I fully reckon that it's early stages, but I'd argue installing the extension is effectively the current way to opt in. What do you think?
This is what I meant, yes, mostly to make it possible to keep all resources together in the same storage and to be future proof. As I wrote, the eventual solution would be for all resources to have their hash known. |
As it was integrated until now, yes. But I have adapted it. CrossOriginStorage now has a fallback per request if the hash is not found. In addition, the opt-in is now such that a dev can activate it via
But then I always have to load it twice initially. Once for the origin so I can calculate the hash, then again from the COS. |
❤️ Really appreciate your receptiveness to my feedback! I think this is the way to go, as it allows developers to roll this out with no side effects to regular users, and power users with the extension installed will get the cache benefit!
Can you maybe async function fetchAndProcess(url) {
const response = await fetch(url);
// stream1 goes to the caller, stream2 goes to background tasks
const [stream1, stream2] = response.body.tee();
processStreamInBackground(stream2);
// Convert the first stream into a Blob for the caller
return new Response(stream1, {
headers: response.headers
}).blob();
}
async function processStreamInBackground(stream) {
const blob = await new Response(stream).blob();
const hash = await calculateSHA256(blob);
await storeInCrossOriginStorage(blob, hash);
} |
TIL 🤯 |
Ok, thats really cool. I did not know that. So it still needs to download files where we have no hash per origin, but
I will try that :) |
Which is a super important point, and what I love about making this progressively enhanced. We're never making it worse than it is at the moment, only better. I would like to add one (arguably tiny lever, but still) point:
Awesome, thanks! It's one of those APIs I rarely use (and only got to know because I wrote an article about it, but when it comes in handy, it's fantastic. |
Adds opt-in support for the Cross-Origin Storage API as a cache backend, allowing model weights to be shared across origins so users only download a given model once regardless of which site requests it.
Changes
CrossOriginStorageCache.js: newCrossOriginStorageclass implementingCacheInterface. Resolves the SHA-256 hash of a Hugging Face resource via its raw Git LFS pointer file and uses that hash as the key fornavigator.crossOriginStorage. Hash lookups use a network-first strategy with a Cache API fallback (experimental_transformers-hash-cache) so lookups continue to work when the user is offline.env.js: addsexperimental_useCrossOriginStorage(defaultfalse) toTransformersEnvironment. Theexperimental_prefix is documented to signal that the underlying browser API is not yet standardised and may change without a major version bump.cache.js: wiresCrossOriginStorageintogetCache(), checked afteruseCustomCacheand beforeuseBrowserCache.Usage
Known limitation: only LFS-tracked files are cached via COS
Cross-origin storage keys files by SHA-256 hash. The implementation resolves that hash by fetching the raw Git LFS pointer file (e.g.
/raw/main/onnx/model.onnx) and extracting theoid sha256:field. This only works for files stored in Git LFS (typically the ONNX model weights). Smaller files such asconfig.json,tokenizer.json, andtokenizer_config.jsonare stored directly in git and have no LFS pointer, so no hash can be resolved aand those files are not cached at all. They will be re-downloaded on every load.Open question: should
CrossOriginStoragefall back to the browser Cache API for files where no hash can be resolved (non-LFS files, or any other case where_getFileHashreturnsnull)? This would give non-LFS files the same caching semantics they have today, while LFS files get the cross-origin sharing benefit. The trade-off is thatCrossOriginStoragewould then silently mix two storage backends, which may be surprising. @tomayac Feedback welcome.