effect 4.0.0-beta.97 → 4.0.0-beta.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/README.md +1 -3
  2. package/dist/Array.js +1 -1
  3. package/dist/Array.js.map +1 -1
  4. package/dist/Graph.d.ts +1187 -196
  5. package/dist/Graph.d.ts.map +1 -1
  6. package/dist/Graph.js +1031 -283
  7. package/dist/Graph.js.map +1 -1
  8. package/dist/Iterable.d.ts.map +1 -1
  9. package/dist/Iterable.js +41 -1
  10. package/dist/Iterable.js.map +1 -1
  11. package/dist/LayerRef.d.ts +4 -6
  12. package/dist/LayerRef.d.ts.map +1 -1
  13. package/dist/LayerRef.js +4 -6
  14. package/dist/LayerRef.js.map +1 -1
  15. package/dist/Number.d.ts.map +1 -1
  16. package/dist/Number.js +28 -10
  17. package/dist/Number.js.map +1 -1
  18. package/dist/Schema.d.ts +22 -22
  19. package/dist/Schema.d.ts.map +1 -1
  20. package/dist/Schema.js +37 -34
  21. package/dist/Schema.js.map +1 -1
  22. package/dist/SchemaAST.d.ts.map +1 -1
  23. package/dist/SchemaAST.js +25 -10
  24. package/dist/SchemaAST.js.map +1 -1
  25. package/dist/SchemaError.d.ts +53 -0
  26. package/dist/SchemaError.d.ts.map +1 -0
  27. package/dist/SchemaError.js +61 -0
  28. package/dist/SchemaError.js.map +1 -0
  29. package/dist/SchemaGetter.d.ts.map +1 -1
  30. package/dist/SchemaGetter.js +17 -12
  31. package/dist/SchemaGetter.js.map +1 -1
  32. package/dist/SchemaRepresentation.d.ts.map +1 -1
  33. package/dist/SchemaRepresentation.js +186 -224
  34. package/dist/SchemaRepresentation.js.map +1 -1
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +8 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/internal/effect.js +35 -11
  40. package/dist/internal/effect.js.map +1 -1
  41. package/dist/internal/schema/equivalence.js +1 -2
  42. package/dist/internal/schema/equivalence.js.map +1 -1
  43. package/dist/internal/schema/representation.js +1 -3
  44. package/dist/internal/schema/representation.js.map +1 -1
  45. package/dist/internal/schema/schema.d.ts +0 -13
  46. package/dist/internal/schema/schema.d.ts.map +1 -1
  47. package/dist/internal/schema/schema.js +4 -29
  48. package/dist/internal/schema/schema.js.map +1 -1
  49. package/dist/unstable/ai/Tool.d.ts.map +1 -1
  50. package/dist/unstable/ai/Tool.js +11 -13
  51. package/dist/unstable/ai/Tool.js.map +1 -1
  52. package/dist/unstable/cli/CliConfig.d.ts +76 -0
  53. package/dist/unstable/cli/CliConfig.d.ts.map +1 -0
  54. package/dist/unstable/cli/CliConfig.js +63 -0
  55. package/dist/unstable/cli/CliConfig.js.map +1 -0
  56. package/dist/unstable/cli/CliError.d.ts +8 -16
  57. package/dist/unstable/cli/CliError.d.ts.map +1 -1
  58. package/dist/unstable/cli/CliError.js +11 -16
  59. package/dist/unstable/cli/CliError.js.map +1 -1
  60. package/dist/unstable/cli/Command.d.ts +40 -4
  61. package/dist/unstable/cli/Command.d.ts.map +1 -1
  62. package/dist/unstable/cli/Command.js +63 -6
  63. package/dist/unstable/cli/Command.js.map +1 -1
  64. package/dist/unstable/cli/GlobalFlag.d.ts +24 -5
  65. package/dist/unstable/cli/GlobalFlag.d.ts.map +1 -1
  66. package/dist/unstable/cli/GlobalFlag.js +26 -10
  67. package/dist/unstable/cli/GlobalFlag.js.map +1 -1
  68. package/dist/unstable/cli/Param.js +6 -2
  69. package/dist/unstable/cli/Param.js.map +1 -1
  70. package/dist/unstable/cli/index.d.ts +4 -0
  71. package/dist/unstable/cli/index.d.ts.map +1 -1
  72. package/dist/unstable/cli/index.js +4 -0
  73. package/dist/unstable/cli/index.js.map +1 -1
  74. package/dist/unstable/cli/internal/ansi.d.ts.map +1 -1
  75. package/dist/unstable/cli/internal/ansi.js +2 -0
  76. package/dist/unstable/cli/internal/ansi.js.map +1 -1
  77. package/dist/unstable/cli/internal/parser.js +11 -2
  78. package/dist/unstable/cli/internal/parser.js.map +1 -1
  79. package/dist/unstable/cli/internal/wizard.d.ts +13 -0
  80. package/dist/unstable/cli/internal/wizard.d.ts.map +1 -0
  81. package/dist/unstable/cli/internal/wizard.js +212 -0
  82. package/dist/unstable/cli/internal/wizard.js.map +1 -0
  83. package/dist/unstable/cluster/EntityProxyServer.d.ts +1 -1
  84. package/dist/unstable/cluster/EntityProxyServer.d.ts.map +1 -1
  85. package/dist/unstable/cluster/EntityProxyServer.js +2 -4
  86. package/dist/unstable/cluster/EntityProxyServer.js.map +1 -1
  87. package/dist/unstable/cluster/RunnerStorage.js +1 -1
  88. package/dist/unstable/cluster/RunnerStorage.js.map +1 -1
  89. package/dist/unstable/cluster/internal/entityManager.js +15 -12
  90. package/dist/unstable/cluster/internal/entityManager.js.map +1 -1
  91. package/dist/unstable/http/Multipart.d.ts.map +1 -1
  92. package/dist/unstable/http/Multipart.js +3 -1
  93. package/dist/unstable/http/Multipart.js.map +1 -1
  94. package/dist/unstable/httpapi/HttpApi.d.ts +36 -15
  95. package/dist/unstable/httpapi/HttpApi.d.ts.map +1 -1
  96. package/dist/unstable/httpapi/HttpApi.js +19 -20
  97. package/dist/unstable/httpapi/HttpApi.js.map +1 -1
  98. package/dist/unstable/httpapi/HttpApiBuilder.d.ts +51 -62
  99. package/dist/unstable/httpapi/HttpApiBuilder.d.ts.map +1 -1
  100. package/dist/unstable/httpapi/HttpApiBuilder.js +68 -58
  101. package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
  102. package/dist/unstable/httpapi/HttpApiClient.d.ts +53 -53
  103. package/dist/unstable/httpapi/HttpApiClient.d.ts.map +1 -1
  104. package/dist/unstable/httpapi/HttpApiClient.js +40 -30
  105. package/dist/unstable/httpapi/HttpApiClient.js.map +1 -1
  106. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts +165 -164
  107. package/dist/unstable/httpapi/HttpApiEndpoint.d.ts.map +1 -1
  108. package/dist/unstable/httpapi/HttpApiEndpoint.js +31 -19
  109. package/dist/unstable/httpapi/HttpApiEndpoint.js.map +1 -1
  110. package/dist/unstable/httpapi/HttpApiError.d.ts +22 -0
  111. package/dist/unstable/httpapi/HttpApiError.d.ts.map +1 -1
  112. package/dist/unstable/httpapi/HttpApiError.js +31 -0
  113. package/dist/unstable/httpapi/HttpApiError.js.map +1 -1
  114. package/dist/unstable/httpapi/HttpApiGroup.d.ts +55 -30
  115. package/dist/unstable/httpapi/HttpApiGroup.d.ts.map +1 -1
  116. package/dist/unstable/httpapi/HttpApiGroup.js +22 -29
  117. package/dist/unstable/httpapi/HttpApiGroup.js.map +1 -1
  118. package/dist/unstable/httpapi/HttpApiMiddleware.d.ts +8 -8
  119. package/dist/unstable/httpapi/HttpApiMiddleware.d.ts.map +1 -1
  120. package/dist/unstable/httpapi/HttpApiMiddleware.js.map +1 -1
  121. package/dist/unstable/httpapi/HttpApiScalar.d.ts +2 -2
  122. package/dist/unstable/httpapi/HttpApiScalar.d.ts.map +1 -1
  123. package/dist/unstable/httpapi/HttpApiScalar.js +4 -3
  124. package/dist/unstable/httpapi/HttpApiScalar.js.map +1 -1
  125. package/dist/unstable/httpapi/HttpApiSchema.d.ts +8 -0
  126. package/dist/unstable/httpapi/HttpApiSchema.d.ts.map +1 -1
  127. package/dist/unstable/httpapi/HttpApiSchema.js.map +1 -1
  128. package/dist/unstable/httpapi/HttpApiSwagger.d.ts +1 -1
  129. package/dist/unstable/httpapi/HttpApiSwagger.d.ts.map +1 -1
  130. package/dist/unstable/httpapi/HttpApiSwagger.js.map +1 -1
  131. package/dist/unstable/httpapi/HttpApiTest.d.ts +4 -4
  132. package/dist/unstable/httpapi/HttpApiTest.d.ts.map +1 -1
  133. package/dist/unstable/httpapi/HttpApiTest.js +9 -8
  134. package/dist/unstable/httpapi/HttpApiTest.js.map +1 -1
  135. package/dist/unstable/httpapi/OpenApi.d.ts +1 -1
  136. package/dist/unstable/httpapi/OpenApi.d.ts.map +1 -1
  137. package/dist/unstable/httpapi/OpenApi.js +77 -37
  138. package/dist/unstable/httpapi/OpenApi.js.map +1 -1
  139. package/dist/unstable/httpapi/internal/html.js +6 -2
  140. package/dist/unstable/httpapi/internal/html.js.map +1 -1
  141. package/dist/unstable/httpapi/internal/mediaType.d.ts +2 -0
  142. package/dist/unstable/httpapi/internal/mediaType.d.ts.map +1 -0
  143. package/dist/unstable/httpapi/internal/mediaType.js +7 -0
  144. package/dist/unstable/httpapi/internal/mediaType.js.map +1 -0
  145. package/dist/unstable/persistence/PersistedQueue.d.ts.map +1 -1
  146. package/dist/unstable/persistence/PersistedQueue.js +16 -12
  147. package/dist/unstable/persistence/PersistedQueue.js.map +1 -1
  148. package/dist/unstable/persistence/Redis.d.ts.map +1 -1
  149. package/dist/unstable/persistence/Redis.js +5 -3
  150. package/dist/unstable/persistence/Redis.js.map +1 -1
  151. package/dist/unstable/reactivity/Atom.js +1 -1
  152. package/dist/unstable/reactivity/Atom.js.map +1 -1
  153. package/dist/unstable/reactivity/AtomHttpApi.d.ts +7 -7
  154. package/dist/unstable/reactivity/AtomHttpApi.d.ts.map +1 -1
  155. package/dist/unstable/reactivity/AtomHttpApi.js +3 -2
  156. package/dist/unstable/reactivity/AtomHttpApi.js.map +1 -1
  157. package/dist/unstable/rpc/RpcServer.d.ts +3 -1
  158. package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
  159. package/dist/unstable/rpc/RpcServer.js +6 -3
  160. package/dist/unstable/rpc/RpcServer.js.map +1 -1
  161. package/dist/unstable/sql/SqlClient.d.ts +1 -2
  162. package/dist/unstable/sql/SqlClient.d.ts.map +1 -1
  163. package/dist/unstable/sql/SqlClient.js.map +1 -1
  164. package/dist/unstable/workflow/DurableDeferred.js +1 -1
  165. package/dist/unstable/workflow/DurableDeferred.js.map +1 -1
  166. package/dist/unstable/workflow/WorkflowProxyServer.d.ts +1 -1
  167. package/dist/unstable/workflow/WorkflowProxyServer.d.ts.map +1 -1
  168. package/dist/unstable/workflow/WorkflowProxyServer.js +1 -2
  169. package/dist/unstable/workflow/WorkflowProxyServer.js.map +1 -1
  170. package/package.json +3 -3
  171. package/src/Array.ts +1 -1
  172. package/src/Graph.ts +2967 -457
  173. package/src/Iterable.ts +32 -2
  174. package/src/LayerRef.ts +4 -6
  175. package/src/Number.ts +29 -10
  176. package/src/Schema.ts +43 -35
  177. package/src/SchemaAST.ts +25 -13
  178. package/src/SchemaError.ts +64 -0
  179. package/src/SchemaGetter.ts +22 -16
  180. package/src/SchemaRepresentation.ts +165 -202
  181. package/src/index.ts +10 -0
  182. package/src/internal/effect.ts +48 -25
  183. package/src/internal/schema/equivalence.ts +1 -2
  184. package/src/internal/schema/representation.ts +4 -4
  185. package/src/internal/schema/schema.ts +4 -37
  186. package/src/unstable/ai/Tool.ts +13 -16
  187. package/src/unstable/cli/CliConfig.ts +85 -0
  188. package/src/unstable/cli/CliError.ts +27 -16
  189. package/src/unstable/cli/Command.ts +90 -14
  190. package/src/unstable/cli/GlobalFlag.ts +46 -29
  191. package/src/unstable/cli/Param.ts +15 -3
  192. package/src/unstable/cli/index.ts +5 -0
  193. package/src/unstable/cli/internal/ansi.ts +3 -0
  194. package/src/unstable/cli/internal/parser.ts +14 -2
  195. package/src/unstable/cli/internal/wizard.ts +283 -0
  196. package/src/unstable/cluster/EntityProxyServer.ts +15 -17
  197. package/src/unstable/cluster/RunnerStorage.ts +1 -1
  198. package/src/unstable/cluster/internal/entityManager.ts +48 -34
  199. package/src/unstable/http/Multipart.ts +3 -1
  200. package/src/unstable/httpapi/HttpApi.ts +72 -47
  201. package/src/unstable/httpapi/HttpApiBuilder.ts +320 -217
  202. package/src/unstable/httpapi/HttpApiClient.ts +196 -151
  203. package/src/unstable/httpapi/HttpApiEndpoint.ts +251 -447
  204. package/src/unstable/httpapi/HttpApiError.ts +33 -0
  205. package/src/unstable/httpapi/HttpApiGroup.ts +95 -74
  206. package/src/unstable/httpapi/HttpApiMiddleware.ts +10 -7
  207. package/src/unstable/httpapi/HttpApiScalar.ts +15 -12
  208. package/src/unstable/httpapi/HttpApiSchema.ts +8 -0
  209. package/src/unstable/httpapi/HttpApiSwagger.ts +2 -2
  210. package/src/unstable/httpapi/HttpApiTest.ts +15 -14
  211. package/src/unstable/httpapi/OpenApi.ts +74 -36
  212. package/src/unstable/httpapi/internal/html.ts +9 -2
  213. package/src/unstable/httpapi/internal/mediaType.ts +6 -0
  214. package/src/unstable/persistence/PersistedQueue.ts +16 -14
  215. package/src/unstable/persistence/Redis.ts +9 -4
  216. package/src/unstable/reactivity/Atom.ts +1 -1
  217. package/src/unstable/reactivity/AtomHttpApi.ts +164 -162
  218. package/src/unstable/rpc/RpcServer.ts +10 -4
  219. package/src/unstable/sql/SqlClient.ts +1 -2
  220. package/src/unstable/workflow/DurableDeferred.ts +1 -1
  221. package/src/unstable/workflow/WorkflowProxyServer.ts +11 -12
