@effect/platform 0.67.1 → 0.68.1

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 (56) hide show
  1. package/README.md +66 -52
  2. package/dist/cjs/FetchHttpClient.js.map +1 -1
  3. package/dist/cjs/HttpClient.js +43 -31
  4. package/dist/cjs/HttpClient.js.map +1 -1
  5. package/dist/cjs/HttpClientRequest.js.map +1 -1
  6. package/dist/cjs/PlatformConfigProvider.js +24 -1
  7. package/dist/cjs/PlatformConfigProvider.js.map +1 -1
  8. package/dist/cjs/internal/fetchHttpClient.js +1 -1
  9. package/dist/cjs/internal/fetchHttpClient.js.map +1 -1
  10. package/dist/cjs/internal/httpClient.js +41 -38
  11. package/dist/cjs/internal/httpClient.js.map +1 -1
  12. package/dist/cjs/internal/httpClientRequest.js +5 -9
  13. package/dist/cjs/internal/httpClientRequest.js.map +1 -1
  14. package/dist/cjs/internal/platformConfigProvider.js +117 -0
  15. package/dist/cjs/internal/platformConfigProvider.js.map +1 -0
  16. package/dist/dts/FetchHttpClient.d.ts +1 -1
  17. package/dist/dts/FetchHttpClient.d.ts.map +1 -1
  18. package/dist/dts/HttpApiClient.d.ts +2 -2
  19. package/dist/dts/HttpApiClient.d.ts.map +1 -1
  20. package/dist/dts/HttpClient.d.ts +118 -186
  21. package/dist/dts/HttpClient.d.ts.map +1 -1
  22. package/dist/dts/HttpClientRequest.d.ts +2 -5
  23. package/dist/dts/HttpClientRequest.d.ts.map +1 -1
  24. package/dist/dts/HttpServer.d.ts +1 -1
  25. package/dist/dts/HttpServer.d.ts.map +1 -1
  26. package/dist/dts/PlatformConfigProvider.d.ts +23 -0
  27. package/dist/dts/PlatformConfigProvider.d.ts.map +1 -1
  28. package/dist/dts/internal/httpClient.d.ts +23 -1
  29. package/dist/dts/internal/httpClient.d.ts.map +1 -1
  30. package/dist/dts/internal/platformConfigProvider.d.ts +2 -0
  31. package/dist/dts/internal/platformConfigProvider.d.ts.map +1 -0
  32. package/dist/esm/FetchHttpClient.js.map +1 -1
  33. package/dist/esm/HttpClient.js +42 -30
  34. package/dist/esm/HttpClient.js.map +1 -1
  35. package/dist/esm/HttpClientRequest.js.map +1 -1
  36. package/dist/esm/PlatformConfigProvider.js +23 -0
  37. package/dist/esm/PlatformConfigProvider.js.map +1 -1
  38. package/dist/esm/internal/fetchHttpClient.js +1 -1
  39. package/dist/esm/internal/fetchHttpClient.js.map +1 -1
  40. package/dist/esm/internal/httpClient.js +29 -33
  41. package/dist/esm/internal/httpClient.js.map +1 -1
  42. package/dist/esm/internal/httpClientRequest.js +4 -8
  43. package/dist/esm/internal/httpClientRequest.js.map +1 -1
  44. package/dist/esm/internal/platformConfigProvider.js +106 -0
  45. package/dist/esm/internal/platformConfigProvider.js.map +1 -0
  46. package/package.json +2 -2
  47. package/src/FetchHttpClient.ts +1 -1
  48. package/src/HttpApiClient.ts +2 -2
  49. package/src/HttpClient.ts +258 -279
  50. package/src/HttpClientRequest.ts +2 -7
  51. package/src/HttpServer.ts +1 -1
  52. package/src/PlatformConfigProvider.ts +30 -0
  53. package/src/internal/fetchHttpClient.ts +1 -1
  54. package/src/internal/httpClient.ts +191 -303
  55. package/src/internal/httpClientRequest.ts +4 -10
  56. package/src/internal/platformConfigProvider.ts +148 -0
@@ -1,18 +1,16 @@
1
1
  import type { ParseOptions } from "@effect/schema/AST"
