cursedbelt 2.5.1 β†’ 2.6.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.
@@ -1 +1 @@
1
- {"version":3,"file":"unlock.d.ts","sourceRoot":"","sources":["../../../src/server/private-media/unlock.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4C,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAclF,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5E;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,CACd,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACzC,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB,CAAC;AAEN,MAAM,WAAW,aAAa;IAC5B;oEACgE;IAChE,MAAM,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAC7E,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,OAAO,CAAC;KACf,CAAC,CAAC;IACH,0FAA0F;IAC1F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,4FAA4F;IAC5F,YAAY,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;CACrF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,aAAa,CAiDhB"}
1
+ {"version":3,"file":"unlock.d.ts","sourceRoot":"","sources":["../../../src/server/private-media/unlock.ts"],"names":[],"mappings":"AAOA,OAAO,EAA4C,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAclF,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5E;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,CACd,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACzC,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB,CAAC;AAEN,MAAM,WAAW,aAAa;IAC5B;oEACgE;IAChE,MAAM,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAC7E,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,OAAO,CAAC;KACf,CAAC,CAAC;IACH,0FAA0F;IAC1F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,4FAA4F;IAC5F,YAAY,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC;CACrF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,aAAa,CAiDhB"}
@@ -1,5 +1,10 @@
1
1
  import { decryptSecret, deriveKey, encryptSecret } from 'cwip/node';
2
- import { signToken, verifyPurposeToken } from '../auth';
2
+ // πŸ”΄ `../auth/jwt`, NOT `../auth` β€” same reason as `storage/streamToken.ts`, and this is the
3
+ // SECOND edge of the pair: `cursedbelt/server/storage` reaches private-media, so the barrel
4
+ // import here put `otplib` (via `auth/index` β†’ `totp.ts`) back into the storage graph after
5
+ // streamToken.ts had been fixed. Found by bundling the graph and reading the externals, not by
6
+ // grep β€” a two-hop edge is invisible to the obvious search.
7
+ import { signToken, verifyPurposeToken } from '../auth/jwt';
3
8
  import { derivePasswordSetKey, deriveServerSetKey } from './crypto';
4
9
  // ── Unlock service ──────────────────────────────────────────────────────────────
5
10
  // Turns a private-mode unlock into a short-lived token that CARRIES the set key so later
@@ -1 +1 @@
1
- {"version":3,"file":"unlock.js","sourceRoot":"","sources":["../../../src/server/private-media/unlock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAgB,MAAM,UAAU,CAAC;AAElF,mFAAmF;AACnF,yFAAyF;AACzF,0FAA0F;AAC1F,4FAA4F;AAC5F,gFAAgF;AAChF,mGAAmG;AACnG,gGAAgG;AAChG,6FAA6F;AAC7F,sFAAsF;AAEtF,MAAM,OAAO,GAAG,WAAW,CAAC;AAoC5B,MAAM,UAAU,mBAAmB,CAAC,IAOnC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,CAAC,EACpB,MAAM,EACN,QAAQ,EACR,QAAQ,GAKT,EAAU,EAAE,CACX,QAAQ;QACN,CAAC,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC1C,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAEpD,OAAO;QACL,YAAY;QACZ,KAAK,CAAC,MAAM,CAAC,IAAI;YACf,MAAM,IAAI,GAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;YAC9D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,MAAM,SAAS,CAC3B;gBACE,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,OAAO;gBAChB,EAAE,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;gBACrD,CAAC,EAAE,IAAI;aACR,EACD,IAAI,CAAC,YAAY,EACjB,GAAG,CACJ,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACtE,MAAM,MAAM,GAAI,CAAsB,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,GAAI,CAAqB,CAAC,CAAC,CAAC;gBACtC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,UAAU,CAAC;oBAAE,OAAO,IAAI,CAAC;gBAC5F,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACrE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"unlock.js","sourceRoot":"","sources":["../../../src/server/private-media/unlock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACpE,6FAA6F;AAC7F,4FAA4F;AAC5F,4FAA4F;AAC5F,+FAA+F;AAC/F,4DAA4D;AAC5D,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAgB,MAAM,UAAU,CAAC;AAElF,mFAAmF;AACnF,yFAAyF;AACzF,0FAA0F;AAC1F,4FAA4F;AAC5F,gFAAgF;AAChF,mGAAmG;AACnG,gGAAgG;AAChG,6FAA6F;AAC7F,sFAAsF;AAEtF,MAAM,OAAO,GAAG,WAAW,CAAC;AAoC5B,MAAM,UAAU,mBAAmB,CAAC,IAOnC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,CAAC,EACpB,MAAM,EACN,QAAQ,EACR,QAAQ,GAKT,EAAU,EAAE,CACX,QAAQ;QACN,CAAC,CAAC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAC1C,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAEpD,OAAO;QACL,YAAY;QACZ,KAAK,CAAC,MAAM,CAAC,IAAI;YACf,MAAM,IAAI,GAAY,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;YAC9D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,MAAM,SAAS,CAC3B;gBACE,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS,EAAE,IAAI;gBACf,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,OAAO;gBAChB,EAAE,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;gBACrD,CAAC,EAAE,IAAI;aACR,EACD,IAAI,CAAC,YAAY,EACjB,GAAG,CACJ,CAAC;YACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACtE,MAAM,MAAM,GAAI,CAAsB,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,GAAI,CAAqB,CAAC,CAAC,CAAC;gBACtC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,UAAU,CAAC;oBAAE,OAAO,IAAI,CAAC;gBAC5F,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACrE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,44 +1,4 @@
1
- import type { MediaStore } from './types';
2
- /**
3
- * Claims binary-server verifies (see binary-server/src/tokens.ts). This is the ONE
4
- * canonical shape for a binary-server file token across the fleet: cursedbelt's
5
- * injected-signer `createBinaryServerStore` (below) and `@satellites/satellite-kit`'s
6
- * self-signing `createBinaryStore` both mint tokens against the SAME binary-server, so
7
- * the claim set must never drift β€” satellite-kit imports this exact type rather than
8
- * redeclaring it, so a token one side signs is always shaped for the other to read. The
9
- * app's signer turns these into an RS256 JWT.
10
- */
11
- export type FileTokenClaims = {
12
- /** Exact authorized path, app-prefixed: `<app>/<key>`. */
13
- k?: string;
14
- /** Authorized path prefix, app-prefixed (container trees, e.g. an HLS tree). */
15
- p?: string;
16
- /** Acting user/app id β€” audit trail on binary-server's events, never authz. */
17
- uid?: string;
18
- /** Chunk-session id (must match across every chunk of one upload). */
19
- sid?: string;
20
- /** Chunk index (0-based). */
21
- ci?: number;
22
- /** Total chunk count. */
23
- tc?: number;
24
- /** Download filename β†’ Content-Disposition. */
25
- fn?: string;
26
- dl?: 'inline' | 'attachment';
27
- /** Per-op scope. A DELETE against binary-server requires a token carrying `op: 'delete'`
28
- * (in addition to the internal secret) β€” a plain read/download token can never be replayed
29
- * as a delete, and the token's issuer + `k`/`p` tenant-scope the delete. Owner ruling #10. */
30
- op?: 'delete';
31
- };
32
- export type FileTokenSigner = (claims: FileTokenClaims) => Promise<string>;
33
- export type BinaryServerConfig = {
34
- /** e.g. 'https://binary-server.cursedalchemy.com'. */
35
- baseUrl: string;
36
- /** App namespace (path + token scope), e.g. 'cursedalchemy'. */
37
- appId: string;
38
- /** App-provided RS256 signer (app holds the private key). */
39
- signFileToken: FileTokenSigner;
40
- /** Shared secret for internal ops (delete). Sent as x-internal-secret. */
41
- internalSecret?: string;
42
- };
1
+ import type { BinaryServerConfig, MediaStore } from './types';
2
+ export type { BinaryServerConfig, FileTokenClaims, FileTokenSigner } from './types';
43
3
  export declare function createBinaryServerStore(cfg: BinaryServerConfig): MediaStore;
44
4
  //# sourceMappingURL=binaryServerStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"binaryServerStore.d.ts","sourceRoot":"","sources":["../../../src/server/storage/binaryServerStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAW1C;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,0DAA0D;IAC1D,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC7B;;mGAE+F;IAC/F,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE3E,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,aAAa,EAAE,eAAe,CAAC;IAC/B,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,kBAAkB,GAAG,UAAU,CAqF3E"}
1
+ {"version":3,"file":"binaryServerStore.d.ts","sourceRoot":"","sources":["../../../src/server/storage/binaryServerStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK9D,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAWpF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,kBAAkB,GAAG,UAAU,CAqF3E"}
@@ -1,3 +1,11 @@
1
+ // binary-server MediaStore adapter. binary-server (Bun/SQLite, RS256 token-gated, Range-capable)
2
+ // is a production storage path: a home/edge file service the app signs short-lived tokens for.
3
+ // User-facing downloads REDIRECT (303) to the signed edge URL rather than proxying bytes back
4
+ // through the app; server-side reads (transcode source, checks) stream locally via getRange.
5
+ //
6
+ // The RS256 signer is INJECTED β€” the app holds the private key (binary-server holds only the
7
+ // public key). cursedbelt carries no key material and no asymmetric-crypto specifics; it just
8
+ // calls `signFileToken` with the claims binary-server expects.
1
9
  export function createBinaryServerStore(cfg) {
2
10
  const appKey = (key) => `${cfg.appId}/${key}`;
3
11
  const mediaUrl = async (key, extra) => {
@@ -1 +1 @@
1
- {"version":3,"file":"binaryServerStore.js","sourceRoot":"","sources":["../../../src/server/storage/binaryServerStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"binaryServerStore.js","sourceRoot":"","sources":["../../../src/server/storage/binaryServerStore.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"streamToken.d.ts","sourceRoot":"","sources":["../../../src/server/storage/streamToken.ts"],"names":[],"mappings":"AAkBA,+FAA+F;AAC/F,MAAM,MAAM,WAAW,GAAG;IACxB,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACpD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,kBAAkB,CAiCrB"}
1
+ {"version":3,"file":"streamToken.d.ts","sourceRoot":"","sources":["../../../src/server/storage/streamToken.ts"],"names":[],"mappings":"AAyBA,+FAA+F;AAC/F,MAAM,MAAM,WAAW,GAAG;IACxB,uFAAuF;IACvF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACpD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,kBAAkB,CAiCrB"}
@@ -1,4 +1,11 @@
1
- import { signToken, verifyPurposeToken } from '../auth';
1
+ // πŸ”΄ `../auth/jwt`, NOT `../auth`. The jose half is a REAL dependency β€” stream tokens are
2
+ // signed and verified here, and jose is a plain `dependencies` entry every consumer already
3
+ // installs. The BARREL was the accident: `../auth/index.ts` also reaches `totp.ts` β†’ `otplib`,
4
+ // an OPTIONAL peer, so every app that touched anything in `cursedbelt/server/storage` was made
5
+ // to install a one-time-password library for code it never calls. Import the leaf module that
6
+ // has what you need; never the index that has everything. `src/leafSubpathsImportNothing.spec.ts`
7
+ // fails if this file (or anything else the storage barrel reaches) undoes it.
8
+ import { signToken, verifyPurposeToken } from '../auth/jwt';
2
9
  // ── Stream tokens ───────────────────────────────────────────────────────────────
3
10
  // Media bytes are loaded by <video>/hls.js/<img>, which cannot send the platform Bearer
4
11
  // header an app's auth uses. So byte-serving routes live OUTSIDE the guarded API and
@@ -1 +1 @@
1
- {"version":3,"file":"streamToken.js","sourceRoot":"","sources":["../../../src/server/storage/streamToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAExD,mFAAmF;AACnF,wFAAwF;AACxF,qFAAqF;AACrF,0EAA0E;AAC1E,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,+FAA+F;AAC/F,kEAAkE;AAClE,EAAE;AACF,2FAA2F;AAC3F,yFAAyF;AACzF,0EAA0E;AAE1E,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAe5C,MAAM,UAAU,wBAAwB,CAAC,IAIxC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAClD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG;YAChC,yFAAyF;YACzF,uFAAuF;YACvF,uEAAuE;YACvE,OAAO,SAAS,CACd;gBACE,MAAM,EAAE,KAAK,CAAC,KAAK;gBACnB,SAAS,EAAE,cAAc;gBACzB,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,oBAAoB;gBAC7B,GAAG,EAAE,KAAK,CAAC,QAAQ;gBACnB,GAAG,EAAE,KAAK,CAAC,OAAO;aACnB,EACD,IAAI,CAAC,MAAM,EACX,UAAU,CACX,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;gBAC7E,MAAM,GAAG,GAAI,CAAuB,CAAC,GAAG,CAAC;gBACzC,MAAM,GAAG,GAAI,CAAuB,CAAC,GAAG,CAAC;gBACzC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAC;gBACpE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YAC1D,CAAC;YAAC,MAAM,CAAC;gBACP,oDAAoD;gBACpD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"streamToken.js","sourceRoot":"","sources":["../../../src/server/storage/streamToken.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,4FAA4F;AAC5F,+FAA+F;AAC/F,+FAA+F;AAC/F,8FAA8F;AAC9F,kGAAkG;AAClG,8EAA8E;AAC9E,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE5D,mFAAmF;AACnF,wFAAwF;AACxF,qFAAqF;AACrF,0EAA0E;AAC1E,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,+FAA+F;AAC/F,kEAAkE;AAClE,EAAE;AACF,2FAA2F;AAC3F,yFAAyF;AACzF,0EAA0E;AAE1E,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAe5C,MAAM,UAAU,wBAAwB,CAAC,IAIxC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAClD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG;YAChC,yFAAyF;YACzF,uFAAuF;YACvF,uEAAuE;YACvE,OAAO,SAAS,CACd;gBACE,MAAM,EAAE,KAAK,CAAC,KAAK;gBACnB,SAAS,EAAE,cAAc;gBACzB,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,oBAAoB;gBAC7B,GAAG,EAAE,KAAK,CAAC,QAAQ;gBACnB,GAAG,EAAE,KAAK,CAAC,OAAO;aACnB,EACD,IAAI,CAAC,MAAM,EACX,UAAU,CACX,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,KAAK;YAChB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;gBAC7E,MAAM,GAAG,GAAI,CAAuB,CAAC,GAAG,CAAC;gBACzC,MAAM,GAAG,GAAI,CAAuB,CAAC,GAAG,CAAC;gBACzC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,OAAO,IAAI,CAAC;gBACpE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;YAC1D,CAAC;YAAC,MAAM,CAAC;gBACP,oDAAoD;gBACpD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -47,6 +47,47 @@ export interface MediaStore {
47
47
  filename?: string;
48
48
  }): Promise<string | null>;
49
49
  }
50
+ /**
51
+ * Claims binary-server verifies (see binary-server/src/tokens.ts). This is the ONE
52
+ * canonical shape for a binary-server file token across the fleet: cursedbelt's
53
+ * injected-signer `createBinaryServerStore` and `@satellites/satellite-kit`'s
54
+ * self-signing `createBinaryStore` both mint tokens against the SAME binary-server, so
55
+ * the claim set must never drift β€” satellite-kit imports this exact type rather than
56
+ * redeclaring it, so a token one side signs is always shaped for the other to read. The
57
+ * app's signer turns these into an RS256 JWT.
58
+ */
59
+ export type FileTokenClaims = {
60
+ /** Exact authorized path, app-prefixed: `<app>/<key>`. */
61
+ k?: string;
62
+ /** Authorized path prefix, app-prefixed (container trees, e.g. an HLS tree). */
63
+ p?: string;
64
+ /** Acting user/app id β€” audit trail on binary-server's events, never authz. */
65
+ uid?: string;
66
+ /** Chunk-session id (must match across every chunk of one upload). */
67
+ sid?: string;
68
+ /** Chunk index (0-based). */
69
+ ci?: number;
70
+ /** Total chunk count. */
71
+ tc?: number;
72
+ /** Download filename β†’ Content-Disposition. */
73
+ fn?: string;
74
+ dl?: 'inline' | 'attachment';
75
+ /** Per-op scope. A DELETE against binary-server requires a token carrying `op: 'delete'`
76
+ * (in addition to the internal secret) β€” a plain read/download token can never be replayed
77
+ * as a delete, and the token's issuer + `k`/`p` tenant-scope the delete. Owner ruling #10. */
78
+ op?: 'delete';
79
+ };
80
+ export type FileTokenSigner = (claims: FileTokenClaims) => Promise<string>;
81
+ export type BinaryServerConfig = {
82
+ /** e.g. 'https://binary-server.cursedalchemy.com'. */
83
+ baseUrl: string;
84
+ /** App namespace (path + token scope), e.g. 'cursedalchemy'. */
85
+ appId: string;
86
+ /** App-provided RS256 signer (app holds the private key). */
87
+ signFileToken: FileTokenSigner;
88
+ /** Shared secret for internal ops (delete). Sent as x-internal-secret. */
89
+ internalSecret?: string;
90
+ };
50
91
  /** A source of videos for a gallery/catalogue. Apps implement this differently (a disk folder,
51
92
  * a binary-server app, ca's Files tree + private set). Consumers are source-agnostic. */
52
93
  export interface MediaSource {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/storage/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/server/storage/types.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,17 @@
5
5
  // with no Bearer can still be authorized), a source registry, and the ingestβ†’derivatives
6
6
  // pipeline glue. Ported/generalised from ca's proven media stack; the app maps its own records
7
7
  // to a MediaSource. Pairs with the `PlayableVideo` contract in `cursedbelt/media-core`.
8
+ //
9
+ // πŸ”΄ THIS FILE IS A PUBLISHED LEAF β€” `cursedbelt/server/storage/types` β€” AND IT MUST STAY
10
+ // IMPORT-FREE AT RUNTIME. `src/leafSubpathsImportNothing.spec.ts` imports it in a fixture with
11
+ // no packages resolvable at all and fails if it throws, so an `import` here that survives
12
+ // transpilation (anything that is not `import type`) turns that spec red rather than turning
13
+ // up in a consumer's install. The subpath exists because `./server/storage`'s own index is a
14
+ // barrel: it reaches `streamToken` β†’ `auth/jwt` β†’ jose, the whole SQLite file catalogue under
15
+ // `files/`, and a lazily-imported `sharp` β€” while an app that wants only the SHAPE of a file
16
+ // token (apps/collections wanted exactly `FileTokenClaims`, a type TypeScript erases) was made
17
+ // to install a one-time-password library to get it. Add types here freely; add a value import
18
+ // here never.
8
19
  // ── Keyspace helpers ──────────────────────────────────────────────────────────────
9
20
  // One source of truth for every storage key. Sources + serve routes + the pipeline all
10
21
  // address bytes through these, so a key layout is never hand-spelled twice.
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/storage/types.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,4FAA4F;AAC5F,6FAA6F;AAC7F,8FAA8F;AAC9F,yFAAyF;AACzF,+FAA+F;AAC/F,wFAAwF;AA0IxF,qFAAqF;AACrF,uFAAuF;AACvF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,UAAU,KAAK,IAAI,EAAE,EAAE,CAAC;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,MAAM,CAAC;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,cAAc,CAAC;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,GAAW,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;AACpG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,aAAa,CAAC;AACzF;2EAC2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AAC3F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AAC1F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AACvF;;qGAEqG;AACrG,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,MAAM,CAAC;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAC/D,OAAO,KAAK,IAAI,EAAE,kBAAkB,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,GAAW,EAAE,EAAE,CAC1E,OAAO,KAAK,IAAI,EAAE,QAAQ,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,aAAa,CAAC;AAC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,aAAa,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/storage/types.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,4FAA4F;AAC5F,6FAA6F;AAC7F,8FAA8F;AAC9F,yFAAyF;AACzF,+FAA+F;AAC/F,wFAAwF;AACxF,EAAE;AACF,0FAA0F;AAC1F,+FAA+F;AAC/F,0FAA0F;AAC1F,6FAA6F;AAC7F,6FAA6F;AAC7F,8FAA8F;AAC9F,6FAA6F;AAC7F,+FAA+F;AAC/F,8FAA8F;AAC9F,cAAc;AA4Ld,qFAAqF;AACrF,uFAAuF;AACvF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,UAAU,KAAK,IAAI,EAAE,EAAE,CAAC;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,MAAM,CAAC;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;AAC/E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,cAAc,CAAC;AAC9F,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,GAAW,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;AACpG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,aAAa,CAAC;AACzF;2EAC2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AAC3F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AAC1F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,cAAc,CAAC;AACvF;;qGAEqG;AACrG,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,MAAM,CAAC;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAC/D,OAAO,KAAK,IAAI,EAAE,kBAAkB,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,GAAW,EAAE,EAAE,CAC1E,OAAO,KAAK,IAAI,EAAE,QAAQ,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,aAAa,CAAC;AAC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAE,EAAU,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "Shared Bun + React framework",
@@ -459,6 +459,12 @@
459
459
  "source": "./src/server/storage/index.ts",
460
460
  "import": "./dist/server/storage/index.js"
461
461
  },
462
+ "./server/storage/types": {
463
+ "types": "./dist/server/storage/types.d.ts",
464
+ "bun": "./src/server/storage/types.ts",
465
+ "source": "./src/server/storage/types.ts",
466
+ "import": "./dist/server/storage/types.js"
467
+ },
462
468
  "./server/master-lock": {
463
469
  "types": "./dist/server/master-lock/index.d.ts",
464
470
  "bun": "./src/server/master-lock/index.ts",
@@ -0,0 +1,302 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import { fileURLToPath } from 'node:url';
3
+ import pkg from '../package.json';
4
+
5
+ /**
6
+ * A LEAF subpath's whole promise is what it does NOT pull in. Nothing in this repo
7
+ * measured that until now (2026-09-15), so the promise was kept by hand β€” and it was
8
+ * broken twice in two days, in the same shape, one level apart.
9
+ *
10
+ * ## The measurement this exists because of
11
+ *
12
+ * `apps/collections/src/kit/binaryStore.ts` needed exactly one thing from here:
13
+ *
14
+ * import type { FileTokenClaims } from "cursedbelt/server/storage";
15
+ *
16
+ * A TYPE β€” TypeScript erases it, so the app should have paid nothing at runtime. What it
17
+ * actually paid was:
18
+ *
19
+ * error: Cannot find package 'otplib' from
20
+ * …/node_modules/cursedbelt/src/server/auth/totp.ts
21
+ *
22
+ * …and four unrelated route suites died before anything was measured. `server/storage`'s
23
+ * index is a barrel; the barrel reached `streamToken.ts`, which imported the `../auth`
24
+ * INDEX for two jose functions, and that index reaches `totp.ts` β†’ `otplib`, an optional
25
+ * peer. (`sessionStore.ts` takes its Kysely db as a TYPE, so the `kysely` half of the same
26
+ * trap arrives through the `./server` barrel's `db/kysely.ts` instead β€” measured, not
27
+ * assumed: bundling `./server/storage` externals before this change listed `otplib` and
28
+ * `hono/cookie`, never `kysely`.) The app declared `otplib` as a direct dependency to get
29
+ * its route suites back β€” a one-time-password library installed to satisfy a claim shape.
30
+ *
31
+ * That is the exact shape 2.5.1 shipped `./server/login-throttle` to fix, one level
32
+ * deeper, and the rule written down after it ("never import the `cursedbelt/server`
33
+ * barrel for one primitive") could not catch it, because `./server/storage` IS a leaf by
34
+ * that rule's standard and has a barrel of its own. A rule that only a human can apply
35
+ * gets re-broken by the next module that looks like a leaf. So: a check.
36
+ *
37
+ * ## What it does
38
+ *
39
+ * Assembles a throwaway consumer under `$TMPDIR` β€” a `node_modules/cursedbelt` holding
40
+ * this package's REAL package.json (so the real `exports` map is what resolves) and
41
+ * nothing else but the leaf source files themselves β€” then spawns bun in it and imports
42
+ * each leaf by its PUBLIC specifier. No peers are installed, no other file of this package
43
+ * is even on disk, so any import that survives transpilation fails the import and this
44
+ * spec with it. `import type` is erased and costs nothing, which is the whole point:
45
+ * `verbatimModuleSyntax` is on, so a type import that is not written `import type` is
46
+ * already a typecheck error, and source and `dist` therefore carry the same module graph.
47
+ *
48
+ * ## πŸ”΄ The trap that makes the naive version of this check a lie
49
+ *
50
+ * Bun AUTO-INSTALLS a missing bare import out of `~/.bun/install/cache` when the walk up
51
+ * from the importing file finds NO `node_modules` at all. Measured while building this, in
52
+ * a scratch directory holding two files and nothing else: `import { authenticator } from
53
+ * 'otplib'` resolved β€” from
54
+ * `~/.bun/install/cache/otplib@13.5.0@@@1/dist/index.js` β€” and the only error was a missing
55
+ * named export. An "empty fixture" therefore proves NOTHING about what a leaf drags: every
56
+ * peer in the cache answers.
57
+ *
58
+ * Two things hold the line, and the second is the one that matters:
59
+ *
60
+ * 1. `bunfig.toml` with `[install] auto = "disable"` in the fixture root. Note what this
61
+ * is and is not: with a `node_modules/` present (as here) bun does not auto-install
62
+ * anyway β€” removing the line and re-running left the negative control failing exactly
63
+ * as before. It is the second lock, for the day this fixture is refactored into one
64
+ * that has no `node_modules` and the trap silently comes back.
65
+ * 2. The NEGATIVE CONTROL: a file importing `otplib` and nothing else is copied in beside
66
+ * the leaves, and this spec fails if importing it SUCCEEDS. Whatever makes peers
67
+ * resolvable β€” auto-install, a `node_modules` above the scratch root, a future bun
68
+ * default β€” the control sees it and reds, instead of letting every assertion below
69
+ * pass vacuously.
70
+ *
71
+ * ## πŸ”΄ Verified failing, 2026-09-15, before it was trusted β€” every branch
72
+ *
73
+ * Β· `import 'otplib'` added to `src/server/storage/types.ts`
74
+ * β†’ "cursedbelt/server/storage/types must import nothing at runtime … Cannot find
75
+ * package 'otplib' imported from …/node_modules/cursedbelt/src/server/storage/types.ts"
76
+ * Β· the same, but `import { createStreamTokenService } from './streamToken'` β€” a
77
+ * relative import of a module inside this package
78
+ * β†’ red too: "Cannot find module './streamToken'". A leaf may not reach sideways
79
+ * either, which is why ONLY the leaf files are copied into the fixture.
80
+ * Β· `./server/storage/types` re-pointed at `src/server/storage/index.ts`, the barrel it
81
+ * was split out of
82
+ * β†’ red: "Cannot find module './videoDerivativeKeys'". A barrel cannot pass this.
83
+ * Β· the negative control re-pointed at `loginThrottle.ts`, which imports nothing, so the
84
+ * fixture stopped demonstrating that peers are unreachable
85
+ * β†’ red on the control itself: "the fixture resolved 'otplib' … Every assertion below
86
+ * is vacuous until that is fixed". The vacuity guard fires.
87
+ * Β· `src/server/private-media/unlock.ts` put back to `import … from '../auth'` β€” the
88
+ * second, two-hop edge, which grep for `../auth` inside `src/server/storage` cannot see
89
+ * β†’ red: "importing cursedbelt/server/storage statically pulls these OPTIONAL peers
90
+ * … + otplib". This is the branch that found that edge in the first place.
91
+ */
92
+
93
+ const REPO = fileURLToPath(new URL('..', import.meta.url));
94
+
95
+ /**
96
+ * Every subpath that promises to cost a consumer NOTHING at runtime. A leaf earns its
97
+ * place here by being the answer to "I want one type / one primitive out of a module
98
+ * whose index is heavy" β€” the entry names the runtime symbol proving the module really
99
+ * evaluated, so an accidentally-empty module can never pass this vacuously.
100
+ *
101
+ * The file is read from `exports`, never hard-coded: re-target the subpath and the check
102
+ * follows it to the new file rather than going quietly green against the old one.
103
+ */
104
+ const LEAVES = [
105
+ {
106
+ subpath: './server/storage/types',
107
+ /** Claim/config shapes + the keyspace helpers. apps/collections wants `FileTokenClaims`. */
108
+ evaluates: 'fsSourceKey',
109
+ },
110
+ {
111
+ subpath: './server/login-throttle',
112
+ /** The failed-login backoff. Every app with a login door; shipped as 2.5.1. */
113
+ evaluates: 'createLoginThrottle',
114
+ },
115
+ ] as const;
116
+
117
+ /**
118
+ * Imports `otplib` and nothing else, so its failure message is unambiguous. It is the
119
+ * proof that the fixture has no peers β€” not an assertion about `totp.ts` itself.
120
+ */
121
+ const CONTROL = 'src/server/auth/totp.ts';
122
+
123
+ type Outcome = { ok: true; keys: string[] } | { ok: false; error: string };
124
+
125
+ const exportsMap = pkg.exports as Record<string, { bun?: string } | string>;
126
+
127
+ /** `./src/server/storage/types.ts` β†’ `src/server/storage/types.ts`. */
128
+ const sourceOf = (subpath: string): string => {
129
+ const entry = exportsMap[subpath];
130
+ const bun = typeof entry === 'object' && entry !== null ? entry.bun : undefined;
131
+ if (typeof bun !== 'string') {
132
+ throw new Error(`package.json exports has no \`bun\` target for "${subpath}"`);
133
+ }
134
+ return bun.replace(/^\.\//, '');
135
+ };
136
+
137
+ const run = async (): Promise<Record<string, Outcome>> => {
138
+ // Per-process TMPDIR (see scripts/testTmpRoot.ts), so parallel suites cannot collide and
139
+ // the preload's sweep is what cleans up after a killed run.
140
+ const root = `${process.env.TMPDIR ?? '/tmp'}/leaf-subpath-fixture`;
141
+ const pkgDir = `${root}/node_modules/cursedbelt`;
142
+
143
+ // The second lock against bun's auto-install (see the header). The negative control is the
144
+ // first one, and the one that would catch this line being wrong.
145
+ await Bun.write(`${root}/bunfig.toml`, '[install]\nauto = "disable"\n');
146
+ // The REAL manifest: the export map under test, resolved exactly as a consumer resolves it.
147
+ await Bun.write(`${pkgDir}/package.json`, Bun.file(`${REPO}/package.json`));
148
+
149
+ const targets: Array<{ name: string; specifier: string }> = [];
150
+ for (const leaf of LEAVES) {
151
+ const source = sourceOf(leaf.subpath);
152
+ // πŸ”΄ Bun.file/Bun.write, NOT node:fs β€” this repo's test preload virtualizes node:fs, so a
153
+ // copy made through it can land in a mock the spawned child cannot see. Same trap as
154
+ // publishShape.spec.ts.
155
+ await Bun.write(`${pkgDir}/${source}`, Bun.file(`${REPO}/${source}`));
156
+ targets.push({ name: leaf.subpath, specifier: `cursedbelt/${leaf.subpath.slice(2)}` });
157
+ }
158
+ await Bun.write(`${pkgDir}/${CONTROL}`, Bun.file(`${REPO}/${CONTROL}`));
159
+ // By PATH, not by subpath: the control is deliberately not exported, and an
160
+ // ERR_PACKAGE_PATH_NOT_EXPORTED would prove nothing about peer resolution.
161
+ targets.push({ name: 'control', specifier: `./node_modules/cursedbelt/${CONTROL}` });
162
+
163
+ await Bun.write(
164
+ `${root}/entry.ts`,
165
+ `const targets = ${JSON.stringify(targets)};
166
+ const out = {};
167
+ for (const t of targets) {
168
+ try {
169
+ const mod = await import(t.specifier);
170
+ out[t.name] = { ok: true, keys: Object.keys(mod) };
171
+ } catch (error) {
172
+ out[t.name] = { ok: false, error: String((error && error.message) || error) };
173
+ }
174
+ }
175
+ console.log(JSON.stringify(out));
176
+ `,
177
+ );
178
+
179
+ const child = Bun.spawnSync(['bun', 'run', 'entry.ts'], {
180
+ cwd: root,
181
+ stdout: 'pipe',
182
+ stderr: 'pipe',
183
+ });
184
+ const stdout = child.stdout.toString().trim();
185
+ if (child.exitCode !== 0 || stdout === '') {
186
+ throw new Error(
187
+ `the fixture could not run at all (exit ${child.exitCode}) β€” that is a broken check, not a passing one:\n${child.stderr.toString()}`,
188
+ );
189
+ }
190
+ return JSON.parse(stdout) as Record<string, Outcome>;
191
+ };
192
+
193
+ /**
194
+ * The other half, and the one that caught the SECOND edge. A leaf can be clean while the
195
+ * barrel it was split out of still drags an optional peer, and a barrel is what most apps
196
+ * import β€” `music`, `family` and `roms` all take `cursedbelt/server/storage` whole.
197
+ *
198
+ * Measured by bundling the subpath's relative graph with every bare import left external
199
+ * and reading what remains. The subpaths listed must reach NO optional peer with a STATIC
200
+ * import: a static one is paid at import time by every consumer, which is the crash the
201
+ * task above is about; a `await import('sharp')` inside the function that needs it is
202
+ * exactly the right shape and stays legal here.
203
+ *
204
+ * Limitation, stated rather than hidden: the externals are read out of the bundle's import
205
+ * statements textually, so an import bun emits across several lines would be missed. That
206
+ * makes this half a floor, not a ceiling β€” the runtime fixture above is the strict one.
207
+ */
208
+ const NO_STATIC_OPTIONAL_PEERS = [
209
+ {
210
+ subpath: './server/storage',
211
+ /** Its `streamToken.ts` and (two hops out) `private-media/unlock.ts` both imported the
212
+ * `../auth` index for two jose functions, so `otplib` was static in here until 2.6.0. */
213
+ entry: 'src/server/storage/index.ts',
214
+ },
215
+ ] as const;
216
+
217
+ const OPTIONAL_PEERS = new Set(
218
+ Object.entries(
219
+ (pkg as { peerDependenciesMeta?: Record<string, { optional?: boolean }> })
220
+ .peerDependenciesMeta ?? {},
221
+ )
222
+ .filter(([, meta]) => meta?.optional === true)
223
+ .map(([name]) => name),
224
+ );
225
+
226
+ /** `import x from "pkg"`, `import "pkg"`, `export … from "pkg"` β€” one line each, as bun emits. */
227
+ const STATIC_SPECIFIER = /^(?:import|export)\s[^\n]*?["']([^"'\n]+)["'];?$|^import\s*["']([^"'\n]+)["'];?$/gm;
228
+
229
+ const staticOptionalPeersOf = (entry: string): string[] => {
230
+ const build = Bun.spawnSync(
231
+ ['bun', 'build', entry, '--target=bun', '--packages=external'],
232
+ { cwd: REPO, stdout: 'pipe', stderr: 'pipe' },
233
+ );
234
+ const bundle = build.stdout.toString();
235
+ if (build.exitCode !== 0 || bundle.trim() === '') {
236
+ throw new Error(
237
+ `could not bundle ${entry} (exit ${build.exitCode}) β€” a check that cannot measure is not a passing check:\n${build.stderr.toString()}`,
238
+ );
239
+ }
240
+ const found = new Set<string>();
241
+ for (const match of bundle.matchAll(STATIC_SPECIFIER)) {
242
+ const specifier = match[1] ?? match[2];
243
+ if (specifier === undefined || specifier.startsWith('.')) continue;
244
+ // `@scope/name/deep` β†’ `@scope/name`, `pkg/deep` β†’ `pkg`.
245
+ const parts = specifier.split('/');
246
+ const name = specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
247
+ if (name !== undefined && OPTIONAL_PEERS.has(name)) found.add(name);
248
+ }
249
+ return [...found].sort();
250
+ };
251
+
252
+ const outcomes = await run();
253
+
254
+ describe('leaf subpaths import nothing at runtime', () => {
255
+ it('has a fixture with no peers installed (negative control)', () => {
256
+ const control = outcomes.control;
257
+ expect(control, 'the control never ran β€” the fixture is not measuring anything').toBeDefined();
258
+ expect(
259
+ control?.ok === false,
260
+ `the fixture resolved 'otplib' β€” bun auto-installed it out of ~/.bun/install/cache, or a node_modules above the fixture answered. Every assertion below is vacuous until that is fixed; do not delete this test to make it pass.`,
261
+ ).toBe(true);
262
+ expect(
263
+ control?.ok === false ? control.error : '',
264
+ 'the control failed for the wrong reason β€” it must fail on the missing PACKAGE',
265
+ ).toContain("Cannot find package 'otplib'");
266
+ });
267
+
268
+ for (const leaf of LEAVES) {
269
+ it(`cursedbelt/${leaf.subpath.slice(2)} imports clean`, () => {
270
+ const outcome = outcomes[leaf.subpath];
271
+ expect(outcome, `${leaf.subpath} was never imported by the fixture`).toBeDefined();
272
+ expect(
273
+ outcome?.ok === true ? '' : outcome?.ok === false ? outcome.error : 'missing',
274
+ `cursedbelt/${leaf.subpath.slice(2)} must import NOTHING at runtime β€” that is the entire reason the subpath exists. Move whatever it now reaches behind \`import type\`, or split the leaf again; do not add the dependency to a consumer.`,
275
+ ).toBe('');
276
+ // Non-vacuity: a module that resolved but exported nothing would otherwise pass.
277
+ expect(
278
+ outcome?.ok === true ? outcome.keys : [],
279
+ `${leaf.subpath} resolved but does not export ${leaf.evaluates} β€” the check is pointing at the wrong file`,
280
+ ).toContain(leaf.evaluates);
281
+ });
282
+ }
283
+ });
284
+
285
+ describe('barrels reach no optional peer statically', () => {
286
+ it('knows which peers are optional', () => {
287
+ // Guards the assertions below: an empty set makes every one of them pass vacuously.
288
+ expect(OPTIONAL_PEERS.size, 'peerDependenciesMeta lists no optional peer').toBeGreaterThan(10);
289
+ expect([...OPTIONAL_PEERS], 'otplib is the peer this whole spec was written for').toContain(
290
+ 'otplib',
291
+ );
292
+ });
293
+
294
+ for (const target of NO_STATIC_OPTIONAL_PEERS) {
295
+ it(`cursedbelt/${target.subpath.slice(2)} costs a consumer no optional peer to import`, () => {
296
+ expect(
297
+ staticOptionalPeersOf(target.entry),
298
+ `importing cursedbelt/${target.subpath.slice(2)} statically pulls these OPTIONAL peers, so every consumer must install them for code it may never call. Either import the leaf module that has what you need instead of a sibling INDEX (that is how 'otplib' got in here twice), or make the dependency lazy: \`const { x } = await import('pkg')\` inside the function that needs it.`,
299
+ ).toEqual([]);
300
+ });
301
+ }
302
+ });
@@ -1,5 +1,10 @@
1
1
  import { decryptSecret, deriveKey, encryptSecret } from 'cwip/node';
2
- import { signToken, verifyPurposeToken } from '../auth';
2
+ // πŸ”΄ `../auth/jwt`, NOT `../auth` β€” same reason as `storage/streamToken.ts`, and this is the
3
+ // SECOND edge of the pair: `cursedbelt/server/storage` reaches private-media, so the barrel
4
+ // import here put `otplib` (via `auth/index` β†’ `totp.ts`) back into the storage graph after
5
+ // streamToken.ts had been fixed. Found by bundling the graph and reading the externals, not by
6
+ // grep β€” a two-hop edge is invisible to the obvious search.
7
+ import { signToken, verifyPurposeToken } from '../auth/jwt';
3
8
  import { derivePasswordSetKey, deriveServerSetKey, type KeyMode } from './crypto';
4
9
 
5
10
  // ── Unlock service ──────────────────────────────────────────────────────────────
@@ -1,4 +1,9 @@
1
- import type { MediaStore } from './types';
1
+ import type { BinaryServerConfig, MediaStore } from './types';
2
+
3
+ // The token shapes moved to `./types` (published as `cursedbelt/server/storage/types`) so an
4
+ // app can import the CLAIM SHAPE without importing this adapter's module graph. Re-exported
5
+ // here so every existing `from './binaryServerStore'` and the `./index` barrel keep resolving.
6
+ export type { BinaryServerConfig, FileTokenClaims, FileTokenSigner } from './types';
2
7
 
3
8
  // binary-server MediaStore adapter. binary-server (Bun/SQLite, RS256 token-gated, Range-capable)
4
9
  // is a production storage path: a home/edge file service the app signs short-lived tokens for.
@@ -9,50 +14,6 @@ import type { MediaStore } from './types';
9
14
  // public key). cursedbelt carries no key material and no asymmetric-crypto specifics; it just
10
15
  // calls `signFileToken` with the claims binary-server expects.
11
16
 
12
- /**
13
- * Claims binary-server verifies (see binary-server/src/tokens.ts). This is the ONE
14
- * canonical shape for a binary-server file token across the fleet: cursedbelt's
15
- * injected-signer `createBinaryServerStore` (below) and `@satellites/satellite-kit`'s
16
- * self-signing `createBinaryStore` both mint tokens against the SAME binary-server, so
17
- * the claim set must never drift β€” satellite-kit imports this exact type rather than
18
- * redeclaring it, so a token one side signs is always shaped for the other to read. The
19
- * app's signer turns these into an RS256 JWT.
20
- */
21
- export type FileTokenClaims = {
22
- /** Exact authorized path, app-prefixed: `<app>/<key>`. */
23
- k?: string;
24
- /** Authorized path prefix, app-prefixed (container trees, e.g. an HLS tree). */
25
- p?: string;
26
- /** Acting user/app id β€” audit trail on binary-server's events, never authz. */
27
- uid?: string;
28
- /** Chunk-session id (must match across every chunk of one upload). */
29
- sid?: string;
30
- /** Chunk index (0-based). */
31
- ci?: number;
32
- /** Total chunk count. */
33
- tc?: number;
34
- /** Download filename β†’ Content-Disposition. */
35
- fn?: string;
36
- dl?: 'inline' | 'attachment';
37
- /** Per-op scope. A DELETE against binary-server requires a token carrying `op: 'delete'`
38
- * (in addition to the internal secret) β€” a plain read/download token can never be replayed
39
- * as a delete, and the token's issuer + `k`/`p` tenant-scope the delete. Owner ruling #10. */
40
- op?: 'delete';
41
- };
42
-
43
- export type FileTokenSigner = (claims: FileTokenClaims) => Promise<string>;
44
-
45
- export type BinaryServerConfig = {
46
- /** e.g. 'https://binary-server.cursedalchemy.com'. */
47
- baseUrl: string;
48
- /** App namespace (path + token scope), e.g. 'cursedalchemy'. */
49
- appId: string;
50
- /** App-provided RS256 signer (app holds the private key). */
51
- signFileToken: FileTokenSigner;
52
- /** Shared secret for internal ops (delete). Sent as x-internal-secret. */
53
- internalSecret?: string;
54
- };
55
-
56
17
  export function createBinaryServerStore(cfg: BinaryServerConfig): MediaStore {
57
18
  const appKey = (key: string) => `${cfg.appId}/${key}`;
58
19
  const mediaUrl = async (key: string, extra?: { fn?: string; dl?: 'inline' | 'attachment' }) => {
@@ -1,4 +1,11 @@
1
- import { signToken, verifyPurposeToken } from '../auth';
1
+ // πŸ”΄ `../auth/jwt`, NOT `../auth`. The jose half is a REAL dependency β€” stream tokens are
2
+ // signed and verified here, and jose is a plain `dependencies` entry every consumer already
3
+ // installs. The BARREL was the accident: `../auth/index.ts` also reaches `totp.ts` β†’ `otplib`,
4
+ // an OPTIONAL peer, so every app that touched anything in `cursedbelt/server/storage` was made
5
+ // to install a one-time-password library for code it never calls. Import the leaf module that
6
+ // has what you need; never the index that has everything. `src/leafSubpathsImportNothing.spec.ts`
7
+ // fails if this file (or anything else the storage barrel reaches) undoes it.
8
+ import { signToken, verifyPurposeToken } from '../auth/jwt';
2
9
 
3
10
  // ── Stream tokens ───────────────────────────────────────────────────────────────
4
11
  // Media bytes are loaded by <video>/hls.js/<img>, which cannot send the platform Bearer
@@ -5,6 +5,17 @@
5
5
  // with no Bearer can still be authorized), a source registry, and the ingestβ†’derivatives
6
6
  // pipeline glue. Ported/generalised from ca's proven media stack; the app maps its own records
7
7
  // to a MediaSource. Pairs with the `PlayableVideo` contract in `cursedbelt/media-core`.
8
+ //
9
+ // πŸ”΄ THIS FILE IS A PUBLISHED LEAF β€” `cursedbelt/server/storage/types` β€” AND IT MUST STAY
10
+ // IMPORT-FREE AT RUNTIME. `src/leafSubpathsImportNothing.spec.ts` imports it in a fixture with
11
+ // no packages resolvable at all and fails if it throws, so an `import` here that survives
12
+ // transpilation (anything that is not `import type`) turns that spec red rather than turning
13
+ // up in a consumer's install. The subpath exists because `./server/storage`'s own index is a
14
+ // barrel: it reaches `streamToken` β†’ `auth/jwt` β†’ jose, the whole SQLite file catalogue under
15
+ // `files/`, and a lazily-imported `sharp` β€” while an app that wants only the SHAPE of a file
16
+ // token (apps/collections wanted exactly `FileTokenClaims`, a type TypeScript erases) was made
17
+ // to install a one-time-password library to get it. Add types here freely; add a value import
18
+ // here never.
8
19
 
9
20
  import type { ProcessingStatus } from '../../core/media';
10
21
 
@@ -54,6 +65,56 @@ export interface MediaStore {
54
65
  redirectUrl?(key: string, opts: { mime: string; filename?: string }): Promise<string | null>;
55
66
  }
56
67
 
68
+ // ── binary-server file tokens ─────────────────────────────────────────────────────
69
+ // Declared HERE rather than beside the adapter that uses them (`binaryServerStore.ts`, which
70
+ // re-exports them for compatibility) because these three are the shapes a consumer needs
71
+ // WITHOUT the adapter: apps/collections' `binaryStore.ts` mints its own tokens and imports
72
+ // `FileTokenClaims` alone.
73
+
74
+ /**
75
+ * Claims binary-server verifies (see binary-server/src/tokens.ts). This is the ONE
76
+ * canonical shape for a binary-server file token across the fleet: cursedbelt's
77
+ * injected-signer `createBinaryServerStore` and `@satellites/satellite-kit`'s
78
+ * self-signing `createBinaryStore` both mint tokens against the SAME binary-server, so
79
+ * the claim set must never drift β€” satellite-kit imports this exact type rather than
80
+ * redeclaring it, so a token one side signs is always shaped for the other to read. The
81
+ * app's signer turns these into an RS256 JWT.
82
+ */
83
+ export type FileTokenClaims = {
84
+ /** Exact authorized path, app-prefixed: `<app>/<key>`. */
85
+ k?: string;
86
+ /** Authorized path prefix, app-prefixed (container trees, e.g. an HLS tree). */
87
+ p?: string;
88
+ /** Acting user/app id β€” audit trail on binary-server's events, never authz. */
89
+ uid?: string;
90
+ /** Chunk-session id (must match across every chunk of one upload). */
91
+ sid?: string;
92
+ /** Chunk index (0-based). */
93
+ ci?: number;
94
+ /** Total chunk count. */
95
+ tc?: number;
96
+ /** Download filename β†’ Content-Disposition. */
97
+ fn?: string;
98
+ dl?: 'inline' | 'attachment';
99
+ /** Per-op scope. A DELETE against binary-server requires a token carrying `op: 'delete'`
100
+ * (in addition to the internal secret) β€” a plain read/download token can never be replayed
101
+ * as a delete, and the token's issuer + `k`/`p` tenant-scope the delete. Owner ruling #10. */
102
+ op?: 'delete';
103
+ };
104
+
105
+ export type FileTokenSigner = (claims: FileTokenClaims) => Promise<string>;
106
+
107
+ export type BinaryServerConfig = {
108
+ /** e.g. 'https://binary-server.cursedalchemy.com'. */
109
+ baseUrl: string;
110
+ /** App namespace (path + token scope), e.g. 'cursedalchemy'. */
111
+ appId: string;
112
+ /** App-provided RS256 signer (app holds the private key). */
113
+ signFileToken: FileTokenSigner;
114
+ /** Shared secret for internal ops (delete). Sent as x-internal-secret. */
115
+ internalSecret?: string;
116
+ };
117
+
57
118
  /** A source of videos for a gallery/catalogue. Apps implement this differently (a disk folder,
58
119
  * a binary-server app, ca's Files tree + private set). Consumers are source-agnostic. */
59
120
  export interface MediaSource {