@monochromatic-dev/module-logger 0.1.0
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/CHANGELOG.md +11 -0
- package/LICENSES/GPL-3.0-or-later.txt +674 -0
- package/LICENSES/LGPL-3.0-or-later.txt +165 -0
- package/README.md +404 -0
- package/dist/final/neutral/index.d.mts +673 -0
- package/dist/final/neutral/index.mjs +3 -0
- package/dist/final/neutral/rolldown-runtime-5duEfhBv.mjs +1 -0
- package/dist/final/node/index.d.mts +673 -0
- package/dist/final/node/index.mjs +3 -0
- package/dist/final/node/rolldown-runtime-5duEfhBv.mjs +1 -0
- package/package.json +43 -0
- package/src/create-logger.ts +494 -0
- package/src/create-logger.unit.test.ts +752 -0
- package/src/error-format.ts +43 -0
- package/src/index.ts +35 -0
- package/src/logger.ts +67 -0
- package/src/logger.unit.test.ts +190 -0
- package/src/sink/console-control-chars.ts +140 -0
- package/src/sink/console-control-chars.unit.test.ts +206 -0
- package/src/sink/console.ts +531 -0
- package/src/sink/console.unit.test.ts +542 -0
- package/src/sink/file.ts +297 -0
- package/src/sink/file.unit.test.ts +202 -0
- package/src/sink/index.ts +11 -0
- package/src/sink/indexed-db-util.ts +96 -0
- package/src/sink/indexed-db.browser.test.ts +184 -0
- package/src/sink/indexed-db.ts +324 -0
- package/src/sink/indexed-db.unit.test.ts +80 -0
- package/src/sink/local-storage-key.ts +176 -0
- package/src/sink/local-storage-key.unit.test.ts +106 -0
- package/src/sink/local-storage-quota.ts +60 -0
- package/src/sink/local-storage-quota.unit.test.ts +98 -0
- package/src/sink/local-storage-store.ts +368 -0
- package/src/sink/local-storage-store.unit.test.ts +329 -0
- package/src/sink/local-storage.browser.test.ts +125 -0
- package/src/sink/local-storage.ts +182 -0
- package/src/sink/local-storage.unit.test.ts +218 -0
- package/src/sink/noop.ts +46 -0
- package/src/sink/noop.unit.test.ts +47 -0
- package/src/sink/opfs.browser.test.ts +84 -0
- package/src/sink/opfs.ts +212 -0
- package/src/sink/opfs.unit.test.ts +81 -0
- package/src/sink/record-buffer.ts +230 -0
- package/src/sink/record-buffer.unit.test.ts +288 -0
- package/src/sink/session-storage-quota.ts +57 -0
- package/src/sink/session-storage-quota.unit.test.ts +98 -0
- package/src/sink/session-storage-store.ts +178 -0
- package/src/sink/session-storage.browser.test.ts +137 -0
- package/src/sink/session-storage.ts +128 -0
- package/src/sink/session-storage.unit.test.ts +527 -0
- package/src/sink/web-storage-quota-error.ts +43 -0
- package/src/sink/web-storage-quota-error.unit.test.ts +55 -0
- package/src/sink/web-storage-runtime.ts +49 -0
- package/src/startup.unit.test.ts +232 -0
- package/src/tagged.ts +74 -0
- package/src/tagged.unit.test.ts +211 -0
- package/src/types.ts +78 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key naming for the localStorage persistence engine.
|
|
3
|
+
*
|
|
4
|
+
* localStorage is shared by every tab of the origin and survives restarts, so
|
|
5
|
+
* unlike the per-tab sessionStorage keys (`monochromatic.log.{n}`), these keys
|
|
6
|
+
* carry a run identity: `monochromatic.log.{stamp}.{nonce}.{index}`. The stamp
|
|
7
|
+
* orders runs oldest-first for cross-run eviction, the nonce keeps two tabs
|
|
8
|
+
* started in the same millisecond from colliding, and the index orders batches
|
|
9
|
+
* within a run.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Prefix namespacing this logger's localStorage entries away from host
|
|
16
|
+
* application keys.
|
|
17
|
+
*/
|
|
18
|
+
export const LOCAL_STORAGE_KEY_PREFIX = 'monochromatic.log';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Identity segments after the prefix: stamp, nonce, and index.
|
|
22
|
+
*/
|
|
23
|
+
const RUN_KEY_SEGMENTS = 3;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parsed identity of one owned localStorage entry, used to order eviction
|
|
27
|
+
* across runs.
|
|
28
|
+
*/
|
|
29
|
+
export type ParsedLogKey = {
|
|
30
|
+
readonly key: string;
|
|
31
|
+
readonly stamp: number;
|
|
32
|
+
readonly nonce: string;
|
|
33
|
+
readonly index: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reports whether `text` is one or more ASCII digits, so key parsing accepts
|
|
38
|
+
* only counter-shaped segments and never claims a host application's key. A
|
|
39
|
+
* linear scan instead of a regex: the rule is a plain character-range check.
|
|
40
|
+
*
|
|
41
|
+
* @param text - Candidate key segment.
|
|
42
|
+
*
|
|
43
|
+
* @returns Whether every character is an ASCII digit and one exists.
|
|
44
|
+
*/
|
|
45
|
+
function isDigits(text: string,): boolean {
|
|
46
|
+
if (text.length === 0)
|
|
47
|
+
return false;
|
|
48
|
+
for (const character of text) {
|
|
49
|
+
if ((character < '0') || (character > '9'))
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Builds the namespaced localStorage key for one batch slot of one run.
|
|
57
|
+
*
|
|
58
|
+
* @param stamp - Run creation time ordering runs oldest-first.
|
|
59
|
+
*
|
|
60
|
+
* @param nonce - Same-millisecond disambiguator between concurrent tabs.
|
|
61
|
+
*
|
|
62
|
+
* @param index - Zero-based batch slot within the run.
|
|
63
|
+
*
|
|
64
|
+
* @returns Key such as `monochromatic.log.1753000000000.a1b2.3`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* buildLogKey({ stamp: 1753000000000, nonce: 'a1b2', index: 3 });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function buildLogKey(
|
|
72
|
+
{
|
|
73
|
+
stamp,
|
|
74
|
+
nonce,
|
|
75
|
+
index,
|
|
76
|
+
}: {
|
|
77
|
+
readonly stamp: number;
|
|
78
|
+
readonly nonce: string;
|
|
79
|
+
readonly index: number;
|
|
80
|
+
},
|
|
81
|
+
): string {
|
|
82
|
+
return `${LOCAL_STORAGE_KEY_PREFIX}.${stamp}.${nonce}.${index}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parses a localStorage key back into its run identity, or reports it foreign
|
|
87
|
+
* by leaving `parsed` absent. Parsing is strict (exact prefix, exactly the
|
|
88
|
+
* identity segment count, digit-shaped stamp and index, non-empty nonce)
|
|
89
|
+
* because eviction trusts this to never classify a host application's key, or
|
|
90
|
+
* the sessionStorage sink's flat `monochromatic.log.{n}` shape, as evictable.
|
|
91
|
+
*
|
|
92
|
+
* @param key - Candidate localStorage key.
|
|
93
|
+
*
|
|
94
|
+
* @returns Wrapper whose `parsed` property is present only for an owned key.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* parseLogKey('monochromatic.log.1753000000000.a1b2.3').parsed; // ParsedLogKey
|
|
99
|
+
* parseLogKey('monochromatic.log.5').parsed; // undefined: sessionStorage shape
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function parseLogKey(key: string,): { readonly parsed?: ParsedLogKey; } {
|
|
103
|
+
if (!key.startsWith(`${LOCAL_STORAGE_KEY_PREFIX}.`,))
|
|
104
|
+
return {};
|
|
105
|
+
/**
|
|
106
|
+
* Key remainder past the prefix and its trailing dot, holding the run
|
|
107
|
+
* identity segments.
|
|
108
|
+
*/
|
|
109
|
+
const rest = key.slice(LOCAL_STORAGE_KEY_PREFIX.length + 1,);
|
|
110
|
+
/**
|
|
111
|
+
* Dot-separated identity segments; exactly stamp, nonce, index for an owned
|
|
112
|
+
* key.
|
|
113
|
+
*/
|
|
114
|
+
const segments = rest.split('.',);
|
|
115
|
+
if (segments.length !== RUN_KEY_SEGMENTS)
|
|
116
|
+
return {};
|
|
117
|
+
/**
|
|
118
|
+
* Identity segments in declaration order; any missing or malformed one
|
|
119
|
+
* makes the key foreign.
|
|
120
|
+
*/
|
|
121
|
+
const [stampText, nonce, indexText,] = segments;
|
|
122
|
+
if (
|
|
123
|
+
(stampText === undefined)
|
|
124
|
+
|| (nonce === undefined)
|
|
125
|
+
|| (indexText === undefined)
|
|
126
|
+
)
|
|
127
|
+
return {};
|
|
128
|
+
if (!isDigits(stampText,))
|
|
129
|
+
return {};
|
|
130
|
+
if (nonce.length === 0)
|
|
131
|
+
return {};
|
|
132
|
+
if (!isDigits(indexText,))
|
|
133
|
+
return {};
|
|
134
|
+
return {
|
|
135
|
+
parsed: {
|
|
136
|
+
key,
|
|
137
|
+
stamp: Math.trunc(Number(stampText,),),
|
|
138
|
+
nonce,
|
|
139
|
+
index: Math.trunc(Number(indexText,),),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Orders parsed keys oldest-first for eviction: by run stamp, then by nonce
|
|
146
|
+
* (an arbitrary but stable tiebreak between same-millisecond runs), then by
|
|
147
|
+
* batch index within the run.
|
|
148
|
+
*
|
|
149
|
+
* @param first - Parsed key compared first.
|
|
150
|
+
*
|
|
151
|
+
* @param second - Parsed key compared second.
|
|
152
|
+
*
|
|
153
|
+
* @returns Negative when `first` is older, positive when newer, zero on ties.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* entries.toSorted(function byOldestFirst(first, second) {
|
|
158
|
+
* return compareLogKeys({ first, second });
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function compareLogKeys(
|
|
163
|
+
{
|
|
164
|
+
first,
|
|
165
|
+
second,
|
|
166
|
+
}: {
|
|
167
|
+
readonly first: ParsedLogKey;
|
|
168
|
+
readonly second: ParsedLogKey;
|
|
169
|
+
},
|
|
170
|
+
): number {
|
|
171
|
+
if (first.stamp !== second.stamp)
|
|
172
|
+
return first.stamp - second.stamp;
|
|
173
|
+
if (first.nonce !== second.nonce)
|
|
174
|
+
return (first.nonce < second.nonce) ? -1 : 1;
|
|
175
|
+
return first.index - second.index;
|
|
176
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
} from '@monochromatic-dev/module-test/ts';
|
|
6
|
+
import {
|
|
7
|
+
_buildLogKey as buildLogKey,
|
|
8
|
+
_compareLogKeys as compareLogKeys,
|
|
9
|
+
_parseLogKey as parseLogKey,
|
|
10
|
+
} from '@monochromatic-dev/module-logger';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Keys the strict parser must reject: host application keys, the
|
|
14
|
+
* sessionStorage sink's flat shape, and malformed run identities. Eviction
|
|
15
|
+
* safety rests on every one of these staying foreign.
|
|
16
|
+
*/
|
|
17
|
+
const FOREIGN_KEYS: readonly string[] = [
|
|
18
|
+
'other.key',
|
|
19
|
+
'monochromatic.log',
|
|
20
|
+
'monochromatic.log.5',
|
|
21
|
+
'monochromatic.log.10.ab',
|
|
22
|
+
'monochromatic.log.10.ab.3.4',
|
|
23
|
+
'monochromatic.log.x10.ab.3',
|
|
24
|
+
'monochromatic.log.10..3',
|
|
25
|
+
'monochromatic.log.10.ab.3x',
|
|
26
|
+
'monochromatic.log...',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
await describe({
|
|
30
|
+
name: parseLogKey.name,
|
|
31
|
+
children: [
|
|
32
|
+
it({
|
|
33
|
+
name: 'round-trips a built key back to its identity',
|
|
34
|
+
fn: async () => {
|
|
35
|
+
/**
|
|
36
|
+
* Identity pushed through build-then-parse; equality proves the pair inverse.
|
|
37
|
+
*/
|
|
38
|
+
const identity = {
|
|
39
|
+
stamp: 1_753_000_000_000,
|
|
40
|
+
nonce: 'ab12',
|
|
41
|
+
index: 7,
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Key the builder produced for the identity.
|
|
45
|
+
*/
|
|
46
|
+
const built = buildLogKey(identity,);
|
|
47
|
+
/**
|
|
48
|
+
* Identity parsed back out of the built key.
|
|
49
|
+
*/
|
|
50
|
+
const { parsed, } = parseLogKey(built,);
|
|
51
|
+
expect(parsed,)
|
|
52
|
+
.toEqual({
|
|
53
|
+
key: 'monochromatic.log.1753000000000.ab12.7',
|
|
54
|
+
...identity,
|
|
55
|
+
},);
|
|
56
|
+
},
|
|
57
|
+
},),
|
|
58
|
+
|
|
59
|
+
...FOREIGN_KEYS.map(function mapForeign(key,) {
|
|
60
|
+
return it({
|
|
61
|
+
name: `rejects foreign key ${key}`,
|
|
62
|
+
fn: async () => {
|
|
63
|
+
expect(parseLogKey(key,).parsed,)
|
|
64
|
+
.toBeUndefined();
|
|
65
|
+
},
|
|
66
|
+
},);
|
|
67
|
+
},),
|
|
68
|
+
|
|
69
|
+
it({
|
|
70
|
+
name: 'compareLogKeys orders by stamp, then nonce, then index',
|
|
71
|
+
fn: async () => {
|
|
72
|
+
/**
|
|
73
|
+
* Keys deliberately shuffled across all three ordering dimensions.
|
|
74
|
+
*/
|
|
75
|
+
const shuffled = [
|
|
76
|
+
'monochromatic.log.2000.aaaa.0',
|
|
77
|
+
'monochromatic.log.1000.bbbb.1',
|
|
78
|
+
'monochromatic.log.1000.aaaa.1',
|
|
79
|
+
'monochromatic.log.1000.aaaa.0',
|
|
80
|
+
]
|
|
81
|
+
.flatMap(function parseOne(key,) {
|
|
82
|
+
const { parsed, } = parseLogKey(key,);
|
|
83
|
+
return (parsed === undefined) ? [] : [parsed,];
|
|
84
|
+
},);
|
|
85
|
+
/**
|
|
86
|
+
* Oldest-first ordering the eviction queue relies on.
|
|
87
|
+
*/
|
|
88
|
+
const sorted = shuffled.toSorted(function byOldestFirst(first, second,) {
|
|
89
|
+
return compareLogKeys({
|
|
90
|
+
first,
|
|
91
|
+
second,
|
|
92
|
+
},);
|
|
93
|
+
},);
|
|
94
|
+
expect(sorted.map(function keyOf(parsed,) {
|
|
95
|
+
return parsed.key;
|
|
96
|
+
},),)
|
|
97
|
+
.toEqual([
|
|
98
|
+
'monochromatic.log.1000.aaaa.0',
|
|
99
|
+
'monochromatic.log.1000.aaaa.1',
|
|
100
|
+
'monochromatic.log.1000.bbbb.1',
|
|
101
|
+
'monochromatic.log.2000.aaaa.0',
|
|
102
|
+
],);
|
|
103
|
+
},
|
|
104
|
+
},),
|
|
105
|
+
],
|
|
106
|
+
},);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-runtime default localStorage quota heuristics.
|
|
3
|
+
*
|
|
4
|
+
* The Web Storage API exposes no way to read the localStorage quota (unlike
|
|
5
|
+
* `navigator.storage.estimate()`, which reports the unrelated persistent-storage
|
|
6
|
+
* budget), so the sink caps its own footprint from a table of measured
|
|
7
|
+
* defaults. Each figure was fill-probed on a fresh store: values are written at
|
|
8
|
+
* a growing single key until a `QuotaExceededError`, binary-searching the
|
|
9
|
+
* largest that fits. Figures are UTF-16 code units (JS string length, counting
|
|
10
|
+
* key plus value) because that is what localStorage measures and what the sink
|
|
11
|
+
* compares `serialized.length` against.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
detectWebStorageRuntime,
|
|
18
|
+
type WebStorageRuntime,
|
|
19
|
+
} from './web-storage-runtime.ts';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Measured default per-origin localStorage quotas, in UTF-16 code units, one
|
|
23
|
+
* bucket per detectable runtime:
|
|
24
|
+
*
|
|
25
|
+
* - `deno`: 10,477,569 on Deno 2.9, which lands 8 KiB short of the 10 MiB its
|
|
26
|
+
* sessionStorage measures, presumably backing-store overhead; the measured
|
|
27
|
+
* figure is kept as-is rather than rounded up past what actually fits.
|
|
28
|
+
* - `node`: 5 MiB on Node 26 launched with `--localstorage-file`.
|
|
29
|
+
* - `browser`: 5 MiB, measured on headless Chromium 149 over an
|
|
30
|
+
* `http://127.0.0.1` origin. Firefox and WebKit are assumed to share the
|
|
31
|
+
* bucket: both measured 5 MiB for sessionStorage under Playwright v1.61 and
|
|
32
|
+
* neither was fill-probed for localStorage here.
|
|
33
|
+
*
|
|
34
|
+
* Bun 1.3 exposes no `localStorage`, so its bucket is uncapped: its sink never
|
|
35
|
+
* verifies and never reaches the cap. An unrecognized runtime is also uncapped
|
|
36
|
+
* so the caller relies on reactive eviction alone.
|
|
37
|
+
*/
|
|
38
|
+
const RUNTIME_QUOTA_CHARS: Record<WebStorageRuntime, number> = {
|
|
39
|
+
browser: 5_242_880,
|
|
40
|
+
bun: Number.POSITIVE_INFINITY,
|
|
41
|
+
deno: 10_477_569,
|
|
42
|
+
node: 5_242_880,
|
|
43
|
+
unknown: Number.POSITIVE_INFINITY,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Detects the current runtime's default localStorage quota in UTF-16 code
|
|
48
|
+
* units, or `Number.POSITIVE_INFINITY` when the runtime is unrecognized so the
|
|
49
|
+
* caller leaves its footprint uncapped and relies on reactive eviction alone.
|
|
50
|
+
*
|
|
51
|
+
* @returns Total quota in code units, or `Number.POSITIVE_INFINITY` if unknown.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const capChars = detectLocalStorageQuotaChars() / 2; // half the total
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function detectLocalStorageQuotaChars(): number {
|
|
59
|
+
return RUNTIME_QUOTA_CHARS[detectWebStorageRuntime()];
|
|
60
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
} from '@monochromatic-dev/module-test/ts';
|
|
6
|
+
import {
|
|
7
|
+
_detectLocalStorageQuotaChars as detectLocalStorageQuotaChars,
|
|
8
|
+
} from '@monochromatic-dev/module-logger';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Temporarily sets `globalThis` keys to the supplied values, restoring each to
|
|
12
|
+
* its prior value (or deleting keys that were absent) when the returned guard
|
|
13
|
+
* leaves `using` scope, so a runtime-detection test can impersonate Deno, Bun,
|
|
14
|
+
* or a browser without leaking the fake globals into later tests.
|
|
15
|
+
*
|
|
16
|
+
* @param overrides - Global keys to install for the duration of the scope.
|
|
17
|
+
*
|
|
18
|
+
* @returns Disposable that restores the original globals on exit.
|
|
19
|
+
*/
|
|
20
|
+
function withGlobalOverrides(overrides: Record<string, unknown>,): Disposable {
|
|
21
|
+
const host = globalThis as unknown as Record<string, unknown>;
|
|
22
|
+
const saved = Object.entries(overrides,)
|
|
23
|
+
.map(function captureAndSet([key, value,],) {
|
|
24
|
+
const had = key in host;
|
|
25
|
+
const prior = host[key];
|
|
26
|
+
host[key] = value;
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
had,
|
|
30
|
+
prior,
|
|
31
|
+
};
|
|
32
|
+
},);
|
|
33
|
+
return {
|
|
34
|
+
[Symbol.dispose](): void {
|
|
35
|
+
for (const { key, had, prior, } of saved) {
|
|
36
|
+
if (had)
|
|
37
|
+
host[key] = prior;
|
|
38
|
+
else
|
|
39
|
+
// `delete host[key]` (dynamic key) is banned; this removes the key so
|
|
40
|
+
// an absent-before global (e.g. `Deno`) does not leak into later tests.
|
|
41
|
+
Reflect.deleteProperty(host, key,);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await describe({
|
|
48
|
+
name: detectLocalStorageQuotaChars.name,
|
|
49
|
+
// Serial because every test mutates process-global runtime markers.
|
|
50
|
+
concurrency: 1,
|
|
51
|
+
children: [
|
|
52
|
+
it({
|
|
53
|
+
name: 'reads node web storage as 5 MiB',
|
|
54
|
+
fn: async () => {
|
|
55
|
+
expect(detectLocalStorageQuotaChars(),)
|
|
56
|
+
.toBe(5_242_880,);
|
|
57
|
+
},
|
|
58
|
+
},),
|
|
59
|
+
|
|
60
|
+
it({
|
|
61
|
+
name: 'reads Deno web storage as its measured just-under-10-MiB figure',
|
|
62
|
+
fn: async () => {
|
|
63
|
+
using _override = withGlobalOverrides({ Deno: {}, },);
|
|
64
|
+
expect(detectLocalStorageQuotaChars(),)
|
|
65
|
+
.toBe(10_477_569,);
|
|
66
|
+
},
|
|
67
|
+
},),
|
|
68
|
+
|
|
69
|
+
it({
|
|
70
|
+
name: 'leaves Bun uncapped since it exposes no localStorage',
|
|
71
|
+
fn: async () => {
|
|
72
|
+
using _override = withGlobalOverrides({ Bun: {}, },);
|
|
73
|
+
expect(detectLocalStorageQuotaChars(),)
|
|
74
|
+
.toBe(Number.POSITIVE_INFINITY,);
|
|
75
|
+
},
|
|
76
|
+
},),
|
|
77
|
+
|
|
78
|
+
it({
|
|
79
|
+
name: 'reads a browser engine as 5 MiB',
|
|
80
|
+
fn: async () => {
|
|
81
|
+
// No node markers, but a DOM: the browser bucket, measured on Chromium
|
|
82
|
+
// and assumed shared by Firefox and WebKit.
|
|
83
|
+
using _override = withGlobalOverrides({ process: undefined, document: {}, },);
|
|
84
|
+
expect(detectLocalStorageQuotaChars(),)
|
|
85
|
+
.toBe(5_242_880,);
|
|
86
|
+
},
|
|
87
|
+
},),
|
|
88
|
+
|
|
89
|
+
it({
|
|
90
|
+
name: 'leaves an unrecognized runtime uncapped',
|
|
91
|
+
fn: async () => {
|
|
92
|
+
using _override = withGlobalOverrides({ process: undefined, },);
|
|
93
|
+
expect(detectLocalStorageQuotaChars(),)
|
|
94
|
+
.toBe(Number.POSITIVE_INFINITY,);
|
|
95
|
+
},
|
|
96
|
+
},),
|
|
97
|
+
],
|
|
98
|
+
},);
|