@effect-app/vue 4.0.0-beta.18 → 4.0.0-beta.180

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 (100) hide show
  1. package/CHANGELOG.md +1224 -0
  2. package/dist/commander.d.ts +370 -0
  3. package/dist/commander.d.ts.map +1 -0
  4. package/dist/commander.js +591 -0
  5. package/dist/confirm.d.ts +19 -0
  6. package/dist/confirm.d.ts.map +1 -0
  7. package/dist/confirm.js +24 -0
  8. package/dist/errorReporter.d.ts +4 -4
  9. package/dist/errorReporter.d.ts.map +1 -1
  10. package/dist/errorReporter.js +12 -18
  11. package/dist/form.d.ts +13 -4
  12. package/dist/form.d.ts.map +1 -1
  13. package/dist/form.js +41 -12
  14. package/dist/index.d.ts +1 -1
  15. package/dist/intl.d.ts +15 -0
  16. package/dist/intl.d.ts.map +1 -0
  17. package/dist/intl.js +9 -0
  18. package/dist/lib.d.ts +6 -8
  19. package/dist/lib.d.ts.map +1 -1
  20. package/dist/lib.js +34 -7
  21. package/dist/makeClient.d.ts +148 -290
  22. package/dist/makeClient.d.ts.map +1 -1
  23. package/dist/makeClient.js +205 -361
  24. package/dist/makeContext.d.ts +1 -1
  25. package/dist/makeContext.d.ts.map +1 -1
  26. package/dist/makeIntl.d.ts +1 -1
  27. package/dist/makeIntl.d.ts.map +1 -1
  28. package/dist/makeUseCommand.d.ts +8 -0
  29. package/dist/makeUseCommand.d.ts.map +1 -0
  30. package/dist/makeUseCommand.js +13 -0
  31. package/dist/mutate.d.ts +57 -25
  32. package/dist/mutate.d.ts.map +1 -1
  33. package/dist/mutate.js +160 -33
  34. package/dist/query.d.ts +11 -15
  35. package/dist/query.d.ts.map +1 -1
  36. package/dist/query.js +19 -27
  37. package/dist/routeParams.d.ts +1 -1
  38. package/dist/runtime.d.ts +5 -2
  39. package/dist/runtime.d.ts.map +1 -1
  40. package/dist/runtime.js +27 -17
  41. package/dist/toast.d.ts +46 -0
  42. package/dist/toast.d.ts.map +1 -0
  43. package/dist/toast.js +32 -0
  44. package/dist/withToast.d.ts +26 -0
  45. package/dist/withToast.d.ts.map +1 -0
  46. package/dist/withToast.js +49 -0
  47. package/eslint.config.mjs +2 -2
  48. package/examples/streamMutation.ts +83 -0
  49. package/package.json +48 -48
  50. package/src/{experimental/commander.ts → commander.ts} +930 -255
  51. package/src/{experimental/confirm.ts → confirm.ts} +10 -14
  52. package/src/errorReporter.ts +62 -74
  53. package/src/form.ts +55 -16
  54. package/src/intl.ts +12 -0
  55. package/src/lib.ts +46 -13
  56. package/src/makeClient.ts +570 -1038
  57. package/src/{experimental/makeUseCommand.ts → makeUseCommand.ts} +3 -3
  58. package/src/mutate.ts +306 -72
  59. package/src/query.ts +39 -50
  60. package/src/runtime.ts +39 -18
  61. package/src/{experimental/toast.ts → toast.ts} +11 -25
  62. package/src/{experimental/withToast.ts → withToast.ts} +15 -6
  63. package/test/Mutation.test.ts +130 -10
  64. package/test/dist/form.test.d.ts.map +1 -1
  65. package/test/dist/lib.test.d.ts.map +1 -0
  66. package/test/dist/streamFinal.test.d.ts.map +1 -0
  67. package/test/dist/stubs.d.ts +3144 -117
  68. package/test/dist/stubs.d.ts.map +1 -1
  69. package/test/dist/stubs.js +132 -25
  70. package/test/form-validation-errors.test.ts +23 -19
  71. package/test/form.test.ts +20 -2
  72. package/test/lib.test.ts +240 -0
  73. package/test/makeClient.test.ts +241 -38
  74. package/test/streamFinal.test.ts +110 -0
  75. package/test/stubs.ts +172 -42
  76. package/tsconfig.examples.json +20 -0
  77. package/tsconfig.json +0 -1
  78. package/tsconfig.json.bak +5 -2
  79. package/tsconfig.src.json +34 -34
  80. package/tsconfig.test.json +2 -2
  81. package/vitest.config.ts +5 -5
  82. package/dist/experimental/commander.d.ts +0 -359
  83. package/dist/experimental/commander.d.ts.map +0 -1
  84. package/dist/experimental/commander.js +0 -557
  85. package/dist/experimental/confirm.d.ts +0 -19
  86. package/dist/experimental/confirm.d.ts.map +0 -1
  87. package/dist/experimental/confirm.js +0 -28
  88. package/dist/experimental/intl.d.ts +0 -16
  89. package/dist/experimental/intl.d.ts.map +0 -1
  90. package/dist/experimental/intl.js +0 -5
  91. package/dist/experimental/makeUseCommand.d.ts +0 -8
  92. package/dist/experimental/makeUseCommand.d.ts.map +0 -1
  93. package/dist/experimental/makeUseCommand.js +0 -13
  94. package/dist/experimental/toast.d.ts +0 -47
  95. package/dist/experimental/toast.d.ts.map +0 -1
  96. package/dist/experimental/toast.js +0 -41
  97. package/dist/experimental/withToast.d.ts +0 -25
  98. package/dist/experimental/withToast.d.ts.map +0 -1
  99. package/dist/experimental/withToast.js +0 -45
  100. package/src/experimental/intl.ts +0 -9
