@wmaurer/effect-ai-amazon-bedrock 0.1.0 → 0.3.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +97 -16
  3. package/dist/AmazonBedrockClient.d.ts +135 -23
  4. package/dist/AmazonBedrockClient.d.ts.map +1 -1
  5. package/dist/AmazonBedrockClient.js +36 -92
  6. package/dist/AmazonBedrockClient.js.map +1 -1
  7. package/dist/AmazonBedrockConfig.d.ts +6 -6
  8. package/dist/AmazonBedrockConfig.js +4 -4
  9. package/dist/AmazonBedrockEventStream.d.ts +2 -2
  10. package/dist/AmazonBedrockEventStream.js +3 -3
  11. package/dist/AmazonBedrockLanguageModel.d.ts +22 -22
  12. package/dist/AmazonBedrockLanguageModel.d.ts.map +1 -1
  13. package/dist/AmazonBedrockLanguageModel.js +77 -28
  14. package/dist/AmazonBedrockLanguageModel.js.map +1 -1
  15. package/dist/AmazonBedrockSchema.d.ts +76 -55
  16. package/dist/AmazonBedrockSchema.d.ts.map +1 -1
  17. package/dist/AmazonBedrockSchema.js +63 -50
  18. package/dist/AmazonBedrockSchema.js.map +1 -1
  19. package/dist/index.d.ts +6 -6
  20. package/dist/index.js +6 -6
  21. package/dist/internal/credentials.d.ts +79 -0
  22. package/dist/internal/credentials.d.ts.map +1 -0
  23. package/dist/internal/credentials.js +241 -0
  24. package/dist/internal/credentials.js.map +1 -0
  25. package/dist/internal/errors.d.ts +2 -0
  26. package/dist/internal/errors.d.ts.map +1 -1
  27. package/dist/internal/errors.js +6 -0
  28. package/dist/internal/errors.js.map +1 -1
  29. package/dist/internal/utilities.d.ts +1 -1
  30. package/dist/internal/utilities.d.ts.map +1 -1
  31. package/dist/internal/utilities.js +4 -5
  32. package/dist/internal/utilities.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/AmazonBedrockClient.ts +184 -95
  35. package/src/AmazonBedrockConfig.ts +6 -6
  36. package/src/AmazonBedrockEventStream.ts +3 -3
  37. package/src/AmazonBedrockLanguageModel.ts +136 -62
  38. package/src/AmazonBedrockSchema.ts +77 -54
  39. package/src/index.ts +6 -6
  40. package/src/internal/credentials.ts +319 -0
  41. package/src/internal/errors.ts +5 -0
  42. package/src/internal/utilities.ts +7 -7
@@ -13,9 +13,8 @@
13
13
  * `converse-stream` (streaming) endpoints.
14
14
  *
15
15
  * @stability unstable
16
- * @since 4.0.0
16
+ * @since 0.1.0
17
17
  */
18
- import { AwsV4Signer } from "aws4fetch"
19
18
  import type * as AiError from "effect/ai/AiError"
20
19
  import * as Array from "effect/Array"
21
20
  import type * as Config from "effect/Config"
@@ -28,13 +27,13 @@ import * as HttpClient from "effect/http/HttpClient"
28
27
  import * as HttpClientRequest from "effect/http/HttpClientRequest"
29
28
  import * as HttpClientResponse from "effect/http/HttpClientResponse"
30
29
  import * as Layer from "effect/Layer"
31
- import * as Predicate from "effect/Predicate"
32
- import * as Redacted from "effect/Redacted"
30
+ import type * as Redacted from "effect/Redacted"
33
31
  import * as Stream from "effect/Stream"
34
32
  import { AmazonBedrockConfig } from "./AmazonBedrockConfig.ts"
35
33
  import * as EventStream from "./AmazonBedrockEventStream.ts"
36
34
  import type { ConverseRequest } from "./AmazonBedrockSchema.ts"
37
35
  import { ConverseResponse, ConverseResponseStreamEvent } from "./AmazonBedrockSchema.ts"
36
+ import * as Authentication from "./internal/credentials.ts"
38
37
  import * as Errors from "./internal/errors.ts"
39
38
 
