Parcel is a browser HTTP client for SwiftWASM that wraps the browser Fetch API with typed request and response codecs.
Parcel exposes:
ClientClientConfigurationClient.RequestClient.ResponseClient.CodecBodyCodecJSONBodyCodecFormURLEncodedBodyCodecPlainTextBodyCodecRawDataBodyCodecHTTPBodyswift-http-typesmessage-head types used directly by Parcel's public API, includingHTTPField,HTTPFields,HTTPRequest, andHTTPResponseTransportResponseEmptyResponseTransportBrowserTransportonwasm32builds that include Parcel's browser transportClientError
Client.send(_:, as:codec:timeout:)is Parcel's single typed request entry point.Client.raw(_:, body:timeout:)is Parcel's raw escape hatch for directHTTPRequestexecution.Client.Requestmodels typed requests through an explicit method, URL, headers, and optional typed body.Client.Requestprovides convenience factories forget,head,delete,post,put, andpatch.Client.Response<Value>preserves the decoded value, response head, and final response URL.HTTPBodyis Parcel's async byte-stream abstraction for request and response bodies, with optional known length, iteration behavior, and helper collection APIs.HTTPBody.collect(upTo:)andHTTPBody.text(upTo:)default to a 2 MiB in-memory collection limit; callers can raise that limit or opt into.maxexplicitly.Client.raw(_:, body:timeout:)appends configured default header fields without auto-injecting codec-specific request headers.- Raw request and response bodies travel separately from
swift-http-typesheads asHTTPBody?. - Typed request bodies are encoded with the selected
Client.Codecand wrapped inHTTPBody. - Typed response bodies are decoded by collecting the response
HTTPBodyup tomaximumBufferedBodyBytesand passing the resulting bytes through the selectedClient.Codec. Client.Codecwraps aBodyCodecplus optional defaultContent-TypeandAcceptheader values for typed requests.Client.Codecprovides convenience factories for JSON, form URL-encoded, plain-text, raw-data, and custom body coding.ClientConfigurationalso carries an optionaldefaultTimeout, which defaults to 90 seconds and is used whenever a per-call timeout is omitted.ClientConfigurationalso carriesmaximumBufferedBodyBytes, which defaults to 2 MiB and is used when Parcel must buffer response bytes in memory for decoding or error reporting.ClientConfigurationcarries a defaultClient.Codec;Client.Codec.json()is the default implementation.- Typed requests append the selected codec's
Acceptheader values only when the merged client-default and per-request headers do not already provideAccept. - Typed requests append the selected codec's
Content-Typeheader only when Parcel encodes the request body and the merged client-default and per-request headers do not already provideContent-Type. - Parcel uses
swift-http-typesfor HTTP method, status, request-head, response-head, and header field semantics instead of maintaining custom protocol primitives. HTTPFieldspreserves repeated header values and resolves lookups case-insensitively according toswift-http-types.- Configured default header fields are appended ahead of per-call header fields without custom override logic.
- Typed
Client.sendthrowsClientError.unsuccessfulStatusCodefor non-2xx responses before decoding. - Empty successful responses can be decoded as
EmptyResponse. JSONBodyCodecallows callers to supply customJSONEncoder/JSONDecoderfactories.FormURLEncodedBodyCodecsupports flat top-level keyed payloads and repeated keys for array values, but does not support nested keyed containers.PlainTextBodyCodecencodes and decodes UTF-8Stringvalues.RawDataBodyCodecencodes and decodes rawDatavalues.- Successful typed responses preserve the final response
URL?onClient.Response, but typed decoding consumes the response body and does not preserve raw response bytes afterward. - Browser response-body promise rejections from streamed byte reads surface as
ClientError.responseBodyFailure, preserving JavaScript error metadata with the.bytesoperation. - Browser request or response-body cancellation throws
CancellationError. - Browser request and response-body timeouts throw
ClientError.timedOut.
- Core request/response logic is transport-driven via
Transport. Transport.send(_:, body:timeout:)returnsTransportResponse, which contains a rawHTTPResponse, an optionalHTTPBody, and the final responseURL?, regardless of the HTTP status code.Client(configuration:)is only available onwasm32builds that include Parcel's browser transport dependencies; host builds must inject an explicitTransport.BrowserTransportis only exposed onwasm32builds with Parcel's browser transport dependencies available.- The default transport is
BrowserTransportonly onwasm32builds with a browser-capable JavaScript runtime. BrowserTransportuses the browserfetchAPI.BrowserTransport.isSupportedRuntimeaccepts both window and worker-style JavaScript global scopes whenfetch,AbortController,Object, andUint8Arrayare available.BrowserTransportinstalls JavaScriptKit's global event-loop executor when initialized in a supported runtime.BrowserTransportaccepts an optional per-request timeout and enforces it withAbortControllerplussetTimeout.BrowserTransportpasses outgoing headers tofetchas an ordered header-entry list so repeated field names preserve their semantics instead of collapsing to the last value.- Because typed decoding collects response bytes from
HTTPBody, the generic client decode path handles empty-response and malformed-payload behavior consistently for browser requests regardless of the configured codec. - Raw transport responses remain available as
HTTPBody?, which may be single-iteration depending on the transport. BrowserTransportbinds JavaScript instance method calls through JavaScriptKit member-call helpers so browser methods receive the correctthisvalue.BrowserTransportthreads anAbortControllersignal throughfetchand response-body reads so Swift task cancellation aborts the browser request and body consumption.BrowserTransportexposes response bodies lazily as single-iterationHTTPBodyvalues backed byReadableStream.getReader().BrowserTransportpreservesResponse.body == nullasTransportResponse.body == nil.BrowserTransportcancels abandonedReadableStreamreaders when a streamed response body is dropped before it reaches end-of-stream.BrowserTransportcurrently buffers outgoing request bodies before passing them tofetch; streaming uploads are not yet exposed, and the buffer is capped bymaximumBufferedRequestBodyBytes(2 MiB by default).BrowserTransportdoes not retain temporaryJSClosurebridges beyond synchronous JavaScript header iteration, using explicit release on JavaScriptKit no-weakrefs builds.ClientError.unsupportedPlatformremains reserved forwasm32builds where Parcel can compile but no browser-capable JavaScript runtime is available.
Parcel follows the same broad validation split as JavaScriptKit:
- A host build lane verifies that Parcel compiles natively without Wasm-only browser tests.
- Swift formatting is part of validation and runs through the repository formatter script.
- Wasm/JS tests are the primary runtime validation lane for
BrowserTransport. - Host-side tests validate core
Clientbehavior using injected mock transports. - The Wasm-only browser test target is only included when the Wasm validation script opts into it, so host
swift testruns stay native-only. - Full test validation runs the Wasm lane first, then the host lane.
- The host build and host test lanes set
PARCEL_INCLUDE_WASM_TESTS=0. - The Wasm lane sets
PARCEL_INCLUDE_WASM_TESTS=1and usesswift package --swift-sdk ... js test. - Wasm tests run in Node with the repository prelude in
Tests/prelude.mjs, which provides a deterministicfetchshim for browser-oriented transport tests. - By default, the Wasm lane expects the
swift-6.2.4-RELEASE_wasmSDK; override that withPARCEL_SWIFT_SDKwhen needed.
Run the host build lane with:
./skills/swift-build/scripts/run-swift-build.shRun the formatter with:
./skills/swift-format/scripts/run-swift-format.shRun the full test flow with:
./skills/swift-test/scripts/run-swift-tests.shRun only the Wasm test lane with:
./skills/swift-test/scripts/run-wasm-tests.shRun only the host test lane with:
./skills/swift-test/scripts/run-host-tests.sh