package/test/stubs.ts CHANGED
@@ -1,18 +1,20 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { type MessageFormatElement } from "@formatjs/icu-messageformat-parser"
3
3
  import * as Intl from "@formatjs/intl"
4
+ import { QueryClient, VueQueryPlugin } from "@tanstack/vue-query"
4
5
  import { Effect, Layer, ManagedRuntime, Option, S } from "effect-app"
5
6
  import { ApiClientFactory, makeRpcClient } from "effect-app/client"
6
7
  import { RpcContextMap } from "effect-app/rpc"
8
+ import * as Exit from "effect/Exit"
7
9
  import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient"
8
- import { ref } from "vue"
9
- import { Commander } from "../src/experimental/commander.js"
10
- import { I18n } from "../src/experimental/intl.js"
11
- import { makeUseCommand } from "../src/experimental/makeUseCommand.js"
12
- import * as Toast from "../src/experimental/toast.js"
13
- import { WithToast } from "../src/experimental/withToast.js"
14
- import { LegacyMutation, makeClient } from "../src/makeClient.js"
10
+ import { createApp, ref } from "vue"
11
+ import { Commander } from "../src/commander.js"
12
+ import { I18n } from "../src/intl.js"
13
+ import { makeClient } from "../src/makeClient.js"
15
14
  import { type MakeIntlReturn } from "../src/makeIntl.js"
15
+ import { makeUseCommand } from "../src/makeUseCommand.js"
16
+ import * as Toast from "../src/toast.js"
17
+ import { WithToast } from "../src/withToast.js"
16
18
 
17
19
  const fakeToastLayer = (toasts: any[] = []) =>
18
20
  Layer.effect(
@@ -26,33 +28,34 @@ const fakeToastLayer = (toasts: any[] = []) =>
26
28
  toasts.splice(idx, 1)
27
29
  }
28
30
  }