@@ -2898,9 +2898,19 @@ export const getUnderlyingSingleOrThrow = <Kind extends ParamKind, A>(
2898
2898
  */
2899
2899
  export const getParamMetadata = <Kind extends ParamKind, A>(
2900
2900
  param: Param<Kind, A>
2901
- ): { isOptional: boolean; isVariadic: boolean } => {
2901
+ ): {
2902
+ readonly isOptional: boolean
2903
+ readonly isVariadic: boolean
2904
+ readonly variadicMin: Option.Option<number>
2905
+ readonly variadicMax: Option.Option<number>
2906
+ } => {
2902
2907
  return matchParam(param, {
2903
- Single: () => ({ isOptional: false, isVariadic: false }),
2908
+ Single: () => ({
2909
+ isOptional: false,
2910
+ isVariadic: false,
2911
+ variadicMin: Option.none(),
2912
+ variadicMax: Option.none()
2913
+ }),
2904
2914
  Map: (mapped) => getParamMetadata(mapped.param),
2905
2915
  Transform: (mapped) => getParamMetadata(mapped.param),
2906
2916
  Optional: (optional) => ({
@@ -2909,7 +2919,9 @@ export const getParamMetadata = <Kind extends ParamKind, A>(
2909
2919
  }),
2910
2920
  Variadic: (variadic) => ({
2911
2921
  ...getParamMetadata(variadic.param),
2912
- isVariadic: true
2922
+ isVariadic: true,
2923
+ variadicMin: variadic.min,
2924
+ variadicMax: variadic.max
2913
2925
  })
2914
2926
  })
2915
2927
  }
@@ -9,6 +9,11 @@
9
9
  */
10
10
  export * as Argument from "./Argument.ts"
11
11
 
12
+ /**
13
+ * @since 4.0.0
14
+ */
15
+ export * as CliConfig from "./CliConfig.ts"
16
+
12
17
  /**
13
18
  * @since 4.0.0
14
19
  */
@@ -57,6 +57,9 @@ export const red = `${ESC}31m`
57
57
  /** @internal */
58
58
  export const green = `${ESC}32m`
59
59
 
60
+ /** @internal */
61
+ export const magenta = `${ESC}35m`
62
+
60
63
  /** @internal */
61
64
  export const white = `${ESC}37m`
62
65
 
@@ -391,6 +391,18 @@ const invalidNegatedFlagValue = (
391
391
  kind: "flag"
392
392
  })
393
393
 
394
+ const missingFlagValue = (spec: FlagParam): CliError.InvalidValue => {
395
+ const choices = Primitive.getChoiceKeys(spec.primitiveType)
396
+ return new CliError.InvalidValue({
397
+ option: spec.name,
398
+ value: "",
399
+ expected: choices === undefined
400
+ ? spec.typeName ?? Primitive.getTypeName(spec.primitiveType)
401
+ : choices.join(" | "),
402
+ kind: "flag"
403
+ })
404
+ }
405
+
394
406
  /**
395
407
  * Checks whether a token is a boolean literal value.
396
408
  * Recognizes: true/false, yes/no, on/off, 1/0
@@ -497,8 +509,8 @@ const consumeFlagValueWithTokens = (
497
509
  }
498
510
 
499
511
  return {
500
- _tag: "Value",
501
- value: undefined,
512
+ _tag: "Error",
513
+ error: missingFlagValue(spec),
502
514
  tokens: []
503
515
  }
504
516
  }
@@ -0,0 +1,283 @@
1
+ import * as Console from "../../../Console.ts"
2
+ import * as Effect from "../../../Effect.ts"
3
+ import * as Option from "../../../Option.ts"
4
+ import * as Redacted from "../../../Redacted.ts"
5
+ import type * as Terminal from "../../../Terminal.ts"
6
+ import type * as CliError from "../CliError.ts"
7
+ import type * as Command from "../Command.ts"
8
+ import * as Param from "../Param.ts"
9
+ import * as Primitive from "../Primitive.ts"
10
+ import * as Prompt from "../Prompt.ts"
11
+ import * as Ansi from "./ansi.ts"
12
+ import { toImpl } from "./command.ts"
13
+
14
+ export interface Options {
15
+ readonly commandPath?: ReadonlyArray<string> | undefined
16
+ readonly prefix?: ReadonlyArray<string> | undefined
17
+ }
18
+
19
+ export const run: (
20
+ command: Command.Command.Any,
21
+ options?: Options
22
+ ) => Effect.Effect<Array<string>, CliError.CliError | Terminal.QuitError, Command.Environment> = Effect.fnUntraced(
23
+ function*(command, options) {
24
+ const commandPath = options?.commandPath ?? [command.name]
25
+ const selected = getCommandAtPath(command, commandPath)
26
+ const commandLine = [...(options?.prefix ?? commandPath)]
27
+ yield* logCurrentCommand(commandLine)
28
+ yield* promptCommand(selected, commandLine, selected === command ? "ROOT" : selected.name)
29
+ return commandLine
30
+ }
31
+ )
32
+
33
+ const getCommandAtPath = (
34
+ command: Command.Command.Any,
35
+ commandPath: ReadonlyArray<string>
36
+ ): Command.Command.Any => {
37
+ let current = command
38
+ for (const name of commandPath.slice(1)) {
39
+ const child = current.subcommands
40
+ .flatMap((group) => group.commands)
41
+ .find((candidate) => candidate.name === name || candidate.alias === name)
42
+ if (child === undefined) {
43
+ break
44
+ }
45
+ current = child
46
+ }
47
+ return current
48
+ }
49
+
50
+ const promptCommand: (
51
+ command: Command.Command.Any,
52
+ commandLine: Array<string>,
53
+ sectionName: string
54
+ ) => Effect.Effect<void, CliError.CliError | Terminal.QuitError, Command.Environment> = Effect.fnUntraced(
55
+ function*(command, commandLine, sectionName) {
56
+ const impl = toImpl(command)
57
+ const visibleSubcommands = command.subcommands.flatMap((group) => group.commands.filter((child) => !child.hidden))
58
+ const config = visibleSubcommands.length === 0 ? impl.config : impl.contextConfig
59
+
60
+ if (config.flags.length > 0) {
61
+ yield* Console.log(renderSection(sectionName, "FLAGS"))
62
+ for (const param of config.flags) {
63
+ commandLine.push(...yield* promptParam(param))
64
+ }
65
+ if (config.arguments.length > 0 || visibleSubcommands.length > 0) {
66
+ yield* logCurrentCommand(commandLine)
67
+ }
68
+ }
69
+
70
+ if (config.arguments.length > 0) {
71
+ yield* Console.log(renderSection(sectionName, "ARGUMENTS"))
72
+ for (const param of config.arguments) {
73
+ commandLine.push(...yield* promptParam(param))
74
+ }
75
+ if (visibleSubcommands.length > 0) {
76
+ yield* logCurrentCommand(commandLine)
77
+ }
78
+ }
79
+
80
+ if (visibleSubcommands.length === 0) {
81
+ return
82
+ }
83
+
84
+ const child = yield* Prompt.run(Prompt.select({
85
+ message: "Command",
86
+ choices: visibleSubcommands.map((command) => ({
87
+ title: command.name,
88
+ value: command,
89
+ ...(command.shortDescription !== undefined
90
+ ? { description: command.shortDescription }
91
+ : command.description !== undefined
92
+ ? { description: command.description }
93
+ : {})
94
+ }))
95
+ }))
96
+ yield* Console.log()
97
+ commandLine.push(child.name)
98
+ if (hasWizardSteps(child)) {
99
+ yield* logCurrentCommand(commandLine)
100
+ }
101
+ yield* promptCommand(child, commandLine, child.name)
102
+ }
103
+ )
104
+
105
+ const hasWizardSteps = (command: Command.Command.Any): boolean => {
106
+ const hasVisibleSubcommands = command.subcommands.some((group) => group.commands.some((child) => !child.hidden))
107
+ return hasVisibleSubcommands || toImpl(command).config.orderedParams.length > 0
108
+ }
109
+
110
+ const promptParam: (
111
+ param: Param.Any
112
+ ) => Effect.Effect<Array<string>, CliError.CliError | Terminal.QuitError, Command.Environment> = Effect.fnUntraced(
113
+ function*(param) {
114
+ const single = Param.getUnderlyingSingleOrThrow(param)
115
+ const metadata = Param.getParamMetadata(param)
116
+
117
+ if (metadata.isOptional) {
118
+ const include = yield* Prompt.run(Prompt.confirm({
119
+ message: `Set ${renderParamLabel(single)}?`,
120
+ initial: false
121
+ }))
122
+ if (!include) {
123
+ yield* Console.log()
124
+ return []
125
+ }
126
+ }
127
+
128
+ const count = !metadata.isVariadic
129
+ ? 1
130
+ : yield* Prompt.run(Prompt.integer({
131
+ message: `${renderParamLabel(single)} count`,
132
+ default: Option.getOrElse(metadata.variadicMin, () => 0),
133
+ min: Option.getOrElse(metadata.variadicMin, () => 0),
134
+ ...(Option.isSome(metadata.variadicMax) ? { max: metadata.variadicMax.value } : {})
135
+ }))
136
+ const values: Array<string> = []
137
+ for (let i = 0; i < count; i++) {
138
+ values.push(yield* promptSingle(single))
139
+ }
140
+
141
+ const parsed = single.kind === Param.flagKind
142
+ ? {
143
+ flags: { [single.name]: values },
144
+ arguments: []
145
+ }
146
+ : {
147
+ flags: {},
148
+ arguments: values
149
+ }
150
+ yield* param.parse(parsed)
151
+ yield* Console.log()
152
+
153
+ if (single.kind === Param.argumentKind) {
154
+ return values
155
+ }
156
+ return values.flatMap((value) => [`--${single.name}`, value])
157
+ }
158
+ )
159
+
160
+ const promptSingle = (
161
+ single: Param.Single<Param.ParamKind, unknown>
162
+ ): Effect.Effect<string, Terminal.QuitError, Command.Environment> => {
163
+ const message = renderParamMessage(single)
164
+ switch (single.primitiveType._tag) {
165
+ case "Boolean":
166
+ return Effect.map(
167
+ Prompt.run(Prompt.confirm({
168
+ message,
169
+ label: {
170
+ confirm: "true",
171
+ deny: "false"
172
+ },
173
+ placeholder: {
174
+ defaultConfirm: "(T/f)",
175
+ defaultDeny: "(t/F)"
176
+ }
177
+ })),
178
+ String
179
+ )
180
+ case "Choice": {
181
+ const choices = Primitive.getChoiceKeys(single.primitiveType) ?? []
182
+ return Prompt.run(Prompt.select({
183
+ message,
184
+ choices: choices.map((choice) => ({ title: choice, value: choice }))
185
+ }))
186
+ }
187
+ case "Date":
188
+ return Effect.map(Prompt.run(Prompt.date({ message })), (date) => date.toISOString())
189
+ case "Float":
190
+ return Effect.map(Prompt.run(Prompt.float({ message })), String)
191
+ case "Integer":
192
+ return Effect.map(Prompt.run(Prompt.integer({ message })), String)
193
+ case "Redacted":
194
+ return Effect.map(Prompt.run(Prompt.password({ message })), Redacted.value)
195
+ default:
196
+ return Prompt.run(Prompt.text({ message }))
197
+ }
198
+ }
199
+
200
+ const formatName = (single: Param.Single<Param.ParamKind, unknown>): string =>
201
+ single.kind === Param.flagKind ? `--${single.name}` : single.name
202
+
203
+ const renderParamMessage = (single: Param.Single<Param.ParamKind, unknown>): string => renderParamLabel(single)
204
+
205
+ const renderParamLabel = (single: Param.Single<Param.ParamKind, unknown>): string => {
206
+ const description = Option.getOrUndefined(single.description)?.trim()
207
+ const label = single.kind === Param.flagKind && description !== undefined && description.length <= 32
208
+ ? description
209
+ : humanize(single.name)
210
+ return single.kind === Param.flagKind ? `${label} (${formatName(single)})` : label
211
+ }
212
+
213
+ const humanize = (name: string): string => {
214
+ const words = name.split(/[-_]+/).filter((word) => word.length > 0)
215
+ if (words.length === 0) return name
216
+ return [words[0][0].toUpperCase() + words[0].slice(1), ...words.slice(1)].join(" ")
217
+ }
218
+
219
+ const logCurrentCommand = (commandLine: ReadonlyArray<string>): Effect.Effect<void> =>
220
+ Console.log(renderCommandBlock("Current command", commandLine, Ansi.magenta))
221
+
222
+ const renderSection = (commandName: string, section: string): string =>
223
+ `${Ansi.annotate(commandName.toUpperCase(), Ansi.bold, Ansi.cyanBright)} ${Ansi.annotate("·", Ansi.blackBright)} ${
224
+ Ansi.annotate(section, Ansi.bold, Ansi.white)
225
+ }`
226
+
227
+ export const renderIntroduction = (name: string, version: string, summary: string | undefined): string => {
228
+ const title = `${Ansi.annotate(name, Ansi.bold, Ansi.cyanBright)} ${Ansi.annotate(`v${version}`, Ansi.white)} ${
229
+ Ansi.annotate("· Command wizard", Ansi.bold, Ansi.white)
230
+ }`
231
+ return [
232
+ title,
233
+ ...(summary === undefined || summary.length === 0 ? [] : [summary]),
234
+ Ansi.annotate("Build a command interactively. Press Ctrl+C to cancel.", Ansi.blackBright),
235
+ ""
236
+ ].join("\n")
237
+ }
238
+
239
+ export const renderCompletion = (commandLine: ReadonlyArray<string>): string =>
240
+ renderCommandBlock("Command ready", commandLine, Ansi.cyanBright, Ansi.green)
241
+
242
+ export const renderQuit = (): string => `\n${Ansi.annotate("Wizard cancelled.", Ansi.red)}`
243
+
244
+ const renderCommandBlock = (
245
+ label: string,
246
+ commandLine: ReadonlyArray<string>,
247
+ commandColor: string,
248
+ labelColor: string = Ansi.white
249
+ ): string => {
250
+ const lines = wrapCommand(commandLine)
251
+ return [
252
+ Ansi.annotate(label, Ansi.bold, labelColor),
253
+ ...lines.map((line) => Ansi.annotate(line, commandColor)),
254
+ ""
255
+ ].join("\n")
256
+ }
257
+
258
+ const wrapCommand = (commandLine: ReadonlyArray<string>): Array<string> => {
259
+ const width = 88
260
+ const firstIndent = " $ "
261
+ const continuationIndent = " "
262
+ const args = commandLine.map(formatShellArg)
263
+ const lines: Array<string> = []
264
+ let current = firstIndent
265
+
266
+ for (const arg of args) {
267
+ const separator = current === firstIndent || current === continuationIndent ? "" : " "
268
+ if (current.length + separator.length + arg.length > width && current !== firstIndent) {
269
+ lines.push(`${current} \\`)
270
+ current = `${continuationIndent}${arg}`
271
+ } else {
272
+ current += `${separator}${arg}`
273
+ }
274
+ }
275
+
276
+ if (current !== firstIndent) {
277
+ lines.push(current)
278
+ }
279
+ return lines
280
+ }
281
+
282
+ const formatShellArg = (arg: string): string =>
283
+ /^[A-Za-z0-9_./:@%+=,-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", `'"'"'`)}'`
@@ -34,27 +34,25 @@ import type { Sharding } from "./Sharding.ts"
34
34
  */
35
35
  export const layerHttpApi = <
36
36
  ApiId extends string,
37
- Groups extends HttpApiGroup.Any,
38
- Name extends HttpApiGroup.Name<Groups>,
37
+ Groups extends HttpApiGroup.Constraint,
38
+ Identifier extends HttpApiGroup.Identifier<Groups>,
39
39
  Type extends string,
40
40
  Rpcs extends Rpc.Any
41
41
  >(
42
42
  api: HttpApi.HttpApi<ApiId, Groups>,
43
- name: Name,
43
+ identifier: Identifier,
44
44
  entity: Entity.Entity<Type, Rpcs>
45
- ): Layer.Layer<HttpApiGroup.ApiGroup<ApiId, Name>, never, Sharding | Rpc.ServicesServer<Rpcs>> =>
45
+ ): Layer.Layer<HttpApiGroup.Service<ApiId, Identifier>, never, Sharding | Rpc.ServicesServer<Rpcs>> =>
46
46
  HttpApiBuilder.group(
47
47
  api,
48
- name,
49
- Effect.fnUntraced(function*(handlers_) {
48
+ identifier,
49
+ Effect.fnUntraced(function*(handlers: any) {
50
50
  const client = yield* entity.client
51
- let handlers = handlers_
52
- for (const parentRpc_ of entity.protocol.requests.values()) {
53
- const parentRpc = parentRpc_ as any as Rpc.AnyWithProps
51
+ for (const parentRpc of entity.protocol.requests.values()) {
54
52
  handlers = handlers
55
53
  .handle(
56
- parentRpc._tag as any,
57
- (({ params, payload }: { params: { entityId: string }; payload: any }) =>
54
+ parentRpc._tag,
55
+ ({ params, payload }: { params: { entityId: string }; payload: any }) =>
58
56
  (client(params.entityId) as any as Record<string, (p: any) => Effect.Effect<any>>)[parentRpc._tag](
59
57
  payload
60
58
  ).pipe(
@@ -65,11 +63,11 @@ export const layerHttpApi = <
65
63
  entityId: params.entityId,
66
64
  method: parentRpc._tag
67
65
  })
68
- )) as any
66
+ )
69
67
  )
70
68
  .handle(
71
- `${parentRpc._tag}Discard` as any,
72
- (({ params, payload }: { params: { entityId: string }; payload: any }) =>
69
+ `${parentRpc._tag}Discard`,
70
+ ({ params, payload }: { params: { entityId: string }; payload: any }) =>
73
71
  (client(params.entityId) as any as Record<string, (p: any, o: {}) => Effect.Effect<any>>)[parentRpc._tag](
74
72
  payload,
75
73
  { discard: true }
@@ -81,10 +79,10 @@ export const layerHttpApi = <
81
79
  entityId: params.entityId,
82
80
  method: `${parentRpc._tag}Discard`
83
81
  })
84
- )) as any
85
- ) as any
82
+ )
83
+ )
86
84
  }
