@effect/platform-node 4.0.0-beta.99 → 4.0.0-rc.109
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/AGENTS.md +395 -0
- package/CLAUDE.md +395 -0
- package/README.md +10 -3
- package/ai-docs/README.md +44 -0
- package/ai-docs/package.json +36 -0
- package/ai-docs/src/01_effect/01_basics/01_effect-gen.ts +30 -0
- package/ai-docs/src/01_effect/01_basics/02_effect-fn.ts +39 -0
- package/ai-docs/src/01_effect/01_basics/10_creating-effects.ts +74 -0
- package/ai-docs/src/01_effect/01_basics/index.md +5 -0
- package/ai-docs/src/01_effect/02_schema/10_schema-basics.ts +43 -0
- package/ai-docs/src/01_effect/02_schema/index.md +7 -0
- package/ai-docs/src/01_effect/03_services/01_service.ts +45 -0
- package/ai-docs/src/01_effect/03_services/10_reference.ts +10 -0
- package/ai-docs/src/01_effect/03_services/20_layer-composition.ts +70 -0
- package/ai-docs/src/01_effect/03_services/20_layer-unwrap.ts +66 -0
- package/ai-docs/src/01_effect/03_services/index.md +5 -0
- package/ai-docs/src/01_effect/04_errors/01_error-handling.ts +30 -0
- package/ai-docs/src/01_effect/04_errors/10_catch-tags.ts +24 -0
- package/ai-docs/src/01_effect/04_errors/20_reason-errors.ts +64 -0
- package/ai-docs/src/01_effect/04_errors/index.md +1 -0
- package/ai-docs/src/01_effect/05_resources/10_acquire-release.ts +105 -0
- package/ai-docs/src/01_effect/05_resources/20_layer-side-effects.ts +31 -0
- package/ai-docs/src/01_effect/05_resources/30_layer-map.ts +86 -0
- package/ai-docs/src/01_effect/05_resources/index.md +3 -0
- package/ai-docs/src/01_effect/06_running/10_run-main.ts +30 -0
- package/ai-docs/src/01_effect/06_running/20_layer-launch.ts +27 -0
- package/ai-docs/src/01_effect/06_running/index.md +1 -0
- package/ai-docs/src/01_effect/07_pubsub/10_pubsub.ts +56 -0
- package/ai-docs/src/01_effect/07_pubsub/index.md +3 -0
- package/ai-docs/src/03_stream/10_creating-streams.ts +103 -0
- package/ai-docs/src/03_stream/20_consuming-streams.ts +137 -0
- package/ai-docs/src/03_stream/30_encoding.ts +165 -0
- package/ai-docs/src/03_stream/index.md +4 -0
- package/ai-docs/src/04_integration/10_managed-runtime.ts +129 -0
- package/ai-docs/src/04_integration/index.md +5 -0
- package/ai-docs/src/05_batching/10_request-resolver.ts +89 -0
- package/ai-docs/src/05_batching/index.md +3 -0
- package/ai-docs/src/06_schedule/10_schedules.ts +110 -0
- package/ai-docs/src/06_schedule/index.md +3 -0
- package/ai-docs/src/07_datetime/10_creating-and-formatting.ts +30 -0
- package/ai-docs/src/07_datetime/20_time-zones.ts +44 -0
- package/ai-docs/src/07_datetime/index.md +5 -0
- package/ai-docs/src/08_observability/10_logging.ts +66 -0
- package/ai-docs/src/08_observability/20_otlp-tracing.ts +95 -0
- package/ai-docs/src/08_observability/index.md +7 -0
- package/ai-docs/src/09_testing/10_effect-tests.ts +55 -0
- package/ai-docs/src/09_testing/20_layer-tests.ts +138 -0
- package/ai-docs/src/09_testing/index.md +1 -0
- package/ai-docs/src/10_predicate/01_basics.ts +14 -0
- package/ai-docs/src/10_predicate/index.md +9 -0
- package/ai-docs/src/40_sql/10_basics.ts +175 -0
- package/ai-docs/src/40_sql/index.md +6 -0
- package/ai-docs/src/50_http-client/10_basics.ts +102 -0
- package/ai-docs/src/50_http-client/index.md +3 -0
- package/ai-docs/src/51_http-server/10_basics.ts +118 -0
- package/ai-docs/src/51_http-server/20_testing.ts +100 -0
- package/ai-docs/src/51_http-server/fixtures/api/Api.ts +14 -0
- package/ai-docs/src/51_http-server/fixtures/api/Authorization.ts +36 -0
- package/ai-docs/src/51_http-server/fixtures/api/System.ts +10 -0
- package/ai-docs/src/51_http-server/fixtures/api/Users.ts +107 -0
- package/ai-docs/src/51_http-server/fixtures/domain/User.ts +21 -0
- package/ai-docs/src/51_http-server/fixtures/domain/UserErrors.ts +22 -0
- package/ai-docs/src/51_http-server/fixtures/server/Authorization.ts +37 -0
- package/ai-docs/src/51_http-server/fixtures/server/Users/http.ts +80 -0
- package/ai-docs/src/51_http-server/fixtures/server/Users.ts +183 -0
- package/ai-docs/src/51_http-server/index.md +3 -0
- package/ai-docs/src/60_child-process/10_working-with-child-processes.ts +117 -0
- package/ai-docs/src/60_child-process/index.md +3 -0
- package/ai-docs/src/70_cli/10_basics.ts +160 -0
- package/ai-docs/src/70_cli/index.md +5 -0
- package/ai-docs/src/71_ai/10_language-model.ts +156 -0
- package/ai-docs/src/71_ai/20_tools.ts +226 -0
- package/ai-docs/src/71_ai/30_chat.ts +158 -0
- package/ai-docs/src/71_ai/fixtures/domain/LaunchPlan.ts +9 -0
- package/ai-docs/src/71_ai/index.md +5 -0
- package/ai-docs/src/80_cluster/10_entities.ts +97 -0
- package/ai-docs/src/80_cluster/index.md +4 -0
- package/ai-docs/src/index.md +10 -0
- package/ai-docs/tsconfig.json +24 -0
- package/dist/Mime.js.map +1 -1
- package/dist/NodeClusterHttp.d.ts +1 -0
- package/dist/NodeClusterHttp.d.ts.map +1 -1
- package/dist/NodeClusterHttp.js +6 -1
- package/dist/NodeClusterHttp.js.map +1 -1
- package/dist/NodeClusterSocket.d.ts +1 -0
- package/dist/NodeClusterSocket.d.ts.map +1 -1
- package/dist/NodeClusterSocket.js +10 -2
- package/dist/NodeClusterSocket.js.map +1 -1
- package/dist/NodeCrypto.js.map +1 -1
- package/dist/NodeFileSystem.js.map +1 -1
- package/dist/NodeHttpClient.d.ts +18 -18
- package/dist/NodeHttpClient.d.ts.map +1 -1
- package/dist/NodeHttpClient.js +26 -20
- package/dist/NodeHttpClient.js.map +1 -1
- package/dist/NodeHttpIncomingMessage.js.map +1 -1
- package/dist/NodeHttpPlatform.d.ts +8 -4
- package/dist/NodeHttpPlatform.d.ts.map +1 -1
- package/dist/NodeHttpPlatform.js +38 -0
- package/dist/NodeHttpPlatform.js.map +1 -1
- package/dist/NodeHttpServer.d.ts +21 -16
- package/dist/NodeHttpServer.d.ts.map +1 -1
- package/dist/NodeHttpServer.js +29 -21
- package/dist/NodeHttpServer.js.map +1 -1
- package/dist/NodeHttpServerRequest.js.map +1 -1
- package/dist/NodeMultipart.d.ts.map +1 -1
- package/dist/NodeMultipart.js +3 -2
- package/dist/NodeMultipart.js.map +1 -1
- package/dist/NodeMultipartParser.d.ts +97 -0
- package/dist/NodeMultipartParser.d.ts.map +1 -0
- package/dist/NodeMultipartParser.js +108 -0
- package/dist/NodeMultipartParser.js.map +1 -0
- package/dist/NodePath.js.map +1 -1
- package/dist/NodeRedis.d.ts +40 -15
- package/dist/NodeRedis.d.ts.map +1 -1
- package/dist/NodeRedis.js +66 -16
- package/dist/NodeRedis.js.map +1 -1
- package/dist/NodeRuntime.js.map +1 -1
- package/dist/NodeServices.js.map +1 -1
- package/dist/NodeSocket.js.map +1 -1
- package/dist/NodeStdio.js.map +1 -1
- package/dist/NodeTerminal.js.map +1 -1
- package/dist/NodeWorker.js.map +1 -1
- package/dist/NodeWorkerRunner.d.ts.map +1 -1
- package/dist/NodeWorkerRunner.js +30 -18
- package/dist/NodeWorkerRunner.js.map +1 -1
- package/dist/Undici.d.ts +2 -2
- package/dist/Undici.js +2 -2
- package/dist/Undici.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +17 -14
- package/src/NodeClusterHttp.ts +6 -2
- package/src/NodeClusterSocket.ts +8 -2
- package/src/NodeHttpClient.ts +27 -20
- package/src/NodeHttpPlatform.ts +49 -0
- package/src/NodeHttpServer.ts +61 -40
- package/src/NodeMultipart.ts +5 -4
- package/src/NodeMultipartParser.ts +184 -0
- package/src/NodeRedis.ts +86 -26
- package/src/NodeWorkerRunner.ts +39 -23
- package/src/Undici.ts +2 -2
- package/src/index.ts +5 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js streams adapter for the low-level multipart parser.
|
|
3
|
+
*
|
|
4
|
+
* @since 4.0.0
|
|
5
|
+
*/
|
|
6
|
+
// oxlint-disable typescript/no-unsafe-declaration-merging
|
|
7
|
+
/// <reference types="node" />
|
|
8
|
+
import type { BaseConfig, MultipartError, Parser, PartInfo } from "effect/unstable/http/MultipartParser"
|
|
9
|
+
import { make as makeParser } from "effect/unstable/http/MultipartParser"
|
|
10
|
+
import type { IncomingHttpHeaders } from "node:http"
|
|
11
|
+
import { Duplex, Readable } from "node:stream"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A part emitted by the Node.js multipart parser.
|
|
15
|
+
*
|
|
16
|
+
* @category models
|
|
17
|
+
* @since 4.0.0
|
|
18
|
+
*/
|
|
19
|
+
export type Part = Field | FileStream
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A parsed multipart field.
|
|
23
|
+
*
|
|
24
|
+
* @category models
|
|
25
|
+
* @since 4.0.0
|
|
26
|
+
*/
|
|
27
|
+
export interface Field {
|
|
28
|
+
readonly _tag: "Field"
|
|
29
|
+
readonly info: PartInfo
|
|
30
|
+
readonly value: Uint8Array
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A Node.js duplex stream that emits parsed multipart parts.
|
|
35
|
+
*
|
|
36
|
+
* @category models
|
|
37
|
+
* @since 4.0.0
|
|
38
|
+
*/
|
|
39
|
+
export interface MultipartStream extends Duplex {
|
|
40
|
+
[Symbol.asyncIterator](): NodeJS.AsyncIterator<Part>
|
|
41
|
+
|
|
42
|
+
on(event: "field", listener: (field: Field) => void): this
|
|
43
|
+
on(event: "file", listener: (file: FileStream) => void): this
|
|
44
|
+
on(event: "close", listener: () => void): this
|
|
45
|
+
on(event: "data", listener: (part: Part) => void): this
|
|
46
|
+
on(event: "drain", listener: () => void): this
|
|
47
|
+
on(event: "end", listener: () => void): this
|
|
48
|
+
on(event: "error", listener: (err: MultipartError) => void): this
|
|
49
|
+
on(event: "finish", listener: () => void): this
|
|
50
|
+
on(event: "pause", listener: () => void): this
|
|
51
|
+
on(event: "pipe", listener: (src: Readable) => void): this
|
|
52
|
+
on(event: "readable", listener: () => void): this
|
|
53
|
+
on(event: "resume", listener: () => void): this
|
|
54
|
+
on(event: "unpipe", listener: (src: Readable) => void): this
|
|
55
|
+
on(event: string | symbol, listener: (...args: Array<any>) => void): this
|
|
56
|
+
|
|
57
|
+
read(size?: number): Part | null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Configuration for the Node.js multipart parser.
|
|
62
|
+
*
|
|
63
|
+
* @category models
|
|
64
|
+
* @since 4.0.0
|
|
65
|
+
*/
|
|
66
|
+
export type NodeConfig = Omit<BaseConfig, "headers"> & {
|
|
67
|
+
readonly headers: IncomingHttpHeaders
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A Node.js duplex stream that parses multipart input.
|
|
72
|
+
*
|
|
73
|
+
* @category models
|
|
74
|
+
* @since 4.0.0
|
|
75
|
+
*/
|
|
76
|
+
export class MultipartStream extends Duplex {
|
|
77
|
+
private _parser: Parser
|
|
78
|
+
_canWrite = true
|
|
79
|
+
private _writeCallback: (() => void) | undefined
|
|
80
|
+
|
|
81
|
+
constructor(config: NodeConfig) {
|
|
82
|
+
super({ readableObjectMode: true })
|
|
83
|
+
let currentError: MultipartError | undefined
|
|
84
|
+
let currentFile: FileStream | undefined
|
|
85
|
+
this._parser = makeParser({
|
|
86
|
+
...(config as any),
|
|
87
|
+
onField: (info, value) => {
|
|
88
|
+
if (currentError !== undefined) return
|
|
89
|
+
const field: Field = { _tag: "Field", info, value }
|
|
90
|
+
this.push(field)
|
|
91
|
+
this.emit("field", field)
|
|
92
|
+
},
|
|
93
|
+
onFile: (info) => {
|
|
94
|
+
if (currentError !== undefined) return (_) => {}
|
|
95
|
+
const file = new FileStream(info, this)
|
|
96
|
+
currentFile = file
|
|
97
|
+
this.push(file)
|
|
98
|
+
this.emit("file", file)
|
|
99
|
+
return (chunk) => {
|
|
100
|
+
if (currentError !== undefined) return
|
|
101
|
+
this._canWrite = file.push(chunk)
|
|
102
|
+
if (chunk === null && !this._canWrite) {
|
|
103
|
+
currentFile = undefined
|
|
104
|
+
this._resume()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
onError: (error) => {
|
|
109
|
+
this.emit("error", error)
|
|
110
|
+
currentFile?.emit("error", error)
|
|
111
|
+
currentError = error
|
|
112
|
+
},
|
|
113
|
+
onDone: () => {
|
|
114
|
+
this.push(null)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_resume() {
|
|
120
|
+
this._canWrite = true
|
|
121
|
+
if (this._writeCallback !== undefined) {
|
|
122
|
+
const callback = this._writeCallback
|
|
123
|
+
this._writeCallback = undefined
|
|
124
|
+
callback()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
override _read(_size: number) {}
|
|
129
|
+
|
|
130
|
+
override _write(
|
|
131
|
+
chunk: any,
|
|
132
|
+
encoding: BufferEncoding,
|
|
133
|
+
callback: (error?: Error | null | undefined) => void
|
|
134
|
+
): void {
|
|
135
|
+
this._parser.write(
|
|
136
|
+
chunk instanceof Uint8Array ? chunk : Buffer.from(chunk, encoding)
|
|
137
|
+
)
|
|
138
|
+
if (this._canWrite) {
|
|
139
|
+
callback()
|
|
140
|
+
} else {
|
|
141
|
+
this._writeCallback = callback
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override _final(callback: (error?: Error | null | undefined) => void): void {
|
|
146
|
+
this._parser.end()
|
|
147
|
+
callback()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates a Node.js multipart parser stream.
|
|
153
|
+
*
|
|
154
|
+
* @category constructors
|
|
155
|
+
* @since 4.0.0
|
|
156
|
+
*/
|
|
157
|
+
export const make = (config: NodeConfig): MultipartStream => new MultipartStream(config)
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A readable stream containing a parsed multipart file.
|
|
161
|
+
*
|
|
162
|
+
* @category models
|
|
163
|
+
* @since 4.0.0
|
|
164
|
+
*/
|
|
165
|
+
export class FileStream extends Readable {
|
|
166
|
+
readonly _tag = "File"
|
|
167
|
+
readonly filename: string | undefined
|
|
168
|
+
readonly info: PartInfo
|
|
169
|
+
private _parent: MultipartStream
|
|
170
|
+
constructor(
|
|
171
|
+
info: PartInfo,
|
|
172
|
+
parent: MultipartStream
|
|
173
|
+
) {
|
|
174
|
+
super()
|
|
175
|
+
this.info = info
|
|
176
|
+
this._parent = parent
|
|
177
|
+
this.filename = info.filename
|
|
178
|
+
}
|
|
179
|
+
override _read(_size: number) {
|
|
180
|
+
if (this._parent._canWrite === false) {
|
|
181
|
+
this._parent._resume()
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
package/src/NodeRedis.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Node.js Redis integration backed by `
|
|
2
|
+
* Node.js Redis integration backed by `redis` (node-redis).
|
|
3
3
|
*
|
|
4
|
-
* This module creates a scoped `
|
|
4
|
+
* This module creates a scoped `node-redis` client and exposes it in two forms:
|
|
5
5
|
* the generic `Redis` service and the {@link NodeRedis} service for direct
|
|
6
|
-
* access to the underlying client. `layer` accepts
|
|
7
|
-
* while `layerConfig` reads them from Effect config.
|
|
8
|
-
*
|
|
6
|
+
* access to the underlying client. `layer` accepts node-redis client options
|
|
7
|
+
* directly, while `layerConfig` reads them from Effect config. `node-redis`
|
|
8
|
+
* connects explicitly, so layer construction can fail with a `RedisError`.
|
|
9
|
+
* Both layers close the client when the layer scope ends.
|
|
9
10
|
*
|
|
10
11
|
* @since 4.0.0
|
|
11
12
|
*/
|
|
@@ -14,31 +15,68 @@ import * as Context from "effect/Context"
|
|
|
14
15
|
import * as Effect from "effect/Effect"
|
|
15
16
|
import * as Fn from "effect/Function"
|
|
16
17
|
import * as Layer from "effect/Layer"
|
|
17
|
-
import * as Scope from "effect/Scope"
|
|
18
18
|
import * as Redis from "effect/unstable/persistence/Redis"
|
|
19
|
-
import
|
|
19
|
+
import { createClient, SocketTimeoutError } from "redis"
|
|
20
|
+
|
|
21
|
+
type NodeRedisClient = ReturnType<typeof createClient>
|
|
22
|
+
type NodeRedisClientOptions = NonNullable<Parameters<typeof createClient>[0]>
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Service tag for the Node Redis integration, exposing the underlying
|
|
23
|
-
* `
|
|
26
|
+
* `node-redis` client and a `use` helper that maps client failures to
|
|
24
27
|
* `RedisError`.
|
|
25
28
|
*
|
|
26
29
|
* @category services
|
|
27
30
|
* @since 4.0.0
|
|
28
31
|
*/
|
|
29
32
|
export class NodeRedis extends Context.Service<NodeRedis, {
|
|
30
|
-
readonly client:
|
|
31
|
-
readonly use: <A>(f: (client:
|
|
33
|
+
readonly client: NodeRedisClient
|
|
34
|
+
readonly use: <A>(f: (client: NodeRedisClient) => Promise<A>) => Effect.Effect<A, Redis.RedisError>
|
|
32
35
|
}>()("@effect/platform-node/NodeRedis") {}
|
|
33
36
|
|
|
34
37
|
const make = Effect.fnUntraced(function*(
|
|
35
|
-
options?:
|
|
38
|
+
options?: NodeRedisClientOptions
|
|
36
39
|
) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const client =
|
|
40
|
+
let ready = false
|
|
41
|
+
const socket = options?.socket
|
|
42
|
+
const client = yield* Effect.acquireRelease(
|
|
43
|
+
Effect.sync((): NodeRedisClient =>
|
|
44
|
+
createClient({
|
|
45
|
+
...options,
|
|
46
|
+
socket: socket?.reconnectStrategy === undefined
|
|
47
|
+
? {
|
|
48
|
+
...socket,
|
|
49
|
+
reconnectStrategy: (retries, cause) => {
|
|
50
|
+
if (!ready) return cause
|
|
51
|
+
if (cause instanceof SocketTimeoutError) return false
|
|
52
|
+
const jitter = Math.floor(Math.random() * 200)
|
|
53
|
+
const delay = Math.min(2 ** retries * 50, 2000)
|
|
54
|
+
return delay + jitter
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
: socket
|
|
58
|
+
})
|
|
59
|
+
),
|
|
60
|
+
(client) => Effect.ignoreCause(Effect.promise(() => client.close()))
|
|
61
|
+
)
|
|
62
|
+
client.once("ready", () => {
|
|
63
|
+
ready = true
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// node-redis rethrows `error` events that have no listener, which would crash
|
|
67
|
+
// the process on a transient socket failure. Command failures are still
|
|
68
|
+
// reported as `RedisError`.
|
|
69
|
+
const runSync = Effect.runSyncWith(yield* Effect.context<never>())
|
|
70
|
+
client.on("error", (cause) => {
|
|
71
|
+
runSync(Effect.logWarning("NodeRedis client error", cause))
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
yield* Effect.tryPromise({
|
|
75
|
+
try: () => client.connect(),
|
|
76
|
+
catch: (cause) => new Redis.RedisError({ cause })
|
|
77
|
+
})
|
|
40
78
|
|
|
41
|
-
const use = <A>(f: (client:
|
|
79
|
+
const use = <A>(f: (client: NodeRedisClient) => Promise<A>) =>
|
|
42
80
|
Effect.tryPromise({
|
|
43
81
|
try: () => f(client),
|
|
44
82
|
catch: (cause) => new Redis.RedisError({ cause })
|
|
@@ -47,7 +85,7 @@ const make = Effect.fnUntraced(function*(
|
|
|
47
85
|
const redis = yield* Redis.make({
|
|
48
86
|
send: <A = unknown>(command: string, ...args: ReadonlyArray<string>) =>
|
|
49
87
|
Effect.tryPromise({
|
|
50
|
-
try: () => client.
|
|
88
|
+
try: () => client.sendCommand([command, ...args]) as Promise<A>,
|
|
51
89
|
catch: (cause) => new Redis.RedisError({ cause })
|
|
52
90
|
})
|
|
53
91
|
})
|
|
@@ -63,28 +101,50 @@ const make = Effect.fnUntraced(function*(
|
|
|
63
101
|
})
|
|
64
102
|
|
|
65
103
|
/**
|
|
66
|
-
* Provides `Redis` and `NodeRedis` services backed by
|
|
67
|
-
* created with the supplied options
|
|
104
|
+
* Provides `Redis` and `NodeRedis` services backed by a `node-redis` client
|
|
105
|
+
* created with the supplied options, connected when the layer is built and
|
|
106
|
+
* closed when the layer scope ends.
|
|
107
|
+
*
|
|
108
|
+
* **Details**
|
|
109
|
+
*
|
|
110
|
+
* By default, the initial connection fails on its first connection error. A
|
|
111
|
+
* caller-supplied `socket.reconnectStrategy` is used instead when present. Once
|
|
112
|
+
* the client has emitted `ready`, the default reconnect strategy uses
|
|
113
|
+
* node-redis' exponential backoff and stops on socket timeouts.
|
|
114
|
+
*
|
|
115
|
+
* Scope finalization calls `close()`, which waits for in-flight commands,
|
|
116
|
+
* including blocking commands, and can therefore delay scope closure.
|
|
68
117
|
*
|
|
69
118
|
* @category layers
|
|
70
119
|
* @since 4.0.0
|
|
71
120
|
*/
|
|
72
121
|
export const layer = (
|
|
73
|
-
options?:
|
|
74
|
-
): Layer.Layer<Redis.Redis | NodeRedis> => Layer.effectContext(make(options))
|
|
122
|
+
options?: NodeRedisClientOptions | undefined
|
|
123
|
+
): Layer.Layer<Redis.Redis | NodeRedis, Redis.RedisError> => Layer.effectContext(make(options))
|
|
75
124
|
|
|
76
125
|
/**
|
|
77
|
-
* Provides `Redis` and `NodeRedis` services from `Config`-backed
|
|
78
|
-
* options,
|
|
126
|
+
* Provides `Redis` and `NodeRedis` services from `Config`-backed node-redis
|
|
127
|
+
* client options, connecting the client when the layer is built and closing it
|
|
128
|
+
* when the layer scope ends.
|
|
129
|
+
*
|
|
130
|
+
* **Details**
|
|
131
|
+
*
|
|
132
|
+
* By default, the initial connection fails on its first connection error. A
|
|
133
|
+
* caller-supplied `socket.reconnectStrategy` is used instead when present. Once
|
|
134
|
+
* the client has emitted `ready`, the default reconnect strategy uses
|
|
135
|
+
* node-redis' exponential backoff and stops on socket timeouts.
|
|
136
|
+
*
|
|
137
|
+
* Scope finalization calls `close()`, which waits for in-flight commands,
|
|
138
|
+
* including blocking commands, and can therefore delay scope closure.
|
|
79
139
|
*
|
|
80
140
|
* @category layers
|
|
81
141
|
* @since 4.0.0
|
|
82
142
|
*/
|
|
83
143
|
export const layerConfig: (
|
|
84
|
-
options: Config.Wrap<
|
|
85
|
-
) => Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> = (
|
|
86
|
-
options: Config.Wrap<
|
|
87
|
-
): Layer.Layer<Redis.Redis | NodeRedis, Config.ConfigError> =>
|
|
144
|
+
options: Config.Wrap<NodeRedisClientOptions>
|
|
145
|
+
) => Layer.Layer<Redis.Redis | NodeRedis, Redis.RedisError | Config.ConfigError> = (
|
|
146
|
+
options: Config.Wrap<NodeRedisClientOptions>
|
|
147
|
+
): Layer.Layer<Redis.Redis | NodeRedis, Redis.RedisError | Config.ConfigError> =>
|
|
88
148
|
Layer.effectContext(
|
|
89
149
|
Config.unwrap(options).pipe(
|
|
90
150
|
Effect.flatMap(make)
|
package/src/NodeWorkerRunner.ts
CHANGED
|
@@ -16,6 +16,7 @@ import * as Effect from "effect/Effect"
|
|
|
16
16
|
import * as Exit from "effect/Exit"
|
|
17
17
|
import * as Fiber from "effect/Fiber"
|
|
18
18
|
import * as Layer from "effect/Layer"
|
|
19
|
+
import * as Scope from "effect/Scope"
|
|
19
20
|
import { WorkerError, WorkerReceiveError, WorkerSpawnError } from "effect/unstable/workers/WorkerError"
|
|
20
21
|
import * as WorkerRunner from "effect/unstable/workers/WorkerRunner"
|
|
21
22
|
import * as WorkerThreads from "node:worker_threads"
|
|
@@ -56,7 +57,8 @@ export const layer: Layer.Layer<WorkerRunner.WorkerRunnerPlatform> = Layer.succe
|
|
|
56
57
|
runFork(Effect.logError("unhandled error in worker", exit.cause))
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
+
const port = WorkerThreads.parentPort ?? process
|
|
61
|
+
function onMessage(message: WorkerRunner.PlatformMessage<I>) {
|
|
60
62
|
if (message[0] === 0) {
|
|
61
63
|
const result = handler(0, message[1])
|
|
62
64
|
if (Effect.isEffect(result)) {
|
|
@@ -72,32 +74,46 @@ export const layer: Layer.Layer<WorkerRunner.WorkerRunnerPlatform> = Layer.succe
|
|
|
72
74
|
}
|
|
73
75
|
Deferred.doneUnsafe(closeLatch, Exit.void)
|
|
74
76
|
}
|
|
75
|
-
}
|
|
77
|
+
}
|
|
78
|
+
port.on("message", onMessage)
|
|
76
79
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
new
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
cause
|
|
85
|
-
})
|
|
80
|
+
function onMessageError(cause: unknown) {
|
|
81
|
+
Deferred.doneUnsafe(
|
|
82
|
+
closeLatch,
|
|
83
|
+
new WorkerError({
|
|
84
|
+
reason: new WorkerReceiveError({
|
|
85
|
+
message: "received messageerror event",
|
|
86
|
+
cause
|
|
86
87
|
})
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
})
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
function onError(cause: unknown) {
|
|
92
|
+
Deferred.doneUnsafe(
|
|
93
|
+
closeLatch,
|
|
94
|
+
new WorkerError({
|
|
95
|
+
reason: new WorkerReceiveError({
|
|
96
|
+
message: "received error event",
|
|
97
|
+
cause
|
|
97
98
|
})
|
|
98
|
-
)
|
|
99
|
-
|
|
99
|
+
})
|
|
100
|
+
)
|
|
100
101
|
}
|
|
102
|
+
if (WorkerThreads.parentPort) {
|
|
103
|
+
WorkerThreads.parentPort.on("messageerror", onMessageError)
|
|
104
|
+
WorkerThreads.parentPort.on("error", onError)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
yield* Scope.addFinalizer(
|
|
108
|
+
scope,
|
|
109
|
+
Effect.sync(() => {
|
|
110
|
+
port.off("message", onMessage)
|
|
111
|
+
if (WorkerThreads.parentPort) {
|
|
112
|
+
WorkerThreads.parentPort.off("messageerror", onMessageError)
|
|
113
|
+
WorkerThreads.parentPort.off("error", onError)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
)
|
|
101
117
|
|
|
102
118
|
sendUnsafe(0, [0])
|
|
103
119
|
|
package/src/Undici.ts
CHANGED
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
import Undici from "undici"
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* @category
|
|
20
|
+
* @category re-exports
|
|
21
21
|
* @since 4.0.0
|
|
22
22
|
*/
|
|
23
23
|
export * from "undici"
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* @category
|
|
26
|
+
* @category re-exports
|
|
27
27
|
* @since 4.0.0
|
|
28
28
|
*/
|
|
29
29
|
export default Undici
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,11 @@ export * as NodeHttpServerRequest from "./NodeHttpServerRequest.ts"
|
|
|
64
64
|
*/
|
|
65
65
|
export * as NodeMultipart from "./NodeMultipart.ts"
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @since 4.0.0
|
|
69
|
+
*/
|
|
70
|
+
export * as NodeMultipartParser from "./NodeMultipartParser.ts"
|
|
71
|
+
|
|
67
72
|
/**
|
|
68
73
|
* @since 4.0.0
|
|
69
74
|
*/
|