29
- const fakeToast = (message: string, options?: Toast.ToastOpts) => {
30
- const id = options?.id ?? Math.random().toString(36).substring(2, 15)
31
- console.log(`Toast [${id}]: ${message}`, options)
31
+ const fakeToast =
32
+ (type: "error" | "warning" | "success" | "info") => (message: string, options?: Toast.ToastOpts) => {
33
+ const id = options?.id ?? Math.random().toString(36).substring(2, 15)
34
+ console.log(`Toast [${type}][${id}]: ${message}`, options)
32
35
 
33
- options = { ...options, id }
34
- const idx = toasts.findIndex((_) => _.id === id)
35
- if (idx > -1) {
36
- const toast = toasts[idx]
37
- clearTimeout(toast.timeoutId)
38
- Object.assign(toast, { message, options })
39
- toast.timeoutId = setTimeout(() => {
40
- toasts.splice(idx, 1)
41
- }, options?.timeout ?? 3000)
42
- } else {
43
- const toast: any = { id, message, options }
44
- toast.timeoutId = setTimeout(() => {
45
- toasts.splice(idx, 1)
46
- }, options?.timeout ?? 3000)
47
- toasts.push(toast)
36
+ options = { ...options, id }
37
+ const idx = toasts.findIndex((_) => _.id === id)
38
+ if (idx > -1) {
39
+ const toast = toasts[idx]
40
+ clearTimeout(toast.timeoutId)
41
+ Object.assign(toast, { type, message, options })
42
+ toast.timeoutId = setTimeout(() => {
43
+ toasts.splice(idx, 1)
44
+ }, options?.timeout ?? 3000)
45
+ } else {
46
+ const toast: any = { id, type, message, options }
47
+ toast.timeoutId = setTimeout(() => {
48
+ toasts.splice(idx, 1)
49
+ }, options?.timeout ?? 3000)
50
+ toasts.push(toast)
51
+ }
52
+ return id
48
53
  }
49
- return id
50
- }
51
54
  return Toast.Toast.of(Toast.wrap({
52
- error: fakeToast,
53
- warning: fakeToast,
54
- success: fakeToast,
55
- info: fakeToast,
55
+ error: fakeToast("error"),
56
+ warning: fakeToast("warning"),
57
+ success: fakeToast("success"),
58
+ info: fakeToast("info"),
56
59
  dismiss
57
60
  })) as any
58
61
  })
@@ -92,20 +95,125 @@ export const useExperimental = (
92
95
  }
93
96
 
94
97
  export class RequestContextMap extends RpcContextMap.makeMap({}) {}
95
- export const { TaggedRequest: Req } = makeRpcClient(RequestContextMap)
96
- export class GetSomething2 extends Req<GetSomething2>()("GetSomething2", {
98
+ export const { TaggedRequestFor } = makeRpcClient(RequestContextMap)
99
+
100
+ export const SomethingReq = TaggedRequestFor("Something")
101
+ const SomethingQuery = SomethingReq.Query
102
+ const SomethingCommand = SomethingReq.Command
103
+ const SomethingStream = SomethingReq.Stream
104
+
105
+ class SomethingGetSomething2 extends SomethingQuery<SomethingGetSomething2>()("GetSomething2", {
97
106
  id: S.String
98
- }, { success: S.NumberFromString }) {}
107
+ }, { success: S.FiniteFromString }) {}
108
+
109
+ class SomethingGetSomething3 extends SomethingQuery<SomethingGetSomething3>()("GetSomething3", {
110
+ id: S.NullOr(S.String).withDefault
111
+ }, { success: S.FiniteFromString }) {}
112
+
113
+ class SomethingGetSomething4
114
+ extends SomethingQuery<SomethingGetSomething4>()("GetSomething4", {}, { success: S.FiniteFromString })
115
+ {}
116
+
117
+ class SomethingGetSomething2WithDependencies
118
+ extends SomethingQuery<SomethingGetSomething2WithDependencies>()("GetSomething2", {
119
+ id: S.String
120
+ }, {
121
+ // this is intentilally fake, to simulate a codec that requires a dependency
122
+ success: S.FiniteFromString as S.Codec<number, string, "dep-a">,
123
+ error: S.String
124
+ })
125
+ {}
99
126
 
