refactor(mobile-web): drop a test cast and shape-named field maps

The bomb test's inflation log is typed by its hoisted factory's return
instead of an assertion, and the zod field maps shared by the bundle
window schemas are windowParamsFields and windowHeaderFields.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo-H
2026-09-23 00:47:55 -04:00
parent c6e3eb2a3c
commit f4f0915e70
3 changed files with 11 additions and 12 deletions
@@ -12,12 +12,11 @@ import type { RpcClient } from './rpc-client'
import type { RpcResponse } from './types'
type Inflation = { readonly outLength: number; readonly resultLength: number }
type LoggedInflation = Inflation & { readonly body: Uint8Array }
/** Every inflation in the process, keyed by the gzip body it was handed; a host reads back only
* the bodies it sent, so a read left running by an earlier test's fetch never lands in its sink. */
const inflationLog = vi.hoisted(
() => [] as { body: Uint8Array; outLength: number; resultLength: number }[]
)
const inflationLog = vi.hoisted((): LoggedInflation[] => [])
// Observes the bound the decoder hands fflate, and what fflate hands back inside it.
vi.mock('fflate', async (importOriginal) => {
@@ -130,7 +130,7 @@ export const MobileWebBundleManifestReplySchema = z.looseObject({
/** Self-describing on purpose: `buildId`, `path` and `offset` are echoed so a reassembler cannot
* misplace a reply, and `sha256`/`assetByteLength` describe the whole asset rather than this
* window, which is what lets the fetch verify without a second index. Shared by both read replies. */
const windowHeaderShape = {
const windowHeaderFields = {
buildId: z.string().regex(SHA256_PATTERN),
path: MobileWebBundleAssetPathSchema,
offset: z.number().int().nonnegative().max(MOBILE_WEB_BUNDLE_MAX_ASSET_BYTES),
@@ -140,7 +140,7 @@ const windowHeaderShape = {
}
export const MobileWebBundleChunkReplySchema = z.looseObject({
...windowHeaderShape,
...windowHeaderFields,
dataBase64: z.string().max(MAX_DATA_BASE64_LENGTH)
})
@@ -148,7 +148,7 @@ export const MobileWebBundleChunkReplySchema = z.looseObject({
* enum: an encoding this build cannot decode is a typed refusal at the decoder, which names it,
* rather than a reply-shape failure that names nothing. */
export const MobileWebBundleRangeReplySchema = z.looseObject({
...windowHeaderShape,
...windowHeaderFields,
encoding: z.string().min(1).max(32),
dataBase64: z.string().max(MOBILE_WEB_BUNDLE_RANGE_MAX_DATA_BASE64_LENGTH)
})
@@ -64,7 +64,7 @@ export const MobileWebBundleManifestResultSchema = z
})
.strict()
const windowParamsShape = {
const windowParamsFields = {
buildId: z.string().regex(SHA256_PATTERN),
path: MobileWebBundleAssetPathSchema,
offset: z.number().int().nonnegative().max(MOBILE_WEB_BUNDLE_MAX_ASSET_BYTES)
@@ -72,14 +72,14 @@ const windowParamsShape = {
/** No `multipleOf` pin on `offset`: alignment is against the host's advertised `chunkBytes`, which
* may be smaller than the constant, so the host rejects a misaligned offset instead. */
export const MobileWebBundleChunkParamsSchema = z.object(windowParamsShape).strict()
export const MobileWebBundleChunkParamsSchema = z.object(windowParamsFields).strict()
/** The chunk params exactly, on the `rangeBytes` grid the manifest reply advertised. */
export const MobileWebBundleRangeParamsSchema = MobileWebBundleChunkParamsSchema
/** What every chunk or range reply restates about the window it answers. */
const windowHeaderShape = {
...windowParamsShape,
const windowHeaderFields = {
...windowParamsFields,
/** The whole asset, not this window: named for it so a reassembler cannot misread the two, and
* paired with `sha256` it describes the asset without a second index. */
assetByteLength: z.number().int().nonnegative().max(MOBILE_WEB_BUNDLE_MAX_ASSET_BYTES),
@@ -90,14 +90,14 @@ const windowHeaderShape = {
/** Strict, so a later `contentEncoding` is only a Rule 1 optional-field addition for clients whose
* own reply readers are not strict. */
export const MobileWebBundleChunkResultSchema = z
.object({ ...windowHeaderShape, dataBase64: z.string().max(MAX_DATA_BASE64_LENGTH) })
.object({ ...windowHeaderFields, dataBase64: z.string().max(MAX_DATA_BASE64_LENGTH) })
.strict()
/** A chunk result plus the encoding of `dataBase64`, whose decoded length is
* `min(rangeBytes, assetByteLength - offset)`. */
export const MobileWebBundleRangeResultSchema = z
.object({
...windowHeaderShape,
...windowHeaderFields,
encoding: z.enum(MOBILE_WEB_BUNDLE_RANGE_ENCODINGS),
dataBase64: z.string().max(MOBILE_WEB_BUNDLE_RANGE_MAX_DATA_BASE64_LENGTH)
})