2
2
  import type * as Schema from "@effect/schema/Schema"
3
- import * as Context from "effect/Context"
4
3
  import * as Effect from "effect/Effect"
5
- import * as Effectable from "effect/Effectable"
6
4
  import { dual } from "effect/Function"
7
5
  import * as Inspectable from "effect/Inspectable"
8
6
  import * as Option from "effect/Option"
7
+ import { pipeArguments } from "effect/Pipeable"
9
8
  import * as Redacted from "effect/Redacted"
10
9
  import type * as Stream from "effect/Stream"
11
10
  import type * as PlatformError from "../Error.js"
12
11
  import type * as FileSystem from "../FileSystem.js"
13
12
  import * as Headers from "../Headers.js"
14
13
  import type * as Body from "../HttpBody.js"
15
- import type { HttpClient } from "../HttpClient.js"
16
14
  import type * as ClientRequest from "../HttpClientRequest.js"
17
15
  import type { HttpMethod } from "../HttpMethod.js"
18
16
  import * as UrlParams from "../UrlParams.js"
@@ -21,16 +19,9 @@ import * as internalBody from "./httpBody.js"
21
19
  /** @internal */
22
20
  export const TypeId: ClientRequest.TypeId = Symbol.for("@effect/platform/HttpClientRequest") as ClientRequest.TypeId
23
21
 
