cultmesh-ts/content: decide a blank recordKey with C1's IsNullOrWhiteSpace owner

cultnet-ts/content re-exports isNullOrWhiteSpaceCSharp; the provider uses it
instead of key.trim(), which disagreed with C# on U+FEFF and U+0085.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-19 18:21:51 +02:00
commit 2ab66c8922
2 changed files with 5 additions and 2 deletions

View file

@ -2,7 +2,7 @@ import { constants } from "node:fs";
import { open } from "node:fs/promises";
import type { IncomingMessage, ServerResponse } from "node:http";
import { join } from "node:path";
import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, parseSha256Hex, sha256Hex } from "cultnet-ts/content";
import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, isNullOrWhiteSpaceCSharp, parseSha256Hex, sha256Hex } from "cultnet-ts/content";
/** What the provider reads of a request. The path and the headers are never read: the route is the query alone. */
export interface ContentChunkRequest { method: string; url: string; }
@ -63,7 +63,7 @@ export function createContentChunkHandler(store: ContentChunkStore, options: Con
const [hash, ...otherHashes] = query.getAll("chunkHash");
const [key = "", ...otherKeys] = query.getAll("recordKey");
hex = parseSha256Hex(hash ?? "");
if (otherHashes.length || otherKeys.length || (key.trim() !== "" && key !== chunkRecordKey(hex))) return refusal(400);
if (otherHashes.length || otherKeys.length || (!isNullOrWhiteSpaceCSharp(key) && key !== chunkRecordKey(hex))) return refusal(400);
} catch { return refusal(400); }
if (hex === EMPTY_SHA256) return chunkAnswer(new Uint8Array());
let bytes: Uint8Array | undefined;

View file

@ -12,6 +12,9 @@ import { checkPayloadDepth } from "@gamecult/cultcache-ts/document";
import { isNullOrWhiteSpaceCSharp, trimCSharp } from "./cultmesh-authority";
import { wellFormed } from "./utf8-bound";
/** C#'s `string.IsNullOrWhiteSpace`, the one blank rule every consumer of the content shapes shares. */
export { isNullOrWhiteSpaceCSharp };
export const CULTMESH_CDN_MANIFEST_SCHEMA = "gamecult.mesh.cdn_artifact_manifest.v1";
export const DEFAULT_CHUNK_SIZE_BYTES = 4 * 1024 * 1024;
export const EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";