100
- export class GetSomething2WithDependencies extends Req<GetSomething2WithDependencies>()("GetSomething2", {
127
+ type SomethingInvalidationResources = {
128
+ GetSomething2: typeof SomethingGetSomething2
129
+ GetSomething2WithDependencies: typeof SomethingGetSomething2WithDependencies
130
+ GetSomething3: typeof SomethingGetSomething3
131
+ }
132
+
133
+ class SomethingDoSomething extends SomethingCommand<
134
+ SomethingDoSomething,
135
+ { Something: SomethingInvalidationResources }
136
+ >()("DoSomething", {
101
137
  id: S.String
102
138
  }, {
103
- // this is intentilally fake, to simulate a codec that requires a dependency
104
- success: S.NumberFromString as S.Codec<number, string, "dep-a">,
105
- error: S.String
139
+ success: S.FiniteFromString
140
+ }, (queryKey, { Something }, input, output) => {
141
+ return [
142
+ { filters: { queryKey } },
143
+ {
144
+ filters: {
145
+ queryKey: [
146
+ Something["GetSomething2"].id,
147
+ input.id,
148
+ Exit.isSuccess(output) ? output.value.toString() : "failed"
149
+ ]
150
+ }
151
+ }
152
+ ]
153
+ }) {}
154
+
155
+ // success schema has encoded shape { a: string | null } — used to test projection constraints
156
+ class SomethingGetStructNullable extends SomethingQuery<SomethingGetStructNullable>()("GetStructNullable", {}, {
157
+ success: S.Struct({ a: S.NullOr(S.String) })
106
158
  }) {}
107
159
 
108
- export const Something = { GetSomething2, GetSomething2WithDependencies, meta: { moduleName: "Something" as const } }
160
+ /** Stream event: intermediate progress update. */
161
+ export class OperationProgress extends S.TaggedClass<OperationProgress>()("OperationProgress", {
162
+ completed: S.NonNegativeInt,
163
+ total: S.NonNegativeInt
164
+ }) {}
165
+
166
+ /** Stream event: final completion result. */
167
+ export class ExportComplete extends S.TaggedClass<ExportComplete>()("ExportComplete", {
168
+ fileUrl: S.NonEmptyString
169
+ }) {}
170
+
171
+ /** Stream with no `final` schema — execute resolves with `void`. */
172
+ class SomethingStreamWithoutFinal extends SomethingStream<SomethingStreamWithoutFinal>()("StreamWithoutFinal", {
173
+ id: S.String
174
+ }, {
175
+ success: S.Union([OperationProgress, ExportComplete])
176
+ }) {}
177
+
178
+ /** Stream with a `final` schema — execute resolves with `ExportComplete`. */
179
+ class SomethingStreamWithFinal extends SomethingStream<SomethingStreamWithFinal>()("StreamWithFinal", {
180
+ id: S.String
181
+ }, {
182
+ success: S.Union([OperationProgress, ExportComplete]),
183
+ final: ExportComplete
184
+ }) {}
185
+
186
+ export const Something = {
187
+ GetSomething2: SomethingGetSomething2,
188
+ GetSomething2WithDependencies: SomethingGetSomething2WithDependencies,
189
+ GetSomething3: SomethingGetSomething3,
190
+ GetSomething4: SomethingGetSomething4,
191
+ DoSomething: SomethingDoSomething,
192
+ GetStructNullable: SomethingGetStructNullable,
193
+ StreamWithoutFinal: SomethingStreamWithoutFinal,
194
+ StreamWithFinal: SomethingStreamWithFinal
195
+ }
196
+
197
+ export const SomethingElseReq = TaggedRequestFor("SomethingElse")
198
+ const SomethingElseQuery = SomethingElseReq.Query
199
+
200
+ class SomethingElseGetSomething2 extends SomethingElseQuery<SomethingElseGetSomething2>()("GetSomething2", {
201
+ id: S.String
202
+ }, { success: S.FiniteFromString }) {}
203
+
204
+ class SomethingElseGetSomething2WithDependencies
205
+ extends SomethingElseQuery<SomethingElseGetSomething2WithDependencies>()("GetSomething2", {
206
+ id: S.String
207
+ }, {
208
+ success: S.FiniteFromString as S.Codec<number, string, "dep-a">,
209
+ error: S.String
210
+ })
211
+ {}
212
+
213
+ export const SomethingElse = {
214
+ GetSomething2: SomethingElseGetSomething2,
215
+ GetSomething2WithDependencies: SomethingElseGetSomething2WithDependencies
216
+ }
109
217
 
110
218
  export const useClient = (
111
219
  options?: { messages?: Record<string, string> | Record<string, MessageFormatElement[]>; toasts: any[] }
@@ -117,9 +225,31 @@ export const useClient = (
117
225
  const api = ApiClientFactory.layer({ url: "bogus", headers: Option.none() }).pipe(
118
226
  Layer.provide(FetchHttpClient.layer)
119
227
  )
120
- const lm = LegacyMutation.Default.pipe(Layer.provide([FakeIntlLayer, FakeToastLayer]))
121
- const layers = Layer.mergeAll(CommanderLayer, WithToastLayer, FakeToastLayer, FakeIntlLayer, api, lm)
228
+ const layers = Layer.mergeAll(CommanderLayer, WithToastLayer, FakeToastLayer, FakeIntlLayer, api)
122
229
 
123
230
  const clientFor_ = ApiClientFactory.makeFor(Layer.empty)
124
- return makeClient(() => ManagedRuntime.make(layers), clientFor_, Layer.empty)
231
+ const rawClient = makeClient(() => ManagedRuntime.make(layers), clientFor_, Layer.empty)
232
+
233
+ // Provide a Vue injection context so that composition-API hooks (e.g. useQueryClient)
234
+ // called during client initialisation work outside a component setup() function.
235
+ const vueApp = createApp({})
236
+ const testQueryClientConfig = { defaultOptions: { queries: { retry: false }, mutations: { retry: false } } }
237
+ vueApp.use(VueQueryPlugin, { queryClient: new QueryClient(testQueryClientConfig) })
238
+
239
+ const origClientFor = rawClient.clientFor
240
+ const clientFor: typeof origClientFor = function(m, ...args) {
241
+ const proxy = origClientFor(m, ...args)
242
+ // Warm up lazy mutation-hook initialisation inside the Vue injection context.
243
+ // After the first property access, useMutation() is cached and subsequent
244
+ // accesses outside the context succeed.
245
+ const firstPropertyName = Object.keys(m)[0]
246
+ if (firstPropertyName !== undefined) {
247
+ vueApp.runWithContext(() => {
248
+ void (proxy as Record<string, unknown>)[firstPropertyName]
249
+ })
250
+ }
251
+ return proxy
252
+ }
253
+
254
+ return { ...rawClient, clientFor }
125
255
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "include": [
4
+ "examples"
5
+ ],
6
+ "references": [
7
+ {
8
+ "path": "./tsconfig.src.json"
9
+ }
10
+ ],
11
+ "compilerOptions": {
12
+ "lib": [
13
+ "esnext",
14
+ "DOM"
15
+ ],
16
+ "tsBuildInfoFile": ".tsbuildinfo/examples.tsbuildinfo",
17
+ "rootDir": "examples",
18
+ "moduleResolution": "Node16"
19
+ }
20
+ }
package/tsconfig.json CHANGED
@@ -32,7 +32,6 @@
32
32
  "outDir": "build/dist",
33
33
  "resolveJsonModule": true,
34
34
  "moduleResolution": "Node16",
35
- "downlevelIteration": true,
36
35
  "noErrorTruncation": true,
37
36
  "forceConsistentCasingInFileNames": true,
38
37
  "types": [
package/tsconfig.json.bak CHANGED
@@ -7,6 +7,9 @@
7
7
  },
8
8
  {
9
9
  "path": "./tsconfig.test.json"
10
+ },
11
+ {
12
+ "path": "./tsconfig.examples.json"
10
13
  }
11
- ],
12
- }
14
+ ]
15
+ }
package/tsconfig.src.json CHANGED
@@ -1,36 +1,36 @@
1
1
  {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "lib": [
5
- "esnext",
6
- "DOM"
7
- ],
8
- "tsBuildInfoFile": "./dist/.tsbuildinfo",
9
- "esModuleInterop": true,
10
- "rootDir": "./src",
11
- // keep in here, cause madge can't detect it from extended tsconfig
12
- "moduleResolution": "Node16",
13
- "outDir": "./dist"
14
- },
15
- "include": [
16
- "./src/**/*.ts"
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": [
5
+ "esnext",
6
+ "DOM"
17
7
  ],
