You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The HTTP recorder is a public testing library for recording real Effect transport traffic into deterministic cassettes and replaying it without contacting the upstream service.
4
+
5
+
## Language
6
+
7
+
**Library Version**:
8
+
The independently managed semantic version of `@opencode-ai/http-recorder` published to npm.
9
+
_Avoid_: OpenCode version
10
+
11
+
**OpenCode Release Version**:
12
+
The version applied to OpenCode applications and packages by the repository-wide release process. It does not determine the **Library Version**.
13
+
14
+
**Effect Compatibility Version**:
15
+
The exact Effect 4 beta against which the package's unstable HTTP and socket integrations are built and verified.
16
+
17
+
**Provider Conversation**:
18
+
A finite WebSocket connection in which either peer may send first, the client sends one or more JSON commands, server frames follow in causal order, and the application closes after a terminal event.
19
+
20
+
**Connection Identity**:
21
+
The explicit cassette name supplied to the WebSocket recorder. It identifies the recorded conversation during replay.
22
+
23
+
**Completed Conversation**:
24
+
A WebSocket socket run that opened and finished successfully after recording a valid finite transcript.
25
+
26
+
**Client Frame Match**:
27
+
The replay check that requires an outgoing application frame to equal the next recorded client frame after redaction. Text JSON ignores object-key order; other text and binary frames match exactly.
28
+
29
+
## Relationships
30
+
31
+
- The **Library Version** begins with the public beta at `0.1.0` and advances independently through Changesets.
32
+
- Repository-wide OpenCode release synchronization must not rewrite the **Library Version**.
33
+
- The initial **Effect Compatibility Version** is `4.0.0-beta.83`; compatibility with later Effect betas is not implied.
34
+
- Changing the **Effect Compatibility Version** requires a new **Library Version** and clean-consumer package verification.
35
+
- A **Provider Conversation** is the canonical WebSocket scenario for evaluating the public beta contract; arbitrary socket emulation is not implied.
36
+
- Application code owns WebSocket construction, including URL, protocols, timeout, authentication, and close policy; the recorder decorates the resulting Effect `Socket.Socket` service.
37
+
-**Connection Identity**, not the live WebSocket destination, selects and validates a replay. The beta does not validate URL or handshake configuration during replay.
38
+
- Only a **Completed Conversation** is committed to a cassette; failed, interrupted, unopened, or invalid runs do not produce a recording.
39
+
- Replay requires every recorded frame to be consumed before application close.
40
+
- Terminal close codes, close reasons, connection timing, and transport failures are not cassette events in the first public beta.
41
+
- Every outgoing replay frame must satisfy the **Client Frame Match** before later server frames are released.
42
+
- The first public beta does not expose a custom WebSocket frame matcher.
43
+
- Replay starts incoming frame handlers in recorded order and may run them concurrently; it waits for every handler before the socket run completes but does not guarantee handler completion order.
Copy file name to clipboardExpand all lines: packages/http-recorder/README.md
+36-17Lines changed: 36 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,13 +9,13 @@ Use it for provider integrations, retries, polling, multi-step flows, and any te
9
9
## Install
10
10
11
11
```sh
12
-
bun add effect@4.0.0-beta.74
12
+
bun add effect@4.0.0-beta.83 @effect/platform-node@4.0.0-beta.83
13
13
bun add -d @opencode-ai/http-recorder@beta @effect/vitest vitest
14
14
```
15
15
16
16
The package supports Node.js 22+ and Bun. It is not intended for browsers, workers, or Deno.
17
17
18
-
Effect `4.0.0-beta.74` has a known declaration error (`SchemaErrorTypeId` is missing). Until that upstream declaration is fixed, TypeScript consumers need:
18
+
Effect `4.0.0-beta.83` currently contains unresolved symbols in its published declarations. Until those upstream declarations are fixed, TypeScript consumers need:
19
19
20
20
```json
21
21
{
@@ -89,41 +89,58 @@ That is the complete public API. `http` provides a fetch-backed recorded `HttpCl
89
89
90
90
## WebSockets
91
91
92
-
WebSocket cassettes preserve one ordered transcript of client and server text or binary frames. Replay follows that chronology: server frames are released until the next recorded client frame, then replay waits for the application to send the matching frame before continuing.
92
+
Effect models a WebSocket as a `Socket.Socket` service. A program obtains a scoped `writer` for outgoing frames and runs one receive loop for the lifetime of a connection. The application supplies the live URL-bound socket; the recorder decorates that service without owning its URL, protocols, authentication, timeout, or close policy.
93
+
94
+
The cassette name is the connection identity during replay. Replay does not validate the live URL or handshake configuration.
it.effect("completes a provider conversation", () =>conversation.pipe(Effect.scoped, Effect.provide(recordedSocket)))
124
131
```
125
132
126
-
The application owns the WebSocket URL and protocols through normal Effect layer wiring. The recorder wraps that socket without duplicating its URL in recorder configuration. Provide separate socket layers for separate endpoints or concurrent connections.
133
+
`socket.runString` owns the receive loop and finishes when the connection closes or fails. Its optional `onOpen` effect is the safe place to send protocols whose client speaks first. The writer is scoped because sending is valid only while a connection run is active.
134
+
135
+
WebSocket cassettes preserve one ordered transcript of client and server text or binary frames. Replay releases recorded server frames until it reaches a client frame, waits for the application to write the matching frame, then continues. This preserves causal ordering without reproducing network timing.
136
+
137
+
Client text frames containing JSON compare canonically, so object-key order does not matter. Changed fields, extra fields, non-JSON text, and binary frames must match exactly after redaction. There is intentionally no custom WebSocket matcher in this beta.
138
+
139
+
Incoming frame handlers start in recorded order and may run concurrently, matching Effect's socket abstraction. Replay waits for all handlers before the socket run completes, but handler completion order is not guaranteed. Use Effect synchronization such as `Queue`, `Ref`, or `Deferred` instead of unsynchronized mutable state.
140
+
141
+
A cassette is written only after the live socket opened and its run completed successfully. Failed, interrupted, unopened, or invalid runs do not produce a recording. During replay, closing before every recorded frame is consumed fails the test.
142
+
143
+
The application owns the WebSocket URL and protocols through normal Effect layer wiring. Provide separate recorder and live socket layers for separate endpoints or concurrent connections. One recorder layer supports sequential reconnects, but rejects concurrent runs.
127
144
128
145
Text frames use the same JSON-field and body redaction as HTTP bodies. Binary frames are stored losslessly as base64. Client and server frame kinds must match during replay.
`directory` defaults to `<cwd>/test/fixtures/recordings`.
@@ -207,7 +226,7 @@ Cassettes are readable JSON files intended to be committed with your tests. HTTP
207
226
208
227
- Responses are buffered while recording and replaying, so this beta is not suitable for tests that assert streaming timing, cancellation, or backpressure.
209
228
- WebSocket replay preserves frame chronology and content, not real network timing or backpressure.
210
-
- WebSocket V1 cassettes do not reproduce terminal close codes, close reasons, or transport failures. Failed and interrupted live runs are not recorded.
229
+
- WebSocket V1 cassettes do not reproduce terminal close codes, close reasons, handshake configuration, or transport failures. Failed and interrupted live runs are not recorded.
211
230
- WebSocket transcripts are retained in memory until the connection finishes; avoid using this beta for unbounded sessions.
212
231
- The package currently requires the exact Effect beta listed above.
213
232
- Cassette format version `1` has no migration tooling yet.
`@opencode-ai/http-recorder` is versioned independently from OpenCode and published under the npm `beta` tag.
4
+
5
+
## Prepare A Release
6
+
7
+
1. Add a Changeset for every user-facing package change.
8
+
2. Run `bunx changeset status` and confirm that only `@opencode-ai/http-recorder` will be bumped.
9
+
3. Merge the package changes into `dev`.
10
+
4. From a branch based on the latest `dev`, run `bun run version:http-recorder`.
11
+
5. Review the generated version and `packages/http-recorder/CHANGELOG.md`, then open and merge the release PR.
12
+
13
+
The first minor Changeset advances the unpublished `0.0.0` package to `0.1.0`. OpenCode's repository-wide release script deliberately excludes this package from its version synchronization.
14
+
15
+
## Verify And Publish
16
+
17
+
Before merging the release PR, run these commands from `packages/http-recorder`:
18
+
19
+
```sh
20
+
bun run test
21
+
bun typecheck
22
+
bun run verify:package
23
+
```
24
+
25
+
After the release PR reaches `dev`, manually dispatch the `http-recorder release` workflow from the `dev` branch. The workflow repeats the focused tests, builds and verifies the exact tarball in a clean npm consumer, and publishes it with provenance under the `beta` tag.
26
+
27
+
The bootstrap release requires an npm automation token in the repository's `NPM_TOKEN` secret. After the package exists, configure npm trusted publishing for `.github/workflows/http-recorder-release.yml` and the `npm` GitHub environment, then remove the token so later releases use GitHub OIDC.
28
+
29
+
Verify the result:
30
+
31
+
```sh
32
+
npm view @opencode-ai/http-recorder version dist-tags --json
0 commit comments