( delta: Record<string, string>, )
| 424 | * is above our soft cap but below the gateway's observed real threshold). |
| 425 | */ |
| 426 | export function batchDeltaByBytes( |
| 427 | delta: Record<string, string>, |
| 428 | ): Array<Record<string, string>> { |
| 429 | const keys = Object.keys(delta).sort() |
| 430 | if (keys.length === 0) return [] |
| 431 | |
| 432 | // Fixed overhead for `{"entries":{}}` — each entry then adds its marginal |
| 433 | // bytes. jsonStringify (≡ JSON.stringify under the hood) on the raw |
| 434 | // strings handles escaping so the count matches what axios serializes. |
| 435 | const EMPTY_BODY_BYTES = Buffer.byteLength('{"entries":{}}', 'utf8') |
| 436 | const entryBytes = (k: string, v: string): number => |
| 437 | Buffer.byteLength(jsonStringify(k), 'utf8') + |
| 438 | Buffer.byteLength(jsonStringify(v), 'utf8') + |
| 439 | 2 // colon + comma (comma over-counts by 1 on the last entry; harmless slack) |
| 440 | |
| 441 | const batches: Array<Record<string, string>> = [] |
| 442 | let current: Record<string, string> = {} |
| 443 | let currentBytes = EMPTY_BODY_BYTES |
| 444 | |
| 445 | for (const key of keys) { |
| 446 | const added = entryBytes(key, delta[key]!) |
| 447 | if ( |
| 448 | currentBytes + added > MAX_PUT_BODY_BYTES && |
| 449 | Object.keys(current).length > 0 |
| 450 | ) { |
| 451 | batches.push(current) |
| 452 | current = {} |
| 453 | currentBytes = EMPTY_BODY_BYTES |
| 454 | } |
| 455 | current[key] = delta[key]! |
| 456 | currentBytes += added |
| 457 | } |
| 458 | batches.push(current) |
| 459 | return batches |
| 460 | } |
| 461 | |
| 462 | async function uploadTeamMemory( |
| 463 | state: SyncState, |
no test coverage detected