{"_id":"@banou/ponyfill","_rev":"7-ec855dc02d4fa26cb4cdcfba2a934f85","name":"@banou/ponyfill","dist-tags":{"latest":"0.0.7"},"versions":{"0.0.1":{"name":"@banou/ponyfill","version":"0.0.1","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"_id":"@banou/ponyfill@0.0.1","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"32f367ff43106fa82c4782ab2691c7b4085c0a72","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.1.tgz","fileCount":8,"integrity":"sha512-nsR6UBIh3JTYRmpH4fdJ94wQ9SNTHTTOo/7Q0fjKRIp0rq8zsm7Rq8QSRxqHNc0GGVtWDWHcDknjwZPuB6Lofg==","signatures":[{"sig":"MEUCIFknFMJstHtF+QKZ3kQCuilunvnCZSlDQJHpHvK3X82AAiEAsCTdCTsqKx/4TbyHkA06eRJPRUuVqmlxomwFHOg6Xws=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30367},"main":"build/index.cjs","type":"module","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"}},"gitHead":"9cb846ec0231e88a9901eae1150e80957c7a718a","scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"banou26","email":"me@banou.dev"},"repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"11.19.0","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"26.8.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.1_1788412463710_0.15377143785657355","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@banou/ponyfill","version":"0.0.2","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"license":"MIT","_id":"@banou/ponyfill@0.0.2","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"b8c636c24f1084465e66d465d2a9f9c4dc938b11","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.2.tgz","fileCount":9,"integrity":"sha512-BHomr5QvsubyIibfRK+Syqndyybp+IwW80uM0l4+J5rrY+PXNPluyTqsLo5ZzfsytHUauDQN58FYP9cWOAMpBQ==","signatures":[{"sig":"MEQCIBoNAlEBxKFguSarUQ5eKtKFfCnhTsD05FOFL/wybvvCAiBjHrgkiD9lxL8+iJfY/kmBFe58Su0OWp9OayQf+rbTMA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":31464},"main":"build/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.2.tgz","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"}},"scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.2.tgz","_integrity":"sha512-BHomr5QvsubyIibfRK+Syqndyybp+IwW80uM0l4+J5rrY+PXNPluyTqsLo5ZzfsytHUauDQN58FYP9cWOAMpBQ==","repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"12.0.2","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.2_1788419105762_0.016652511161871608","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@banou/ponyfill","version":"0.0.3","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"license":"MIT","_id":"@banou/ponyfill@0.0.3","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"fe017b14d811afd686026b0f219f838d852d9266","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.3.tgz","fileCount":9,"integrity":"sha512-Kmqnts14/PmmsZF9jk03dghoCZQ2pQae3TubDHtRFKQBiN07vf5VZ909RTX06I80d35CeqoZ3UCnelaCM8ebJA==","signatures":[{"sig":"MEQCIBr7Qqjd6pwkz9yLViVbvv28oHNmrzz+BE93Peb+jL56AiBxT4w4FoevJS9y0n9l/pje8xruTusN0eN2QjaxziZQ5g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":34377},"main":"build/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.3.tgz","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"}},"scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.3.tgz","_integrity":"sha512-Kmqnts14/PmmsZF9jk03dghoCZQ2pQae3TubDHtRFKQBiN07vf5VZ909RTX06I80d35CeqoZ3UCnelaCM8ebJA==","repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"12.0.2","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.3_1788419202843_0.812961569115622","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@banou/ponyfill","version":"0.0.4","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"license":"MIT","_id":"@banou/ponyfill@0.0.4","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"d019ca34f08309db523916305f019bf78445cb4c","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.4.tgz","fileCount":9,"integrity":"sha512-U88eGBcmP0JyND1ZwMUNKsCJ3QnkBGAfg2R+Z15DKY/Qs6AvKdTKFhURZU4bKfuoO9X7VLBIEOZ5h1e0c69tEw==","signatures":[{"sig":"MEYCIQDo85voyX9AC9eu4irOC2TPVmZs1ZzMi08OcXNPoOYQuwIhAKfaoVbmc0djPZYhj+UdwVBQnkp8MMAV4DpRITcneOUE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20322},"main":"build/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.4.tgz","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"}},"scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.4.tgz","_integrity":"sha512-U88eGBcmP0JyND1ZwMUNKsCJ3QnkBGAfg2R+Z15DKY/Qs6AvKdTKFhURZU4bKfuoO9X7VLBIEOZ5h1e0c69tEw==","repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"12.0.2","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.4_1788419867939_0.39158556332951133","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@banou/ponyfill","version":"0.0.5","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"license":"MIT","_id":"@banou/ponyfill@0.0.5","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"e317951089efe46bd5032aba75f56dc231a0ea12","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.5.tgz","fileCount":9,"integrity":"sha512-wcbJc3nHWySC923v0Rzl+M586CbgFmL5DpCFHp+lhf7W3qZp6WH4xUZps4/ZEENPk9x+jpqSeZHno+lb1KNtbw==","signatures":[{"sig":"MEYCIQCf0C4mDwLe7G3wV3GNsLZp+UjrqHwdH6T01qQWMXPLAQIhALnlPfJzb3yvrm9IMKYrJoGG3gBnfVwAJsU7DjlB1SJW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":25285},"main":"build/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.5.tgz","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"}},"scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.5.tgz","_integrity":"sha512-wcbJc3nHWySC923v0Rzl+M586CbgFmL5DpCFHp+lhf7W3qZp6WH4xUZps4/ZEENPk9x+jpqSeZHno+lb1KNtbw==","repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"12.0.2","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.5_1788420457229_0.6998793421405953","host":"s3://npm-registry-packages-npm-production"}},"0.0.6":{"name":"@banou/ponyfill","version":"0.0.6","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"license":"MIT","_id":"@banou/ponyfill@0.0.6","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"homepage":"https://github.com/Banou26/ponyfill#readme","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"dist":{"shasum":"b944b0f1ce3f9906bd6d0accf15a6aa0f45fb48a","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.6.tgz","fileCount":15,"integrity":"sha512-0KfIfkf6PFk4QAzJZp3C3Nr05i5mqy9P3MQXzrHK3xEy5VL4cDLGkP2AEK9BByrUtjPyPIKVgqUws6ZJh1xS7g==","signatures":[{"sig":"MEYCIQCwWZv8P4wqeuQA9vpvSkzjp0A1FYOHMZzh0oCY9IE27wIhALZGwq0ORGM2J/xPenoxE+Py/9RdPBxiap8SLpVWBsaf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":40742},"main":"build/index.cjs","type":"module","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.6.tgz","types":"build/index.d.ts","module":"build/index.js","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"},"./file-system":{"types":"./build/file-system.d.ts","import":"./build/file-system.js","require":"./build/file-system.cjs"},"./permissions":{"types":"./build/permissions.d.ts","import":"./build/permissions.js","require":"./build/permissions.cjs"}},"scripts":{"dev":"vp build --mode development --watch","test":"vp test run","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.6.tgz","_integrity":"sha512-0KfIfkf6PFk4QAzJZp3C3Nr05i5mqy9P3MQXzrHK3xEy5VL4cDLGkP2AEK9BByrUtjPyPIKVgqUws6ZJh1xS7g==","repository":{"url":"git+https://github.com/Banou26/ponyfill.git","type":"git"},"_npmVersion":"12.0.2","description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vitest":"4.1.11","vite-plus":"0.3.0","typescript":"^5.9.2","@types/node":"^25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/ponyfill_0.0.6_1788430285876_0.12366798079265195","host":"s3://npm-registry-packages-npm-production"}},"0.0.7":{"name":"@banou/ponyfill","version":"0.0.7","type":"module","main":"build/index.cjs","module":"build/index.js","types":"build/index.d.ts","exports":{".":{"types":"./build/index.d.ts","import":"./build/index.js","require":"./build/index.cjs"},"./storage":{"types":"./build/storage.d.ts","import":"./build/storage.js","require":"./build/storage.cjs"},"./permissions":{"types":"./build/permissions.d.ts","import":"./build/permissions.js","require":"./build/permissions.cjs"},"./file-system":{"types":"./build/file-system.d.ts","import":"./build/file-system.js","require":"./build/file-system.cjs"}},"scripts":{"dev":"vp build --mode development --watch","build":"vp build && tsc -p tsconfig.json","prepack":"npm run build","typecheck":"tsc --noEmit","test":"vp test run"},"description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","license":"MIT","devDependencies":{"@types/node":"^25.9.5","typescript":"^5.9.2","vite":"npm:@voidzero-dev/vite-plus-core@0.3.0","vite-plus":"0.3.0","vitest":"4.1.11"},"repository":{"type":"git","url":"git+https://github.com/Banou26/ponyfill.git"},"publishConfig":{"access":"public"},"keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"sideEffects":false,"_id":"@banou/ponyfill@0.0.7","bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"homepage":"https://github.com/Banou26/ponyfill#readme","_integrity":"sha512-JejUrUTKYNu6qBwhlT10ZFcIDPviQttB1cvzMsdyAm7PYYhxlBVREaIdok36NVizmR9UEr5OIMVzP7qTl+jTbw==","_resolved":"/home/runner/work/_temp/banou-ponyfill-0.0.7.tgz","_from":"file:/home/runner/work/_temp/banou-ponyfill-0.0.7.tgz","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-JejUrUTKYNu6qBwhlT10ZFcIDPviQttB1cvzMsdyAm7PYYhxlBVREaIdok36NVizmR9UEr5OIMVzP7qTl+jTbw==","shasum":"669be025108f4d7ce34ebd563cca74018fe6221f","tarball":"https://registry.npmjs.org/@banou/ponyfill/-/ponyfill-0.0.7.tgz","fileCount":15,"unpackedSize":74250,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@banou%2fponyfill@0.0.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIF8PdwH+mA2ewIbVREUel5PzL+bx+rMgnDkdZ8xtClqjAiEAyDlCseM3aht0UTdZKIOKPODF6EVLK+zJHGH5eDIifBE="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9066cb0e-7676-4b27-9cf8-56a3a5bd2d77"}},"directories":{},"maintainers":[{"name":"banou26","email":"me@banou.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ponyfill_0.0.7_1788432173827_0.34642491223375926"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T05:14:23.507Z","modified":"2026-09-03T10:42:55.769Z","0.0.1":"2026-09-03T05:14:23.831Z","0.0.2":"2026-09-03T07:05:05.899Z","0.0.3":"2026-09-03T07:06:42.989Z","0.0.4":"2026-09-03T07:17:48.078Z","0.0.5":"2026-09-03T07:27:37.358Z","0.0.6":"2026-09-03T10:11:26.027Z","0.0.7":"2026-09-03T10:42:53.959Z"},"bugs":{"url":"https://github.com/Banou26/ponyfill/issues"},"license":"MIT","homepage":"https://github.com/Banou26/ponyfill#readme","keywords":["ponyfill","browser","storage","opfs","quota","compatibility"],"repository":{"type":"git","url":"git+https://github.com/Banou26/ponyfill.git"},"description":"Ponyfills for the places browsers disagree, with the measurement behind each one. Imports only, never a global.","maintainers":[{"name":"banou26","email":"me@banou.dev"}],"readme":"# @banou/ponyfill\n\nPonyfills for the places browsers disagree, with the measurement behind each one.\n\n```ts\nimport { storage } from '@banou/ponyfill'\n\nconst { usage, quota } = await storage.estimate()\n```\n\n## Why this is a package and not a file in an app\n\n**It is a ponyfill, never a polyfill.** Nothing here writes to a global. You import the wrapped API\nand call the same method names the platform uses, so a call site reads the same as the native one and\n`grep` can still find every place that needed the workaround.\n\nPatching `navigator.storage` would change what every other script on the page sees, including code\nthat was correct against the real behaviour, and it would hide the difference at exactly the call\nsites that most need to show it.\n\n**Every workaround carries its measurement.** What was measured, on what, and when. A workaround with\nno measurement behind it is a guess that outlives the bug it was written for, and there is no way to\ntell the two apart later.\n\n## What is in it\n\n### `storage`\n\nThe same method names as `navigator.storage`, fixing two things.\n\n**`usage` can be six orders of magnitude short.** Measured on Chrome 151: an origin holding a\nverified 1,783,407,077 bytes reported `usage: 1,813,502` with `usageDetails.fileSystem: 752`. 752\nbytes against 1.78 GB. Anything sizing a write from that decides everything fits, then fails with\n`QuotaExceededError` at the real limit. `storage.estimate()` walks the origin and reports the larger\nof the two, keeping the parts the browser counts correctly (IndexedDB, caches) rather than replacing\nthem.\n\n**`quota` means a different thing on each engine.** Measured 2026-09-03, one machine with 2.7 TiB\nfree, one origin, three 512 MiB sparse writes per engine, same page and same code:\n\n| engine | quota at rest | after 1.615 GB written | `quota - usage` |\n| --- | --- | --- | --- |\n| Chromium 152 | 10,737,491,968 | rose by exactly what was written | 10,737,418,240 every time, moved **0 bytes** |\n| Firefox | 10,737,418,240 | unmoved | fell 536,870,912 per write |\n\nBoth cap at 10 GiB; they cap **different quantities**. Chromium's quota is a floating ceiling\n(`usage + headroom`), so the headroom is a constant and can never shrink. Firefox's is a fixed\nceiling, so writing consumes it.\n\nNeither is a bug: the Storage Standard calls quota \"a conservative estimate\" and never says how to\ncompute it. But it means this very common line is dead on one engine and live on the other:\n\n```ts\nif (quota - usage < someFloor) { /* ... */ }   // can never be true on Chromium\n```\n\nThat is not hypothetical. It is why four of ripple's storage eviction tests sat failing for months:\nthey filled the origin to provoke that condition, and 3.5 GB of padding left the free figure\nidentical to the byte.\n\n**The behaviour picked is Firefox's: a ceiling does not rise because you put something under it.**\n`quota` is reported as the lowest the platform has stated for this origin, which needs no probe and\nno user agent sniffing, and invents nothing: the platform really did say the origin could hold that\nmuch. Two ordinary things are broken by the rising version, and both were seen in ripple:\n`usage / quota` as a gauge never fills, and `quota - usage < floor` never fires, so nothing can\ndetect pressure at all.\n\nThe cost is deliberate and in the safe direction. On Chromium, once bytes are written the reported\nheadroom is smaller than what could really be written, so a caller reclaims cache slightly early.\nCache is the thing that can be fetched again; a caller that never reclaims because it never sees\npressure is the failure this replaces. The ceiling still follows the platform DOWNWARD, and is never\nreported below the bytes already held, so `quota - usage` reaches zero and never goes negative.\n\nThe ceiling is held per realm and in memory, and it **lets go when the origin's persistence changes**.\nA granted `persist()` moved the reported quota from 12 GB to 3.97 TB on Firefox (measured\n2026-09-01), so the figure learned before that is worse than useless afterwards. The release is keyed\non the state rather than on the call, because `persist()` only exists on the main thread: a worker\nthat latched the old ceiling and could never call it would go on deciding what to delete from a\nnumber that no longer exists.\n\n### `permissions`\n\n`query()` has four ways of behaving and only one of them is an answer: the engine may have no\nPermissions API, may reject a name it does not implement, may **throw synchronously** for one (which\na `.catch` on the returned promise never sees), or may answer a real state.\n\nAll three non-answers collapse to `'prompt'`. Not `'denied'`, because an engine that cannot be asked\nhas not refused anything, and treating silence as refusal costs the person a control that might have\nworked.\n\n### `showOpenFilePicker`, `showDirectoryPicker`, `showSaveFilePicker`\n\nMeasured 2026-09-03 across Chromium 149, Firefox 151 and WebKit 26:\n\n| | Chromium | Firefox | WebKit |\n| --- | --- | --- | --- |\n| the three pickers | present | **absent** | **absent** |\n| `FileSystemHandle` and friends as globals | present | present | **absent** |\n| `<input>.webkitdirectory` and its `cancel` event | yes | yes | yes |\n| an object holding its methods as own properties, cloned | `DataCloneError` | `DataCloneError` | `DataCloneError` |\n| the same object with its methods on a prototype | clones, silently | clones, silently | clones, silently |\n| `<input webkitdirectory>` file order, same tree | `a`, `sub/b` | `sub/b`, `a` | `sub/b`, `a` |\n\n**Reading always works, and always answers handles.** Where the platform has a picker it is used and\nits handles come back untouched. Where it does not, an `<input type=\"file\">` is opened and what comes\nback is wrapped in the same shape, so a caller has one call and one return type instead of a\n`FileSystemFileHandle | File` union threaded through everything downstream.\n\n**Writing is refused rather than faked.** `showSaveFilePicker` has no fallback, `showDirectoryPicker`\nrefuses `mode: 'readwrite'` where there is no native picker, and a wrapped handle's\n`createWritable()` throws. There is no way to write to a chosen location without the platform's\npicker.\n\n**Refusals happen before the gesture is spent**, and are named `NotAllowedError` so a caller can tell\nthem from the `AbortError` the platform throws when the person cancels. A caller has one transient\nactivation, and a picker that rejects at call time has already spent part of it.\n\n**A wrapped handle cannot be persisted, and says so loudly.** This is the one difference that cannot\nbe absorbed, so what is picked is how it fails. A native handle survives `structuredClone` and comes\nback out of IndexedDB still usable; a wrapper around a `File` cannot, because a snapshot is not an\nentry on a disk. Left as an ordinary object it would clone *successfully* and come back with its\nprototype gone and every method with it, failing after a reload with nothing pointing at the pick. So\nevery wrapped handle carries its methods as own properties, which makes the store throw\n`DataCloneError` at the moment of the mistake: one `.catch` where it matters instead of a capability\nprobe at every call site.\n\n## Adding to it\n\nIf you hit something that behaves differently between engines, or differently from its own\nspecification, it goes here rather than into the app that found it. State what you measured, on what,\nand when, and pin it with a test that fails when the workaround is removed.\n","readmeFilename":"README.md"}