diff --git a/packages/cli-server/src/audit/query-action-family/protobuf-codec.test.ts b/packages/cli-server/src/audit/query-action-family/protobuf-codec.test.ts index ed8cb1e6..ef70ee68 100644 --- a/packages/cli-server/src/audit/query-action-family/protobuf-codec.test.ts +++ b/packages/cli-server/src/audit/query-action-family/protobuf-codec.test.ts @@ -671,13 +671,15 @@ describe("query action protobuf codec", () => { type: "prepare_validate_query", }; const canonicalBytes = encodeQueryActionEffectPayload(effect); - const bytesWithUnknownField = Buffer.concat([ - canonicalBytes, + const bytesWithUnknownField = Buffer.from([ + ...canonicalBytes, // Unknown top-level varint field 99. Domain conversion ignores it. - Buffer.from([0x98, 0x06, 0x7b]), + 0x98, + 0x06, + 0x7b, ]); - expect(bytesWithUnknownField.equals(canonicalBytes)).toBe(false); + expect([...bytesWithUnknownField]).not.toEqual([...canonicalBytes]); expect( expectOk( decodeQueryActionEffectPayload( diff --git a/packages/cli-server/src/audit/source-api-action-family/protobuf-codec.test.ts b/packages/cli-server/src/audit/source-api-action-family/protobuf-codec.test.ts index e0df7d10..2a0af45b 100644 --- a/packages/cli-server/src/audit/source-api-action-family/protobuf-codec.test.ts +++ b/packages/cli-server/src/audit/source-api-action-family/protobuf-codec.test.ts @@ -701,13 +701,15 @@ describe("source api action protobuf codec", () => { type: "load_source", }; const canonicalBytes = encodeSourceApiActionEffectPayload(effect); - const bytesWithUnknownField = Buffer.concat([ - canonicalBytes, + const bytesWithUnknownField = Buffer.from([ + ...canonicalBytes, // Unknown top-level varint field 99. Domain conversion ignores it. - Buffer.from([0x98, 0x06, 0x7b]), + 0x98, + 0x06, + 0x7b, ]); - expect(bytesWithUnknownField.equals(canonicalBytes)).toBe(false); + expect([...bytesWithUnknownField]).not.toEqual([...canonicalBytes]); expect( expectOk( decodeSourceApiActionEffectPayload( diff --git a/packages/cli-server/src/audit/storage/protobuf-codec.ts b/packages/cli-server/src/audit/storage/protobuf-codec.ts index c03bf12b..ca02bd66 100644 --- a/packages/cli-server/src/audit/storage/protobuf-codec.ts +++ b/packages/cli-server/src/audit/storage/protobuf-codec.ts @@ -51,7 +51,7 @@ export function decodeWorkflowPayload( ): ResultType, WorkflowStorageCorruptRowError> { let decoded: MessageShape; try { - decoded = fromBinary(schema, bytes); + decoded = fromBinary(schema, Uint8Array.from(bytes)); } catch (cause: unknown) { return Result.err(corruptPayloadError({ ...context, cause })); } diff --git a/packages/db/src/pglite.ts b/packages/db/src/pglite.ts index c0e67ee4..9704664a 100644 --- a/packages/db/src/pglite.ts +++ b/packages/db/src/pglite.ts @@ -103,11 +103,15 @@ export function resolvePgliteRuntimeOptions( const fsBundlePath = resolve(assetDir, PGLITE_DATA_FILENAME); const options = { - fsBundle: new Blob([readFileSync(fsBundlePath)]), - initdbWasmModule: new WebAssembly.Module(readFileSync(initdbWasmPath)), + fsBundle: new Blob([readArrayBufferBackedFile(fsBundlePath)]), + initdbWasmModule: new WebAssembly.Module( + readArrayBufferBackedFile(initdbWasmPath) + ), // Comment: the packaged server runtime loads PGlite's wasm assets from the // staged runtime directory instead of relying on module-relative URLs. - pgliteWasmModule: new WebAssembly.Module(readFileSync(pgliteWasmPath)), + pgliteWasmModule: new WebAssembly.Module( + readArrayBufferBackedFile(pgliteWasmPath) + ), } satisfies PGliteRuntimeOptions; cachedAssetDir = assetDir; @@ -115,6 +119,13 @@ export function resolvePgliteRuntimeOptions( return options; } +function readArrayBufferBackedFile(path: string): Uint8Array { + const fileBytes = readFileSync(path); + const bytes = new Uint8Array(fileBytes.byteLength); + bytes.set(fileBytes); + return bytes; +} + export function resolvePgliteAssetDir( processEnv: RuntimeAssetEnvironment = process.env ): string { diff --git a/packages/server/src/audit/feed.test.ts b/packages/server/src/audit/feed.test.ts index d687c984..5766b79d 100644 --- a/packages/server/src/audit/feed.test.ts +++ b/packages/server/src/audit/feed.test.ts @@ -60,9 +60,9 @@ describe("audit feed projection", { timeout: 60_000 }, () => { id: commandId, occurredAt: new Date("2026-04-26T00:00:00.000Z"), organizationId: "org_audit_feed_corrupt_payload", - payloadBytes: Buffer.concat([ - Buffer.from([0xff]), - Buffer.from(rawCommandBody), + payloadBytes: Buffer.from([ + 0xff, + ...new TextEncoder().encode(rawCommandBody), ]), payloadType: "start_execute", requestId: "request_audit_feed_corrupt_payload", diff --git a/packages/server/src/audit/feed/detail.ts b/packages/server/src/audit/feed/detail.ts index 4c16d11e..3d0d6720 100644 --- a/packages/server/src/audit/feed/detail.ts +++ b/packages/server/src/audit/feed/detail.ts @@ -8,6 +8,7 @@ import type { AuditActionDetail, AuditFamily, } from "@onequery/audit-contracts/audit"; +import { base64ToBytes } from "@onequery/codecs/base64"; import { and, asc, @@ -46,22 +47,24 @@ type CommandDecision = rejectDetail: string | null; }; -function serializeBytes(bytes: Buffer | Uint8Array) { - const buffer = Buffer.from(bytes); +const utf8Decoder = new TextDecoder(); + +function serializeBytes(bytes: ArrayLike) { + const normalizedBytes = Uint8Array.from(bytes); return { - base64: buffer.toString("base64"), - byteLength: buffer.byteLength, + base64: base64ToBytes.encode(normalizedBytes), + byteLength: normalizedBytes.byteLength, }; } function decodeJsonPayload( schema: Schema, - bytes: Buffer | Uint8Array + bytes: ArrayLike ): JsonValue { const decoded = decodeValidatedAuditFeedPayload( schema, - Buffer.from(bytes) + bytes ) as MessageShape; return toJson(schema, decoded); } @@ -111,7 +114,7 @@ function decodeJsonCheckpointPayload(input: { payloadBytes: Buffer | Uint8Array; }): unknown { try { - return JSON.parse(Buffer.from(input.payloadBytes).toString("utf8")); + return JSON.parse(utf8Decoder.decode(Uint8Array.from(input.payloadBytes))); } catch (error: unknown) { const message = error instanceof Error ? error.message : String(error); throw new Error(`${input.label} has invalid JSON payload: ${message}`, { diff --git a/packages/server/src/audit/feed/workflow-payload-codec.ts b/packages/server/src/audit/feed/workflow-payload-codec.ts index 9523587a..ed6e8e9e 100644 --- a/packages/server/src/audit/feed/workflow-payload-codec.ts +++ b/packages/server/src/audit/feed/workflow-payload-codec.ts @@ -19,9 +19,9 @@ const auditFeedPayloadValidator = createValidator(); export function decodeValidatedAuditFeedPayload( schema: Schema, - bytes: Buffer + bytes: ArrayLike ): MessageShape { - const decoded = fromBinary(schema, bytes); + const decoded = fromBinary(schema, Uint8Array.from(bytes)); const validation = auditFeedPayloadValidator.validate(schema, decoded); if (validation.kind !== "valid") { throw validation.error; diff --git a/packages/server/src/source-api/helpers/continuation-token.ts b/packages/server/src/source-api/helpers/continuation-token.ts index fb3210a8..06918e53 100644 --- a/packages/server/src/source-api/helpers/continuation-token.ts +++ b/packages/server/src/source-api/helpers/continuation-token.ts @@ -138,8 +138,8 @@ function readSignedTokenParts(token: string): { } function hasMatchingSignature(signature: string, expectedSignature: string) { - const receivedBytes = Buffer.from(signature, "utf8"); - const expectedBytes = Buffer.from(expectedSignature, "utf8"); + const receivedBytes = new TextEncoder().encode(signature); + const expectedBytes = new TextEncoder().encode(expectedSignature); if (receivedBytes.length !== expectedBytes.length) { return false; }