24
- /** @internal */
25
- export const clientTag = Context.GenericTag<HttpClient.Service>("@effect/platform/HttpClient")
26
-
27
22
  const Proto = {
28
23
  [TypeId]: TypeId,
29
- ...Effectable.CommitPrototype,
30
24
  ...Inspectable.BaseProto,
31
- commit(this: ClientRequest.HttpClientRequest) {
32
- return Effect.flatMap(clientTag, (client) => client.execute(this))
33
- },
34
25
  toJSON(this: ClientRequest.HttpClientRequest): unknown {
35
26
  return {
36
27
  _id: "@effect/platform/HttpClientRequest",
@@ -41,6 +32,9 @@ const Proto = {
41
32
  headers: this.headers,
42
33
  body: this.body.toJSON()
43
34
  }
35
+ },
36
+ pipe() {
37
+ return pipeArguments(this, arguments)
44
38
  }
45
39
  }
46
40
 
@@ -0,0 +1,148 @@
1
+ import type { PlatformError } from "@effect/platform/Error"
2
+ import * as FileSystem from "@effect/platform/FileSystem"
3
+ import * as ConfigProvider from "effect/ConfigProvider"
4
+ import * as Context from "effect/Context"
5
+ import * as DefaultServices from "effect/DefaultServices"
6
+ import * as Effect from "effect/Effect"
7
+ import * as FiberRef from "effect/FiberRef"
8
+ import * as Layer from "effect/Layer"
9
+
10
+ /**
11
+ * dot env ConfigProvider
12
+ *
13
+ * Based on
14
+ * - https://github.com/motdotla/dotenv
15
+ * - https://github.com/motdotla/dotenv-expand
16
+ */
17
+
18
+ /** @internal */
19
+ export const fromDotEnv = (
20
+ path: string
21
+ ): Effect.Effect<ConfigProvider.ConfigProvider, PlatformError, FileSystem.FileSystem> =>
22
+ Effect.gen(function*(_) {
23
+ const fs = yield* FileSystem.FileSystem
24
+ const content = yield* fs.readFileString(path)
25
+ const obj = parseDotEnv(content)
26
+ return ConfigProvider.fromJson(obj)
27
+ })
28
+
29
+ /** @internal */
30
+ export const layerDotEnv = (path: string): Layer.Layer<never, PlatformError, FileSystem.FileSystem> =>
31
+ fromDotEnv(path).pipe(
32
+ Effect.map(Layer.setConfigProvider),
33
+ Layer.unwrapEffect
34
+ )
35
+
36
+ /** @internal */
37
+ export const layerDotEnvAdd = (path: string): Layer.Layer<never, never, FileSystem.FileSystem> =>
38
+ Effect.gen(function*(_) {
39
+ const dotEnvConfigProvider = yield* Effect.orElseSucceed(fromDotEnv(path), () => null)
40
+
41
+ if (dotEnvConfigProvider === null) {
42
+ yield* Effect.logDebug(`File '${path}' not found, skipping dotenv ConfigProvider.`)
43
+ return Layer.empty
44
+ }
45
+
46
+ const currentConfigProvider = yield* FiberRef.get(DefaultServices.currentServices).pipe(
47
+ Effect.map((services) => Context.get(services, ConfigProvider.ConfigProvider))
48
+ )
49
+ const configProvider = ConfigProvider.orElse(currentConfigProvider, () => dotEnvConfigProvider)
50
+ return Layer.setConfigProvider(configProvider)
51
+ }).pipe(Layer.unwrapEffect)
52
+
53
+ /** @internal */
54
+ const DOT_ENV_LINE =
55
+ /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
56
+
57
+ /** @internal */
58
+ const parseDotEnv = (lines: string): Record<string, string> => {
59
+ const obj: Record<string, string> = {}
60
+
61
+ // Convert line breaks to same format
62
+ lines = lines.replace(/\r\n?/gm, "\n")
63
+
64
+ let match: RegExpExecArray | null
65
+ while ((match = DOT_ENV_LINE.exec(lines)) != null) {
66
+ const key = match[1]
67
+
68
+ // Default undefined or null to empty string
69
+ let value = match[2] || ""
70
+
71
+ // Remove whitespace
72
+ value = value.trim()
73
+
74
+ // Check if double quoted
75
+ const maybeQuote = value[0]
76
+
77
+ // Remove surrounding quotes
78
+ value = value.replace(/^(['"`])([\s\S]*)\1$/gm, "$2")
79
+
80
+ // Expand newlines if double quoted
81
+ if (maybeQuote === "\"") {
82
+ value = value.replace(/\\n/g, "\n")
83
+ value = value.replace(/\\r/g, "\r")
84
+ }
85
+
86
+ // Add to object
87
+ obj[key] = value
88
+ }
89
+
90
+ return expand(obj)
91
+ }
92
+
93
+ /** @internal */
94
+ const expand = (parsed: Record<string, string>) => {
95
+ const newParsed: Record<string, string> = {}
96
+
97
+ for (const configKey in parsed) {
98
+ // resolve escape sequences
99
+ newParsed[configKey] = interpolate(parsed[configKey], parsed).replace(/\\\$/g, "$")
100
+ }
101
+
102
+ return newParsed
103
+ }
104
+
105
+ /** @internal */
106
+ const interpolate = (envValue: string, parsed: Record<string, string>) => {
107
+ // find the last unescaped dollar sign in the
108
+ // value so that we can evaluate it
109
+ const lastUnescapedDollarSignIndex = searchLast(envValue, /(?!(?<=\\))\$/g)
110
+
111
+ // If we couldn't match any unescaped dollar sign
112
+ // let's return the string as is
113
+ if (lastUnescapedDollarSignIndex === -1) return envValue
114
+
115
+ // This is the right-most group of variables in the string
116
+ const rightMostGroup = envValue.slice(lastUnescapedDollarSignIndex)
117
+
118
+ /**
119
+ * This finds the inner most variable/group divided
120
+ * by variable name and default value (if present)
121
+ * (
122
+ * (?!(?<=\\))\$ // only match dollar signs that are not escaped
123
+ * {? // optional opening curly brace
124
+ * ([\w]+) // match the variable name
125
+ * (?::-([^}\\]*))? // match an optional default value
126
+ * }? // optional closing curly brace
127
+ * )
128
+ */
129
+ const matchGroup = /((?!(?<=\\))\${?([\w]+)(?::-([^}\\]*))?}?)/
130
+ const match = rightMostGroup.match(matchGroup)
131
+
132
+ if (match !== null) {
133
+ const [_, group, variableName, defaultValue] = match
134
+
135
+ return interpolate(
136
+ envValue.replace(group, defaultValue || parsed[variableName] || ""),
137
+ parsed
138
+ )
139
+ }
140
+
141
+ return envValue
142
+ }
143
+
144
+ /** @internal */
145
+ const searchLast = (str: string, rgx: RegExp) => {
146
+ const matches = Array.from(str.matchAll(rgx))
147
+ return matches.length > 0 ? matches.slice(-1)[0].index : -1
148
+ }