| 90 | * Serializes an envelope. |
| 91 | */ |
| 92 | export function serializeEnvelope(envelope: Envelope): string | Uint8Array { |
| 93 | const [envHeaders, items] = envelope; |
| 94 | // Initially we construct our envelope as a string and only convert to binary chunks if we encounter binary data |
| 95 | let parts: string | Uint8Array[] = JSON.stringify(envHeaders); |
| 96 | |
| 97 | function append(next: string | Uint8Array): void { |
| 98 | if (typeof parts === 'string') { |
| 99 | parts = typeof next === 'string' ? parts + next : [encodeUTF8(parts), next]; |
| 100 | } else { |
| 101 | parts.push(typeof next === 'string' ? encodeUTF8(next) : next); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | for (const item of items) { |
| 106 | const [itemHeaders, payload] = item; |
| 107 | |
| 108 | append(`\n${JSON.stringify(itemHeaders)}\n`); |
| 109 | |
| 110 | if (typeof payload === 'string' || payload instanceof Uint8Array) { |
| 111 | append(payload); |
| 112 | } else { |
| 113 | let stringifiedPayload: string; |
| 114 | try { |
| 115 | stringifiedPayload = JSON.stringify(payload); |
| 116 | } catch { |
| 117 | // In case, despite all our efforts to keep `payload` circular-dependency-free, `JSON.stringify()` still |
| 118 | // fails, we try again after normalizing it again with infinite normalization depth. This of course has a |
| 119 | // performance impact but in this case a performance hit is better than throwing. |
| 120 | stringifiedPayload = JSON.stringify(normalize(payload)); |
| 121 | } |
| 122 | append(stringifiedPayload); |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | return typeof parts === 'string' ? parts : concatBuffers(parts); |
| 127 | } |
| 128 | |
| 129 | function concatBuffers(buffers: Uint8Array[]): Uint8Array { |
| 130 | const totalLength = buffers.reduce((acc, buf) => acc + buf.length, 0); |