reactor-effect-client 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +7 -2
- package/README.md +103 -141
- package/dist/Coordinator.d.ts +382 -0
- package/dist/Coordinator.d.ts.map +1 -0
- package/dist/Coordinator.js +732 -0
- package/dist/Coordinator.js.map +1 -0
- package/dist/H3.d.ts +159 -0
- package/dist/H3.d.ts.map +1 -0
- package/dist/H3.js +21 -0
- package/dist/H3.js.map +1 -0
- package/dist/H3Source.d.ts +93 -0
- package/dist/H3Source.d.ts.map +1 -0
- package/dist/H3Source.js +401 -0
- package/dist/H3Source.js.map +1 -0
- package/dist/LocalSource.d.ts +68 -0
- package/dist/LocalSource.d.ts.map +1 -0
- package/dist/LocalSource.js +354 -0
- package/dist/LocalSource.js.map +1 -0
- package/dist/Media.d.ts +106 -0
- package/dist/Media.d.ts.map +1 -0
- package/dist/Media.js +16 -0
- package/dist/Media.js.map +1 -0
- package/dist/Peer.d.ts +134 -0
- package/dist/Peer.d.ts.map +1 -0
- package/dist/Peer.js +57 -0
- package/dist/Peer.js.map +1 -0
- package/dist/Playout.d.ts +724 -0
- package/dist/Playout.d.ts.map +1 -0
- package/dist/Playout.js +28 -0
- package/dist/Playout.js.map +1 -0
- package/dist/Reactor.d.ts +135 -0
- package/dist/Reactor.d.ts.map +1 -0
- package/dist/Reactor.js +158 -0
- package/dist/Reactor.js.map +1 -0
- package/dist/ReactorError.d.ts +331 -0
- package/dist/ReactorError.d.ts.map +1 -0
- package/dist/ReactorError.js +316 -0
- package/dist/ReactorError.js.map +1 -0
- package/dist/ReactorTest.d.ts +383 -0
- package/dist/ReactorTest.d.ts.map +1 -0
- package/dist/ReactorTest.js +317 -0
- package/dist/ReactorTest.js.map +1 -0
- package/dist/Session.d.ts +314 -0
- package/dist/Session.d.ts.map +1 -0
- package/dist/Session.js +51 -0
- package/dist/Session.js.map +1 -0
- package/dist/index.d.ts +12 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -11
- package/dist/index.js.map +1 -1
- package/dist/internal/correlator.d.ts +46 -0
- package/dist/internal/correlator.d.ts.map +1 -0
- package/dist/internal/correlator.js +150 -0
- package/dist/internal/correlator.js.map +1 -0
- package/dist/internal/deadline.d.ts +24 -0
- package/dist/internal/deadline.d.ts.map +1 -0
- package/dist/internal/deadline.js +44 -0
- package/dist/internal/deadline.js.map +1 -0
- package/dist/{h3/_internal/contracts.d.ts → internal/h3/commands.d.ts} +39 -33
- package/dist/internal/h3/commands.d.ts.map +1 -0
- package/dist/internal/h3/commands.js +128 -0
- package/dist/internal/h3/commands.js.map +1 -0
- package/dist/{h3 → internal/h3}/messages.d.ts +16 -11
- package/dist/internal/h3/messages.d.ts.map +1 -0
- package/dist/{h3 → internal/h3}/messages.js +19 -31
- package/dist/internal/h3/messages.js.map +1 -0
- package/dist/internal/h3/operations.d.ts +145 -0
- package/dist/internal/h3/operations.d.ts.map +1 -0
- package/dist/internal/h3/operations.js +284 -0
- package/dist/internal/h3/operations.js.map +1 -0
- package/dist/{h3 → internal/h3}/profile.d.ts +63 -65
- package/dist/internal/h3/profile.d.ts.map +1 -0
- package/dist/{h3 → internal/h3}/profile.js +39 -39
- package/dist/internal/h3/profile.js.map +1 -0
- package/dist/internal/h3/provider.d.ts +14 -0
- package/dist/internal/h3/provider.d.ts.map +1 -0
- package/dist/internal/h3/provider.js +672 -0
- package/dist/internal/h3/provider.js.map +1 -0
- package/dist/internal/h3/references.d.ts +68 -0
- package/dist/internal/h3/references.d.ts.map +1 -0
- package/dist/internal/h3/references.js +339 -0
- package/dist/internal/h3/references.js.map +1 -0
- package/dist/internal/h3/request.d.ts +56 -0
- package/dist/internal/h3/request.d.ts.map +1 -0
- package/dist/internal/h3/request.js +70 -0
- package/dist/internal/h3/request.js.map +1 -0
- package/dist/internal/h3/state.d.ts +120 -0
- package/dist/internal/h3/state.d.ts.map +1 -0
- package/dist/internal/h3/state.js +270 -0
- package/dist/internal/h3/state.js.map +1 -0
- package/dist/{Submission.d.ts → internal/h3/submission.d.ts} +1 -3
- package/dist/internal/h3/submission.d.ts.map +1 -0
- package/dist/{Submission.js → internal/h3/submission.js} +1 -9
- package/dist/internal/h3/submission.js.map +1 -0
- package/dist/internal/hub.d.ts +32 -0
- package/dist/internal/hub.d.ts.map +1 -0
- package/dist/internal/hub.js +92 -0
- package/dist/internal/hub.js.map +1 -0
- package/dist/internal/playout/errors.d.ts +51 -0
- package/dist/internal/playout/errors.d.ts.map +1 -0
- package/dist/internal/playout/errors.js +40 -0
- package/dist/internal/playout/errors.js.map +1 -0
- package/dist/internal/playout/policy.d.ts +559 -0
- package/dist/internal/playout/policy.d.ts.map +1 -0
- package/dist/internal/playout/policy.js +2338 -0
- package/dist/internal/playout/policy.js.map +1 -0
- package/dist/internal/playout/runtime.d.ts +28 -0
- package/dist/internal/playout/runtime.d.ts.map +1 -0
- package/dist/internal/playout/runtime.js +766 -0
- package/dist/internal/playout/runtime.js.map +1 -0
- package/dist/internal/playout/tag.d.ts +14 -0
- package/dist/internal/playout/tag.d.ts.map +1 -0
- package/dist/internal/playout/tag.js +43 -0
- package/dist/internal/playout/tag.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/common_pb.d.ts +55 -0
- package/dist/internal/proto/reactor_wire/v1/common_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/common_pb.js +42 -0
- package/dist/internal/proto/reactor_wire/v1/common_pb.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/control_pb.d.ts +160 -0
- package/dist/internal/proto/reactor_wire/v1/control_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/control_pb.js +21 -0
- package/dist/internal/proto/reactor_wire/v1/control_pb.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/data_pb.d.ts +89 -0
- package/dist/internal/proto/reactor_wire/v1/data_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/data_pb.js +20 -0
- package/dist/internal/proto/reactor_wire/v1/data_pb.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/model_pb.d.ts +85 -0
- package/dist/internal/proto/reactor_wire/v1/model_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/model_pb.js +24 -0
- package/dist/internal/proto/reactor_wire/v1/model_pb.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/platform_pb.d.ts +190 -0
- package/dist/internal/proto/reactor_wire/v1/platform_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/platform_pb.js +54 -0
- package/dist/internal/proto/reactor_wire/v1/platform_pb.js.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/track_pb.d.ts +88 -0
- package/dist/internal/proto/reactor_wire/v1/track_pb.d.ts.map +1 -0
- package/dist/internal/proto/reactor_wire/v1/track_pb.js +33 -0
- package/dist/internal/proto/reactor_wire/v1/track_pb.js.map +1 -0
- package/dist/internal/queue.d.ts +4 -0
- package/dist/internal/queue.d.ts.map +1 -0
- package/dist/{_internal → internal}/queue.js +0 -9
- package/dist/internal/queue.js.map +1 -0
- package/dist/internal/reactorTest/coordinator.d.ts +5 -0
- package/dist/internal/reactorTest/coordinator.d.ts.map +1 -0
- package/dist/internal/reactorTest/coordinator.js +178 -0
- package/dist/internal/reactorTest/coordinator.js.map +1 -0
- package/dist/internal/reactorTest/faults.d.ts +172 -0
- package/dist/internal/reactorTest/faults.d.ts.map +1 -0
- package/dist/internal/reactorTest/faults.js +23 -0
- package/dist/internal/reactorTest/faults.js.map +1 -0
- package/dist/internal/reactorTest/h3.d.ts +431 -0
- package/dist/internal/reactorTest/h3.d.ts.map +1 -0
- package/dist/internal/reactorTest/h3.js +625 -0
- package/dist/internal/reactorTest/h3.js.map +1 -0
- package/dist/internal/reactorTest/media.d.ts +22 -0
- package/dist/internal/reactorTest/media.d.ts.map +1 -0
- package/dist/internal/reactorTest/media.js +34 -0
- package/dist/internal/reactorTest/media.js.map +1 -0
- package/dist/internal/reactorTest/peer.d.ts +318 -0
- package/dist/internal/reactorTest/peer.d.ts.map +1 -0
- package/dist/internal/reactorTest/peer.js +206 -0
- package/dist/internal/reactorTest/peer.js.map +1 -0
- package/dist/internal/reactorTest/playout.d.ts +34 -0
- package/dist/internal/reactorTest/playout.d.ts.map +1 -0
- package/dist/internal/reactorTest/playout.js +340 -0
- package/dist/internal/reactorTest/playout.js.map +1 -0
- package/dist/internal/reactorTest/references.d.ts +25 -0
- package/dist/internal/reactorTest/references.d.ts.map +1 -0
- package/dist/{testing/Png.js → internal/reactorTest/references.js} +50 -12
- package/dist/internal/reactorTest/references.js.map +1 -0
- package/dist/internal/reactorTest/sessions.d.ts +364 -0
- package/dist/internal/reactorTest/sessions.d.ts.map +1 -0
- package/dist/internal/reactorTest/sessions.js +592 -0
- package/dist/internal/reactorTest/sessions.js.map +1 -0
- package/dist/internal/reactorTest/timing.d.ts +13 -0
- package/dist/internal/reactorTest/timing.d.ts.map +1 -0
- package/dist/internal/reactorTest/timing.js +20 -0
- package/dist/internal/reactorTest/timing.js.map +1 -0
- package/dist/internal/recording.d.ts +52 -0
- package/dist/internal/recording.d.ts.map +1 -0
- package/dist/internal/recording.js +141 -0
- package/dist/internal/recording.js.map +1 -0
- package/dist/internal/session/connect.d.ts +34 -0
- package/dist/internal/session/connect.d.ts.map +1 -0
- package/dist/internal/session/connect.js +502 -0
- package/dist/internal/session/connect.js.map +1 -0
- package/dist/internal/session/generation.d.ts +35 -0
- package/dist/internal/session/generation.d.ts.map +1 -0
- package/dist/internal/session/generation.js +185 -0
- package/dist/internal/session/generation.js.map +1 -0
- package/dist/internal/session/ice.d.ts +23 -0
- package/dist/internal/session/ice.d.ts.map +1 -0
- package/dist/internal/session/ice.js +57 -0
- package/dist/internal/session/ice.js.map +1 -0
- package/dist/internal/session/inbound.d.ts +50 -0
- package/dist/internal/session/inbound.d.ts.map +1 -0
- package/dist/internal/session/inbound.js +202 -0
- package/dist/internal/session/inbound.js.map +1 -0
- package/dist/internal/session/model.d.ts +163 -0
- package/dist/internal/session/model.d.ts.map +1 -0
- package/dist/internal/session/model.js +78 -0
- package/dist/internal/session/model.js.map +1 -0
- package/dist/internal/session/requests.d.ts +71 -0
- package/dist/internal/session/requests.d.ts.map +1 -0
- package/dist/internal/session/requests.js +240 -0
- package/dist/internal/session/requests.js.map +1 -0
- package/dist/internal/session/tracks.d.ts +21 -0
- package/dist/internal/session/tracks.d.ts.map +1 -0
- package/dist/internal/session/tracks.js +166 -0
- package/dist/internal/session/tracks.js.map +1 -0
- package/dist/internal/session/upload.d.ts +21 -0
- package/dist/internal/session/upload.d.ts.map +1 -0
- package/dist/internal/session/upload.js +68 -0
- package/dist/internal/session/upload.js.map +1 -0
- package/dist/internal/session.d.ts +66 -0
- package/dist/internal/session.d.ts.map +1 -0
- package/dist/internal/session.js +280 -0
- package/dist/internal/session.js.map +1 -0
- package/dist/{stats.d.ts → internal/stats.d.ts} +30 -16
- package/dist/internal/stats.d.ts.map +1 -0
- package/dist/internal/stats.js +201 -0
- package/dist/internal/stats.js.map +1 -0
- package/dist/internal/token.d.ts +22 -0
- package/dist/internal/token.d.ts.map +1 -0
- package/dist/internal/token.js +65 -0
- package/dist/internal/token.js.map +1 -0
- package/dist/internal/wire.d.ts +37 -0
- package/dist/internal/wire.d.ts.map +1 -0
- package/dist/internal/wire.js +49 -0
- package/dist/internal/wire.js.map +1 -0
- package/notices/bufbuild-protobuf-LICENSE +201 -0
- package/package.json +17 -38
- package/dist/FetchHttp.d.ts +0 -9
- package/dist/FetchHttp.d.ts.map +0 -1
- package/dist/FetchHttp.js +0 -63
- package/dist/FetchHttp.js.map +0 -1
- package/dist/PeerFactory.d.ts +0 -26
- package/dist/PeerFactory.d.ts.map +0 -1
- package/dist/PeerFactory.js +0 -4
- package/dist/PeerFactory.js.map +0 -1
- package/dist/PeerTypes.d.ts +0 -64
- package/dist/PeerTypes.d.ts.map +0 -1
- package/dist/PeerTypes.js +0 -2
- package/dist/PeerTypes.js.map +0 -1
- package/dist/Sequence.d.ts +0 -85
- package/dist/Sequence.d.ts.map +0 -1
- package/dist/Sequence.js +0 -210
- package/dist/Sequence.js.map +0 -1
- package/dist/SessionTypes.d.ts +0 -312
- package/dist/SessionTypes.d.ts.map +0 -1
- package/dist/SessionTypes.js +0 -19
- package/dist/SessionTypes.js.map +0 -1
- package/dist/Submission.d.ts.map +0 -1
- package/dist/Submission.js.map +0 -1
- package/dist/_internal/queue.d.ts +0 -6
- package/dist/_internal/queue.d.ts.map +0 -1
- package/dist/_internal/queue.js.map +0 -1
- package/dist/bytes.d.ts +0 -6
- package/dist/bytes.d.ts.map +0 -1
- package/dist/bytes.js +0 -32
- package/dist/bytes.js.map +0 -1
- package/dist/contract.d.ts +0 -149
- package/dist/contract.d.ts.map +0 -1
- package/dist/contract.js +0 -119
- package/dist/contract.js.map +0 -1
- package/dist/coordinator/_internal/client.d.ts +0 -215
- package/dist/coordinator/_internal/client.d.ts.map +0 -1
- package/dist/coordinator/_internal/client.js +0 -563
- package/dist/coordinator/_internal/client.js.map +0 -1
- package/dist/coordinator/_internal/recording.d.ts +0 -31
- package/dist/coordinator/_internal/recording.d.ts.map +0 -1
- package/dist/coordinator/_internal/recording.js +0 -123
- package/dist/coordinator/_internal/recording.js.map +0 -1
- package/dist/coordinator/_internal/response.d.ts +0 -15
- package/dist/coordinator/_internal/response.d.ts.map +0 -1
- package/dist/coordinator/_internal/response.js +0 -55
- package/dist/coordinator/_internal/response.js.map +0 -1
- package/dist/coordinator/_internal/schemas.d.ts +0 -73
- package/dist/coordinator/_internal/schemas.d.ts.map +0 -1
- package/dist/coordinator/_internal/schemas.js +0 -200
- package/dist/coordinator/_internal/schemas.js.map +0 -1
- package/dist/coordinator/index.d.ts +0 -40
- package/dist/coordinator/index.d.ts.map +0 -1
- package/dist/coordinator/index.js +0 -21
- package/dist/coordinator/index.js.map +0 -1
- package/dist/correlation.d.ts +0 -47
- package/dist/correlation.d.ts.map +0 -1
- package/dist/correlation.js +0 -131
- package/dist/correlation.js.map +0 -1
- package/dist/duration.d.ts +0 -27
- package/dist/duration.d.ts.map +0 -1
- package/dist/duration.js +0 -47
- package/dist/duration.js.map +0 -1
- package/dist/errors.d.ts +0 -1303
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -745
- package/dist/errors.js.map +0 -1
- package/dist/h3/_internal/client.d.ts +0 -9
- package/dist/h3/_internal/client.d.ts.map +0 -1
- package/dist/h3/_internal/client.js +0 -652
- package/dist/h3/_internal/client.js.map +0 -1
- package/dist/h3/_internal/contracts.d.ts.map +0 -1
- package/dist/h3/_internal/contracts.js +0 -123
- package/dist/h3/_internal/contracts.js.map +0 -1
- package/dist/h3/_internal/deployment.d.ts +0 -8
- package/dist/h3/_internal/deployment.d.ts.map +0 -1
- package/dist/h3/_internal/deployment.js +0 -149
- package/dist/h3/_internal/deployment.js.map +0 -1
- package/dist/h3/_internal/evidence.d.ts +0 -17
- package/dist/h3/_internal/evidence.d.ts.map +0 -1
- package/dist/h3/_internal/evidence.js +0 -48
- package/dist/h3/_internal/evidence.js.map +0 -1
- package/dist/h3/_internal/operations.d.ts +0 -58
- package/dist/h3/_internal/operations.d.ts.map +0 -1
- package/dist/h3/_internal/operations.js +0 -268
- package/dist/h3/_internal/operations.js.map +0 -1
- package/dist/h3/_internal/references.d.ts +0 -24
- package/dist/h3/_internal/references.d.ts.map +0 -1
- package/dist/h3/_internal/references.js +0 -309
- package/dist/h3/_internal/references.js.map +0 -1
- package/dist/h3/_internal/request.d.ts +0 -21
- package/dist/h3/_internal/request.d.ts.map +0 -1
- package/dist/h3/_internal/request.js +0 -97
- package/dist/h3/_internal/request.js.map +0 -1
- package/dist/h3/_internal/retained.d.ts +0 -22
- package/dist/h3/_internal/retained.d.ts.map +0 -1
- package/dist/h3/_internal/retained.js +0 -89
- package/dist/h3/_internal/retained.js.map +0 -1
- package/dist/h3/_internal/state.d.ts +0 -44
- package/dist/h3/_internal/state.d.ts.map +0 -1
- package/dist/h3/_internal/state.js +0 -283
- package/dist/h3/_internal/state.js.map +0 -1
- package/dist/h3/index.d.ts +0 -10
- package/dist/h3/index.d.ts.map +0 -1
- package/dist/h3/index.js +0 -7
- package/dist/h3/index.js.map +0 -1
- package/dist/h3/messages.d.ts.map +0 -1
- package/dist/h3/messages.js.map +0 -1
- package/dist/h3/profile.d.ts.map +0 -1
- package/dist/h3/profile.js.map +0 -1
- package/dist/h3/types.d.ts +0 -291
- package/dist/h3/types.d.ts.map +0 -1
- package/dist/h3/types.js +0 -2
- package/dist/h3/types.js.map +0 -1
- package/dist/host.d.ts +0 -26
- package/dist/host.d.ts.map +0 -1
- package/dist/host.js +0 -20
- package/dist/host.js.map +0 -1
- package/dist/json.d.ts +0 -25
- package/dist/json.d.ts.map +0 -1
- package/dist/json.js +0 -143
- package/dist/json.js.map +0 -1
- package/dist/media-stream.d.ts +0 -10
- package/dist/media-stream.d.ts.map +0 -1
- package/dist/media-stream.js +0 -18
- package/dist/media-stream.js.map +0 -1
- package/dist/observation.d.ts +0 -38
- package/dist/observation.d.ts.map +0 -1
- package/dist/observation.js +0 -113
- package/dist/observation.js.map +0 -1
- package/dist/orchestration/elapsed.d.ts +0 -9
- package/dist/orchestration/elapsed.d.ts.map +0 -1
- package/dist/orchestration/elapsed.js +0 -8
- package/dist/orchestration/elapsed.js.map +0 -1
- package/dist/orchestration/h3-source.d.ts +0 -58
- package/dist/orchestration/h3-source.d.ts.map +0 -1
- package/dist/orchestration/h3-source.js +0 -362
- package/dist/orchestration/h3-source.js.map +0 -1
- package/dist/orchestration/index.d.ts +0 -17
- package/dist/orchestration/index.d.ts.map +0 -1
- package/dist/orchestration/index.js +0 -12
- package/dist/orchestration/index.js.map +0 -1
- package/dist/orchestration/media-buffer.d.ts +0 -32
- package/dist/orchestration/media-buffer.d.ts.map +0 -1
- package/dist/orchestration/media-buffer.js +0 -94
- package/dist/orchestration/media-buffer.js.map +0 -1
- package/dist/orchestration/open-h3.d.ts +0 -101
- package/dist/orchestration/open-h3.d.ts.map +0 -1
- package/dist/orchestration/open-h3.js +0 -127
- package/dist/orchestration/open-h3.js.map +0 -1
- package/dist/orchestration/queries.d.ts +0 -10
- package/dist/orchestration/queries.d.ts.map +0 -1
- package/dist/orchestration/queries.js +0 -43
- package/dist/orchestration/queries.js.map +0 -1
- package/dist/orchestration/references.d.ts +0 -18
- package/dist/orchestration/references.d.ts.map +0 -1
- package/dist/orchestration/references.js +0 -79
- package/dist/orchestration/references.js.map +0 -1
- package/dist/orchestration/renewal-state.d.ts +0 -84
- package/dist/orchestration/renewal-state.d.ts.map +0 -1
- package/dist/orchestration/renewal-state.js +0 -95
- package/dist/orchestration/renewal-state.js.map +0 -1
- package/dist/orchestration/renewal.d.ts +0 -103
- package/dist/orchestration/renewal.d.ts.map +0 -1
- package/dist/orchestration/renewal.js +0 -1099
- package/dist/orchestration/renewal.js.map +0 -1
- package/dist/orchestration/request.d.ts +0 -65
- package/dist/orchestration/request.d.ts.map +0 -1
- package/dist/orchestration/request.js +0 -134
- package/dist/orchestration/request.js.map +0 -1
- package/dist/orchestration/retention.d.ts +0 -100
- package/dist/orchestration/retention.d.ts.map +0 -1
- package/dist/orchestration/retention.js +0 -134
- package/dist/orchestration/retention.js.map +0 -1
- package/dist/orchestration/routing.d.ts +0 -21
- package/dist/orchestration/routing.d.ts.map +0 -1
- package/dist/orchestration/routing.js +0 -93
- package/dist/orchestration/routing.js.map +0 -1
- package/dist/orchestration/scheduler-key.d.ts +0 -14
- package/dist/orchestration/scheduler-key.d.ts.map +0 -1
- package/dist/orchestration/scheduler-key.js +0 -62
- package/dist/orchestration/scheduler-key.js.map +0 -1
- package/dist/orchestration/scheduler-policy.d.ts +0 -246
- package/dist/orchestration/scheduler-policy.d.ts.map +0 -1
- package/dist/orchestration/scheduler-policy.js +0 -668
- package/dist/orchestration/scheduler-policy.js.map +0 -1
- package/dist/orchestration/scheduler.d.ts +0 -393
- package/dist/orchestration/scheduler.d.ts.map +0 -1
- package/dist/orchestration/scheduler.js +0 -2621
- package/dist/orchestration/scheduler.js.map +0 -1
- package/dist/orchestration/source-slot.d.ts +0 -124
- package/dist/orchestration/source-slot.d.ts.map +0 -1
- package/dist/orchestration/source-slot.js +0 -348
- package/dist/orchestration/source-slot.js.map +0 -1
- package/dist/orchestration/types.d.ts +0 -1462
- package/dist/orchestration/types.d.ts.map +0 -1
- package/dist/orchestration/types.js +0 -135
- package/dist/orchestration/types.js.map +0 -1
- package/dist/protobuf.d.ts +0 -63
- package/dist/protobuf.d.ts.map +0 -1
- package/dist/protobuf.js +0 -252
- package/dist/protobuf.js.map +0 -1
- package/dist/session/_internal/acquire.d.ts +0 -21
- package/dist/session/_internal/acquire.d.ts.map +0 -1
- package/dist/session/_internal/acquire.js +0 -168
- package/dist/session/_internal/acquire.js.map +0 -1
- package/dist/session/_internal/cleanup.d.ts +0 -19
- package/dist/session/_internal/cleanup.d.ts.map +0 -1
- package/dist/session/_internal/cleanup.js +0 -102
- package/dist/session/_internal/cleanup.js.map +0 -1
- package/dist/session/_internal/lifecycle.d.ts +0 -67
- package/dist/session/_internal/lifecycle.d.ts.map +0 -1
- package/dist/session/_internal/lifecycle.js +0 -142
- package/dist/session/_internal/lifecycle.js.map +0 -1
- package/dist/session/_internal/remote.d.ts +0 -28
- package/dist/session/_internal/remote.d.ts.map +0 -1
- package/dist/session/_internal/remote.js +0 -71
- package/dist/session/_internal/remote.js.map +0 -1
- package/dist/session/_internal/uploads.d.ts +0 -7
- package/dist/session/_internal/uploads.d.ts.map +0 -1
- package/dist/session/_internal/uploads.js +0 -31
- package/dist/session/_internal/uploads.js.map +0 -1
- package/dist/session/commands.d.ts +0 -2
- package/dist/session/commands.d.ts.map +0 -1
- package/dist/session/commands.js +0 -2
- package/dist/session/commands.js.map +0 -1
- package/dist/session/files.d.ts +0 -21
- package/dist/session/files.d.ts.map +0 -1
- package/dist/session/files.js +0 -49
- package/dist/session/files.js.map +0 -1
- package/dist/session/index.d.ts +0 -84
- package/dist/session/index.d.ts.map +0 -1
- package/dist/session/index.js +0 -16
- package/dist/session/index.js.map +0 -1
- package/dist/session/media.d.ts +0 -114
- package/dist/session/media.d.ts.map +0 -1
- package/dist/session/media.js +0 -2
- package/dist/session/media.js.map +0 -1
- package/dist/session/recorder.d.ts +0 -24
- package/dist/session/recorder.d.ts.map +0 -1
- package/dist/session/recorder.js +0 -19
- package/dist/session/recorder.js.map +0 -1
- package/dist/session.d.ts +0 -105
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -976
- package/dist/session.js.map +0 -1
- package/dist/simulation/_internal/source.d.ts +0 -12
- package/dist/simulation/_internal/source.d.ts.map +0 -1
- package/dist/simulation/_internal/source.js +0 -513
- package/dist/simulation/_internal/source.js.map +0 -1
- package/dist/simulation/index.d.ts +0 -13
- package/dist/simulation/index.d.ts.map +0 -1
- package/dist/simulation/index.js +0 -12
- package/dist/simulation/index.js.map +0 -1
- package/dist/simulation/types.d.ts +0 -39
- package/dist/simulation/types.d.ts.map +0 -1
- package/dist/simulation/types.js +0 -2
- package/dist/simulation/types.js.map +0 -1
- package/dist/stats.d.ts.map +0 -1
- package/dist/stats.js +0 -205
- package/dist/stats.js.map +0 -1
- package/dist/testing/Faults.d.ts +0 -4
- package/dist/testing/Faults.d.ts.map +0 -1
- package/dist/testing/Faults.js +0 -7
- package/dist/testing/Faults.js.map +0 -1
- package/dist/testing/Png.d.ts +0 -3
- package/dist/testing/Png.d.ts.map +0 -1
- package/dist/testing/Png.js.map +0 -1
- package/dist/testing/Wav.d.ts +0 -14
- package/dist/testing/Wav.d.ts.map +0 -1
- package/dist/testing/Wav.js +0 -37
- package/dist/testing/Wav.js.map +0 -1
- package/dist/testing/index.d.ts +0 -5
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js +0 -4
- package/dist/testing/index.js.map +0 -1
- package/dist/wire.d.ts +0 -7
- package/dist/wire.d.ts.map +0 -1
- package/dist/wire.generated.d.ts +0 -305
- package/dist/wire.generated.d.ts.map +0 -1
- package/dist/wire.generated.js +0 -1257
- package/dist/wire.generated.js.map +0 -1
- package/dist/wire.js +0 -5
- package/dist/wire.js.map +0 -1
package/NOTICE
CHANGED
|
@@ -7,8 +7,13 @@ The canonical wire definitions and selected protocol behavior derive from:
|
|
|
7
7
|
- reactor-runtime, commit 8e98536c6daedca298700dc45cbb5fd9e3676f16
|
|
8
8
|
Their upstream licenses and notices are retained under notices/.
|
|
9
9
|
The repository's packages/client/wire/proto directory contains the selected
|
|
10
|
-
canonical protocol sources
|
|
11
|
-
|
|
10
|
+
canonical protocol sources; protoc-gen-es generates the wire module from them.
|
|
11
|
+
|
|
12
|
+
The wire module runs on @bufbuild/protobuf, a runtime dependency licensed
|
|
13
|
+
Apache-2.0 AND BSD-3-Clause: Buf Technologies' Apache terms are retained in
|
|
14
|
+
notices/bufbuild-protobuf-LICENSE, and the BSD terms of the Google protobuf
|
|
15
|
+
code it incorporates, including the Struct descriptor, in
|
|
16
|
+
notices/google-protobuf-LICENSE.
|
|
12
17
|
|
|
13
18
|
Session, correlation and observation implementations incorporate the
|
|
14
19
|
user-supplied reactor-effect-client reference source. Reusable H3, coordinator,
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# reactor-effect-client
|
|
2
2
|
|
|
3
|
-
An independent Effect SDK for scoped
|
|
3
|
+
An independent Effect SDK for Reactor's real-time video models: scoped sessions, the H3 provider, a playout that airs a keyed schedule across renewing sessions, and Reactor simulated in memory for tests. This is the portable core of the [reactor-effect workspace](https://github.com/mannyc2/reactor-effect-client); the browser and native transports are the separate `reactor-effect-browser` and `reactor-effect-native` packages.
|
|
4
4
|
|
|
5
|
-
One
|
|
5
|
+
One `Session` owns each allocation or attachment: its commands, connection generations and cleanup evidence. `H3` reads that session and never allocates one. `Playout` gets its sessions from a source and never allocates around it. Application scheduling, pricing, personas and proof of presented output stay with the application.
|
|
6
6
|
|
|
7
7
|
This is not an official Reactor SDK. Protocol material is attributed in [NOTICE](./NOTICE) and [`notices/`](./notices/).
|
|
8
8
|
|
|
@@ -12,197 +12,159 @@ This is not an official Reactor SDK. Protocol material is attributed in [NOTICE]
|
|
|
12
12
|
npm install reactor-effect-client effect@4.0.0-rc.117
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Effect `4.0.0-rc.117
|
|
15
|
+
Effect is a peer dependency at exactly `4.0.0-rc.117`: Effect's release candidates can move modules, and `4.0.0-rc.118` moved the `effect/unstable/*` modules this package imports, so a later rc needs a new SDK release. An application that adds `@effect/platform-node` itself should install it with `--save-exact`, since a later rc of it peers on a later Effect. The platform depends on `@effect/platform-node-shared` with a caret range, under which npm installs a later rc that fails to load on this Effect, so an application without `reactor-effect-native`, which peers on that package exactly, should pin it in its own manifest: `"overrides": { "@effect/platform-node-shared": "4.0.0-rc.117" }`. Every module in this package is portable: importing it selects no host and loads no native code. Add `reactor-effect-browser` or `reactor-effect-native` for a transport, or run on `ReactorTest` without one.
|
|
16
16
|
|
|
17
17
|
## Modules
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
| ------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
21
|
-
| `reactor-effect-client` | Canonical `Client`, `Session`, `make`/`layer`, errors, `Coordinator`, `Peers`, and `FetchHttp` |
|
|
22
|
-
| `reactor-effect-client/h3` | H3 provider contract, state/queue/clip evidence, controls, and reference validation |
|
|
23
|
-
| `reactor-effect-client/orchestration` | Scheduling, renewal, source adaptation, references, submissions, and sequences |
|
|
24
|
-
| `reactor-effect-client/simulation` | Production simulation source, factory, and Effect service layer |
|
|
25
|
-
| `reactor-effect-client/testing` | Reusable fault, PNG and WAV fixtures |
|
|
26
|
-
| `reactor-effect-client/wire` | Generated protocol messages and wire encoding/decoding |
|
|
27
|
-
| `reactor-effect-client/host` | Host transport extension surface used by the first-party host packages |
|
|
19
|
+
Each module is its own subpath, `reactor-effect-client/<Module>`, and the root exports every one as a namespace: `import { Playout, Reactor } from "reactor-effect-client"`. Nothing under `internal/` is reachable.
|
|
28
20
|
|
|
29
|
-
|
|
21
|
+
| Module | What it is |
|
|
22
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `Reactor` | The service that acquires sessions: `create` allocates one this process owns, `attach` joins one |
|
|
24
|
+
| `Session` | One session: its status, events, commands, uploads, recordings, media and close report |
|
|
25
|
+
| `Coordinator` | Reactor's HTTP API: pricing, tokens (`Tokens`, `fixedTokens`), inspection, termination and recordings |
|
|
26
|
+
| `H3` | The H3 provider over a session: its state and queue, its commands, acceptance evidence and reference validation |
|
|
27
|
+
| `Playout` | Airs keyed items in priority lanes across sessions it renews, and reports what aired |
|
|
28
|
+
| `H3Source` | A paid H3 session as a playout source: `open`, `resume` and the owner record `Allocation` |
|
|
29
|
+
| `LocalSource` | A playout source rendered in this process by the application's hooks |
|
|
30
|
+
| `Media` | Decoded frames and platform tracks of one connection generation, and `recorder` |
|
|
31
|
+
| `Peer` | The transport port a host implements, and the `PeerFactory` service |
|
|
32
|
+
| `ReactorError` | Every failure the client raises, its tagged reason and its dispatch outcome |
|
|
33
|
+
| `ReactorTest` | Reactor simulated in memory: the coordinator, peers and an H3 model, driven by the Effect clock |
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
The modules' doc comments state each option's default and bound; this page is the map.
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
## Sessions
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
`Reactor.layer()` needs a `Coordinator` and a host's `PeerFactory`; `Coordinator.layer(options)` and `Coordinator.layerConfig` (`REACTOR_API_URL`, and the API key from `REACTOR_API_KEY`) need an Effect `HttpClient`. `reactor.create` returns a connected session in the caller's scope, and closing the scope closes it:
|
|
36
40
|
|
|
37
41
|
```ts
|
|
38
|
-
import { Effect, Redacted } from "effect";
|
|
39
|
-
import * as Reactor from "reactor-effect-client";
|
|
40
|
-
|
|
41
|
-
const useSession = Effect.gen(function* () {
|
|
42
|
-
const client = yield* Reactor.Client;
|
|
43
|
-
const session = yield* client.create({
|
|
44
|
-
model: "your-model",
|
|
45
|
-
jwt: Redacted.make("session-token"),
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
yield* session.connect;
|
|
49
|
-
return yield* session.current;
|
|
50
|
-
});
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
The surrounding application supplies the `Client` layer and Effect platform services. Credentials, HTTP policy, scopes, and host transport selection stay visible in composition. A host package supplies the `PeerFactory`:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import { Effect, Layer } from "effect";
|
|
57
42
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
58
|
-
import
|
|
59
|
-
import * as
|
|
43
|
+
import { Effect, Layer } from "effect";
|
|
44
|
+
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
|
|
45
|
+
import { Coordinator, H3, Reactor } from "reactor-effect-client";
|
|
46
|
+
import { NativePeer } from "reactor-effect-native";
|
|
47
|
+
|
|
48
|
+
const firstClip = Effect.gen(function* () {
|
|
49
|
+
const coordinator = yield* Coordinator.Coordinator;
|
|
50
|
+
const reactor = yield* Reactor.Reactor;
|
|
51
|
+
const session = yield* reactor.create({
|
|
52
|
+
model: H3.modelName,
|
|
53
|
+
tokens: coordinator.tokens({ modelName: H3.modelName, maxSessionDuration: "5 minutes" }),
|
|
54
|
+
});
|
|
55
|
+
const provider = yield* H3.make(session);
|
|
56
|
+
return yield* provider.enqueue({ prompt: "A slow camera move through a sunlit garden" });
|
|
57
|
+
}).pipe(Effect.scoped);
|
|
60
58
|
|
|
61
|
-
const
|
|
62
|
-
Layer.
|
|
59
|
+
const ReactorLive = Reactor.layer().pipe(
|
|
60
|
+
Layer.provideMerge(Layer.mergeAll(Coordinator.layerConfig, NativePeer.layer())),
|
|
61
|
+
Layer.provide(FetchHttpClient.layer),
|
|
63
62
|
);
|
|
64
63
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
const main = Effect.scoped(useSession).pipe(Effect.provide(clientLayer));
|
|
64
|
+
// The application's entry point provides the layers once. Running it allocates a paid session.
|
|
65
|
+
export const main = firstClip.pipe(Effect.provide(Layer.mergeAll(ReactorLive, NodeServices.layer)));
|
|
68
66
|
```
|
|
69
67
|
|
|
70
|
-
Building a host layer is its preflight: `
|
|
71
|
-
|
|
72
|
-
Browser and native media values stay bound to their negotiated generation. A reconnect creates a new generation; existing readers end or fail with their source. Applications obtain the new media generation explicitly, or opt into orchestration's recovering media streams. Each `VideoFrame` declares its pixel `format` (`"BGRA"` from the native host); nothing converts between formats implicitly. A recorder reads a track directly and sees loss before admission as a rise in `pressure`'s `droppedVideo`/`droppedAudio`, and a reader that falls behind its bound fails with `Overflow` and counts in `readerOverflows`. Every frame carries its admission `sequence` on its track, so `recorder(stream)` yields each frame plus a `Lost { after, count }` wherever the host dropped frames, at their position. A preview keeps only the newest frame with `Stream.buffer({ capacity: 1, strategy: "sliding" })`.
|
|
73
|
-
|
|
74
|
-
## Errors
|
|
75
|
-
|
|
76
|
-
Every failure the client raises is one of four classes, each with its own `_tag`, so `Effect.catchTag` and a Schema union tell them apart:
|
|
68
|
+
Building a host layer is its preflight: `NativePeer.layer()` loads the addon and `BrowserPeer.layer` detects WebRTC, so a host that cannot run fails before anything is allocated, and the factory's `check` runs again before every allocation. Over `FetchHttpClient`, every coordinator request omits ambient credentials and refuses redirects.
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
- `CommandFailure`: a failed command, with the dispatch evidence its owner established;
|
|
80
|
-
- `AcquisitionFailure`: a failed acquisition, with the `cleanup` report of its partial lease, kept by reference;
|
|
81
|
-
- `PolicyFailure`, from `/orchestration`: a local refusal, which was never dispatched.
|
|
70
|
+
**Ownership.** `create` allocates a session this process owns: closing it terminates the session and confirms the end with an independent read, since a `DELETE` response alone proves nothing. `onAllocated` runs after allocation and before connecting, so a supervisor can record the owner first; if it fails, the session is closed and the acquisition fails with an `AcquisitionFailure` carrying the close report, the hook's own error kept in its `Redacted` `context.detail`. `attach` joins a session without its remote lifetime; with `adopt: true` it takes that lifetime over, as a process resuming a dead owner's session does. `session.close` returns a `CloseReport`, a Schema you can persist, with the termination verdict and every local cleanup error; a failed acquisition's `AcquisitionFailure` carries the same report. `Session.mayStillBill(report)` says whether its session may still be billing: one this process owned that no read confirmed ended, or an allocation whose outcome, and so whose id, never arrived. Reconnecting keeps a session billing through its drops: an owned session its application never closed, or one a viewer holds after its owner has gone, runs on for as long as the process holding it does, to its cap if it has one; `Reactor.layer({ reconnect: false })` lets a drop end it 30 seconds later. The library keeps no pool of sessions: Effect's `Pool.makeWithTTL` over `reactor.create`, with `min: 0`, and a short `timeToLive`, closes a session left idle, where `Pool.make` keeps every session, and its bill, until the pool's scope closes.
|
|
82
71
|
|
|
83
|
-
`
|
|
72
|
+
**Tokens.** A session never sees the API key. It runs on `Tokens`: `create`, a token that may create one session, and `bind(sessionId)`, a fresh token bound to an open session. The session keeps one token for all its calls and mints the next with `bind` a minute before it expires, or a quarter of a shorter token's life, so it outlives any one token; Reactor keeps a token at most six hours. `coordinator.tokens({ modelName, maxSessionDuration })` mints both with the key the Coordinator holds. `maxSessionDuration` is required, a duration or `"unlimited"`, because an uncapped session bills until something ends it. `coordinator.mintToken` takes `bind` and `maxSessions` directly and refuses a grant Reactor echoes wider than asked. `Coordinator.fixedTokens(grant)` serves a session shorter than its token, and a browser gets its tokens from a server that holds the key (see the [browser example](https://github.com/mannyc2/reactor-effect-client/tree/main/packages/browser/examples)); that server should bind only sessions its caller created, since a bound token commands, watches and ends its session. Each call has its own credential: `mintToken` and `tokens` use the API key; `inspect`, `terminate` and `downloadClip` use the Coordinator's `credential`, or the key when none is set, so a server holding the key can read and end any session of its account; and a session's own calls use its token.
|
|
84
73
|
|
|
85
|
-
|
|
74
|
+
**Lifecycle.** A session reads `INACTIVE` while its last connection is gone; it is still live and billed, and Reactor ends it 30 seconds later unless a connection returns. Only `CLOSED` is terminal (`Coordinator.isTerminal`). A session reconnects a dropped connection on its own, owned or attached, whoever reads it: one attempt at once, then more on the `reconnect` schedule, until a connection has stayed ready 10 seconds, the schedule stops, the session is closing or Reactor or moderation ended it, Reactor refuses this client's protocol (`VersionMismatch`), or `reconnectTimeout` (30 seconds) has passed since the drop. A connection that drops sooner is a failed attempt of the same reconnect, so one that keeps dropping is tried on the schedule, not at once. The session stops trying 30 seconds after the first drop, or, if a connection is up then, once that connection drops before it has been ready 10 seconds; Reactor ends the session 30 seconds after its last connection drops. By default the second attempt comes 250 ms after the first fails and each wait doubles, to at most 4 seconds, jittered, and never sooner than a refusal's `Retry-After`, from which it is jittered only upward; a refusal that may lift, a 401 or 403 included, is tried again, with a fresh token only from its `Tokens`, once the current one nears its expiry. A schedule with no delay of its own tries again at once for all of `reconnectTimeout`, with a new peer each time, so space its attempts as the default does. Each failed attempt is a `Diagnostic` event, and a reconnect out of time stops with `Timeout`, the last attempt's failure, or why the connection up as the time ran out dropped, in its `Redacted` `context.detail`. Each attempt is a new connection generation of the same session: it allocates nothing and never replays a command. Meanwhile the status goes `disconnected`, then `connecting`, `waiting` and `ready` on the new generation, and the snapshot's `reconnecting` is true from the drop until a connection is ready or the session stops trying; `disconnected` without it is lasting, and `lastError` says why; a drop no attempt could get past (moderation or Reactor ended the session, or Reactor refuses this client's protocol) is lasting from the drop on. `Reactor.layer({ reconnect: false })` leaves a dropped connection down. `session.reconnect` opens a new connection generation at once, from a ready connection or a lasting drop, within `reconnectTimeout`, and never replays a command. While the session reconnects on its own, `session.reconnect` joins that reconnect rather than begin another: it succeeds once a connection is ready again, and fails as the reconnect stops, with the session's `lastError`, or with `Closed` if the session closes first. One whose connection is replaced while it makes its peer, as the session reconnects a drop or another reconnect asked for takes over, begins nothing either: it succeeds once a later connection is ready, and fails with the session's `lastError` once a later one is down for good, as the session's own reconnect stops or as another reconnect asked for fails meanwhile, whose failure it then takes. It fails with `InvalidState` while another reconnect asked for is under way. It fails with `Closed`, not submitted, if the session's close has begun before it takes the session over, or once its connection is open and becoming ready; one the close overtakes earlier in its negotiation fails with `Aborted`. What a host dies of as it fences or shuts down a peer never fails the session's work: a `ReactorError` is a `Diagnostic` event on that peer's generation, and any other defect goes to the `ErrorReporter`, except at the session's close, whose `CloseReport` keeps it in `localErrors`. A reconnect goes on past a replaced peer that fails to shut down, and a failed attempt fails with its own failure alone. Each generation's media and replies belong to it: a reconnect ends the old generation's readers, and a late reply is published labelled `stale-generation`. A `Moderation` event reports a content-moderation verdict; after `terminate` Reactor ends the session and it is not reconnected (`Moderated`). `session.snapshot`, `session.changes` and `session.observe` read the status: `changes` gives the snapshot at every change, in order, to a reader that falls behind too (its status, generation, `reconnecting`, `lastError`, received tracks and close as that change left them, the rest as the reader takes it), and `observe` pairs a snapshot with every event after it, with no gap.
|
|
86
75
|
|
|
87
|
-
`
|
|
76
|
+
**Deadlines.** `Reactor.layer(options)` sets the session deadlines: `replyTimeout`, `uploadTimeout`, `connectTimeout` (3 minutes, the wait for a GPU included, which is not billed), `reconnectTimeout`, `readyTimeout` and `heartbeatInterval`; `reconnect` is the `Schedule` a session reconnects a dropped connection on, or `false` (see Lifecycle). `connectTimeout` and `reconnectTimeout` cut the allocation and the negotiation, not the host's work on either side of them: making a peer, and shutting one down, which the native peer bounds by its `shutdownTimeout`. Every duration is a `Duration.Input`, and a bare number is milliseconds, so write the unit. One that is not a finite, non-negative duration fails with `InvalidInput`, not submitted. `replyTimeout` is the library's own deadline for a reply, not a caller's wait: after dispatch its expiry fails with `Timeout`, outcome `unknown`, and the request stays attributable. To stop waiting without abandoning a command, fork it and bound the join:
|
|
88
77
|
|
|
89
78
|
```ts
|
|
90
|
-
|
|
91
|
-
failure.context.outcome === "unknown" ? "reconcile" : failure.isRetryable ? "defer" : "reject";
|
|
92
|
-
|
|
93
|
-
const enqueued = engine.enqueue(request).pipe(
|
|
94
|
-
Effect.catchReasons("PolicyFailure", {
|
|
95
|
-
QueueFull: () => Effect.succeed("wait for a free generation slot"),
|
|
96
|
-
SessionRecovering: () => Effect.succeed("wait for the session to recover"),
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`message` is written by the library and never contains provider or payload text, so spans and logs that record it stay payload-free. Provider and backend text is kept only for explicit inspection: `Http.body`, `Remote.body`, the Redacted `Native.backendMessage` and `context.detail`. Diagnostic JSON leaves all of them out, and none of them is part of the cause chain that exporters render.
|
|
102
|
-
|
|
103
|
-
## Tracing
|
|
104
|
-
|
|
105
|
-
The client traces through Effect's `Tracer`, so any tracer the application provides, such as `OtlpTracer`, receives its spans. An operation a caller can cancel has a client span at the call: `reactor.session.create` and `reactor.session.attach`, `reactor.session.connect` and `reactor.session.reconnect` (with an event per phase, from `reactor.connect.described` to `reactor.connect.ready`), `reactor.session.upload` and `reactor.session.close`, and in orchestration `reactor.orchestration.resume` and `reactor.orchestration.renewal.open`, `recover`, `replace` and `switch`. A request the session owns past its caller's wait, a command or control request (`reactor.session.command`, `reactor.session.control`) or an H3 enqueue (`reactor.h3.enqueue`, with `reactor.h3.reconcile`), has its span on its own execution, so the span ends with the request's outcome even after the caller stopped waiting. Termination returns a verdict rather than failing, so `reactor.coordinator.terminate` and `reactor.session.close` carry it as `reactor.termination.attempted`, `confirmed` and `evidence`: a span that ended without error does not mean a paid session stopped. Spans name identity and outcome only: never a credential, command input, a reply, an upload's name or bytes, or provider text. The renewal tick, frames, streams and heartbeats are not traced.
|
|
106
|
-
|
|
107
|
-
## Time options
|
|
108
|
-
|
|
109
|
-
Every time option is an Effect `Duration.Input` named by its role:
|
|
110
|
-
|
|
111
|
-
- on the session, `connectTimeout`, `readyTimeout`, `heartbeatInterval`, `replyTimeout` and `uploadTimeout`;
|
|
112
|
-
- on the coordinator, `requestTimeout` and the poll's `initialDelay` and `maxDelay`, and on a token, `maxSessionDuration` and `expiresAfter`, which must be whole seconds;
|
|
113
|
-
- on H3, `replyTimeout`, `uploadTimeout`, `setupTimeout`, `reconcileWindow` and `resultHookTimeout`;
|
|
114
|
-
- in orchestration, `lead`, `reconnectTimeout`, `handoffGrace` and the `lifetime` that `open` returns.
|
|
115
|
-
|
|
116
|
-
A bare number is milliseconds, as everywhere in Effect, so write the unit: `lead: "30 seconds"`, because `lead: 30` is 30 milliseconds. `"Infinity"` disables the heartbeat and marks a source that never expires. A value that is NaN, negative, zero where zero means nothing, or longer than the option's maximum fails with `InvalidInput`, not submitted. Measurements, instants and media lengths stay numbers in the unit their name carries: `requestRecordingClip(seconds)`, `ClipRequest.durationSeconds`, a renewal's `ageSeconds`.
|
|
117
|
-
|
|
118
|
-
`replyTimeout` is the session's own deadline for a reply. The session's default and a command's override share the key: `session.command(name, data, { uploads, replyTimeout })`. It is not a caller's wait. After dispatch it fails with `Timeout`, outcome `unknown`, and the command's `requestId`, and the request's slot stays held until a late reply or the connection generation retires. To stop waiting without abandoning the command, fork it and bound only the join:
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
const fiber = yield * Effect.forkScoped(session.command("set_seed", { seed: 1 }));
|
|
122
|
-
const reply = yield * Fiber.join(fiber).pipe(Effect.timeout("2 seconds"));
|
|
123
|
-
// Later, Fiber.await(fiber) still reads the command's own outcome.
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
When the command must be replayed rather than awaited, prepare it as an `Orchestration.Submission`.
|
|
127
|
-
|
|
128
|
-
## Coordinator helpers
|
|
129
|
-
|
|
130
|
-
`Coordinator` is a namespace on the root export. `Coordinator.make(configuration)` provides pricing, bounded token minting, session inspection, termination reports, and `downloadClip` for a prepared recording (`clip_ready`), which polls its HLS playlist and concatenates its segments within a caller wall deadline, through Effect HTTP services. Constructing this client makes no network request and requires no peer implementation. The root exports the Schemas the client decodes a session descriptor with, `SessionDescriptor`, `Capabilities`, `Track` and `Mapping`, and derives their types from them.
|
|
131
|
-
|
|
132
|
-
## H3 provider
|
|
133
|
-
|
|
134
|
-
`H3.make(session, options)` consumes an already connected canonical `Session`. It checks the deployment contract and exposes provider state, queue and clip messages, observations, command replies, and locally correlated acceptance evidence. Provider facts remain visible even when another client authored the clip. A command ACK establishes receipt; state changes require the corresponding model evidence.
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
import { Effect } from "effect";
|
|
79
|
+
import { Effect, Fiber } from "effect";
|
|
138
80
|
import type { Session } from "reactor-effect-client";
|
|
139
|
-
import * as H3 from "reactor-effect-client/h3";
|
|
140
81
|
|
|
141
|
-
const
|
|
82
|
+
export const seed = (session: Session.Session) =>
|
|
142
83
|
Effect.gen(function* () {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
seconds: 5,
|
|
147
|
-
});
|
|
84
|
+
const fiber = yield* Effect.forkScoped(session.command("set_seed", { seed: 1 }));
|
|
85
|
+
// Later, Fiber.await(fiber) still reads the command's own outcome.
|
|
86
|
+
return yield* Fiber.join(fiber).pipe(Effect.timeout("2 seconds"));
|
|
148
87
|
});
|
|
149
88
|
```
|
|
150
89
|
|
|
151
|
-
|
|
90
|
+
**Media.** `session.decoded` is the current generation's decoded media, from the native host or `ReactorTest`; `session.tracks` is its platform tracks, from the browser host. Every frame carries its admission `sequence` on its track, so `Media.recorder(stream)` yields each frame plus a `Lost { after, count }` wherever the host dropped frames. A reader that falls behind its bound fails alone with `Overflow` and is counted in `pressure`'s `readerOverflows`; a preview keeps only the newest frame with `Stream.buffer({ capacity: 1, strategy: "sliding" })`.
|
|
152
91
|
|
|
153
|
-
|
|
92
|
+
Uploads (`session.upload`), recordings (`requestRecordingClip`, `recording`, then `coordinator.downloadClip`) and the deployment's OpenAPI document (`session.schema`) are on the session too.
|
|
154
93
|
|
|
155
|
-
|
|
94
|
+
## Errors
|
|
156
95
|
|
|
157
|
-
|
|
96
|
+
Every failure is one of three classes, each with its own `_tag`: `ReactorError`, `CommandFailure` (a command, with the dispatch evidence its owner established) and `AcquisitionFailure` (a failed acquisition, with its cleanup report). `ReactorError.isReactorFailure` recognizes any of them. Each carries a tagged `reason`: route on it with `Effect.catchReason`, `catchReasons` or `unwrapReason`. A reason's tag is a code such as `Timeout`, `Disconnected`, `InvalidInput` or `Moderated`, or one of the reasons with fields of their own: `Http` (`status`, `retryAfter`, `body`), `Remote` and `RecorderDisabled` (`remoteCode`, `body`), `Native` (`backendMessage`), `IceFailed`, `TransportFailed` and `ClipEnded`.
|
|
158
97
|
|
|
159
|
-
|
|
98
|
+
`context.outcome` says whether the remote may have applied the request: `not-submitted`, `unknown` or `replied`. `isRetryable` is true for backpressure, a connection lost before dispatch, and an HTTP refusal for now (a 5xx, 408, 429 or a named `Retry-After`), and never when the outcome is `unknown`, since the remote may already have applied it. A request whose token could not be had in time was never sent, and a create answered with a 5xx may have allocated a session, so its allocation is `unknown`.
|
|
160
99
|
|
|
161
|
-
|
|
100
|
+
```ts
|
|
101
|
+
import { Effect } from "effect";
|
|
102
|
+
import type { H3 } from "reactor-effect-client";
|
|
103
|
+
|
|
104
|
+
export const enqueue = (provider: H3.Provider, request: H3.Request) =>
|
|
105
|
+
provider.enqueue(request).pipe(
|
|
106
|
+
Effect.map((acceptance) => acceptance.clip.clip_id),
|
|
107
|
+
// Nothing was sent: this deployment takes no reference audio.
|
|
108
|
+
Effect.catchReason("CommandFailure", "UnsupportedCapability", () => Effect.succeed(undefined)),
|
|
109
|
+
);
|
|
110
|
+
```
|
|
162
111
|
|
|
163
|
-
`
|
|
112
|
+
`message` is written by the library and never holds provider or payload text, so spans and logs that record it stay payload-free. Provider and native text is kept only in `Redacted` fields for explicit inspection (`body`, `backendMessage`, `context.detail`) and never enters the cause chain that exporters render. Persist a failure as `ReactorError.FailureSummary`, never the error itself.
|
|
164
113
|
|
|
165
|
-
|
|
114
|
+
## Tracing
|
|
166
115
|
|
|
167
|
-
`
|
|
116
|
+
The client traces through Effect's `Tracer`, so any tracer the application provides, such as `OtlpTracer`, receives its spans. An operation a caller can cancel has a client span at the call: `Reactor.create` and `Reactor.attach`, `Session.connect` and `Session.reconnect` (with an event per phase, from `reactor.connect.described` to `reactor.connect.ready`; each attempt of a session's own reconnect is a `Session.reconnect` span too, the root of a trace of its own, linked to the span of the `create` or `attach` that acquired the session; that reconnect runs with the tracer, `ErrorReporter`s and clock the acquisition ran with), `Session.upload` and `Session.close`, and `Coordinator.mintToken`, `pricing`, `inspect` and `terminate`. A request the session owns past its caller's wait, a command or control request (`Session.command`, `Session.control`) or an H3 enqueue (`H3.enqueue`, with `H3.reconcile`), has its span on its own execution, so the span ends with the request's outcome even after the caller stopped waiting. `Playout.submit` and the playout's other edits have spans, and so do `H3Source.open` and `H3Source.resume`. Termination returns a verdict rather than failing, so `Coordinator.terminate` and `Session.close` carry it as `reactor.termination.attempted`, `confirmed` and `evidence`: a span that ended without error does not mean a paid session stopped. Spans name identity and outcome only, never a credential, command input, a reply, an upload's name or bytes, or provider text. Frames, streams and heartbeats are not traced.
|
|
168
117
|
|
|
169
|
-
|
|
118
|
+
## H3
|
|
170
119
|
|
|
171
|
-
`
|
|
120
|
+
`H3.make(session)` is the provider over a connected session created with `H3.modelName`. It targets the documented `0.5.5` schema of `reactor/h3-reference-to-video-turbo-realtime`: prompts with up to nine image references and three audio references, as owned bytes or earlier uploads. It reads the deployment's schema, requires only `enqueue`, `get_state` and `get_queue` to start, and fails any other command the deployment lacks as `UnsupportedCapability` before sending it (`provider.contract` says what it found). A request H3 would refuse is refused locally, `not-submitted`, before anything is uploaded; `H3.validateReference` and `H3.validateAudioReference` check a reference once for reuse, and the profile's constants (`requestSeconds`, `referenceLimits`, `audioReferenceLimits`, `canvases`) state the bounds.
|
|
172
121
|
|
|
173
|
-
|
|
122
|
+
An enqueue is accepted by its correlated reply, or by the clip's metadata: metadata that came before the reply decides once the reply has stayed away `reconcileWindow` (5 seconds), and an enqueue whose reply is lost waits that long for it. One whose outcome stays `unknown` is never sent again, though later evidence within `reconcileWindow`, or on a later connection generation, can still prove its clip. `provider.operation(submission)` follows a committed clip through `accepted`, `reached("generated")`, `reached("started")` and `ended`, each naming the generation of its evidence. H3 replies to a command before it broadcasts the state the command changed, so a command that needs current facts waits for them; `snapshot`, `changes` and `observe` read them. A command's acknowledgement proves receipt, never a state change.
|
|
174
123
|
|
|
175
|
-
|
|
124
|
+
## Playout
|
|
176
125
|
|
|
177
|
-
|
|
126
|
+
`Playout.make(options)` (or `Playout.layer`) airs a schedule: the application submits keyed items into priority lanes, and one plan decides what to build, in what order, what to withdraw and when a replacement session takes over. A pure policy makes every decision; the service applies them one provider command at a time on each session, with sessions' commands running side by side, so a slow command, a filler enqueue's included, holds up only its own session. It wakes on a submission, a session's evidence or the plan's next deadline, and never polls. Sessions come from the `open` effect, called for the first session and for each replacement:
|
|
178
127
|
|
|
179
|
-
`
|
|
128
|
+
- `H3Source.open({ tokens, canvas, holdLastFrame, onAllocated })` mints a token, allocates, runs `onAllocated` with the owner record (`H3Source.Allocation`, without a token), connects and sets H3 up: autoplay off until the playout turns it on, the last frame held between clips unless `holdLastFrame: false` flushes to black, and the canvas set before the first enqueue. Its lifetime is what remains of the create token's cap when it returns, counted from the allocation request, so the playout never plans past the session's end; an uncapped session never expires and is replaced only when lost. Its session reconnects a dropped connection itself, and the source follows it once, whoever reads its events: it gives the session `recovery` (20 seconds) to be ready again and H3 to be read afresh, waiting out a connection that drops again during that read, and otherwise counts the session lost; a session that will not come back, with `reconnect: false`, once moderation ended it or once it stops trying, is lost at once, with no `Reconnecting` before the loss. The playout sends the session nothing meanwhile.
|
|
129
|
+
- `H3Source.resume({ allocation, tokens })` adopts a session its dead owner recorded, with tokens bound to it; a session the owner already set up gets only reads.
|
|
130
|
+
- `LocalSource.open({ build, present, lifetime })` renders clips in this process, with H3's autoplay semantics, for locally rendered material and demos. `build` makes a clip's value, and its built length when that differs (`LocalSource.Rendered`), and `present` plays that value into the source's `video` and `audio`. Both run in a scope the clip owns, which closes once the clip leaves the source, so a finalizer releases what they made. A hook that fails with the application's own error fails that clip alone, reason `Clip` with the error `Redacted` in `provider`; one that dies stops the source, and the playout replaces its session. Without hooks, `buildRatio` gives a stand-in whose clips build for that share of their length and play for their length. `lifetime` caps the session, as a paid one is capped, so the playout renews it; it is unending by default.
|
|
180
131
|
|
|
181
|
-
|
|
132
|
+
What an application can ask for:
|
|
182
133
|
|
|
183
|
-
|
|
134
|
+
- **Items** (`submit`) in lanes listed highest first. A lane queues (the default), replaces its waiting items make-before-break, or skips while busy (`LaneBusy`), and a `cut: true` lane stops a lower lane's playing clip once its own is Ready. An item starts `Follow` (its lane's next boundary), `Asap`, `Manual` (held until `release`) or `At` a wall-clock instant, within an optional `notBefore`/`startBy` window; `WouldMissDeadline` refuses one the plan cannot start in time. A request outside H3's documented limits, its references included and its metadata counted as sent, wrapped with the item's key and H3's own identity, is refused with `InvalidItem`, naming each field and limit, and nothing is sent for it.
|
|
135
|
+
- **Edits**: `submitGroup` (parts that build in order and air back to back), `insert` before or after any item, `replace` a queued item make-before-break (if the item starts first, the replacement is dropped as `withdrawn`), `edit` for several edits applied together with the old clips as cover until the new ones are Ready, `withdraw` and `drain`. Keys are idempotent: the same spec returns the same handle, a changed one fails with `KeyMismatch`. Withdrawing a group key answers `withdrawn` if any part was, else `already-started` if any started; once the playout has stopped, a withdrawal answers from what became of the item or the parts.
|
|
136
|
+
- **Filler** in the bottom lane keeps a runway of Ready seconds between `floor` and `target`, sized to tile the gap before an `At` anchor. Once three builds were measured, filler's counted, the floor covers one p95 build, so a refill started there is Ready in time. A tile asks for no less than its share, and H3 aligns it up to its frame grid, so the anchor may air up to 0.7 s late for each tile. By default (`protect: "air"`) filler also goes before queue order: an item whose p95 build, at the continued rate if it continues a clip, would outlast the air secured (`state.runwaySeconds`) waits for one filler clip that builds sooner than it does, long enough within `lengths` to cover the rest and a second more, and airing no longer than the item builds unless `lengths.min` is longer, and the floor covers the next such item's build and a second more. An item waits for one such clip at most, and once more on a session it is carried to. One with a time to meet goes at once: one with an `At` start or a `startBy`, and, as its time is now, one with an `Asap` start, a released `Manual` one, or one on a lane that cuts. `protect: "order"` builds each item as soon as it may: it airs sooner, but the air may go dark while it builds. A filler request outside H3's documented limits fails the playout with `InvalidFiller`, naming the clip's index, since asking again would get the same request. `Playout.lineup(filler)` is one `line` lane above it.
|
|
137
|
+
- **Cues** fire at offsets from a clip's observed start or end, and `continuity: "previous"` builds a clip continuing from the one that airs before it.
|
|
184
138
|
|
|
185
|
-
|
|
139
|
+
The playout reports what happened, kept apart from what was asked. `asRun` gives an item's statuses: Accepted, Building, Ready, Started, Ended, Dropped, Failed, `Unobserved` (acknowledged, start never seen) or `Unknown` (sent, acknowledgement never seen). An `Unknown` is never sent again and no time is invented for it. A handle's `started` resolves with the item's start or how it settled without one (`Playout.NotStarted`), and its `outcome` with how it settled (`Playout.Settled`): Ended, Dropped, Failed, Unobserved, or an `Unknown` once it is terminal. `Failed` says why with a tagged `reason`: `Clip` (the provider failed the clip; its own words stay `Redacted` in `provider`, out of `message`, logs and spans), `Command` (a command for it failed, with its `CommandFailure`; an enqueue refused unsent because its session was not ready is sent there again once what the session reports has changed, as a reconnect changes it, and fails only if refused again while the session reports itself ready), `Lost` (its session was lost while it played, or before it was built twice), `Moderated` (with the verdict's `categories`) or `Closed`. `events` adds cues, session events (`Opened`, `Switched`, `Replaced`, `SetupFailed`, `Moderated`, and `Reconnecting` and `Reconnected { afterMillis }` around a dropped connection), each filler clip's start and end (`Filler`), `ReaderOverflow` when a reader of a session's video or audio falls behind its bound (with the session's `MediaPressure`), and `Starved`. `state` gives the clip on air (`playing`: its key, `"filler"` or `"other"`, when its start was seen, and its length when known), the lanes, the sessions, the runway (the air secured, on the session on air and then on its replacement) and the build estimates it learned. `video` and `audio` are the on-air picture and sound across renewals, as decoded frames, and end when the playout stops; on a host with only platform tracks, such as a browser, they fail with `UnsupportedCapability`. `cleanup` holds the close reports of retired sessions and of opens that failed after allocating: every one that may still bill, and the latest others.
|
|
186
140
|
|
|
187
|
-
`
|
|
141
|
+
**Renewal.** A capped session builds only what airs before its cap. The replacement opens `lead` (30 seconds) before the cap ends, and never earlier, so what cannot air before the cap waits for it; it takes new work, and takes the air at a boundary once the retiring session is idle and a `grace` (250 ms) has passed since its last clip ended or failed on air. A session lost before a planned switch is closed, and the clips it never aired are rebuilt on the next one. An enqueue whose outcome stays unknown holds no build slot, since H3 builds in order, and after `unknownTimeout` (60 seconds) it makes its session indeterminate, so a replacement takes over. A failed setup, an open that fails or a session lost before any clip sent to it started, is followed by the next open a second later for each failure in a row, but at most `maxSetupFailures` (3) seconds later, and never sooner than a refusal's `Retry-After`. A run of failed setups ends only when a session airs its first clip; more clips on the session already on air don't end it. After `maxSetupFailures` that count, the playout fails and closes every session, unless a session still holds the air. An open refused with nothing allocated, such as with a 4xx, billed nothing: refused while a session holds the air, it counts neither then nor later, and it is asked again after its delay however often it is refused. Once enough that count have failed while a session holds the air, the playout airs on, opens nothing until that session ends, and tries once more, once the last failure's delay and `Retry-After` have passed.
|
|
188
142
|
|
|
189
|
-
`
|
|
143
|
+
**Supervision.** `failure` completes with why the playout stopped: a session it could not open or keep, `InvalidFiller`, `Moderated`, or `Closed` when its scope closed. A defect that stopped it, such as a throwing `filler.clip`, is the defect `failure` dies with, and every defect the playout catches, in its plan, an open or a source, goes to Effect's `ErrorReporter`, a `Source` method that throws when called included. Whether that command applied is then unknown, and the playout goes on: an enqueue is never sent again, and a replacement takes over unless a read of the session's queues shows its clip within `unknownTimeout`; a `remove` is asked again once the session's queues change, and a `move` a second later; after a `setAutoplay` the session's autoplay is unknown, and the value the playout wants goes again, a second later if it is the one that died and at once if not, while that session is sent nothing else but, as it retires, the removal of its filler once its replacement has an item Ready; a `stop` or `play` ends its cut, and the cutter airs at the next boundary. A supervisor restarts a stopped playout by failing with its reason under a `Schedule`, which leaves a defect alone:
|
|
190
144
|
|
|
191
|
-
|
|
145
|
+
```ts
|
|
146
|
+
import { Effect, Schedule } from "effect";
|
|
147
|
+
import { Playout } from "reactor-effect-client";
|
|
192
148
|
|
|
193
|
-
|
|
149
|
+
export const supervised = (options: Playout.Options) =>
|
|
150
|
+
Effect.gen(function* () {
|
|
151
|
+
const playout = yield* Playout.make(options);
|
|
152
|
+
// Submit the programme here; closing the scope closes the playout and its sessions.
|
|
153
|
+
return yield* Effect.flatMap(playout.failure, Effect.fail);
|
|
154
|
+
}).pipe(Effect.scoped, Effect.retry(Schedule.exponential("5 seconds")));
|
|
155
|
+
```
|
|
194
156
|
|
|
195
|
-
|
|
157
|
+
**Moderation.** Reactor terminates a session given flagged content, and the verdict names no clip, category or request; hosted H3 sent it about a second after answering the enqueue. The playout blames the item whose enqueue was sent there last, settles it `Failed` with reason `Moderated` and never builds it again, and fails after `maxModerations` (2) moderated sessions rather than keep opening paid ones. A verdict need not come, so a clip lost unbuilt with two sessions in a row fails too; a clip that was built passed screening and is rebuilt however often it is lost.
|
|
196
158
|
|
|
197
|
-
`
|
|
159
|
+
**On hosted H3.** `stop` names no clip and lands after its reply, so a cut is a step at a time: the playout turns autoplay off, stops the clip it cuts if that still plays, waits for H3 to report it ended, looks again, plays the cutter and restores autoplay. A cutter withdrawn meanwhile is removed instead of played. The stepped cut passed on hosted H3 (the 0.8.0 `show` run) with one `stop` and a 168 ms pause, with no dark frame. A continued build took 5.45 s against about 2.2 s for an independent 5 s clip, so the plan projects it and, when it would be late, continues from the clip that will be playing then. H3 falls back to an independent clip without saying so, so as-run never claims continuity. A `Started` event is a provider fact, not proof that a frame was presented or encoded.
|
|
198
160
|
|
|
199
|
-
|
|
161
|
+
## Testing with ReactorTest
|
|
200
162
|
|
|
201
|
-
`
|
|
163
|
+
`ReactorTest.layer({ timing })` provides the `HttpClient` and `PeerFactory` that `Coordinator.layer()` and `Reactor.layer()` need, backed by an in-memory coordinator and an H3 model that speaks the real wire protocol, so an application and every SDK layer above it run unchanged without a paid session. `layerCoordinator` is the HTTP API alone, with no host. Every delay is an `Effect.sleep` drawn from `timing`: `Timing.fixed` for a scenario that names the delays it depends on, `Timing.random({ seed })` for wide ranges that repeat for a seed, and `Timing.hosted` for the ranges paid runs measured, for demos. Under `TestClock`, fork `ReactorTest.flow()` into the test's scope and minutes of programme run in milliseconds; on the live clock it plays in real time.
|
|
202
164
|
|
|
203
|
-
|
|
165
|
+
`ReactorTest` keeps Reactor's documented rules and the facts paid runs observed: tokens bound to sessions, expiry and unbound tokens refused, the API key accepted as a bearer only to read and end sessions, several connections per session, `INACTIVE` for 30 seconds after the last one drops, five concurrent sessions and ten a minute refused with `429`, H3's request, reference and metadata limits, a `stop` that lands after its acknowledgement, moderation as observed and per-second billing. The `ReactorTest` service reports `sessions`, `billing` and a `log` of every command, message and request, and `inject` arms a `Fault`: a refused allocation, connect or reconnect, the last with a `Retry-After` if asked, a spent token that allocates again or answers with its session, a create reply that names no session or a create never answered, a dropped or late reply, a stalled or failed build, a disconnect or expiry, a cap Reactor ignores, a slow or ignored `DELETE`, a read that answers 404 for a session still running, black, frozen or absent video, no audio, an invalid image, an over-granting token, a late recording or a moderation verdict. `ReactorTest.pngBytes` and `wavBytes` make reference media H3's local checks accept, and `frameOf` names the clip a simulated frame belongs to. A session on `ReactorTest` reconnects a dropped connection on its own, as on Reactor; `Reactor.layer({ reconnect: false })` keeps a disconnect down.
|
|
204
166
|
|
|
205
|
-
|
|
167
|
+
It models what H3 does, not hosted performance, billing, TURN relays or interop: those need the [hosted checks](https://github.com/mannyc2/reactor-effect-client/tree/main/integration/hosted).
|
|
206
168
|
|
|
207
169
|
## Declarations without DOM types
|
|
208
170
|
|
|
@@ -210,11 +172,11 @@ Effect `4.0.0-rc.117` itself references the global `TextDecoderOptions` type in
|
|
|
210
172
|
|
|
211
173
|
## Example
|
|
212
174
|
|
|
213
|
-
[`examples/`](https://github.com/mannyc2/reactor-effect-client/tree/main/packages/client/examples) is an application service written against
|
|
175
|
+
[`examples/`](https://github.com/mannyc2/reactor-effect-client/tree/main/packages/client/examples) is an application service written against `Playout`, run offline on `ReactorTest` and tested on Effect's test clock with faults standing in for a failed build and a lost reply. The repository's [other examples](https://github.com/mannyc2/reactor-effect-client/tree/main/examples) include a server that broadcasts one renewing playout to many browsers.
|
|
214
176
|
|
|
215
177
|
## Development
|
|
216
178
|
|
|
217
|
-
This package is built and tested from the workspace root; see the repository [CONTRIBUTING](https://github.com/mannyc2/reactor-effect-client/blob/main/CONTRIBUTING.md). Inside `packages/client`, `bun run test` runs the portable suite under Vitest and `bun run typecheck` checks the source closure both with browser types and with Node types.
|
|
179
|
+
This package is built and tested from the workspace root; see the repository [CONTRIBUTING](https://github.com/mannyc2/reactor-effect-client/blob/main/CONTRIBUTING.md). Inside `packages/client`, `bun run test` runs the portable suite under Vitest and `bun run typecheck` checks the source closure both with browser types and with Node types. The wire codec is generated from the protocol sources in [`wire/`](./wire/README.md).
|
|
218
180
|
|
|
219
181
|
## License
|
|
220
182
|
|