87
- return handlers as HttpApiBuilder.Handlers<never, never>
85
+ return handlers as HttpApiBuilder.Handlers<never>
88
86
  })
89
87
  )
90
88
 
@@ -220,7 +220,7 @@ export const makeMemory = Effect.gen(function*() {
220
220
  setRunnerHealth: () => Effect.void,
221
221
  acquire: (_address, shardIds) => {
222
222
  acquired = Array.from(shardIds)
223
- return Effect.succeed(Array.from(shardIds))
223
+ return Effect.succeed(acquired)
224
224
  },
225
225
  refresh: () => Effect.sync(() => acquired),
226
226
  release: () => Effect.void,
@@ -207,15 +207,21 @@ export const make = Effect.fnUntraced(function*<
207
207
  (isShuttingDown || isUninterruptibleForServer(request.message.annotations))
208
208
  ) {
209
209
  if (!isShuttingDown) {
210
- return server.write(0, {
211
- ...request.message.envelope,
212
- id: request.message.envelope.requestId as any,
213
- tag: request.message.envelope.tag as any,
214
- payload: new Request({
210
+ return server.write(
211
+ 0,
212
+ {
215
213
  ...request.message.envelope,
216
- lastSentChunk: request.lastSentChunk
217
- } as any) as any
218
- }).pipe(
214
+ id: request.message.envelope.requestId as any,
215
+ tag: request.message.envelope.tag as any,
216
+ payload: new Request({
217
+ ...request.message.envelope,
218
+ lastSentChunk: request.lastSentChunk
219
+ } as any) as any
220
+ },
221
+ Context.get(request.rpc.annotations, WithTransaction)
222
+ ? { onRequest: options.storage.withTransaction }
223
+ : undefined
224
+ ).pipe(
219
225
  Effect.forkIn(scope)
220
226
  )
221
227
  }
@@ -295,16 +301,22 @@ export const make = Effect.fnUntraced(function*<
295
301
  for (const id of defectRequestIds) {
296
302
  const request = activeRequests.get(id)
297
303
  if (!request) continue
298
- const { lastSentChunk, message } = request
299
- yield* server.write(0, {
300
- ...message.envelope,
301
- id: message.envelope.requestId as any,
302
- tag: message.envelope.tag as any,
303
- payload: new Request({
304
+ const { lastSentChunk, message, rpc } = request
305
+ yield* server.write(
306
+ 0,
307
+ {
304
308
  ...message.envelope,
305
- lastSentChunk
306
- } as any) as any
307
- })
309
+ id: message.envelope.requestId as any,
310
+ tag: message.envelope.tag as any,
311
+ payload: new Request({
312
+ ...message.envelope,
313
+ lastSentChunk
314
+ } as any) as any
315
+ },
316
+ Context.get(rpc.annotations, WithTransaction)
317
+ ? { onRequest: options.storage.withTransaction }
318
+ : undefined
319
+ )
308
320
  }
309
321
  defectRequestIds.clear()
310
322
  }
@@ -341,11 +353,11 @@ export const make = Effect.fnUntraced(function*<
341
353
  const state: EntityState = {
342
354
  scope,
343
355
  address,
344
- write(clientId, message) {
356
+ write(clientId, message, writeOptions) {
345
357
  if (writeRef.state.current._tag !== "Acquired") {
346
- return Effect.flatMap(writeRef.await, (write) => write(clientId, message))
358
+ return Effect.flatMap(writeRef.await, (write) => write(clientId, message, writeOptions))
347
359
  }
348
- return writeRef.state.current.value(clientId, message)
360
+ return writeRef.state.current.value(clientId, message, writeOptions)
349
361
  },
350
362
  activeRequests,
351
363
  lastActiveCheck: clock.currentTimeMillisUnsafe(),
@@ -472,21 +484,23 @@ export const make = Effect.fnUntraced(function*<
472
484
  })
473
485
  }
474
486
  server.activeRequests.set(message.envelope.requestId, entry)
475
- let write = server.write(0, {
476
- ...message.envelope,
477
- id: message.envelope.requestId as any,
478
- payload: new Request({
487
+ return server.write(
488
+ 0,
489
+ {
479
490
  ...message.envelope,
480
- lastSentChunk: Option.filter(
481
- message.lastSentReply,
482
- (reply): reply is Reply.Chunk<R> => reply._tag === "Chunk"
483
- )
484
- })
485
- })
486
- if (Context.get(message.annotations, WithTransaction)) {
487
- write = options.storage.withTransaction(write)
488
- }
489
- return write
491
+ id: message.envelope.requestId as any,
492
+ payload: new Request({
493
+ ...message.envelope,
494
+ lastSentChunk: Option.filter(
495
+ message.lastSentReply,
496
+ (reply): reply is Reply.Chunk<R> => reply._tag === "Chunk"
497
+ )
498
+ })
499
+ },
500
+ Context.get(message.annotations, WithTransaction)
501
+ ? { onRequest: options.storage.withTransaction }
502
+ : undefined
503
+ )
490
504
  }
491
505
  case "IncomingEnvelope": {
492
506
  const entry = server.activeRequests.get(message.envelope.requestId)
@@ -452,7 +452,9 @@ export const makeChannel = <IE>(headers: Record<string, string>): Channel.Channe
452
452
  exit = Option.some(Exit.fail(convertError(error_)))
453
453
  },
454
454
  onDone() {
455
- exit = Option.some(Exit.fail(Cause.Done()))
455
+ if (Option.isNone(exit)) {
456
+ exit = Option.some(Exit.fail(Cause.Done()))
457
+ }
456
458
  }
457
459
  })
458
460