effect 4.0.0-beta.35 → 4.0.0-beta.37
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/dist/Cause.d.ts +31 -0
- package/dist/Cause.d.ts.map +1 -1
- package/dist/Cause.js +19 -0
- package/dist/Cause.js.map +1 -1
- package/dist/Channel.d.ts +2 -2
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +9 -7
- package/dist/Channel.js.map +1 -1
- package/dist/Cron.d.ts +7 -0
- package/dist/Cron.d.ts.map +1 -1
- package/dist/Cron.js +109 -45
- package/dist/Cron.js.map +1 -1
- package/dist/Effect.d.ts +1 -16
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js.map +1 -1
- package/dist/Equivalence.d.ts +52 -0
- package/dist/Equivalence.d.ts.map +1 -1
- package/dist/Equivalence.js +52 -0
- package/dist/Equivalence.js.map +1 -1
- package/dist/LayerMap.d.ts +5 -4
- package/dist/LayerMap.d.ts.map +1 -1
- package/dist/LayerMap.js.map +1 -1
- package/dist/PubSub.d.ts.map +1 -1
- package/dist/PubSub.js +9 -3
- package/dist/PubSub.js.map +1 -1
- package/dist/Schedule.d.ts.map +1 -1
- package/dist/Schedule.js +19 -1
- package/dist/Schedule.js.map +1 -1
- package/dist/Schema.d.ts +37 -41
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +20 -0
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaParser.d.ts +39 -54
- package/dist/SchemaParser.d.ts.map +1 -1
- package/dist/SchemaParser.js +38 -0
- package/dist/SchemaParser.js.map +1 -1
- package/dist/Sink.d.ts +5 -2
- package/dist/Sink.d.ts.map +1 -1
- package/dist/Sink.js.map +1 -1
- package/dist/Stream.d.ts +1 -1
- package/dist/Stream.d.ts.map +1 -1
- package/dist/internal/effect.js +18 -3
- package/dist/internal/effect.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +15 -3
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/cli/Prompt.js +158 -15
- package/dist/unstable/cli/Prompt.js.map +1 -1
- package/dist/unstable/devtools/DevToolsClient.d.ts.map +1 -1
- package/dist/unstable/devtools/DevToolsClient.js +4 -3
- package/dist/unstable/devtools/DevToolsClient.js.map +1 -1
- package/dist/unstable/devtools/DevToolsSchema.d.ts +2 -3
- package/dist/unstable/devtools/DevToolsSchema.d.ts.map +1 -1
- package/dist/unstable/devtools/DevToolsSchema.js +11 -1
- package/dist/unstable/devtools/DevToolsSchema.js.map +1 -1
- package/dist/unstable/http/HttpClientRequest.d.ts +24 -2
- package/dist/unstable/http/HttpClientRequest.d.ts.map +1 -1
- package/dist/unstable/http/HttpClientRequest.js +97 -0
- package/dist/unstable/http/HttpClientRequest.js.map +1 -1
- package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerResponse.js +2 -1
- package/dist/unstable/http/HttpServerResponse.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiEndpoint.js +2 -2
- package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiMiddleware.d.ts +15 -13
- package/dist/unstable/httpapi/HttpApiMiddleware.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiMiddleware.js +5 -3
- package/dist/unstable/httpapi/HttpApiMiddleware.js.map +1 -1
- package/dist/unstable/sql/Migrator.d.ts.map +1 -1
- package/dist/unstable/sql/Migrator.js +2 -2
- package/dist/unstable/sql/Migrator.js.map +1 -1
- package/dist/unstable/sql/SqlError.d.ts +229 -9
- package/dist/unstable/sql/SqlError.d.ts.map +1 -1
- package/dist/unstable/sql/SqlError.js +256 -6
- package/dist/unstable/sql/SqlError.js.map +1 -1
- package/package.json +1 -1
- package/src/Cause.ts +35 -0
- package/src/Channel.ts +14 -12
- package/src/Cron.ts +142 -45
- package/src/Effect.ts +1 -16
- package/src/Equivalence.ts +56 -0
- package/src/LayerMap.ts +7 -5
- package/src/PubSub.ts +13 -5
- package/src/Schedule.ts +20 -8
- package/src/Schema.ts +38 -18
- package/src/SchemaParser.ts +74 -25
- package/src/Sink.ts +5 -2
- package/src/Stream.ts +1 -1
- package/src/internal/effect.ts +30 -4
- package/src/unstable/ai/LanguageModel.ts +17 -2
- package/src/unstable/cli/Prompt.ts +158 -16
- package/src/unstable/devtools/DevToolsClient.ts +23 -18
- package/src/unstable/devtools/DevToolsSchema.ts +13 -1
- package/src/unstable/http/HttpClientRequest.ts +104 -2
- package/src/unstable/http/HttpServerResponse.ts +8 -4
- package/src/unstable/httpapi/HttpApiEndpoint.ts +2 -2
- package/src/unstable/httpapi/HttpApiMiddleware.ts +36 -20
- package/src/unstable/sql/Migrator.ts +7 -5
- package/src/unstable/sql/SqlError.ts +360 -8
|
@@ -739,7 +739,7 @@ export const file = (options: FileOptions = {}): Prompt<string> => {
|
|
|
739
739
|
const currentPath = yield* resolveCurrentPath(Option.none(), opts)
|
|
740
740
|
const files = yield* getFileList(currentPath, opts)
|
|
741
741
|
const confirm = Confirm.Hide()
|
|
742
|
-
return { cursor: 0, files, path: Option.none(), confirm }
|
|
742
|
+
return { cursor: 0, files, allFiles: files, query: "", path: Option.none(), confirm }
|
|
743
743
|
})
|
|
744
744
|
return custom(initialState, {
|
|
745
745
|
render: handleFileRender(opts),
|
|
@@ -1855,11 +1855,16 @@ interface FileOptionsReq extends Required<Omit<FileOptions, "startingPath">> {
|
|
|
1855
1855
|
interface FileState {
|
|
1856
1856
|
readonly cursor: number
|
|
1857
1857
|
readonly files: ReadonlyArray<string>
|
|
1858
|
+
readonly allFiles: ReadonlyArray<string>
|
|
1859
|
+
readonly query: string
|
|
1858
1860
|
readonly path: Option.Option<string>
|
|
1859
1861
|
readonly confirm: Confirm
|
|
1860
1862
|
}
|
|
1861
1863
|
|
|
1862
1864
|
const CONFIRM_MESSAGE = "The selected directory contains files. Would you like to traverse the selected directory?"
|
|
1865
|
+
const FILE_FILTER_LABEL = "filter"
|
|
1866
|
+
const FILE_FILTER_PLACEHOLDER = "type to filter"
|
|
1867
|
+
const FILE_EMPTY_MESSAGE = "No matches"
|
|
1863
1868
|
type Confirm = Data.TaggedEnum<{
|
|
1864
1869
|
readonly Show: {}
|
|
1865
1870
|
readonly Hide: {}
|
|
@@ -1914,6 +1919,40 @@ const getFileList = Effect.fnUntraced(function*(directory: string, options: File
|
|
|
1914
1919
|
}, { concurrency: files.length })
|
|
1915
1920
|
})
|
|
1916
1921
|
|
|
1922
|
+
const filterFiles = (files: ReadonlyArray<string>, query: string) => {
|
|
1923
|
+
if (query.length === 0) {
|
|
1924
|
+
return files
|
|
1925
|
+
}
|
|
1926
|
+
const normalizedQuery = query.toLowerCase()
|
|
1927
|
+
const filtered: Array<string> = []
|
|
1928
|
+
for (let index = 0; index < files.length; index++) {
|
|
1929
|
+
if (files[index].toLowerCase().includes(normalizedQuery)) {
|
|
1930
|
+
filtered.push(files[index])
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return filtered
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
const updateFileState = (
|
|
1937
|
+
state: FileState,
|
|
1938
|
+
query: string,
|
|
1939
|
+
allFiles: ReadonlyArray<string> = state.allFiles
|
|
1940
|
+
): FileState => {
|
|
1941
|
+
const files = filterFiles(allFiles, query)
|
|
1942
|
+
if (files.length === 0) {
|
|
1943
|
+
return { ...state, query, allFiles, files, cursor: 0 }
|
|
1944
|
+
}
|
|
1945
|
+
const selected = state.files[state.cursor]
|
|
1946
|
+
const cursor = selected === undefined ? 0 : files.indexOf(selected)
|
|
1947
|
+
return {
|
|
1948
|
+
...state,
|
|
1949
|
+
query,
|
|
1950
|
+
allFiles,
|
|
1951
|
+
files,
|
|
1952
|
+
cursor: cursor === -1 ? 0 : cursor
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1917
1956
|
const handleFileClear = (options: FileOptionsReq) => {
|
|
1918
1957
|
return Effect.fnUntraced(function*(state: FileState, _: Action<FileState, string>) {
|
|
1919
1958
|
const terminal = yield* Terminal.Terminal
|
|
@@ -1922,12 +1961,14 @@ const handleFileClear = (options: FileOptionsReq) => {
|
|
|
1922
1961
|
const figures = yield* platformFigures
|
|
1923
1962
|
const currentPath = yield* resolveCurrentPath(state.path, options)
|
|
1924
1963
|
const selectedPath = state.files[state.cursor]
|
|
1925
|
-
const resolvedPath = path.resolve(currentPath, selectedPath)
|
|
1964
|
+
const resolvedPath = selectedPath === undefined ? currentPath : path.resolve(currentPath, selectedPath)
|
|
1926
1965
|
const resolvedPathText = `${figures.pointerSmall} ${resolvedPath}`
|
|
1927
1966
|
const isConfirming = showConfirmation(state.confirm)
|
|
1928
1967
|
const promptText = isConfirming
|
|
1929
1968
|
? renderPrompt("(Y/n)", CONFIRM_MESSAGE, "?", figures.pointerSmall, { plain: true })
|
|
1930
|
-
: renderPrompt(
|
|
1969
|
+
: renderPrompt(renderFileFilter(state, { plain: true }), options.message, figures.tick, figures.ellipsis, {
|
|
1970
|
+
plain: true
|
|
1971
|
+
})
|
|
1931
1972
|
const filesText = isConfirming
|
|
1932
1973
|
? ""
|
|
1933
1974
|
: renderFiles(state, state.files, figures, options, { plain: true })
|
|
@@ -1995,6 +2036,17 @@ const renderFileName = (file: string, isSelected: boolean, renderOptions?: Rende
|
|
|
1995
2036
|
: file
|
|
1996
2037
|
}
|
|
1997
2038
|
|
|
2039
|
+
const renderFileFilter = (state: FileState, renderOptions?: RenderOptions | undefined) => {
|
|
2040
|
+
const filterValue = state.query.length === 0
|
|
2041
|
+
? renderOptions?.plain === true
|
|
2042
|
+
? FILE_FILTER_PLACEHOLDER
|
|
2043
|
+
: Ansi.annotate(FILE_FILTER_PLACEHOLDER, Ansi.blackBright)
|
|
2044
|
+
: renderOptions?.plain === true
|
|
2045
|
+
? state.query
|
|
2046
|
+
: Ansi.annotate(state.query, Ansi.combine(Ansi.underlined, Ansi.cyanBright))
|
|
2047
|
+
return `[${FILE_FILTER_LABEL}: ${filterValue}]`
|
|
2048
|
+
}
|
|
2049
|
+
|
|
1998
2050
|
const renderFiles = (
|
|
1999
2051
|
state: FileState,
|
|
2000
2052
|
files: ReadonlyArray<string>,
|
|
@@ -2003,6 +2055,11 @@ const renderFiles = (
|
|
|
2003
2055
|
renderOptions?: RenderOptions | undefined
|
|
2004
2056
|
) => {
|
|
2005
2057
|
const length = files.length
|
|
2058
|
+
if (length === 0) {
|
|
2059
|
+
return renderOptions?.plain === true
|
|
2060
|
+
? FILE_EMPTY_MESSAGE
|
|
2061
|
+
: Ansi.annotate(FILE_EMPTY_MESSAGE, Ansi.blackBright)
|
|
2062
|
+
}
|
|
2006
2063
|
const toDisplay = entriesToDisplay(state.cursor, length, options.maxPerPage)
|
|
2007
2064
|
const documents: Array<string> = []
|
|
2008
2065
|
for (let index = toDisplay.startIndex; index < toDisplay.endIndex; index++) {
|
|
@@ -2019,7 +2076,7 @@ const renderFileNextFrame = Effect.fnUntraced(function*(state: FileState, option
|
|
|
2019
2076
|
const figures = yield* platformFigures
|
|
2020
2077
|
const currentPath = yield* resolveCurrentPath(state.path, options)
|
|
2021
2078
|
const selectedPath = state.files[state.cursor]
|
|
2022
|
-
const resolvedPath = path.resolve(currentPath, selectedPath)
|
|
2079
|
+
const resolvedPath = selectedPath === undefined ? currentPath : path.resolve(currentPath, selectedPath)
|
|
2023
2080
|
const resolvedPathMsg = Ansi.annotate(figures.pointerSmall + " " + resolvedPath, Ansi.blackBright)
|
|
2024
2081
|
|
|
2025
2082
|
if (showConfirmation(state.confirm)) {
|
|
@@ -2031,33 +2088,36 @@ const renderFileNextFrame = Effect.fnUntraced(function*(state: FileState, option
|
|
|
2031
2088
|
}
|
|
2032
2089
|
const leadingSymbol = Ansi.annotate(figures.tick, Ansi.green)
|
|
2033
2090
|
const trailingSymbol = Ansi.annotate(figures.ellipsis, Ansi.blackBright)
|
|
2034
|
-
const promptMsg = renderPrompt(
|
|
2091
|
+
const promptMsg = renderPrompt(renderFileFilter(state), options.message, leadingSymbol, trailingSymbol)
|
|
2035
2092
|
const files = renderFiles(state, state.files, figures, options)
|
|
2036
2093
|
return Ansi.cursorHide + promptMsg + "\n" + resolvedPathMsg + "\n" + files
|
|
2037
2094
|
})
|
|
2038
2095
|
|
|
2039
|
-
const renderFileSubmission = Effect.fnUntraced(function*(value: string, options: FileOptionsReq) {
|
|
2096
|
+
const renderFileSubmission = Effect.fnUntraced(function*(state: FileState, value: string, options: FileOptionsReq) {
|
|
2040
2097
|
const figures = yield* platformFigures
|
|
2041
2098
|
const leadingSymbol = Ansi.annotate(figures.tick, Ansi.green)
|
|
2042
2099
|
const trailingSymbol = Ansi.annotate(figures.ellipsis, Ansi.blackBright)
|
|
2043
|
-
const promptMsg = renderPrompt(
|
|
2100
|
+
const promptMsg = renderPrompt(renderFileFilter(state), options.message, leadingSymbol, trailingSymbol)
|
|
2044
2101
|
return promptMsg + " " + Ansi.annotate(value, Ansi.white) + "\n"
|
|
2045
2102
|
})
|
|
2046
2103
|
|
|
2047
2104
|
const handleFileRender = (options: FileOptionsReq) => {
|
|
2048
2105
|
return (
|
|
2049
|
-
|
|
2106
|
+
state: FileState,
|
|
2050
2107
|
action: Action<FileState, string>
|
|
2051
2108
|
): Effect.Effect<string, never, Path.Path | FileSystem.FileSystem> => {
|
|
2052
2109
|
return Action.$match(action, {
|
|
2053
2110
|
Beep: () => Effect.succeed(renderBeep),
|
|
2054
2111
|
NextFrame: ({ state }) => renderFileNextFrame(state, options),
|
|
2055
|
-
Submit: ({ value }) => renderFileSubmission(value, options)
|
|
2112
|
+
Submit: ({ value }) => renderFileSubmission(state, value, options)
|
|
2056
2113
|
})
|
|
2057
2114
|
}
|
|
2058
2115
|
}
|
|
2059
2116
|
|
|
2060
2117
|
const processFileCursorUp = (state: FileState) => {
|
|
2118
|
+
if (state.files.length === 0) {
|
|
2119
|
+
return Effect.succeed(Action.Beep())
|
|
2120
|
+
}
|
|
2061
2121
|
const cursor = state.cursor - 1
|
|
2062
2122
|
return Effect.succeed(Action.NextFrame({
|
|
2063
2123
|
state: { ...state, cursor: cursor < 0 ? state.files.length - 1 : cursor }
|
|
@@ -2065,12 +2125,36 @@ const processFileCursorUp = (state: FileState) => {
|
|
|
2065
2125
|
}
|
|
2066
2126
|
|
|
2067
2127
|
const processFileCursorDown = (state: FileState) => {
|
|
2128
|
+
if (state.files.length === 0) {
|
|
2129
|
+
return Effect.succeed(Action.Beep())
|
|
2130
|
+
}
|
|
2068
2131
|
return Effect.succeed(Action.NextFrame({
|
|
2069
2132
|
state: { ...state, cursor: (state.cursor + 1) % state.files.length }
|
|
2070
2133
|
}))
|
|
2071
2134
|
}
|
|
2072
2135
|
|
|
2136
|
+
const processFileBackspace = (state: FileState) => {
|
|
2137
|
+
if (state.query.length === 0) {
|
|
2138
|
+
return Effect.succeed(Action.Beep())
|
|
2139
|
+
}
|
|
2140
|
+
const query = state.query.slice(0, state.query.length - 1)
|
|
2141
|
+
return Effect.succeed(Action.NextFrame({ state: updateFileState(state, query) }))
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
const processFileClear = (state: FileState) => Effect.succeed(Action.NextFrame({ state: updateFileState(state, "") }))
|
|
2145
|
+
|
|
2146
|
+
const processFileInput = (input: string, state: FileState) => {
|
|
2147
|
+
if (input.length === 0) {
|
|
2148
|
+
return Effect.succeed(Action.Beep())
|
|
2149
|
+
}
|
|
2150
|
+
const query = state.query + input
|
|
2151
|
+
return Effect.succeed(Action.NextFrame({ state: updateFileState(state, query) }))
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2073
2154
|
const processSelection = Effect.fnUntraced(function*(state: FileState, options: FileOptionsReq) {
|
|
2155
|
+
if (state.files.length === 0) {
|
|
2156
|
+
return Action.Beep()
|
|
2157
|
+
}
|
|
2074
2158
|
const fs = yield* FileSystem.FileSystem
|
|
2075
2159
|
const path = yield* Path.Path
|
|
2076
2160
|
const currentPath = yield* resolveCurrentPath(state.path, options)
|
|
@@ -2097,6 +2181,8 @@ const processSelection = Effect.fnUntraced(function*(state: FileState, options:
|
|
|
2097
2181
|
state: {
|
|
2098
2182
|
cursor: 0,
|
|
2099
2183
|
files,
|
|
2184
|
+
allFiles: files,
|
|
2185
|
+
query: "",
|
|
2100
2186
|
path: Option.some(resolvedPath),
|
|
2101
2187
|
confirm: Confirm.Hide()
|
|
2102
2188
|
}
|
|
@@ -2107,6 +2193,15 @@ const processSelection = Effect.fnUntraced(function*(state: FileState, options:
|
|
|
2107
2193
|
|
|
2108
2194
|
const handleFileProcess = (options: FileOptionsReq) => {
|
|
2109
2195
|
return Effect.fnUntraced(function*(input: Terminal.UserInput, state: FileState) {
|
|
2196
|
+
if (input.key.ctrl) {
|
|
2197
|
+
if (input.key.name === "u") {
|
|
2198
|
+
if (showConfirmation(state.confirm)) {
|
|
2199
|
+
return Action.Beep()
|
|
2200
|
+
}
|
|
2201
|
+
return yield* processFileClear(state)
|
|
2202
|
+
}
|
|
2203
|
+
return Action.Beep()
|
|
2204
|
+
}
|
|
2110
2205
|
switch (input.key.name) {
|
|
2111
2206
|
case "k":
|
|
2112
2207
|
case "up": {
|
|
@@ -2117,6 +2212,12 @@ const handleFileProcess = (options: FileOptionsReq) => {
|
|
|
2117
2212
|
case "tab": {
|
|
2118
2213
|
return yield* processFileCursorDown(state)
|
|
2119
2214
|
}
|
|
2215
|
+
case "backspace": {
|
|
2216
|
+
if (showConfirmation(state.confirm)) {
|
|
2217
|
+
return Action.Beep()
|
|
2218
|
+
}
|
|
2219
|
+
return yield* processFileBackspace(state)
|
|
2220
|
+
}
|
|
2120
2221
|
case "enter":
|
|
2121
2222
|
case "return": {
|
|
2122
2223
|
return yield* processSelection(state, options)
|
|
@@ -2133,12 +2234,14 @@ const handleFileProcess = (options: FileOptionsReq) => {
|
|
|
2133
2234
|
state: {
|
|
2134
2235
|
cursor: 0,
|
|
2135
2236
|
files,
|
|
2237
|
+
allFiles: files,
|
|
2238
|
+
query: "",
|
|
2136
2239
|
path: Option.some(resolvedPath),
|
|
2137
2240
|
confirm: Confirm.Hide()
|
|
2138
2241
|
}
|
|
2139
2242
|
})
|
|
2140
2243
|
}
|
|
2141
|
-
return
|
|
2244
|
+
return yield* processFileInput(Option.getOrElse(input.input, () => ""), state)
|
|
2142
2245
|
}
|
|
2143
2246
|
case "n":
|
|
2144
2247
|
case "f": {
|
|
@@ -2149,10 +2252,13 @@ const handleFileProcess = (options: FileOptionsReq) => {
|
|
|
2149
2252
|
const resolvedPath = path.resolve(currentPath, selectedPath)
|
|
2150
2253
|
return Action.Submit({ value: resolvedPath })
|
|
2151
2254
|
}
|
|
2152
|
-
return
|
|
2255
|
+
return yield* processFileInput(Option.getOrElse(input.input, () => ""), state)
|
|
2153
2256
|
}
|
|
2154
2257
|
default: {
|
|
2155
|
-
|
|
2258
|
+
if (showConfirmation(state.confirm)) {
|
|
2259
|
+
return Action.Beep()
|
|
2260
|
+
}
|
|
2261
|
+
return yield* processFileInput(Option.getOrElse(input.input, () => ""), state)
|
|
2156
2262
|
}
|
|
2157
2263
|
}
|
|
2158
2264
|
})
|
|
@@ -3057,8 +3163,11 @@ const handleSelectProcess = <A>(options: SelectOptionsReq<A>) => {
|
|
|
3057
3163
|
|
|
3058
3164
|
const handleAutoCompleteProcess = <A>(options: AutoCompleteOptionsReq<A>) => {
|
|
3059
3165
|
return (input: Terminal.UserInput, state: AutoCompleteState) => {
|
|
3060
|
-
if (input.key.ctrl
|
|
3061
|
-
|
|
3166
|
+
if (input.key.ctrl) {
|
|
3167
|
+
if (input.key.name === "u") {
|
|
3168
|
+
return processAutoCompleteClear(state, options)
|
|
3169
|
+
}
|
|
3170
|
+
return Effect.succeed(Action.Beep())
|
|
3062
3171
|
}
|
|
3063
3172
|
switch (input.key.name) {
|
|
3064
3173
|
case "k":
|
|
@@ -3259,6 +3368,20 @@ const processTextCursorRight = (state: TextState) => {
|
|
|
3259
3368
|
)
|
|
3260
3369
|
}
|
|
3261
3370
|
|
|
3371
|
+
const processTextCursorStart = (state: TextState) =>
|
|
3372
|
+
Effect.succeed(
|
|
3373
|
+
Action.NextFrame({
|
|
3374
|
+
state: { ...state, cursor: 0, error: Option.none() }
|
|
3375
|
+
})
|
|
3376
|
+
)
|
|
3377
|
+
|
|
3378
|
+
const processTextCursorEnd = (state: TextState) =>
|
|
3379
|
+
Effect.succeed(
|
|
3380
|
+
Action.NextFrame({
|
|
3381
|
+
state: { ...state, cursor: state.value.length, error: Option.none() }
|
|
3382
|
+
})
|
|
3383
|
+
)
|
|
3384
|
+
|
|
3262
3385
|
const processTab = (state: TextState, options: TextOptionsReq) => {
|
|
3263
3386
|
if (state.value === options.default) {
|
|
3264
3387
|
return Effect.succeed(Action.Beep())
|
|
@@ -3295,8 +3418,21 @@ const handleTextRender = (options: TextOptionsReq) => {
|
|
|
3295
3418
|
|
|
3296
3419
|
const handleTextProcess = (options: TextOptionsReq) => {
|
|
3297
3420
|
return (input: Terminal.UserInput, state: TextState) => {
|
|
3298
|
-
if (input.key.ctrl
|
|
3299
|
-
|
|
3421
|
+
if (input.key.ctrl) {
|
|
3422
|
+
switch (input.key.name) {
|
|
3423
|
+
case "u": {
|
|
3424
|
+
return processTextClear(state)
|
|
3425
|
+
}
|
|
3426
|
+
case "a": {
|
|
3427
|
+
return processTextCursorStart(state)
|
|
3428
|
+
}
|
|
3429
|
+
case "e": {
|
|
3430
|
+
return processTextCursorEnd(state)
|
|
3431
|
+
}
|
|
3432
|
+
default: {
|
|
3433
|
+
return Effect.succeed(Action.Beep())
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3300
3436
|
}
|
|
3301
3437
|
switch (input.key.name) {
|
|
3302
3438
|
case "backspace": {
|
|
@@ -3308,6 +3444,12 @@ const handleTextProcess = (options: TextOptionsReq) => {
|
|
|
3308
3444
|
case "right": {
|
|
3309
3445
|
return processTextCursorRight(state)
|
|
3310
3446
|
}
|
|
3447
|
+
case "home": {
|
|
3448
|
+
return processTextCursorStart(state)
|
|
3449
|
+
}
|
|
3450
|
+
case "end": {
|
|
3451
|
+
return processTextCursorEnd(state)
|
|
3452
|
+
}
|
|
3311
3453
|
case "enter":
|
|
3312
3454
|
case "return": {
|
|
3313
3455
|
const value = state.value
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as Cause from "../../Cause.ts"
|
|
5
5
|
import * as Deferred from "../../Deferred.ts"
|
|
6
6
|
import * as Effect from "../../Effect.ts"
|
|
7
|
+
import * as Fiber from "../../Fiber.ts"
|
|
7
8
|
import * as Layer from "../../Layer.ts"
|
|
8
9
|
import * as Metric from "../../Metric.ts"
|
|
9
10
|
import * as Queue from "../../Queue.ts"
|
|
@@ -23,9 +24,14 @@ const ResponseSchema = Schema.toCodecJson(DevToolsSchema.Response)
|
|
|
23
24
|
* @since 4.0.0
|
|
24
25
|
* @category tags
|
|
25
26
|
*/
|
|
26
|
-
export class DevToolsClient extends ServiceMap.Service<
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
export class DevToolsClient extends ServiceMap.Service<
|
|
28
|
+
DevToolsClient,
|
|
29
|
+
{
|
|
30
|
+
readonly sendUnsafe: (
|
|
31
|
+
_: DevToolsSchema.Span | DevToolsSchema.SpanEvent
|
|
32
|
+
) => void
|
|
33
|
+
}
|
|
34
|
+
>()("effect/devtools/DevToolsClient") {}
|
|
29
35
|
|
|
30
36
|
const makeEffect = Effect.gen(function*() {
|
|
31
37
|
const socket = yield* Socket.Socket
|
|
@@ -37,7 +43,9 @@ const makeEffect = Effect.gen(function*() {
|
|
|
37
43
|
Queue.offerUnsafe(requests, toMetricsSnapshot(services))
|
|
38
44
|
})
|
|
39
45
|
|
|
40
|
-
const handleResponse = (
|
|
46
|
+
const handleResponse = (
|
|
47
|
+
response: DevToolsSchema.Response
|
|
48
|
+
): Effect.Effect<void> => {
|
|
41
49
|
switch (response._tag) {
|
|
42
50
|
case "MetricsRequest": {
|
|
43
51
|
return offerMetricsSnapshot
|
|
@@ -48,7 +56,7 @@ const makeEffect = Effect.gen(function*() {
|
|
|
48
56
|
}
|
|
49
57
|
}
|
|
50
58
|
|
|
51
|
-
yield* Stream.fromQueue(requests).pipe(
|
|
59
|
+
const fiber = yield* Stream.fromQueue(requests).pipe(
|
|
52
60
|
Stream.pipeThroughChannel(
|
|
53
61
|
Ndjson.duplexSchemaString(Socket.toChannelString(socket), {
|
|
54
62
|
inputSchema: RequestSchema,
|
|
@@ -57,12 +65,15 @@ const makeEffect = Effect.gen(function*() {
|
|
|
57
65
|
),
|
|
58
66
|
Stream.onFirst(() => Deferred.completeWith(connected, Effect.void)),
|
|
59
67
|
Stream.runForEach(handleResponse),
|
|
60
|
-
Effect.
|
|
68
|
+
Effect.forkDetach
|
|
61
69
|
)
|
|
62
70
|
|
|
63
71
|
yield* Effect.addFinalizer(() =>
|
|
64
72
|
offerMetricsSnapshot.pipe(
|
|
65
|
-
Effect.andThen(
|
|
73
|
+
Effect.andThen(
|
|
74
|
+
Effect.flatMap(Effect.fiberId, (id) => Queue.failCause(requests, Cause.interrupt(id)))
|
|
75
|
+
),
|
|
76
|
+
Effect.andThen(Fiber.await(fiber))
|
|
66
77
|
)
|
|
67
78
|
)
|
|
68
79
|
|
|
@@ -84,7 +95,9 @@ const makeEffect = Effect.gen(function*() {
|
|
|
84
95
|
})
|
|
85
96
|
})
|
|
86
97
|
|
|
87
|
-
const toMetricsSnapshot = (
|
|
98
|
+
const toMetricsSnapshot = (
|
|
99
|
+
services: ServiceMap.ServiceMap<never>
|
|
100
|
+
): DevToolsSchema.MetricsSnapshot => ({
|
|
88
101
|
_tag: "MetricsSnapshot",
|
|
89
102
|
metrics: Metric.snapshotUnsafe(services)
|
|
90
103
|
})
|
|
@@ -108,11 +121,7 @@ export const make: Effect.Effect<
|
|
|
108
121
|
* @since 4.0.0
|
|
109
122
|
* @category layers
|
|
110
123
|
*/
|
|
111
|
-
export const layer: Layer.Layer<
|
|
112
|
-
DevToolsClient,
|
|
113
|
-
never,
|
|
114
|
-
Socket.Socket
|
|
115
|
-
> = Layer.effect(DevToolsClient, make)
|
|
124
|
+
export const layer: Layer.Layer<DevToolsClient, never, Socket.Socket> = Layer.effect(DevToolsClient, make)
|
|
116
125
|
|
|
117
126
|
const makeTracerEffect = Effect.gen(function*() {
|
|
118
127
|
const client = yield* DevToolsClient
|
|
@@ -162,10 +171,6 @@ export const makeTracer: Effect.Effect<Tracer.Tracer, never, DevToolsClient> = m
|
|
|
162
171
|
* @since 4.0.0
|
|
163
172
|
* @category layers
|
|
164
173
|
*/
|
|
165
|
-
export const layerTracer: Layer.Layer<
|
|
166
|
-
never,
|
|
167
|
-
never,
|
|
168
|
-
Socket.Socket
|
|
169
|
-
> = Layer.effect(Tracer.Tracer, makeTracer).pipe(
|
|
174
|
+
export const layerTracer: Layer.Layer<never, never, Socket.Socket> = Layer.effect(Tracer.Tracer, makeTracer).pipe(
|
|
170
175
|
Layer.provide(layer)
|
|
171
176
|
)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 4.0.0
|
|
3
3
|
*/
|
|
4
|
+
import * as Exit from "../../Exit.ts"
|
|
5
|
+
import { identity } from "../../Function.ts"
|
|
4
6
|
import type * as Option from "../../Option.ts"
|
|
5
7
|
import * as Schema from "../../Schema.ts"
|
|
8
|
+
import * as SchemaTransformation from "../../SchemaTransformation.ts"
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* @since 4.0.0
|
|
@@ -26,7 +29,16 @@ export type SpanStatusStarted = Schema.Schema.Type<typeof SpanStatusStarted>
|
|
|
26
29
|
export const SpanStatusEnded = Schema.Struct({
|
|
27
30
|
_tag: Schema.tag("Ended"),
|
|
28
31
|
startTime: Schema.BigInt,
|
|
29
|
-
endTime: Schema.BigInt
|
|
32
|
+
endTime: Schema.BigInt,
|
|
33
|
+
exit: Schema.Exit(Schema.Void, Schema.DefectWithStack, Schema.DefectWithStack).pipe(
|
|
34
|
+
Schema.decodeTo(
|
|
35
|
+
Schema.Exit(Schema.Unknown, Schema.Unknown, Schema.Unknown),
|
|
36
|
+
SchemaTransformation.transform({
|
|
37
|
+
decode: identity,
|
|
38
|
+
encode: Exit.asVoid
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
)
|
|
30
42
|
})
|
|
31
43
|
|
|
32
44
|
/**
|
|
@@ -15,10 +15,11 @@ import type * as Redacted from "../../Redacted.ts"
|
|
|
15
15
|
import * as Result from "../../Result.ts"
|
|
16
16
|
import type * as Schema from "../../Schema.ts"
|
|
17
17
|
import type { ParseOptions } from "../../SchemaAST.ts"
|
|
18
|
-
import
|
|
18
|
+
import * as ServiceMap from "../../ServiceMap.ts"
|
|
19
|
+
import * as Stream from "../../Stream.ts"
|
|
19
20
|
import * as Headers from "./Headers.ts"
|
|
20
21
|
import * as HttpBody from "./HttpBody.ts"
|
|
21
|
-
import type
|
|
22
|
+
import { hasBody, type HttpMethod } from "./HttpMethod.ts"
|
|
22
23
|
import * as UrlParams from "./UrlParams.ts"
|
|
23
24
|
|
|
24
25
|
const TypeId = "~effect/http/HttpClientRequest"
|
|
@@ -954,3 +955,104 @@ export function toUrl(self: HttpClientRequest): Option.Option<URL> {
|
|
|
954
955
|
}
|
|
955
956
|
return Option.none()
|
|
956
957
|
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* @since 4.0.0
|
|
961
|
+
* @category conversions
|
|
962
|
+
*/
|
|
963
|
+
export const fromWeb = (request: globalThis.Request): HttpClientRequest => {
|
|
964
|
+
const method = request.method.toUpperCase() as HttpMethod
|
|
965
|
+
return modify(empty, {
|
|
966
|
+
method,
|
|
967
|
+
url: new URL(request.url),
|
|
968
|
+
headers: request.headers,
|
|
969
|
+
body: fromWebBody(request, method)
|
|
970
|
+
})
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const fromWebBody = (request: globalThis.Request, method: HttpMethod): HttpBody.HttpBody => {
|
|
974
|
+
if (!hasBody(method) || request.body === null) {
|
|
975
|
+
return HttpBody.empty
|
|
976
|
+
}
|
|
977
|
+
return HttpBody.raw(request.body, {
|
|
978
|
+
contentType: request.headers.get("content-type") ?? undefined,
|
|
979
|
+
contentLength: parseContentLength(request.headers.get("content-length"))
|
|
980
|
+
})
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const parseContentLength = (contentLength: string | null): number | undefined => {
|
|
984
|
+
if (contentLength === null) {
|
|
985
|
+
return undefined
|
|
986
|
+
}
|
|
987
|
+
const parsed = Number.parseInt(contentLength, 10)
|
|
988
|
+
return Number.isNaN(parsed) ? undefined : parsed
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* @since 4.0.0
|
|
993
|
+
* @category conversions
|
|
994
|
+
*/
|
|
995
|
+
export const toWebResult = (self: HttpClientRequest, options?: {
|
|
996
|
+
readonly signal?: AbortSignal | undefined
|
|
997
|
+
readonly services?: ServiceMap.ServiceMap<never> | undefined
|
|
998
|
+
}): Result.Result<Request, UrlParams.UrlParamsError> => {
|
|
999
|
+
const url = UrlParams.makeUrl(self.url, self.urlParams, Option.getOrUndefined(self.hash))
|
|
1000
|
+
if (Result.isFailure(url)) {
|
|
1001
|
+
return Result.fail(url.failure)
|
|
1002
|
+
}
|
|
1003
|
+
const requestInit: RequestInit = {
|
|
1004
|
+
method: self.method,
|
|
1005
|
+
headers: self.headers
|
|
1006
|
+
}
|
|
1007
|
+
if (options?.signal) {
|
|
1008
|
+
requestInit.signal = options.signal
|
|
1009
|
+
}
|
|
1010
|
+
if (hasBody(self.method)) {
|
|
1011
|
+
switch (self.body._tag) {
|
|
1012
|
+
case "Empty": {
|
|
1013
|
+
break
|
|
1014
|
+
}
|
|
1015
|
+
case "Raw": {
|
|
1016
|
+
requestInit.body = self.body.body as any
|
|
1017
|
+
if (isReadableStream(self.body.body)) {
|
|
1018
|
+
;(requestInit as any).duplex = "half"
|
|
1019
|
+
}
|
|
1020
|
+
break
|
|
1021
|
+
}
|
|
1022
|
+
case "Uint8Array": {
|
|
1023
|
+
requestInit.body = self.body.body as any
|
|
1024
|
+
break
|
|
1025
|
+
}
|
|
1026
|
+
case "FormData": {
|
|
1027
|
+
requestInit.body = self.body.formData
|
|
1028
|
+
break
|
|
1029
|
+
}
|
|
1030
|
+
case "Stream": {
|
|
1031
|
+
requestInit.body = Stream.toReadableStreamWith(self.body.stream, options?.services ?? ServiceMap.empty())
|
|
1032
|
+
;(requestInit as any).duplex = "half"
|
|
1033
|
+
break
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
return Result.try({
|
|
1038
|
+
try: () => new Request(url.success, requestInit),
|
|
1039
|
+
catch: (cause) => new UrlParams.UrlParamsError({ cause })
|
|
1040
|
+
})
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const isReadableStream = (u: unknown): u is ReadableStream<Uint8Array> =>
|
|
1044
|
+
typeof ReadableStream !== "undefined" && u instanceof ReadableStream
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* @since 4.0.0
|
|
1048
|
+
* @category conversions
|
|
1049
|
+
*/
|
|
1050
|
+
export const toWeb = (self: HttpClientRequest, options?: {
|
|
1051
|
+
readonly signal?: AbortSignal | undefined
|
|
1052
|
+
}): Effect.Effect<Request, UrlParams.UrlParamsError> =>
|
|
1053
|
+
Effect.servicesWith((services) =>
|
|
1054
|
+
toWebResult(self, {
|
|
1055
|
+
services,
|
|
1056
|
+
signal: options?.signal
|
|
1057
|
+
}).asEffect()
|
|
1058
|
+
)
|
|
@@ -1225,12 +1225,16 @@ export const fromWeb = (response: Response): HttpServerResponse => {
|
|
|
1225
1225
|
cookies: Cookies.fromSetCookie(setCookieHeaders)
|
|
1226
1226
|
})
|
|
1227
1227
|
if (response.body) {
|
|
1228
|
+
const contentType = response.headers.get("content-type")
|
|
1228
1229
|
self = setBody(
|
|
1229
1230
|
self,
|
|
1230
|
-
Body.stream(
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1231
|
+
Body.stream(
|
|
1232
|
+
Stream.fromReadableStream({
|
|
1233
|
+
evaluate: () => response.body!,
|
|
1234
|
+
onError: (e) => e
|
|
1235
|
+
}),
|
|
1236
|
+
contentType ?? undefined
|
|
1237
|
+
)
|
|
1234
1238
|
)
|
|
1235
1239
|
}
|
|
1236
1240
|
return self
|
|
@@ -175,8 +175,8 @@ export function getErrorSchemas(endpoint: AnyWithProps): [Schema.Top, ...Array<S
|
|
|
175
175
|
const schemas = new Set<Schema.Top>(endpoint.error)
|
|
176
176
|
for (const middleware of endpoint.middlewares) {
|
|
177
177
|
const key = middleware as any as HttpApiMiddleware.AnyService
|
|
178
|
-
|
|
179
|
-
schemas.add(
|
|
178
|
+
for (const schema of key.error) {
|
|
179
|
+
schemas.add(schema)
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
return Arr.append(Array.from(schemas), BadRequestFromSchemaError)
|