18
- "exclude": [
19
- "./dist",
20
- "*.test.ts",
21
- "node_modules",
22
- "build",
23
- "lib",
24
- "dist",
25
- "**/*.d.ts.map",
26
- ".git",
27
- ".data",
28
- "**/.*",
29
- "**/*.tmp"
30
- ],
31
- "references": [
32
- {
33
- "path": "../effect-app"
34
- }
35
- ]
36
- }
8
+ "tsBuildInfoFile": "./dist/.tsbuildinfo",
9
+ "esModuleInterop": true,
10
+ "rootDir": "./src",
11
+ // keep in here, cause madge can't detect it from extended tsconfig
12
+ "moduleResolution": "Node16",
13
+ "outDir": "./dist"
14
+ },
15
+ "include": [
16
+ "./src/**/*.ts"
17
+ ],
18
+ "exclude": [
19
+ "./dist",
20
+ "*.test.ts",
21
+ "node_modules",
22
+ "build",
23
+ "lib",
24
+ "dist",
25
+ "**/*.d.ts.map",
26
+ ".git",
27
+ ".data",
28
+ "**/.*",
29
+ "**/*.tmp"
30
+ ],
31
+ "references": [
32
+ {
33
+ "path": "../effect-app"
34
+ }
35
+ ]
36
+ }
@@ -28,6 +28,6 @@
28
28
  "references": [
29
29
  {
30
30
  "path": "./tsconfig.src.json"
31
- },
31
+ }
32
32
  ]
