cursedbelt-server 4.0.0 → 4.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.
@@ -0,0 +1,111 @@
1
+ /**
2
+ * A `BinaryStore` that does nothing, so adding a method to the interface stops
3
+ * breaking twenty-two test files in apps nobody touched.
4
+ *
5
+ * ── The measurement (2026-09-08) ────────────────────────────────────────────
6
+ * `BinaryStore.fetchMedia` was added to serve audio off this Mac while
7
+ * Cloudflare's daily Worker quota was spent — a good change, landed on `main`,
8
+ * with apps/music green. It also broke **apps/collections and apps/roms**, four
9
+ * test files each, with `Property 'fetchMedia' is missing in type`. Both apps
10
+ * were left unable to typecheck, and therefore unable to gate or deploy, by a
11
+ * commit neither of them appears in. Nobody noticed for hours: a worker's
12
+ * `verify:scoped` only typechecks the workspaces its own diff touches, which is
13
+ * exactly the property that makes it fast.
14
+ *
15
+ * The owner's rule, in his words: *"a change to roms for example cannot block
16
+ * family tree app from passing its tests."* This is that rule for the one
17
+ * interface twenty-two suites all fake by hand.
18
+ *
19
+ * 🔴 **This is why the fake travels WITH the interface, into this package.** An
20
+ * interface whose change can break two other apps from a third app's commit is a
21
+ * shared interface already; a fake living in a different repo from the interface it
22
+ * fakes cannot do the job it exists for, because the two can be changed
23
+ * independently. Published as `cursedbelt-server/binary-store/testing`, beside
24
+ * `cursedbelt-server/binary-store` — the same split as `./d1` and `./d1/testing`, and
25
+ * for the same reason: a consumer's PRODUCTION graph must not be able to reach a
26
+ * fake.
27
+ *
28
+ * ── 🔴 Why defaults and not optional members ────────────────────────────────
29
+ * The obvious alternative is to mark each new capability `fetchMedia?:` on the
30
+ * interface. That moves the cost to every REAL consumer — each one then has to
31
+ * narrow before calling, for a method the production store always has — and it
32
+ * makes "did we implement this?" unanswerable by the typechecker, which is the
33
+ * one question the interface exists to answer. The fakes are the side that
34
+ * should absorb the change, so the defaults live here.
35
+ *
36
+ * ── What a default may do ───────────────────────────────────────────────────
37
+ * As little as possible, and never something a test could mistake for a result.
38
+ * `get` and `meta` answer "not here"; `fetchMedia` answers 404; the mutators do
39
+ * nothing. A suite that cares about any of them overrides it — spread this first
40
+ * and the file's own members win:
41
+ *
42
+ * const store: BinaryStore = {
43
+ * ...binaryStoreFakeDefaults("collections"),
44
+ * async meta(key) { … what this suite is actually about … },
45
+ * };
46
+ */
47
+ import type { BinaryStore, FileTokenClaims } from './binaryStore';
48
+
49
+ /**
50
+ * Every member of {@link BinaryStore}, inert.
51
+ *
52
+ * @param appId the tenant the fake claims to be. Required, and deliberately so —
53
+ * a blank tenant is the mistake `binaryStoreTenant` exists to catch, and a
54
+ * fake that quietly defaults it would hide a test written against the
55
+ * wrong app.
56
+ */
57
+ export function binaryStoreFakeDefaults(appId: string): BinaryStore {
58
+ return {
59
+ appId,
60
+ async put(): Promise<void> {},
61
+ async putLarge(): Promise<void> {},
62
+ async get(): Promise<Uint8Array | null> {
63
+ return null;
64
+ },
65
+ async meta(): Promise<null> {
66
+ return null;
67
+ },
68
+ async stat(): Promise<null> {
69
+ return null;
70
+ },
71
+ async has(): Promise<boolean> {
72
+ return false;
73
+ },
74
+ // 🔴 `"unknown"`, never `"absent"`. A fake that claimed to know a key is missing
75
+ // would let a listing route's "answer only from the memo" branch look exercised
76
+ // when nothing was ever memoized — the one thing a test of that branch is for.
77
+ known(): 'present' | 'absent' | 'unknown' {
78
+ return 'unknown';
79
+ },
80
+ // 🔴 `0`, and never a lie about work done. The real one returns how many
81
+ // negative memos it dropped, and an app's repair route reports that number to
82
+ // the owner — a fake that invented one would make a broken repair read as a
83
+ // working one in the only test that could catch it.
84
+ forgetMisses(): number {
85
+ return 0;
86
+ },
87
+ cacheStats(): { present: number; absent: number } {
88
+ return { present: 0, absent: 0 };
89
+ },
90
+ async remove(): Promise<void> {},
91
+ async removePrefix(): Promise<void> {},
92
+ async mediaUrl(key: string): Promise<string> {
93
+ // Carries the key, so an assertion on "which object was linked" reads.
94
+ return `https://binary-server.test/media/${appId}/${key}`;
95
+ },
96
+ async mediaPrefixUrl(prefix: string, master: string): Promise<string> {
97
+ // Carries BOTH, because the bug this shape exists to prevent is signing the wrong
98
+ // one of them — a URL pointing at the master but scoped to the wrong prefix 403s
99
+ // every segment while the master itself loads fine.
100
+ return `https://binary-server.test/media/${appId}/${master}?p=${encodeURIComponent(prefix)}`;
101
+ },
102
+ async fetchMedia(): Promise<Response> {
103
+ // 🔴 404, not an empty 200. A fake that answers "here are zero bytes" makes a
104
+ // streaming route look like it worked on an object that does not exist.
105
+ return new Response(null, { status: 404 });
106
+ },
107
+ async signToken(_claims: FileTokenClaims, _ttlSeconds: number): Promise<string> {
108
+ return 'fake-token';
109
+ },
110
+ };
111
+ }