effect 4.0.0-beta.105 → 4.0.0-beta.107
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/Channel.d.ts +26 -0
- package/dist/Channel.d.ts.map +1 -1
- package/dist/Channel.js +47 -0
- package/dist/Channel.js.map +1 -1
- package/dist/Config.js +3 -3
- package/dist/Config.js.map +1 -1
- package/dist/ConfigProvider.d.ts +35 -3
- package/dist/ConfigProvider.d.ts.map +1 -1
- package/dist/ConfigProvider.js +41 -8
- package/dist/ConfigProvider.js.map +1 -1
- package/dist/Duration.d.ts.map +1 -1
- package/dist/Duration.js +13 -1
- package/dist/Duration.js.map +1 -1
- package/dist/Fiber.d.ts +1 -1
- package/dist/Fiber.d.ts.map +1 -1
- package/dist/Function.d.ts +26 -0
- package/dist/Function.d.ts.map +1 -1
- package/dist/Function.js +36 -0
- package/dist/Function.js.map +1 -1
- package/dist/JsonSchema.d.ts.map +1 -1
- package/dist/JsonSchema.js +34 -17
- package/dist/JsonSchema.js.map +1 -1
- package/dist/Schema.d.ts +32 -84
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +58 -54
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts +2 -17
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +39 -28
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +44 -7
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +15 -4
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/ScopedRef.d.ts.map +1 -1
- package/dist/ScopedRef.js +1 -1
- package/dist/ScopedRef.js.map +1 -1
- package/dist/Stream.d.ts +10 -0
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +12 -23
- package/dist/Stream.js.map +1 -1
- package/dist/TxQueue.js +1 -1
- package/dist/TxQueue.js.map +1 -1
- package/dist/internal/effect.js +2 -4
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/executionPlan.js +3 -2
- package/dist/internal/executionPlan.js.map +1 -1
- package/dist/internal/rcRef.js +18 -13
- package/dist/internal/rcRef.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +32 -16
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toArbitrary.d.ts +1 -4
- package/dist/internal/schema/toArbitrary.d.ts.map +1 -1
- package/dist/internal/schema/toArbitrary.js +0 -74
- package/dist/internal/schema/toArbitrary.js.map +1 -1
- package/dist/internal/schema/toJsonSchemaDocument.js +18 -4
- package/dist/internal/schema/toJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toRepresentation.js +45 -43
- package/dist/internal/schema/toRepresentation.js.map +1 -1
- package/dist/testing/TestSchema.js +2 -2
- package/dist/testing/TestSchema.js.map +1 -1
- package/dist/unstable/ai/McpSchema.d.ts +128 -128
- package/dist/unstable/ai/McpSchema.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.d.ts.map +1 -1
- package/dist/unstable/ai/McpServer.js +23 -11
- package/dist/unstable/ai/McpServer.js.map +1 -1
- package/dist/unstable/ai/Prompt.d.ts +4 -3
- package/dist/unstable/ai/Prompt.d.ts.map +1 -1
- package/dist/unstable/ai/Prompt.js +38 -13
- package/dist/unstable/ai/Prompt.js.map +1 -1
- package/dist/unstable/cli/Argument.d.ts +6 -3
- package/dist/unstable/cli/Argument.d.ts.map +1 -1
- package/dist/unstable/cli/Argument.js +2 -1
- package/dist/unstable/cli/Argument.js.map +1 -1
- package/dist/unstable/cli/CliError.d.ts +20 -1
- package/dist/unstable/cli/CliError.d.ts.map +1 -1
- package/dist/unstable/cli/CliError.js +26 -2
- package/dist/unstable/cli/CliError.js.map +1 -1
- package/dist/unstable/cli/Command.d.ts +23 -0
- package/dist/unstable/cli/Command.d.ts.map +1 -1
- package/dist/unstable/cli/Command.js +23 -4
- package/dist/unstable/cli/Command.js.map +1 -1
- package/dist/unstable/cluster/Entity.d.ts +2 -2
- package/dist/unstable/cluster/Entity.d.ts.map +1 -1
- package/dist/unstable/cluster/Entity.js.map +1 -1
- package/dist/unstable/cluster/EntityProxy.d.ts +3 -3
- package/dist/unstable/cluster/EntityProxy.d.ts.map +1 -1
- package/dist/unstable/cluster/EntityProxy.js +4 -3
- package/dist/unstable/cluster/EntityProxy.js.map +1 -1
- package/dist/unstable/cluster/Sharding.d.ts +2 -2
- package/dist/unstable/cluster/Sharding.d.ts.map +1 -1
- package/dist/unstable/cluster/Sharding.js +14 -5
- package/dist/unstable/cluster/Sharding.js.map +1 -1
- package/dist/unstable/eventlog/EventLogEncryption.d.ts +6 -5
- package/dist/unstable/eventlog/EventLogEncryption.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLogEncryption.js +14 -12
- package/dist/unstable/eventlog/EventLogEncryption.js.map +1 -1
- package/dist/unstable/eventlog/EventLogMessage.d.ts +3 -3
- package/dist/unstable/eventlog/EventLogMessage.d.ts.map +1 -1
- package/dist/unstable/eventlog/EventLogMessage.js +2 -3
- package/dist/unstable/eventlog/EventLogMessage.js.map +1 -1
- package/dist/unstable/eventlog/EventLogRemote.js +4 -4
- package/dist/unstable/eventlog/EventLogRemote.js.map +1 -1
- package/dist/unstable/eventlog/EventLogServerEncrypted.js +3 -2
- package/dist/unstable/eventlog/EventLogServerEncrypted.js.map +1 -1
- package/dist/unstable/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerRequest.js +7 -1
- package/dist/unstable/http/HttpServerRequest.js.map +1 -1
- package/dist/unstable/http/Multipart.d.ts +2 -0
- package/dist/unstable/http/Multipart.d.ts.map +1 -1
- package/dist/unstable/http/Multipart.js +4 -12
- package/dist/unstable/http/Multipart.js.map +1 -1
- package/dist/unstable/http/MultipartParser/internal/headers.d.ts.map +1 -1
- package/dist/unstable/http/MultipartParser/internal/headers.js +16 -2
- package/dist/unstable/http/MultipartParser/internal/headers.js.map +1 -1
- package/dist/unstable/http/MultipartParser/internal/multipart.d.ts.map +1 -1
- package/dist/unstable/http/MultipartParser/internal/multipart.js +23 -8
- package/dist/unstable/http/MultipartParser/internal/multipart.js.map +1 -1
- package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
- package/dist/unstable/httpapi/OpenApi.js +1 -1
- package/dist/unstable/httpapi/OpenApi.js.map +1 -1
- package/dist/unstable/process/ChildProcess.d.ts +8 -0
- package/dist/unstable/process/ChildProcess.d.ts.map +1 -1
- package/dist/unstable/process/ChildProcess.js.map +1 -1
- package/dist/unstable/rpc/RpcClient.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcClient.js +5 -0
- package/dist/unstable/rpc/RpcClient.js.map +1 -1
- package/dist/unstable/sql/Migrator.d.ts +9 -1
- package/dist/unstable/sql/Migrator.d.ts.map +1 -1
- package/dist/unstable/sql/Migrator.js +15 -2
- package/dist/unstable/sql/Migrator.js.map +1 -1
- package/dist/unstable/sql/SqlResolver.d.ts.map +1 -1
- package/dist/unstable/sql/SqlResolver.js +20 -16
- package/dist/unstable/sql/SqlResolver.js.map +1 -1
- package/dist/unstable/workers/Worker.d.ts.map +1 -1
- package/dist/unstable/workers/Worker.js +11 -12
- package/dist/unstable/workers/Worker.js.map +1 -1
- package/package.json +1 -1
- package/src/Channel.ts +58 -0
- package/src/Config.ts +3 -3
- package/src/ConfigProvider.ts +43 -8
- package/src/Duration.ts +12 -1
- package/src/Fiber.ts +1 -1
- package/src/Function.ts +37 -0
- package/src/JsonSchema.ts +43 -42
- package/src/Schema.ts +68 -146
- package/src/SchemaAST.ts +50 -30
- package/src/SchemaRepresentation.ts +44 -7
- package/src/ScopedRef.ts +3 -1
- package/src/Stream.ts +12 -30
- package/src/TxQueue.ts +1 -1
- package/src/internal/effect.ts +3 -6
- package/src/internal/executionPlan.ts +3 -2
- package/src/internal/rcRef.ts +24 -16
- package/src/internal/schema/fromJsonSchemaDocument.ts +36 -18
- package/src/internal/schema/toArbitrary.ts +0 -72
- package/src/internal/schema/toJsonSchemaDocument.ts +24 -4
- package/src/internal/schema/toRepresentation.ts +66 -48
- package/src/testing/TestSchema.ts +2 -2
- package/src/unstable/ai/McpServer.ts +23 -11
- package/src/unstable/ai/Prompt.ts +37 -15
- package/src/unstable/cli/Argument.ts +6 -3
- package/src/unstable/cli/CliError.ts +28 -2
- package/src/unstable/cli/Command.ts +44 -4
- package/src/unstable/cluster/Entity.ts +7 -2
- package/src/unstable/cluster/EntityProxy.ts +12 -5
- package/src/unstable/cluster/Sharding.ts +29 -17
- package/src/unstable/eventlog/EventLogEncryption.ts +15 -16
- package/src/unstable/eventlog/EventLogMessage.ts +2 -3
- package/src/unstable/eventlog/EventLogRemote.ts +4 -4
- package/src/unstable/eventlog/EventLogServerEncrypted.ts +2 -2
- package/src/unstable/http/HttpServerRequest.ts +8 -3
- package/src/unstable/http/Multipart.ts +4 -13
- package/src/unstable/http/MultipartParser/internal/headers.ts +16 -387
- package/src/unstable/http/MultipartParser/internal/multipart.ts +25 -8
- package/src/unstable/httpapi/OpenApi.ts +4 -1
- package/src/unstable/process/ChildProcess.ts +8 -0
- package/src/unstable/rpc/RpcClient.ts +5 -0
- package/src/unstable/sql/Migrator.ts +22 -9
- package/src/unstable/sql/SqlResolver.ts +28 -20
- package/src/unstable/workers/Worker.ts +13 -14
|
@@ -489,7 +489,7 @@ const runWithProtocolState = Effect.fnUntraced(function*(options: {
|
|
|
489
489
|
const isHttp = Option.isSome(yield* Effect.serviceOption(HttpRouter.HttpRouter))
|
|
490
490
|
const sessions = protocolState.sessions
|
|
491
491
|
const clientProtocols = new Map<number, McpProtocol.ProtocolAdapter>()
|
|
492
|
-
const
|
|
492
|
+
const activeRequests = new Map<number, Map<string, boolean>>()
|
|
493
493
|
const handlers = yield* Layer.build(layerHandlers(options, {
|
|
494
494
|
sessions,
|
|
495
495
|
protocolRegistry
|
|
@@ -577,11 +577,13 @@ const runWithProtocolState = Effect.fnUntraced(function*(options: {
|
|
|
577
577
|
...protocol,
|
|
578
578
|
send: (clientId, response) => {
|
|
579
579
|
if (response._tag === "Exit") {
|
|
580
|
-
const requests =
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
580
|
+
const requests = activeRequests.get(clientId)
|
|
581
|
+
const key = requestKey(response.requestId)
|
|
582
|
+
const cancelled = requests?.get(key)
|
|
583
|
+
if (requests !== undefined && requests.delete(key) && requests.size === 0) {
|
|
584
|
+
activeRequests.delete(clientId)
|
|
585
|
+
}
|
|
586
|
+
if (cancelled === true) {
|
|
585
587
|
return Effect.void
|
|
586
588
|
}
|
|
587
589
|
}
|
|
@@ -670,9 +672,12 @@ const runWithProtocolState = Effect.fnUntraced(function*(options: {
|
|
|
670
672
|
if (request.tag === "notifications/cancelled") {
|
|
671
673
|
return decodeCancelledNotification(request.payload).pipe(
|
|
672
674
|
Effect.flatMap(({ requestId }) => {
|
|
673
|
-
const
|
|
674
|
-
requests.
|
|
675
|
-
|
|
675
|
+
const key = requestKey(requestId)
|
|
676
|
+
const requests = activeRequests.get(clientId)
|
|
677
|
+
if (requests?.has(key) !== true) {
|
|
678
|
+
return Effect.void
|
|
679
|
+
}
|
|
680
|
+
requests.set(key, true)
|
|
676
681
|
return f(clientId, {
|
|
677
682
|
_tag: "Interrupt",
|
|
678
683
|
requestId: RpcMessage.RequestId(requestId)
|
|
@@ -732,7 +737,14 @@ const runWithProtocolState = Effect.fnUntraced(function*(options: {
|
|
|
732
737
|
}
|
|
733
738
|
return selectedProtocol.payloadCodecs(rpc).decode(request.payload).pipe(
|
|
734
739
|
Effect.matchEffect({
|
|
735
|
-
onSuccess: () =>
|
|
740
|
+
onSuccess: () => {
|
|
741
|
+
if (request.isNotification !== true) {
|
|
742
|
+
const requests = activeRequests.get(clientId) ?? new Map<string, boolean>()
|
|
743
|
+
requests.set(requestKey(request.id), false)
|
|
744
|
+
activeRequests.set(clientId, requests)
|
|
745
|
+
}
|
|
746
|
+
return f(clientId, routedRequest)
|
|
747
|
+
},
|
|
736
748
|
onFailure: () =>
|
|
737
749
|
request.isNotification
|
|
738
750
|
? Effect.void
|
|
@@ -752,7 +764,7 @@ const runWithProtocolState = Effect.fnUntraced(function*(options: {
|
|
|
752
764
|
case "Interrupt":
|
|
753
765
|
return f(clientId, request)
|
|
754
766
|
case "Eof":
|
|
755
|
-
|
|
767
|
+
activeRequests.delete(clientId)
|
|
756
768
|
return f(clientId, request)
|
|
757
769
|
case "Pong":
|
|
758
770
|
case "Exit":
|
|
@@ -2004,11 +2004,23 @@ export const make = (input: RawInput): Prompt => {
|
|
|
2004
2004
|
*/
|
|
2005
2005
|
export const fromMessages = (messages: ReadonlyArray<Message>): Prompt => makePrompt(messages)
|
|
2006
2006
|
|
|
2007
|
+
const mergeOptions = (left: ProviderOptions, right: ProviderOptions): ProviderOptions => {
|
|
2008
|
+
const result: Record<string, ProviderOptions[string]> = { ...left }
|
|
2009
|
+
for (const [provider, metadata] of Object.entries(right)) {
|
|
2010
|
+
const previous = result[provider]
|
|
2011
|
+
result[provider] = Predicate.isObject(previous) && Predicate.isObject(metadata)
|
|
2012
|
+
? Object.assign({}, previous, metadata)
|
|
2013
|
+
: metadata
|
|
2014
|
+
}
|
|
2015
|
+
return result
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2007
2018
|
/**
|
|
2008
2019
|
* Creates a `Prompt` from response parts by folding completed text and
|
|
2009
|
-
* reasoning streams into assistant parts,
|
|
2010
|
-
*
|
|
2011
|
-
* in a tool message using
|
|
2020
|
+
* reasoning streams into assistant parts, preserving provider metadata as
|
|
2021
|
+
* prompt options, placing tool calls and approval requests in an assistant
|
|
2022
|
+
* message, and placing non-preliminary tool results in a tool message using
|
|
2023
|
+
* their encoded results.
|
|
2012
2024
|
*
|
|
2013
2025
|
* **Example** (Creating prompts from response parts)
|
|
2014
2026
|
*
|
|
@@ -2052,55 +2064,63 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
|
|
|
2052
2064
|
const assistantParts: Array<AssistantMessagePart> = []
|
|
2053
2065
|
const toolParts: Array<ToolMessagePart> = []
|
|
2054
2066
|
|
|
2055
|
-
const activeTextDeltas = new Map<string, { text: string }>()
|
|
2056
|
-
const activeReasoningDeltas = new Map<string, { text: string }>()
|
|
2067
|
+
const activeTextDeltas = new Map<string, { text: string; options: ProviderOptions }>()
|
|
2068
|
+
const activeReasoningDeltas = new Map<string, { text: string; options: ProviderOptions }>()
|
|
2057
2069
|
|
|
2058
2070
|
for (const part of parts) {
|
|
2059
2071
|
switch (part.type) {
|
|
2060
2072
|
// Text Parts
|
|
2061
2073
|
case "text": {
|
|
2062
|
-
assistantParts.push(makePart("text", { text: part.text }))
|
|
2074
|
+
assistantParts.push(makePart("text", { text: part.text, options: part.metadata }))
|
|
2063
2075
|
break
|
|
2064
2076
|
}
|
|
2065
2077
|
|
|
2066
2078
|
// Text Parts (streaming)
|
|
2067
2079
|
case "text-start": {
|
|
2068
|
-
activeTextDeltas.set(part.id, { text: "" })
|
|
2080
|
+
activeTextDeltas.set(part.id, { text: "", options: part.metadata })
|
|
2069
2081
|
break
|
|
2070
2082
|
}
|
|
2071
2083
|
case "text-delta": {
|
|
2072
2084
|
if (activeTextDeltas.has(part.id)) {
|
|
2073
|
-
activeTextDeltas.get(part.id)
|
|
2085
|
+
const active = activeTextDeltas.get(part.id)!
|
|
2086
|
+
active.text += part.delta
|
|
2087
|
+
active.options = mergeOptions(active.options, part.metadata)
|
|
2074
2088
|
}
|
|
2075
2089
|
break
|
|
2076
2090
|
}
|
|
2077
2091
|
case "text-end": {
|
|
2078
2092
|
if (activeTextDeltas.has(part.id)) {
|
|
2079
|
-
|
|
2093
|
+
const active = activeTextDeltas.get(part.id)!
|
|
2094
|
+
active.options = mergeOptions(active.options, part.metadata)
|
|
2095
|
+
assistantParts.push(makePart("text", active))
|
|
2080
2096
|
}
|
|
2081
2097
|
break
|
|
2082
2098
|
}
|
|
2083
2099
|
|
|
2084
2100
|
// Reasoning Parts
|
|
2085
2101
|
case "reasoning": {
|
|
2086
|
-
assistantParts.push(makePart("reasoning", { text: part.text }))
|
|
2102
|
+
assistantParts.push(makePart("reasoning", { text: part.text, options: part.metadata }))
|
|
2087
2103
|
break
|
|
2088
2104
|
}
|
|
2089
2105
|
|
|
2090
2106
|
// Reasoning Parts (streaming)
|
|
2091
2107
|
case "reasoning-start": {
|
|
2092
|
-
activeReasoningDeltas.set(part.id, { text: "" })
|
|
2108
|
+
activeReasoningDeltas.set(part.id, { text: "", options: part.metadata })
|
|
2093
2109
|
break
|
|
2094
2110
|
}
|
|
2095
2111
|
case "reasoning-delta": {
|
|
2096
2112
|
if (activeReasoningDeltas.has(part.id)) {
|
|
2097
|
-
activeReasoningDeltas.get(part.id)
|
|
2113
|
+
const active = activeReasoningDeltas.get(part.id)!
|
|
2114
|
+
active.text += part.delta
|
|
2115
|
+
active.options = mergeOptions(active.options, part.metadata)
|
|
2098
2116
|
}
|
|
2099
2117
|
break
|
|
2100
2118
|
}
|
|
2101
2119
|
case "reasoning-end": {
|
|
2102
2120
|
if (activeReasoningDeltas.has(part.id)) {
|
|
2103
|
-
|
|
2121
|
+
const active = activeReasoningDeltas.get(part.id)!
|
|
2122
|
+
active.options = mergeOptions(active.options, part.metadata)
|
|
2123
|
+
assistantParts.push(makePart("reasoning", active))
|
|
2104
2124
|
}
|
|
2105
2125
|
break
|
|
2106
2126
|
}
|
|
@@ -2111,7 +2131,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
|
|
|
2111
2131
|
id: part.id,
|
|
2112
2132
|
name: part.name,
|
|
2113
2133
|
params: part.params,
|
|
2114
|
-
providerExecuted: part.providerExecuted ?? false
|
|
2134
|
+
providerExecuted: part.providerExecuted ?? false,
|
|
2135
|
+
options: part.metadata
|
|
2115
2136
|
}))
|
|
2116
2137
|
break
|
|
2117
2138
|
}
|
|
@@ -2125,7 +2146,8 @@ export const fromResponseParts = (parts: ReadonlyArray<Response.AnyPart>): Promp
|
|
|
2125
2146
|
name: part.name,
|
|
2126
2147
|
isFailure: part.isFailure,
|
|
2127
2148
|
result: part.encodedResult,
|
|
2128
|
-
providerExecuted: part.providerExecuted ?? false
|
|
2149
|
+
providerExecuted: part.providerExecuted ?? false,
|
|
2150
|
+
options: part.metadata
|
|
2129
2151
|
}))
|
|
2130
2152
|
}
|
|
2131
2153
|
break
|
|
@@ -719,7 +719,8 @@ export const map: {
|
|
|
719
719
|
* ? Effect.succeed(file)
|
|
720
720
|
* : Effect.fail(
|
|
721
721
|
* new CliError.UserError({
|
|
722
|
-
* cause: new Error(
|
|
722
|
+
* cause: new Error(`Unsupported file extension: ${file}`),
|
|
723
|
+
* userMessage: "Only .txt files allowed"
|
|
723
724
|
* })
|
|
724
725
|
* )
|
|
725
726
|
* )
|
|
@@ -768,7 +769,8 @@ export const mapEffect: {
|
|
|
768
769
|
* ? Effect.succeed(file)
|
|
769
770
|
* : Effect.fail(
|
|
770
771
|
* new CliError.UserError({
|
|
771
|
-
* cause: new Error(
|
|
772
|
+
* cause: new Error(`Unsupported file extension: ${file}`),
|
|
773
|
+
* userMessage: "Only .txt files allowed"
|
|
772
774
|
* })
|
|
773
775
|
* )
|
|
774
776
|
* )
|
|
@@ -817,7 +819,8 @@ export const mapEffect: {
|
|
|
817
819
|
* ? Effect.succeed(file)
|
|
818
820
|
* : Effect.fail(
|
|
819
821
|
* new CliError.UserError({
|
|
820
|
-
* cause: new Error(
|
|
822
|
+
* cause: new Error(`Unsupported file extension: ${file}`),
|
|
823
|
+
* userMessage: "Only .txt files allowed"
|
|
821
824
|
* })
|
|
822
825
|
* )
|
|
823
826
|
* )
|
|
@@ -478,6 +478,10 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
|
|
|
478
478
|
/**
|
|
479
479
|
* Error wrapper for user handler failures in the CLI error channel.
|
|
480
480
|
*
|
|
481
|
+
* `userMessage` can provide safe, user-facing text independently of the
|
|
482
|
+
* underlying cause. When omitted or empty, `message` uses a non-empty string
|
|
483
|
+
* cause or `Error.message`, then falls back to `"An error occurred"`.
|
|
484
|
+
*
|
|
481
485
|
* **Example** (Wrapping user errors)
|
|
482
486
|
*
|
|
483
487
|
* ```ts import.meta.vitest
|
|
@@ -486,7 +490,8 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
|
|
|
486
490
|
*
|
|
487
491
|
* // Wrapping user errors
|
|
488
492
|
* const userError = new CliError.UserError({
|
|
489
|
-
* cause: new Error("Database connection failed")
|
|
493
|
+
* cause: new Error("Database connection failed for postgres://localhost"),
|
|
494
|
+
* userMessage: "Could not connect to the database"
|
|
490
495
|
* })
|
|
491
496
|
*
|
|
492
497
|
* // In command handler
|
|
@@ -516,7 +521,8 @@ export class UnknownSubcommand extends Schema.TaggedError<UnknownSubcommand>(
|
|
|
516
521
|
export class UserError extends Schema.TaggedError<UserError>(
|
|
517
522
|
`${TypeId}/UserError`
|
|
518
523
|
)("UserError", {
|
|
519
|
-
cause: Schema.Defect()
|
|
524
|
+
cause: Schema.Defect(),
|
|
525
|
+
userMessage: Schema.optionalKey(Schema.String)
|
|
520
526
|
}) {
|
|
521
527
|
/**
|
|
522
528
|
* Marks this value as a user handler error for runtime guards.
|
|
@@ -524,6 +530,26 @@ export class UserError extends Schema.TaggedError<UserError>(
|
|
|
524
530
|
* @since 4.0.0
|
|
525
531
|
*/
|
|
526
532
|
readonly [TypeId] = TypeId
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Controls whether the runtime logger should report this error. The CLI
|
|
536
|
+
* runner sets this to `false` after rendering the error itself.
|
|
537
|
+
*
|
|
538
|
+
* @since 4.0.0
|
|
539
|
+
*/
|
|
540
|
+
override [Runtime.errorReported] = true
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Returns the explicit user-facing message or a safe fallback from `cause`.
|
|
544
|
+
*
|
|
545
|
+
* @since 4.0.0
|
|
546
|
+
*/
|
|
547
|
+
override get message() {
|
|
548
|
+
if (this.userMessage) return this.userMessage
|
|
549
|
+
if (typeof this.cause === "string" && this.cause) return this.cause
|
|
550
|
+
if (this.cause instanceof Error && this.cause.message) return this.cause.message
|
|
551
|
+
return "An error occurred"
|
|
552
|
+
}
|
|
527
553
|
}
|
|
528
554
|
|
|
529
555
|
/**
|
|
@@ -22,6 +22,7 @@ import type * as Path from "../../Path.ts"
|
|
|
22
22
|
import * as Predicate from "../../Predicate.ts"
|
|
23
23
|
import * as References from "../../References.ts"
|
|
24
24
|
import * as Result from "../../Result.ts"
|
|
25
|
+
import * as Runtime from "../../Runtime.ts"
|
|
25
26
|
import * as Stdio from "../../Stdio.ts"
|
|
26
27
|
import * as Terminal from "../../Terminal.ts"
|
|
27
28
|
import type { Contravariant, Covariant, NoInfer, Simplify } from "../../Types.ts"
|
|
@@ -2669,18 +2670,26 @@ const getOutOfScopeGlobalFlagErrors = (
|
|
|
2669
2670
|
|
|
2670
2671
|
const showHelp = <Name extends string, Input, E, R, ContextInput>(
|
|
2671
2672
|
command: Command<Name, Input, ContextInput, E, R>,
|
|
2672
|
-
error: CliError.ShowHelp
|
|
2673
|
+
error: CliError.ShowHelp,
|
|
2674
|
+
renderErrors: boolean
|
|
2673
2675
|
): Effect.Effect<void, CliError.CliError, Environment> =>
|
|
2674
2676
|
Effect.gen(function*() {
|
|
2675
2677
|
const { builtIns } = yield* CliConfig.CliConfig
|
|
2676
2678
|
const formatter = yield* CliOutput.Formatter
|
|
2677
2679
|
const helpDoc = yield* getHelpForCommandPath(command, error.commandPath, builtIns)
|
|
2678
2680
|
yield* Console.log(formatter.formatHelpDoc(helpDoc))
|
|
2679
|
-
if (error.errors.length > 0) {
|
|
2681
|
+
if (renderErrors && error.errors.length > 0) {
|
|
2680
2682
|
yield* Console.error(formatter.formatErrors(error.errors as any))
|
|
2681
2683
|
}
|
|
2682
2684
|
})
|
|
2683
2685
|
|
|
2686
|
+
const showUserError = (error: CliError.UserError): Effect.Effect<void> =>
|
|
2687
|
+
Effect.gen(function*() {
|
|
2688
|
+
const formatter = yield* CliOutput.Formatter
|
|
2689
|
+
yield* Console.error(formatter.formatError(error))
|
|
2690
|
+
error[Runtime.errorReported] = false
|
|
2691
|
+
})
|
|
2692
|
+
|
|
2684
2693
|
/**
|
|
2685
2694
|
* Runs a command using the arguments supplied by the `Stdio` service.
|
|
2686
2695
|
*
|
|
@@ -2689,6 +2698,11 @@ const showHelp = <Name extends string, Input, E, R, ContextInput>(
|
|
|
2689
2698
|
* Use when command-line arguments should come from `Stdio` at the application
|
|
2690
2699
|
* entry point.
|
|
2691
2700
|
*
|
|
2701
|
+
* Help documents are always rendered. By default, parse error details and
|
|
2702
|
+
* `CliError.UserError` failures are also rendered with the installed
|
|
2703
|
+
* `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
|
|
2704
|
+
* `false` when the host application owns error rendering.
|
|
2705
|
+
*
|
|
2692
2706
|
* **Example** (Running commands with standard input)
|
|
2693
2707
|
*
|
|
2694
2708
|
* ```ts import.meta.vitest
|
|
@@ -2746,6 +2760,11 @@ export const run: {
|
|
|
2746
2760
|
* Use when command-line arguments should come from `Stdio` at the application
|
|
2747
2761
|
* entry point.
|
|
2748
2762
|
*
|
|
2763
|
+
* Help documents are always rendered. By default, parse error details and
|
|
2764
|
+
* `CliError.UserError` failures are also rendered with the installed
|
|
2765
|
+
* `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
|
|
2766
|
+
* `false` when the host application owns error rendering.
|
|
2767
|
+
*
|
|
2749
2768
|
* **Example** (Running commands with standard input)
|
|
2750
2769
|
*
|
|
2751
2770
|
* ```ts import.meta.vitest
|
|
@@ -2797,6 +2816,7 @@ export const run: {
|
|
|
2797
2816
|
(
|
|
2798
2817
|
config: {
|
|
2799
2818
|
readonly version: string
|
|
2819
|
+
readonly renderErrors?: boolean | undefined
|
|
2800
2820
|
}
|
|
2801
2821
|
): <Name extends string, Input, E, R, ContextInput>(
|
|
2802
2822
|
command: Command<Name, Input, ContextInput, E, R>
|
|
@@ -2809,6 +2829,11 @@ export const run: {
|
|
|
2809
2829
|
* Use when command-line arguments should come from `Stdio` at the application
|
|
2810
2830
|
* entry point.
|
|
2811
2831
|
*
|
|
2832
|
+
* Help documents are always rendered. By default, parse error details and
|
|
2833
|
+
* `CliError.UserError` failures are also rendered with the installed
|
|
2834
|
+
* `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
|
|
2835
|
+
* `false` when the host application owns error rendering.
|
|
2836
|
+
*
|
|
2812
2837
|
* **Example** (Running commands with standard input)
|
|
2813
2838
|
*
|
|
2814
2839
|
* ```ts import.meta.vitest
|
|
@@ -2861,12 +2886,14 @@ export const run: {
|
|
|
2861
2886
|
command: Command<Name, Input, ContextInput, E, R>,
|
|
2862
2887
|
config: {
|
|
2863
2888
|
readonly version: string
|
|
2889
|
+
readonly renderErrors?: boolean | undefined
|
|
2864
2890
|
}
|
|
2865
2891
|
): Effect.Effect<void, E | CliError.CliError, R | Environment>
|
|
2866
2892
|
} = dual(2, <Name extends string, Input, E, R, ContextInput>(
|
|
2867
2893
|
command: Command<Name, Input, ContextInput, E, R>,
|
|
2868
2894
|
config: {
|
|
2869
2895
|
readonly version: string
|
|
2896
|
+
readonly renderErrors?: boolean | undefined
|
|
2870
2897
|
}
|
|
2871
2898
|
) =>
|
|
2872
2899
|
Stdio.Stdio.use(({ args }) =>
|
|
@@ -2884,6 +2911,11 @@ export const run: {
|
|
|
2884
2911
|
* Use when you need to test CLI applications or programmatically execute
|
|
2885
2912
|
* commands with specific arguments.
|
|
2886
2913
|
*
|
|
2914
|
+
* Help documents are always rendered. By default, parse error details and
|
|
2915
|
+
* `CliError.UserError` failures are also rendered with the installed
|
|
2916
|
+
* `CliOutput.Formatter` before the error is rethrown. Set `renderErrors` to
|
|
2917
|
+
* `false` when the host application owns error rendering.
|
|
2918
|
+
*
|
|
2887
2919
|
* **Example** (Running commands with explicit arguments)
|
|
2888
2920
|
*
|
|
2889
2921
|
* ```ts import.meta.vitest
|
|
@@ -2937,6 +2969,7 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
|
|
|
2937
2969
|
command: Command<Name, Input, ContextInput, E, R>,
|
|
2938
2970
|
config: {
|
|
2939
2971
|
readonly version: string
|
|
2972
|
+
readonly renderErrors?: boolean | undefined
|
|
2940
2973
|
}
|
|
2941
2974
|
): (
|
|
2942
2975
|
input: ReadonlyArray<string>
|
|
@@ -3003,7 +3036,7 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
|
|
|
3003
3036
|
}))
|
|
3004
3037
|
if (shouldRun) {
|
|
3005
3038
|
yield* Console.log()
|
|
3006
|
-
yield* runWith(command, config)(wizardArgs.slice(1))
|
|
3039
|
+
yield* runWith(command, { ...config, renderErrors: false })(wizardArgs.slice(1))
|
|
3007
3040
|
}
|
|
3008
3041
|
}).pipe(
|
|
3009
3042
|
Effect.catchTag("QuitError", () => Console.log(Wizard.renderQuit()))
|
|
@@ -3051,7 +3084,14 @@ export const runWith = <const Name extends string, Input, E, R, ContextInput>(
|
|
|
3051
3084
|
CliError.isCliError(error) && error._tag === "ShowHelp"
|
|
3052
3085
|
? Result.succeed(error)
|
|
3053
3086
|
: Result.fail(error),
|
|
3054
|
-
(error) => Effect.andThen(showHelp(command, error), Effect.fail(error))
|
|
3087
|
+
(error) => Effect.andThen(showHelp(command, error, config.renderErrors !== false), Effect.fail(error))
|
|
3088
|
+
),
|
|
3089
|
+
Effect.catchFilter(
|
|
3090
|
+
(error) =>
|
|
3091
|
+
config.renderErrors !== false && CliError.isCliError(error) && error._tag === "UserError"
|
|
3092
|
+
? Result.succeed(error)
|
|
3093
|
+
: Result.fail(error),
|
|
3094
|
+
(error) => Effect.andThen(showUserError(error), Effect.fail(error))
|
|
3055
3095
|
),
|
|
3056
3096
|
Effect.catchFilter(
|
|
3057
3097
|
(e) =>
|
|
@@ -34,7 +34,12 @@ import * as RpcClient from "../rpc/RpcClient.ts"
|
|
|
34
34
|
import * as RpcGroup from "../rpc/RpcGroup.ts"
|
|
35
35
|
import * as RpcSchema from "../rpc/RpcSchema.ts"
|
|
36
36
|
import * as RpcServer from "../rpc/RpcServer.ts"
|
|
37
|
-
import type {
|
|
37
|
+
import type {
|
|
38
|
+
AlreadyProcessingMessage,
|
|
39
|
+
EntityNotAssignedToRunner,
|
|
40
|
+
MailboxFull,
|
|
41
|
+
PersistenceError
|
|
42
|
+
} from "./ClusterError.ts"
|
|
38
43
|
import { Persisted, ShardGroup, Uninterruptible } from "./ClusterSchema.ts"
|
|
39
44
|
import { EntityAddress } from "./EntityAddress.ts"
|
|
40
45
|
import type { EntityId } from "./EntityId.ts"
|
|
@@ -117,7 +122,7 @@ export interface Entity<
|
|
|
117
122
|
entityId: string
|
|
118
123
|
) => RpcClient.RpcClient.From<
|
|
119
124
|
Rpcs,
|
|
120
|
-
MailboxFull | AlreadyProcessingMessage | PersistenceError
|
|
125
|
+
MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner
|
|
121
126
|
>,
|
|
122
127
|
never,
|
|
123
128
|
Sharding
|
|
@@ -14,7 +14,7 @@ import * as HttpApiEndpoint from "../httpapi/HttpApiEndpoint.ts"
|
|
|
14
14
|
import * as HttpApiGroup from "../httpapi/HttpApiGroup.ts"
|
|
15
15
|
import * as Rpc from "../rpc/Rpc.ts"
|
|
16
16
|
import * as RpcGroup from "../rpc/RpcGroup.ts"
|
|
17
|
-
import { AlreadyProcessingMessage, MailboxFull, PersistenceError } from "./ClusterError.ts"
|
|
17
|
+
import { AlreadyProcessingMessage, EntityNotAssignedToRunner, MailboxFull, PersistenceError } from "./ClusterError.ts"
|
|
18
18
|
import type * as Entity from "./Entity.ts"
|
|
19
19
|
import type { EntityId } from "./EntityId.ts"
|
|
20
20
|
|
|
@@ -24,6 +24,11 @@ const clientErrors = [
|
|
|
24
24
|
PersistenceError
|
|
25
25
|
] as const
|
|
26
26
|
|
|
27
|
+
const requestErrors = [
|
|
28
|
+
...clientErrors,
|
|
29
|
+
EntityNotAssignedToRunner
|
|
30
|
+
] as const
|
|
31
|
+
|
|
27
32
|
/**
|
|
28
33
|
* Derives an `RpcGroup` from an `Entity`.
|
|
29
34
|
*
|
|
@@ -75,7 +80,7 @@ export const toRpcGroup = <Type extends string, Rpcs extends Rpc.Any>(
|
|
|
75
80
|
}
|
|
76
81
|
const rpc = Rpc.make(`${entity.type}.${parentRpc._tag}`, {
|
|
77
82
|
payload: payloadSchema,
|
|
78
|
-
error: Schema.Union([parentRpc.errorSchema, ...
|
|
83
|
+
error: Schema.Union([parentRpc.errorSchema, ...requestErrors]),
|
|
79
84
|
success: parentRpc.successSchema
|
|
80
85
|
}).annotateMerge(parentRpc.annotations)
|
|
81
86
|
const rpcDiscard = Rpc.make(`${entity.type}.${parentRpc._tag}Discard`, {
|
|
@@ -115,11 +120,12 @@ export type ConvertRpcs<Rpcs extends Rpc.Any, Prefix extends string> = Rpcs exte
|
|
|
115
120
|
}>,
|
|
116
121
|
_Success,
|
|
117
122
|
Schema.Codec<
|
|
118
|
-
_Error["Type"] | MailboxFull | AlreadyProcessingMessage | PersistenceError,
|
|
123
|
+
_Error["Type"] | MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner,
|
|
119
124
|
| _Error["Encoded"]
|
|
120
125
|
| typeof MailboxFull["Encoded"]
|
|
121
126
|
| typeof AlreadyProcessingMessage["Encoded"]
|
|
122
|
-
| typeof PersistenceError["Encoded"]
|
|
127
|
+
| typeof PersistenceError["Encoded"]
|
|
128
|
+
| typeof EntityNotAssignedToRunner["Encoded"],
|
|
123
129
|
_Error["DecodingServices"],
|
|
124
130
|
_Error["EncodingServices"]
|
|
125
131
|
>
|
|
@@ -193,7 +199,7 @@ export const toHttpApiGroup = <const Name extends string, Type extends string, R
|
|
|
193
199
|
params: entityIdPath,
|
|
194
200
|
payload: parentRpc.payloadSchema,
|
|
195
201
|
success: parentRpc.successSchema,
|
|
196
|
-
error: [parentRpc.errorSchema, ...
|
|
202
|
+
error: [parentRpc.errorSchema, ...requestErrors]
|
|
197
203
|
}).annotateMerge(parentRpc.annotations)
|
|
198
204
|
const endpointDiscard = HttpApiEndpoint.post(
|
|
199
205
|
`${parentRpc._tag}Discard`,
|
|
@@ -250,6 +256,7 @@ export type ConvertHttpApi<Rpcs extends Rpc.Any> = Rpcs extends Rpc.Rpc<
|
|
|
250
256
|
| typeof MailboxFull
|
|
251
257
|
| typeof AlreadyProcessingMessage
|
|
252
258
|
| typeof PersistenceError
|
|
259
|
+
| typeof EntityNotAssignedToRunner
|
|
253
260
|
>
|
|
254
261
|
| HttpApiEndpoint.HttpApiEndpoint<
|
|
255
262
|
`${_Tag}Discard`,
|
|
@@ -124,7 +124,7 @@ export class Sharding extends Context.Service<Sharding, {
|
|
|
124
124
|
entityId: string
|
|
125
125
|
) => RpcClient.RpcClient.From<
|
|
126
126
|
Rpcs,
|
|
127
|
-
MailboxFull | AlreadyProcessingMessage | PersistenceError
|
|
127
|
+
MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner
|
|
128
128
|
>
|
|
129
129
|
>
|
|
130
130
|
|
|
@@ -178,7 +178,7 @@ export class Sharding extends Context.Service<Sharding, {
|
|
|
178
178
|
discard: boolean
|
|
179
179
|
) => Effect.Effect<
|
|
180
180
|
void,
|
|
181
|
-
MailboxFull | AlreadyProcessingMessage | PersistenceError
|
|
181
|
+
MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner
|
|
182
182
|
>
|
|
183
183
|
|
|
184
184
|
/**
|
|
@@ -967,18 +967,40 @@ const make = Effect.gen(function*() {
|
|
|
967
967
|
retries?: number
|
|
968
968
|
): Effect.Effect<
|
|
969
969
|
void,
|
|
970
|
-
MailboxFull | AlreadyProcessingMessage | PersistenceError
|
|
970
|
+
MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner
|
|
971
971
|
> {
|
|
972
972
|
const isPersisted = Context.get(
|
|
973
973
|
message._tag === "OutgoingRequest" ? message.annotations : message.rpc.annotations,
|
|
974
974
|
Persisted
|
|
975
975
|
)
|
|
976
|
+
const shouldFail = !discard &&
|
|
977
|
+
(message._tag === "OutgoingRequest" || message.envelope._tag === "AckChunk")
|
|
978
|
+
const abandon = (error: EntityNotAssignedToRunner) => {
|
|
979
|
+
if (!isPersisted) {
|
|
980
|
+
return shouldFail
|
|
981
|
+
? Effect.fail(error)
|
|
982
|
+
: Effect.logDebug("Abandoning outgoing message during shutdown", message.envelope.address)
|
|
983
|
+
}
|
|
984
|
+
const persist = message._tag === "OutgoingRequest"
|
|
985
|
+
? storage.saveRequest(message)
|
|
986
|
+
: storage.saveEnvelope(message)
|
|
987
|
+
return Effect.catchTag(persist, "MalformedMessage", Effect.die).pipe(
|
|
988
|
+
Effect.andThen(
|
|
989
|
+
shouldFail
|
|
990
|
+
? Effect.fail(error)
|
|
991
|
+
: Effect.logWarning("Persisting outgoing message abandoned during shutdown", message.envelope.address)
|
|
992
|
+
)
|
|
993
|
+
)
|
|
994
|
+
}
|
|
976
995
|
return Effect.catchFilter(
|
|
977
996
|
Effect.suspend(() => {
|
|
978
997
|
const address = message.envelope.address
|
|
979
998
|
if (isPersisted && !storageEnabled) {
|
|
980
999
|
return Effect.die("Sharding.sendOutgoing: Persisted messages require MessageStorage")
|
|
981
1000
|
}
|
|
1001
|
+
if (shouldFail && MutableRef.get(isShutdown)) {
|
|
1002
|
+
return Effect.fail(new EntityNotAssignedToRunner({ address }))
|
|
1003
|
+
}
|
|
982
1004
|
const maybeRunner = MutableHashMap.get(shardAssignments, address.shardId)
|
|
983
1005
|
const runnerIsLocal = Option.isSome(maybeRunner) && isLocalRunner(maybeRunner.value)
|
|
984
1006
|
if (isPersisted) {
|
|
@@ -1003,17 +1025,7 @@ const make = Effect.gen(function*() {
|
|
|
1003
1025
|
const cannotRecover = MutableRef.get(isShutdown) ||
|
|
1004
1026
|
(targetManager !== undefined && targetManager.status !== "alive")
|
|
1005
1027
|
if (cannotRecover) {
|
|
1006
|
-
|
|
1007
|
-
return Effect.logDebug("Abandoning outgoing message during shutdown", message.envelope.address)
|
|
1008
|
-
}
|
|
1009
|
-
const persist = message._tag === "OutgoingRequest"
|
|
1010
|
-
? storage.saveRequest(message)
|
|
1011
|
-
: storage.saveEnvelope(message)
|
|
1012
|
-
return Effect.catchTag(persist, "MalformedMessage", Effect.die).pipe(
|
|
1013
|
-
Effect.andThen(
|
|
1014
|
-
Effect.logWarning("Persisting outgoing message abandoned during shutdown", message.envelope.address)
|
|
1015
|
-
)
|
|
1016
|
-
)
|
|
1028
|
+
return abandon(error)
|
|
1017
1029
|
}
|
|
1018
1030
|
}
|
|
1019
1031
|
if (retries === 0) {
|
|
@@ -1183,7 +1195,7 @@ const make = Effect.gen(function*() {
|
|
|
1183
1195
|
Entity<any, any>,
|
|
1184
1196
|
(entityId: string) => RpcClient.RpcClient<
|
|
1185
1197
|
any,
|
|
1186
|
-
MailboxFull | AlreadyProcessingMessage
|
|
1198
|
+
MailboxFull | AlreadyProcessingMessage | EntityNotAssignedToRunner
|
|
1187
1199
|
>,
|
|
1188
1200
|
never
|
|
1189
1201
|
> = yield* ResourceMap.make(
|
|
@@ -1196,7 +1208,7 @@ const make = Effect.gen(function*() {
|
|
|
1196
1208
|
flatten: true,
|
|
1197
1209
|
onFromClient(options): Effect.Effect<
|
|
1198
1210
|
void,
|
|
1199
|
-
MailboxFull | AlreadyProcessingMessage | PersistenceError
|
|
1211
|
+
MailboxFull | AlreadyProcessingMessage | PersistenceError | EntityNotAssignedToRunner
|
|
1200
1212
|
> {
|
|
1201
1213
|
const address = Context.getUnsafe(options.context, ClientAddressTag)
|
|
1202
1214
|
switch (options.message._tag) {
|
|
@@ -1337,7 +1349,7 @@ const make = Effect.gen(function*() {
|
|
|
1337
1349
|
const makeClient = <Type extends string, Rpcs extends Rpc.Any>(entity: Entity<Type, Rpcs>): Effect.Effect<
|
|
1338
1350
|
(
|
|
1339
1351
|
entityId: string
|
|
1340
|
-
) => RpcClient.RpcClient.From<Rpcs, MailboxFull | AlreadyProcessingMessage>
|
|
1352
|
+
) => RpcClient.RpcClient.From<Rpcs, MailboxFull | AlreadyProcessingMessage | EntityNotAssignedToRunner>
|
|
1341
1353
|
> => clients.get(entity) as any
|
|
1342
1354
|
|
|
1343
1355
|
const clientRespondDiscard = (_reply: Reply.Reply<any>) => Effect.void
|
|
@@ -19,14 +19,15 @@ import type { Identity } from "./EventLog.ts"
|
|
|
19
19
|
import { makeGetIdentityRootSecretMaterial } from "./internal/identityRootSecretDerivation.ts"
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Schema for an encrypted journal entry paired with
|
|
23
|
-
* entry.
|
|
22
|
+
* Schema for an encrypted journal entry paired with its initialization vector
|
|
23
|
+
* and the id of the original entry.
|
|
24
24
|
*
|
|
25
25
|
* @category models
|
|
26
26
|
* @since 4.0.0
|
|
27
27
|
*/
|
|
28
28
|
export const EncryptedEntry = Schema.Struct({
|
|
29
29
|
entryId: EntryId,
|
|
30
|
+
iv: Transferable.Uint8Array,
|
|
30
31
|
encryptedEntry: Transferable.Uint8Array
|
|
31
32
|
})
|
|
32
33
|
|
|
@@ -76,10 +77,12 @@ export class EventLogEncryption extends Context.Service<EventLogEncryption, {
|
|
|
76
77
|
readonly encrypt: (
|
|
77
78
|
identity: Identity["Service"],
|
|
78
79
|
entries: ReadonlyArray<Entry>
|
|
79
|
-
) => Effect.Effect<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
) => Effect.Effect<
|
|
81
|
+
ReadonlyArray<{
|
|
82
|
+
readonly iv: Uint8Array<ArrayBuffer>
|
|
83
|
+
readonly encryptedEntry: Uint8Array<ArrayBuffer>
|
|
84
|
+
}>
|
|
85
|
+
>
|
|
83
86
|
readonly decrypt: (
|
|
84
87
|
identity: Identity["Service"],
|
|
85
88
|
entries: ReadonlyArray<EncryptedRemoteEntry>
|
|
@@ -104,22 +107,18 @@ export const makeEncryptionSubtle = (crypto: Crypto): Effect.Effect<EventLogEncr
|
|
|
104
107
|
encrypt: Effect.fnUntraced(function*(identity, entries) {
|
|
105
108
|
const data = yield* Effect.orDie(Entry.encodeArray(entries))
|
|
106
109
|
const key = (yield* getIdentityRootSecretMaterial(identity)).encryptionKey
|
|
107
|
-
|
|
108
|
-
const encryptedEntries = yield* Effect.promise(() =>
|
|
110
|
+
return yield* Effect.promise(() =>
|
|
109
111
|
Promise.all(
|
|
110
|
-
data.map((entry) =>
|
|
111
|
-
crypto.
|
|
112
|
+
data.map((entry) => {
|
|
113
|
+
const iv = crypto.getRandomValues(new Uint8Array(12))
|
|
114
|
+
return crypto.subtle.encrypt(
|
|
112
115
|
{ name: "AES-GCM", iv: toBufferSource(iv), tagLength: 128 },
|
|
113
116
|
key,
|
|
114
117
|
toBufferSource(entry)
|
|
115
|
-
)
|
|
116
|
-
)
|
|
118
|
+
).then((encryptedEntry) => ({ iv, encryptedEntry: new Uint8Array(encryptedEntry) }))
|
|
119
|
+
})
|
|
117
120
|
)
|
|
118
121
|
)
|
|
119
|
-
return {
|
|
120
|
-
iv,
|
|
121
|
-
encryptedEntries: encryptedEntries.map((entry) => new Uint8Array(entry))
|
|
122
|
-
}
|
|
123
122
|
}),
|
|
124
123
|
decrypt: Effect.fnUntraced(function*(identity, entries) {
|
|
125
124
|
const key = (yield* getIdentityRootSecretMaterial(identity)).encryptionKey
|