33
- }
33
+ }
package/vitest.config.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  /// <reference types="vitest" />
2
+ import vue from "@vitejs/plugin-vue"
2
3
  import { defineConfig } from "vitest/config"
3
- import vue from '@vitejs/plugin-vue'
4
4
  import makeConfig from "../../vite.config.base"
5
5
 
6
6
  export default defineConfig({
7
7
  ...makeConfig(__dirname),
8
8
  plugins: [vue()],
9
9
  test: {
10
- environment: 'jsdom',
11
- include: ['src/**/*.test.{ts,tsx}', '**/test/**/*.test.{ts,tsx}', '**/__tests__/**/*.test.{ts,tsx}'],
12
- exclude: ['node_modules/**', 'dist/**'],
10
+ environment: "jsdom",
11
+ include: ["src/**/*.test.{ts,tsx}", "**/test/**/*.test.{ts,tsx}", "**/__tests__/**/*.test.{ts,tsx}"],
12
+ exclude: ["node_modules/**", "dist/**"],
13
13
  globals: true
14
14
  },
15
15
  optimizeDeps: {
16
- exclude: ['**/__tests__/**', '**/test/**', '**/*.test.*']
16
+ exclude: ["**/__tests__/**", "**/test/**", "**/*.test.*"]
17
17
  }
18
18
  })