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,56 @@
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 } from './binaryStore';
48
+ /**
49
+ * Every member of {@link BinaryStore}, inert.
50
+ *
51
+ * @param appId the tenant the fake claims to be. Required, and deliberately so —
52
+ * a blank tenant is the mistake `binaryStoreTenant` exists to catch, and a
53
+ * fake that quietly defaults it would hide a test written against the
54
+ * wrong app.
55
+ */
56
+ export declare function binaryStoreFakeDefaults(appId: string): BinaryStore;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Every member of {@link BinaryStore}, inert.
3
+ *
4
+ * @param appId the tenant the fake claims to be. Required, and deliberately so —
5
+ * a blank tenant is the mistake `binaryStoreTenant` exists to catch, and a
6
+ * fake that quietly defaults it would hide a test written against the
7
+ * wrong app.
8
+ */
9
+ export function binaryStoreFakeDefaults(appId) {
10
+ return {
11
+ appId,
12
+ async put() { },
13
+ async putLarge() { },
14
+ async get() {
15
+ return null;
16
+ },
17
+ async meta() {
18
+ return null;
19
+ },
20
+ async stat() {
21
+ return null;
22
+ },
23
+ async has() {
24
+ return false;
25
+ },
26
+ // 🔴 `"unknown"`, never `"absent"`. A fake that claimed to know a key is missing
27
+ // would let a listing route's "answer only from the memo" branch look exercised
28
+ // when nothing was ever memoized — the one thing a test of that branch is for.
29
+ known() {
30
+ return 'unknown';
31
+ },
32
+ // 🔴 `0`, and never a lie about work done. The real one returns how many
33
+ // negative memos it dropped, and an app's repair route reports that number to
34
+ // the owner — a fake that invented one would make a broken repair read as a
35
+ // working one in the only test that could catch it.
36
+ forgetMisses() {
37
+ return 0;
38
+ },
39
+ cacheStats() {
40
+ return { present: 0, absent: 0 };
41
+ },
42
+ async remove() { },
43
+ async removePrefix() { },
44
+ async mediaUrl(key) {
45
+ // Carries the key, so an assertion on "which object was linked" reads.
46
+ return `https://binary-server.test/media/${appId}/${key}`;
47
+ },
48
+ async mediaPrefixUrl(prefix, master) {
49
+ // Carries BOTH, because the bug this shape exists to prevent is signing the wrong
50
+ // one of them — a URL pointing at the master but scoped to the wrong prefix 403s
51
+ // every segment while the master itself loads fine.
52
+ return `https://binary-server.test/media/${appId}/${master}?p=${encodeURIComponent(prefix)}`;
53
+ },
54
+ async fetchMedia() {
55
+ // 🔴 404, not an empty 200. A fake that answers "here are zero bytes" makes a
56
+ // streaming route look like it worked on an object that does not exist.
57
+ return new Response(null, { status: 404 });
58
+ },
59
+ async signToken(_claims, _ttlSeconds) {
60
+ return 'fake-token';
61
+ },
62
+ };
63
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt-server",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The app-facing Bun/Hono server tier of the cursedbelt split \u2014 storage, sharing, activity, guard, sync. React-free; cursedbelt-core below it.",
@@ -54,6 +54,18 @@
54
54
  "source": "./src/server/bench/index.ts",
55
55
  "import": "./dist/server/bench/index.js"
56
56
  },
57
+ "./binary-store": {
58
+ "types": "./dist/server/storage/binaryStore.d.ts",
59
+ "bun": "./src/server/storage/binaryStore.ts",
60
+ "source": "./src/server/storage/binaryStore.ts",
61
+ "import": "./dist/server/storage/binaryStore.js"
62
+ },
63
+ "./binary-store/testing": {
64
+ "types": "./dist/server/storage/binaryStoreFake.d.ts",
65
+ "bun": "./src/server/storage/binaryStoreFake.ts",
66
+ "source": "./src/server/storage/binaryStoreFake.ts",
67
+ "import": "./dist/server/storage/binaryStoreFake.js"
68
+ },
57
69
  "./d1": {
58
70
  "types": "./dist/server/d1/index.d.ts",
59
71
  "bun": "./src/server/d1/index.ts",
@@ -114,6 +114,30 @@ const LEAVES = [
114
114
  /** The failed-login backoff. Every app with a login door; shipped as 2.5.1. */
115
115
  evaluates: 'createLoginThrottle',
116
116
  },
117
+ {
118
+ subpath: './binary-store',
119
+ /**
120
+ * 🔴 The binary-server CLIENT, and the leaf whose promise is the largest. It arrived
121
+ * in 4.1.0 from five app-side copies, and it is the module that decides whether a ROM
122
+ * byte, a photograph, a song and a scanned document are readable — so every app takes
123
+ * it, and none of them may pay `sharp`/`otplib`/`kysely` for the privilege. It sits
124
+ * in `src/server/storage/` beside the file-catalogue and transcode graph, which is
125
+ * exactly the barrel this must never be reached through: `./storage`'s index is heavy
126
+ * and this module's whole point is that it costs `node:crypto` and nothing else.
127
+ */
128
+ evaluates: 'createBinaryStore',
129
+ },
130
+ {
131
+ subpath: './binary-store/testing',
132
+ /**
133
+ * The fake travels WITH the interface — it exists so that adding a method to
134
+ * `BinaryStore` stops breaking twenty-two suites in apps nobody touched, and a fake
135
+ * in a different package from its interface cannot do that job. Split from
136
+ * `./binary-store` so a consumer's PRODUCTION graph can never reach it, the same way
137
+ * `./d1/testing` is split from `./d1`.
138
+ */
139
+ evaluates: 'binaryStoreFakeDefaults',
140
+ },
117
141
  ] as const;
118
142
 
119
143
  /**