40
39
  // =============================================================================
@@ -47,7 +46,7 @@ import * as Errors from "./internal/errors.ts"
47
46
  *
48
47
  * @stability unstable
49
48
  * @category models
50
- * @since 4.0.0
49
+ * @since 0.1.0
51
50
  */
52
51
  export interface Service {
53
52
  /**
@@ -76,7 +75,7 @@ export interface Service {
76
75
  *
77
76
  * @stability unstable
78
77
  * @category services
79
- * @since 4.0.0
78
+ * @since 0.1.0
80
79
  */
81
80
  export class AmazonBedrockClient extends Context.Service<AmazonBedrockClient, Service>()(
82
81
  "@wmaurer/effect-ai-amazon-bedrock/AmazonBedrockClient"
@@ -87,13 +86,58 @@ export class AmazonBedrockClient extends Context.Service<AmazonBedrockClient, Se
87
86
  // =============================================================================
88
87
 
89
88
  /**
90
- * Configuration for creating an Amazon Bedrock client.
89
+ * SigV4 credentials as a {@link CredentialProvider} returns them. The shape is
90
+ * the AWS SDK's `AwsCredentialIdentity`, so the SDK's providers fit without an
91
+ * adapter.
91
92
  *
92
93
  * @stability unstable
93
94
  * @category options
94
- * @since 4.0.0
95
+ * @since 0.2.0
95
96
  */
96
- export type Options = {
97
+ export interface Credentials {
98
+ readonly accessKeyId: string
99
+ readonly secretAccessKey: string
100
+ /** An empty token is sent as no token. */
101
+ readonly sessionToken?: string | undefined
102
+ /** The client asks the provider for new credentials five minutes before this time. */
103
+ readonly expiration?: Date | undefined
104
+ }
105
+
106
+ /**
107
+ * Supplies SigV4 credentials that can change while the program runs.
108
+ *
109
+ * **Details**
110
+ *
111
+ * A provider is one of these:
112
+ *
113
+ * - A function in the shape of the AWS SDK's credential providers, such as
114
+ * `fromNodeProviderChain()` from `@aws-sdk/credential-providers`. A rejected
115
+ * promise fails the request with an `AuthenticationError` of kind
116
+ * `"Unknown"`. After Bedrock rejects the credentials, the client calls the
117
+ * function with `{ forceRefresh: true }`.
118
+ * - An `Effect`. It can fail with an `AiError`, which the request fails with
119
+ * unchanged, or with an `AiError` reason, such as an `AuthenticationError`,
120
+ * which the client wraps in an `AiError`. The services that it requires
121
+ * become requirements of the layer. It runs with the services of the
122
+ * request first, and the services that the layer was built with fill in the
123
+ * rest.
124
+ *
125
+ * The client runs the provider at most once at a time, and keeps the
126
+ * credentials until five minutes before their `expiration`. Credentials with
127
+ * no `expiration` are kept until Bedrock rejects them. Keys that are empty fail
128
+ * the request with an `AuthenticationError` of kind `"MissingKey"`.
129
+ *
130
+ * @stability unstable
131
+ * @category options
132
+ * @since 0.2.0
133
+ */
134
+ export type CredentialProvider<R = never> =
135
+ // `forceRefresh` has no `| undefined`: with `exactOptionalPropertyTypes`, the
136
+ // AWS SDK's provider types would not assign to it.
137
+ | ((options?: { readonly forceRefresh?: boolean }) => PromiseLike<Credentials>)
138
+ | Effect.Effect<Credentials, AiError.AiError | AiError.AiErrorReason, R>
139
+
140
+ interface CommonOptions {
97
141
  /**
98
142
  * The base URL for the Bedrock runtime API. Override to use a proxy or a
99
143
  * different endpoint.
@@ -101,9 +145,6 @@ export type Options = {
101
145
  * @default `https://bedrock-runtime.${region}.amazonaws.com`
102
146
  */
103
147
  readonly apiUrl?: string | undefined
104
- readonly accessKeyId: string
105
- readonly secretAccessKey: Redacted.Redacted<string>
106
- readonly sessionToken?: Redacted.Redacted<string> | undefined
107
148
  /**
108
149
  * The AWS region.
109
150
  *
@@ -113,6 +154,81 @@ export type Options = {
113
154
  readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
114
155
  }
115
156
 
157
+ interface StaticKeys {
158
+ readonly accessKeyId: string
159
+ readonly secretAccessKey: Redacted.Redacted<string>
160
+ readonly sessionToken?: Redacted.Redacted<string> | undefined
161
+ readonly credentialProvider?: never
162
+ readonly apiKey?: never
163
+ }
164
+
165
+ interface ProvidedKeys<R> {
166
+ readonly credentialProvider: CredentialProvider<R>
167
+ readonly accessKeyId?: never
168
+ readonly secretAccessKey?: never
169
+ readonly sessionToken?: never
170
+ readonly apiKey?: never
171
+ }
172
+
173
+ interface ApiKey {
174
+ /** A Bedrock API key, sent as `Authorization: Bearer <key>` in place of a SigV4 signature. */
175
+ readonly apiKey: Redacted.Redacted<string>
176
+ readonly accessKeyId?: never
177
+ readonly secretAccessKey?: never
178
+ readonly sessionToken?: never
179
+ readonly credentialProvider?: never
180
+ }
181
+
182
+ /**
183
+ * Configuration for creating an Amazon Bedrock client.
184
+ *
185
+ * **Details**
186
+ *
187
+ * The options take exactly one way to authenticate:
188
+ *
189
+ * - `accessKeyId` and `secretAccessKey`, and an optional `sessionToken`.
190
+ * - `credentialProvider`, a {@link CredentialProvider}.
191
+ * - `apiKey`, a Bedrock API key.
192
+ *
193
+ * @stability unstable
194
+ * @category options
195
+ * @since 0.1.0
196
+ */
197
+ export type Options<R = never> = CommonOptions & (StaticKeys | ProvidedKeys<R> | ApiKey)
198
+
199
+ /**
200
+ * The {@link Options} of {@link layerConfig}, with a `Config` for each value.
201
+ * `credentialProvider` and `transformClient` are not configuration, so they
202
+ * take the same values as in {@link Options}.
203
+ *
204
+ * @stability unstable
205
+ * @category options
206
+ * @since 0.2.0
207
+ */
208
+ export type ConfigOptions<R = never> =
209
+ & {
210
+ readonly apiUrl?: Config.Config<string> | undefined
211
+ readonly region?: Config.Config<string> | undefined
212
+ readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
213
+ }
214
+ & (
215
+ | {
216
+ readonly accessKeyId: Config.Config<string>
217
+ readonly secretAccessKey: Config.Config<Redacted.Redacted<string>>
218
+ readonly sessionToken?: Config.Config<Redacted.Redacted<string>> | undefined
219
+ readonly credentialProvider?: never
220
+ readonly apiKey?: never
221
+ }
222
+ | ProvidedKeys<R>
223
+ | {
224
+ readonly apiKey: Config.Config<Redacted.Redacted<string>>
225
+ readonly accessKeyId?: never
226
+ readonly secretAccessKey?: never
227
+ readonly sessionToken?: never
228
+ readonly credentialProvider?: never
229
+ }
230
+ )
231
+
116
232
  // =============================================================================
117
233
  // Constructor
118
234
  // =============================================================================
@@ -130,11 +246,19 @@ const withRedactedHeaders = Effect.updateService(Headers.CurrentRedactedNames, a
130
246
  *
131
247
  * @stability unstable
132
248
  * @category constructors
133
- * @since 4.0.0
249
+ * @since 0.1.0
134
250
  */
135
- export const make = Effect.fnUntraced(
136
- function*(options: Options): Effect.fn.Return<Service, never, HttpClient.HttpClient> {
251
+ export const make = <R = never>(options: Options<R>): Effect.Effect<Service, never, HttpClient.HttpClient | R> =>
252
+ makeUnsafe(options)
253
+
254
+ // Takes each authentication field as optional, as `layerConfig` reads them.
255
+ // `Authentication.make` dies on a mix of the ways to authenticate.
256
+ const makeUnsafe = <R>(
257
+ options: CommonOptions & Authentication.AuthenticationOptions<R>
258
+ ): Effect.Effect<Service, never, HttpClient.HttpClient | R> =>
259
+ Effect.gen(function*() {
137
260
  const region = options.region ?? "us-east-1"
261
+ const authenticator = yield* Authentication.make(options)
138
262
 
139
263
  const baseClient = yield* HttpClient.HttpClient
140
264
 
@@ -145,23 +269,7 @@ export const make = Effect.fnUntraced(
145
269
  HttpClientRequest.acceptJson
146
270
  )
147
271
  ),
148
- HttpClient.mapRequestEffect(Effect.fnUntraced(function*(request) {
149
- const originalHeaders = request.headers
150
- const signer = new AwsV4Signer({
151
- service: "bedrock",
152
- url: request.url,
153
- method: request.method,
154
- headers: Object.entries(originalHeaders),
155
- body: prepareBody(request.body),
156
- region,
157
- accessKeyId: options.accessKeyId,
158
- secretAccessKey: Redacted.value(options.secretAccessKey),
159
- ...(options.sessionToken ? { sessionToken: Redacted.value(options.sessionToken) } : {})
160
- })
161
- const { headers: signedHeaders } = yield* Effect.promise(() => signer.sign())
162
- const headers = Headers.merge(originalHeaders, Headers.fromInput(signedHeaders))
163
- return HttpClientRequest.setHeaders(request, headers)
164
- })),
272
+ HttpClient.mapRequestEffect(Authentication.authenticateRequest(region)),
165
273
  options.transformClient ? options.transformClient : identity
166
274
  )
167
275
 
@@ -172,15 +280,24 @@ export const make = Effect.fnUntraced(
172
280
  return config?.transformClient ? config.transformClient(httpClientOk) : httpClientOk
173
281
  })
174
282
 
283
+ const resolveCredentials = (method: string) =>
284
+ Effect.mapError(authenticator.resolve, Errors.mapCredentialProviderError(method))
285
+
175
286
  const converse: Service["converse"] = ({ payload: { modelId, ...body } }) =>
176
- Effect.flatMap(withConfigClient(), (client) => {
287
+ Effect.gen(function*() {
288
+ const client = yield* withConfigClient()
289
+ const credentials = yield* resolveCredentials("converse")
177
290
  const request = HttpClientRequest.post(`/model/${modelId}/converse`, {
178
291
  body: HttpBody.jsonUnsafe(body)
179
292
  })
180
- return client.execute(request).pipe(
293
+ return yield* client.execute(request).pipe(
294
+ Effect.provideService(Authentication.CurrentRequestCredentials, credentials),
181
295
  Effect.flatMap(HttpClientResponse.schemaBodyJson(ConverseResponse)),
182
296
  Effect.catchTags({
183
- HttpClientError: (error) => Errors.mapHttpClientError(error, "converse"),
297
+ HttpClientError: (error) =>
298
+ Errors.mapHttpClientError(error, "converse").pipe(
299
+ Effect.tapError(Authentication.invalidateIfRejected(authenticator, credentials))
300
+ ),
184
301
  SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "converse"))
185
302
  }),
186
303
  withRedactedHeaders
@@ -192,18 +309,27 @@ export const make = Effect.fnUntraced(
192
309
  body: HttpBody.jsonUnsafe(body)
193
310
  })
194
311
  return Stream.unwrap(
195
- Effect.map(withConfigClient(), (client) =>
196
- client.execute(request).pipe(
312
+ Effect.gen(function*() {
313
+ const client = yield* withConfigClient()
314
+ const credentials = yield* resolveCredentials("converseStream")
315
+ return client.execute(request).pipe(
316
+ Effect.provideService(Authentication.CurrentRequestCredentials, credentials),
197
317
  Effect.map((response) => response.stream),
198
318
  Stream.unwrap,
199
319
  Stream.pipeThroughChannel(EventStream.makeChannel(ConverseResponseStreamEvent)),
200
320
  Stream.catchTags({
201
- HttpClientError: (error) => Stream.fromEffect(Errors.mapHttpClientError(error, "converseStream")),
321
+ HttpClientError: (error) =>
322
+ Stream.fromEffect(
323
+ Errors.mapHttpClientError(error, "converseStream").pipe(
324
+ Effect.tapError(Authentication.invalidateIfRejected(authenticator, credentials))
325
+ )
326
+ ),
202
327
  SchemaError: (error) => Stream.fail(Errors.mapSchemaError(error, "converseStream")),
203
328
  EventStreamError: (error) => Stream.fail(Errors.mapEventStreamError(error, "converseStream"))
204
329
  }),
205
330
  Stream.updateService(Headers.CurrentRedactedNames, appendRedactedHeaders)
206
- ))
331
+ )
332
+ })
207
333
  )
208
334
  }
209
335
 
@@ -211,9 +337,7 @@ export const make = Effect.fnUntraced(
211
337
  converse,
212
338
  converseStream
213
339
  })
214
- },
215
- withRedactedHeaders
216
- )
340
+ }).pipe(withRedactedHeaders)
217
341
 
218
342
  // =============================================================================
219
343
  // Layers
@@ -224,9 +348,11 @@ export const make = Effect.fnUntraced(
224
348
  *
225
349
  * @stability unstable
226
350
  * @category layers
227
- * @since 4.0.0
351
+ * @since 0.1.0
228
352
  */
229
- export const layer = (options: Options): Layer.Layer<AmazonBedrockClient, never, HttpClient.HttpClient> =>
353
+ export const layer = <R = never>(
354
+ options: Options<R>
355
+ ): Layer.Layer<AmazonBedrockClient, never, HttpClient.HttpClient | R> =>
230
356
  Layer.effect(AmazonBedrockClient, make(options))
231
357
 
232
358
  /**
@@ -235,63 +361,26 @@ export const layer = (options: Options): Layer.Layer<AmazonBedrockClient, never,
235
361
  *
236
362
  * @stability unstable
237
363
  * @category layers
238
- * @since 4.0.0
364
+ * @since 0.1.0
239
365
  */
240
- export const layerConfig = (options: {
241
- readonly apiUrl?: Config.Config<string> | undefined
242
- readonly accessKeyId: Config.Config<string>
243
- readonly secretAccessKey: Config.Config<Redacted.Redacted<string>>
244
- readonly sessionToken?: Config.Config<Redacted.Redacted<string>> | undefined
245
- readonly region?: Config.Config<string> | undefined
246
- readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
247
- }): Layer.Layer<AmazonBedrockClient, Config.ConfigError, HttpClient.HttpClient> =>
366
+ export const layerConfig = <R = never>(
367
+ options: ConfigOptions<R>
368
+ ): Layer.Layer<AmazonBedrockClient, Config.ConfigError, HttpClient.HttpClient | R> =>
248
369
  Layer.effect(
249
370
  AmazonBedrockClient,
250
371
  Effect.gen(function*() {
251
- const apiUrl = Predicate.isNotUndefined(options.apiUrl)
252
- ? yield* options.apiUrl :
253
- undefined
254
- const accessKeyId = yield* options.accessKeyId
255
- const secretAccessKey = yield* options.secretAccessKey
256
- const sessionToken = Predicate.isNotUndefined(options.sessionToken)
257
- ? yield* options.sessionToken :
258
- undefined
259
- const region = Predicate.isNotUndefined(options.region)
260
- ? yield* options.region :
261
- undefined
262
- return yield* make({
263
- apiUrl,
264
- accessKeyId,
265
- secretAccessKey,
266
- sessionToken,
267
- region,
372
+ return yield* makeUnsafe({
373
+ apiUrl: yield* readOptional(options.apiUrl),
374
+ region: yield* readOptional(options.region),
375
+ accessKeyId: yield* readOptional(options.accessKeyId),
376
+ secretAccessKey: yield* readOptional(options.secretAccessKey),
377
+ sessionToken: yield* readOptional(options.sessionToken),
378
+ apiKey: yield* readOptional(options.apiKey),
379
+ credentialProvider: options.credentialProvider,
268
380
  transformClient: options.transformClient
269
381
  })
270
382
  })
271
383
  )
272
384
 
273
- // =============================================================================
274
- // Utilities
275
- // =============================================================================
276
-
277
- const prepareBody = (body: HttpBody.HttpBody): string => {
278
- switch (body._tag) {
279
- case "Empty": {
280
- return ""
281
- }
282
- case "Raw":
283
- case "Uint8Array": {
284
- if (typeof body.body === "string") {
285
- return body.body
286
- }
287
- if (body.body instanceof Uint8Array) {
288
- return new TextDecoder().decode(body.body)
289
- }
290
- if (body.body instanceof ArrayBuffer) {
291
- return new TextDecoder().decode(body.body)
292
- }
293
- return JSON.stringify(body.body)
294
- }
295
- }
296
- throw new Error("Unsupported HttpBody: " + body._tag)
297
- }
385
+ const readOptional = <A>(config: Config.Config<A> | undefined): Effect.Effect<A | undefined, Config.ConfigError> =>
386
+ config === undefined ? Effect.undefined : config
@@ -4,7 +4,7 @@
4
4
  * underlying HTTP client without changing individual request code.
5
5
  *
6
6
  * @stability unstable
7
- * @since 4.0.0
7
+ * @since 0.1.0
8
8
  */
9
9
  import * as Context from "effect/Context"
10
10
  import * as Effect from "effect/Effect"
@@ -17,7 +17,7 @@ import type { HttpClient } from "effect/http/HttpClient"
17
17
  *
18
18
  * @stability unstable
19
19
  * @category services
20
- * @since 4.0.0
20
+ * @since 0.1.0
21
21
  */
22
22
  export class AmazonBedrockConfig extends Context.Service<
23
23
  AmazonBedrockConfig,
@@ -26,7 +26,7 @@ export class AmazonBedrockConfig extends Context.Service<
26
26
  /**
27
27
  * Gets the configured Amazon Bedrock service from the current context when present.
28
28
  *
29
- * @since 4.0.0
29
+ * @since 0.1.0
30
30
  */
31
31
  static readonly getOrUndefined: Effect.Effect<typeof AmazonBedrockConfig.Service | undefined> = Effect.map(
32
32
  Effect.context<never>(),
@@ -38,14 +38,14 @@ export class AmazonBedrockConfig extends Context.Service<
38
38
  * Namespace containing types associated with the `AmazonBedrockConfig` service.
39
39
  *
40
40
  * @stability unstable
41
- * @since 4.0.0
41
+ * @since 0.1.0
42
42
  */
43
43
  export declare namespace AmazonBedrockConfig {
44
44
  /**
45
45
  * Configuration provided through `AmazonBedrockConfig`.
46
46
  *
47
47
  * @category models
48
- * @since 4.0.0
48
+ * @since 0.1.0
49
49
  */
50
50
  export interface Service {
51
51
  readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined
@@ -58,7 +58,7 @@ export declare namespace AmazonBedrockConfig {
58
58
  *
59
59
  * @stability unstable
60
60
  * @category configuration
61
- * @since 4.0.0
61
+ * @since 0.1.0
62
62
  */
63
63
  export const withClientTransform: {
64
64
  (transform: (client: HttpClient) => HttpClient): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
@@ -17,7 +17,7 @@
17
17
  * for more information.
18
18
  *
19
19
  * @stability unstable
20
- * @since 4.0.0
20
+ * @since 0.1.0
21
21
  */
22
22
  import * as Arr from "effect/Array"
23
23
  import type { NonEmptyReadonlyArray } from "effect/Array"
@@ -35,7 +35,7 @@ const textDecoder = new TextDecoder()
35
35
  *
36
36
  * @stability unstable
37
37
  * @category errors
38
- * @since 4.0.0
38
+ * @since 0.1.0
39
39
  */
40
40
  export class EventStreamError extends Schema.TaggedError<EventStreamError>(
41
41
  "@wmaurer/effect-ai-amazon-bedrock/AmazonBedrockEventStream/EventStreamError"
@@ -138,7 +138,7 @@ const decodeFrame = (frame: Uint8Array): DecodedFrame => {
138
138
  *
139
139
  * @stability unstable
140
140
  * @category constructors
141
- * @since 4.0.0
141
+ * @since 0.1.0
142
142
  */
143
143
  export const makeChannel = <A, I, RD, IE, Done>(
144
144
  schema: Schema.Codec<A, I, RD>