@banou/ponyfill 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,10 +58,18 @@ That is not hypothetical. It is why four of ripple's storage eviction tests sat
58
58
  they filled the origin to provoke that condition, and 3.5 GB of padding left the free figure
59
59
  identical to the byte.
60
60
 
61
- This package does **not** invent a normalised quota, and does not add API for the difference either:
62
- on Chromium you really can write 10 more GiB, so the native answer is true, and there is no platform
63
- name for "which shape is this". It is written down here and in the source because the two are
64
- indistinguishable at rest, which is how the difference went unnoticed for months.
61
+ **The behaviour picked is Firefox's: a ceiling does not rise because you put something under it.**
62
+ `quota` is reported as the lowest the platform has stated for this origin, which needs no probe and
63
+ no user agent sniffing, and invents nothing: the platform really did say the origin could hold that
64
+ much. Two ordinary things are broken by the rising version, and both were seen in ripple:
65
+ `usage / quota` as a gauge never fills, and `quota - usage < floor` never fires, so nothing can
66
+ detect pressure at all.
67
+
68
+ The cost is deliberate and in the safe direction. On Chromium, once bytes are written the reported
69
+ headroom is smaller than what could really be written, so a caller reclaims cache slightly early.
70
+ Cache is the thing that can be fetched again; a caller that never reclaims because it never sees
71
+ pressure is the failure this replaces. The ceiling still follows the platform DOWNWARD, and is never
72
+ reported below the bytes already held, so `quota - usage` reaches zero and never goes negative.
65
73
 
66
74
  ## Adding to it
67
75
 
package/build/storage.cjs CHANGED
@@ -66,6 +66,40 @@ var reconcile = (estimate, walked) => {
66
66
  }
67
67
  return Math.max(reported, walked);
68
68
  };
69
+ /**
70
+ * The narrowest quota this origin has reported, which is the one that gets reported back.
71
+ *
72
+ * THE DIVERGENCE, AND THE PICK. `quota - usage` already means the same on both engines: bytes you
73
+ * can still write. What diverges is `quota` as a TOTAL, and Chromium never states one. It states
74
+ * `usage + headroom`, recomputed on every read, so the number grows as you fill the origin: measured
75
+ * 10.737 GB rising to 12.353 GB across 1.615 GB written. Firefox states a real total and holds it.
76
+ *
77
+ * Two things a caller does with `quota` are broken by the growing version and neither is exotic:
78
+ *
79
+ * - `usage / quota` as a gauge never fills, because the denominator runs away from the numerator.
80
+ * Ripple showed "2 MB / 10.74 GB" over a library holding 1.78 GB for exactly this reason.
81
+ * - `quota - usage < floor` never fires, so nothing can ever detect pressure. That is what left four
82
+ * of ripple's eviction tests failing for months against a condition that could not occur.
83
+ *
84
+ * So the behaviour picked here is FIREFOX'S: a ceiling, and a ceiling does not rise because you put
85
+ * something under it. It is implemented as the lowest quota seen for this origin, which needs no
86
+ * probe and no user agent sniffing, and it is TRUE in the strong sense: the platform really did say
87
+ * the origin could hold this much, and nothing here invents a number the platform never stated.
88
+ *
89
+ * The cost is deliberate and is in the safe direction. On Chromium, once some bytes are written, the
90
+ * reported headroom is smaller than what could really be written, so a caller reclaims cache
91
+ * slightly early. Cache is the thing that can be fetched again; a caller that never reclaims because
92
+ * it never sees pressure is the failure this replaces.
93
+ *
94
+ * In memory, and per page. Persisting it would mean owning storage to describe storage, and a reload
95
+ * re-anchors on a figure the platform stated at that moment, which is the same guarantee.
96
+ */
97
+ var narrowest;
98
+ var ceiling = (reported, usage) => {
99
+ if (reported === void 0) return void 0;
100
+ narrowest = narrowest === void 0 ? reported : Math.min(narrowest, reported);
101
+ return Math.max(narrowest, usage ?? 0);
102
+ };
69
103
  var storage = {
70
104
  /**
71
105
  * Same name and same shape as the platform's, with `usage` MEASURED rather than reported.
@@ -78,10 +112,11 @@ var storage = {
78
112
  const native = globalThis.navigator?.storage;
79
113
  if (!native?.estimate) return {};
80
114
  const estimate = await native.estimate();
81
- const walked = native.getDirectory ? await native.getDirectory().then((directory) => walkBytes(directory)).catch(() => null) : null;
115
+ const usage = reconcile(estimate, native.getDirectory ? await native.getDirectory().then((directory) => walkBytes(directory)).catch(() => null) : null);
82
116
  return {
83
117
  ...estimate,
84
- usage: reconcile(estimate, walked)
118
+ usage,
119
+ quota: ceiling(estimate.quota, usage)
85
120
  };
86
121
  },
87
122
  persist: () => globalThis.navigator?.storage?.persist?.() ?? Promise.resolve(false),
package/build/storage.js CHANGED
@@ -65,6 +65,40 @@ var reconcile = (estimate, walked) => {
65
65
  }
66
66
  return Math.max(reported, walked);
67
67
  };
68
+ /**
69
+ * The narrowest quota this origin has reported, which is the one that gets reported back.
70
+ *
71
+ * THE DIVERGENCE, AND THE PICK. `quota - usage` already means the same on both engines: bytes you
72
+ * can still write. What diverges is `quota` as a TOTAL, and Chromium never states one. It states
73
+ * `usage + headroom`, recomputed on every read, so the number grows as you fill the origin: measured
74
+ * 10.737 GB rising to 12.353 GB across 1.615 GB written. Firefox states a real total and holds it.
75
+ *
76
+ * Two things a caller does with `quota` are broken by the growing version and neither is exotic:
77
+ *
78
+ * - `usage / quota` as a gauge never fills, because the denominator runs away from the numerator.
79
+ * Ripple showed "2 MB / 10.74 GB" over a library holding 1.78 GB for exactly this reason.
80
+ * - `quota - usage < floor` never fires, so nothing can ever detect pressure. That is what left four
81
+ * of ripple's eviction tests failing for months against a condition that could not occur.
82
+ *
83
+ * So the behaviour picked here is FIREFOX'S: a ceiling, and a ceiling does not rise because you put
84
+ * something under it. It is implemented as the lowest quota seen for this origin, which needs no
85
+ * probe and no user agent sniffing, and it is TRUE in the strong sense: the platform really did say
86
+ * the origin could hold this much, and nothing here invents a number the platform never stated.
87
+ *
88
+ * The cost is deliberate and is in the safe direction. On Chromium, once some bytes are written, the
89
+ * reported headroom is smaller than what could really be written, so a caller reclaims cache
90
+ * slightly early. Cache is the thing that can be fetched again; a caller that never reclaims because
91
+ * it never sees pressure is the failure this replaces.
92
+ *
93
+ * In memory, and per page. Persisting it would mean owning storage to describe storage, and a reload
94
+ * re-anchors on a figure the platform stated at that moment, which is the same guarantee.
95
+ */
96
+ var narrowest;
97
+ var ceiling = (reported, usage) => {
98
+ if (reported === void 0) return void 0;
99
+ narrowest = narrowest === void 0 ? reported : Math.min(narrowest, reported);
100
+ return Math.max(narrowest, usage ?? 0);
101
+ };
68
102
  var storage = {
69
103
  /**
70
104
  * Same name and same shape as the platform's, with `usage` MEASURED rather than reported.
@@ -77,10 +111,11 @@ var storage = {
77
111
  const native = globalThis.navigator?.storage;
78
112
  if (!native?.estimate) return {};
79
113
  const estimate = await native.estimate();
80
- const walked = native.getDirectory ? await native.getDirectory().then((directory) => walkBytes(directory)).catch(() => null) : null;
114
+ const usage = reconcile(estimate, native.getDirectory ? await native.getDirectory().then((directory) => walkBytes(directory)).catch(() => null) : null);
81
115
  return {
82
116
  ...estimate,
83
- usage: reconcile(estimate, walked)
117
+ usage,
118
+ quota: ceiling(estimate.quota, usage)
84
119
  };
85
120
  },
86
121
  persist: () => globalThis.navigator?.storage?.persist?.() ?? Promise.resolve(false),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@banou/ponyfill",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "main": "build/index.cjs",
6
6
  "module": "build/index.js",