@prover-coder-ai/openapi-effect 1.0.19
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/README.md +36 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -0
- package/package.json +58 -0
- package/src/app/main.ts +18 -0
- package/src/app/program.ts +33 -0
- package/src/core/api/openapi.d.ts +445 -0
- package/src/core/api-client/index.ts +32 -0
- package/src/core/api-client/strict-types.ts +349 -0
- package/src/core/axioms.ts +143 -0
- package/src/core/greeting.ts +22 -0
- package/src/generated/decoders.ts +318 -0
- package/src/generated/dispatch.ts +172 -0
- package/src/generated/dispatchers-by-path.ts +40 -0
- package/src/generated/index.ts +9 -0
- package/src/index.ts +42 -0
- package/src/shell/api-client/create-client-types.ts +310 -0
- package/src/shell/api-client/create-client.ts +517 -0
- package/src/shell/api-client/index.ts +37 -0
- package/src/shell/api-client/strict-client.ts +471 -0
- package/src/shell/cli.ts +22 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// CHANGE: Extract public createClient types into dedicated module
|
|
2
|
+
// WHY: Keep create-client.ts under lint max-lines without weakening type-level invariants
|
|
3
|
+
// QUOTE(ТЗ): "Только прогони по всему проекту линтеры"
|
|
4
|
+
// REF: user-msg-2
|
|
5
|
+
// SOURCE: n/a
|
|
6
|
+
// PURITY: CORE
|
|
7
|
+
// EFFECT: none
|
|
8
|
+
// INVARIANT: All type-level correlations remain unchanged
|
|
9
|
+
// COMPLEXITY: O(1) compile-time / O(0) runtime
|
|
10
|
+
|
|
11
|
+
import type * as HttpClient from "@effect/platform/HttpClient"
|
|
12
|
+
import type { Effect } from "effect"
|
|
13
|
+
import type { ClientOptions as OpenapiFetchClientOptions } from "openapi-fetch"
|
|
14
|
+
import type { HttpMethod } from "openapi-typescript-helpers"
|
|
15
|
+
|
|
16
|
+
import type {
|
|
17
|
+
ApiFailure,
|
|
18
|
+
ApiSuccess,
|
|
19
|
+
HttpError,
|
|
20
|
+
OperationFor,
|
|
21
|
+
PathsForMethod,
|
|
22
|
+
RequestOptionsFor,
|
|
23
|
+
ResponsesFor
|
|
24
|
+
} from "../../core/api-client/strict-types.js"
|
|
25
|
+
import type { Dispatcher } from "../../core/axioms.js"
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Client configuration options
|
|
29
|
+
*
|
|
30
|
+
* @pure - immutable configuration
|
|
31
|
+
*/
|
|
32
|
+
export type ClientOptions = OpenapiFetchClientOptions
|
|
33
|
+
|
|
34
|
+
// CHANGE: Add dispatcher map type for auto-dispatching clients
|
|
35
|
+
// WHY: Enable creating clients that infer dispatcher from path+method without per-call parameter
|
|
36
|
+
// QUOTE(ТЗ): "ApiClient и так знает текущие типы. Зачем передавать что либо в GET"
|
|
37
|
+
// REF: user-msg-1
|
|
38
|
+
// SOURCE: n/a
|
|
39
|
+
// FORMAT THEOREM: ∀ path, method: dispatchers[path][method] = Dispatcher<ResponsesFor<OperationFor<Paths, path, method>>>
|
|
40
|
+
// PURITY: CORE
|
|
41
|
+
// EFFECT: none
|
|
42
|
+
// INVARIANT: dispatcher map is total for all operations in Paths
|
|
43
|
+
// COMPLEXITY: O(1) compile-time / O(0) runtime
|
|
44
|
+
export type DispatchersForMethod<
|
|
45
|
+
Paths extends object,
|
|
46
|
+
Method extends HttpMethod
|
|
47
|
+
> = {
|
|
48
|
+
readonly [Path in PathsForMethod<Paths, Method>]: {
|
|
49
|
+
readonly [K in Method]: Dispatcher<ResponsesFor<OperationFor<Paths, Path, Method>>>
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type DispatchersFor<Paths extends object> =
|
|
54
|
+
& DispatchersForMethod<Paths, "get">
|
|
55
|
+
& DispatchersForMethod<Paths, "post">
|
|
56
|
+
& DispatchersForMethod<Paths, "put">
|
|
57
|
+
& DispatchersForMethod<Paths, "delete">
|
|
58
|
+
& DispatchersForMethod<Paths, "patch">
|
|
59
|
+
& DispatchersForMethod<Paths, "head">
|
|
60
|
+
& DispatchersForMethod<Paths, "options">
|
|
61
|
+
|
|
62
|
+
type ResponsesForOperation<
|
|
63
|
+
Paths extends object,
|
|
64
|
+
Path extends keyof Paths,
|
|
65
|
+
Method extends HttpMethod
|
|
66
|
+
> = ResponsesFor<OperationFor<Paths, Path, Method>>
|
|
67
|
+
|
|
68
|
+
type RequestEffect<
|
|
69
|
+
Paths extends object,
|
|
70
|
+
Path extends keyof Paths,
|
|
71
|
+
Method extends HttpMethod
|
|
72
|
+
> = Effect.Effect<
|
|
73
|
+
ApiSuccess<ResponsesForOperation<Paths, Path, Method>>,
|
|
74
|
+
ApiFailure<ResponsesForOperation<Paths, Path, Method>>,
|
|
75
|
+
HttpClient.HttpClient
|
|
76
|
+
>
|
|
77
|
+
|
|
78
|
+
type RequestEffectWithHttpErrorsInSuccess<
|
|
79
|
+
Paths extends object,
|
|
80
|
+
Path extends keyof Paths,
|
|
81
|
+
Method extends HttpMethod
|
|
82
|
+
> = Effect.Effect<
|
|
83
|
+
| ApiSuccess<ResponsesForOperation<Paths, Path, Method>>
|
|
84
|
+
| HttpError<ResponsesForOperation<Paths, Path, Method>>,
|
|
85
|
+
Exclude<
|
|
86
|
+
ApiFailure<ResponsesForOperation<Paths, Path, Method>>,
|
|
87
|
+
HttpError<ResponsesForOperation<Paths, Path, Method>>
|
|
88
|
+
>,
|
|
89
|
+
HttpClient.HttpClient
|
|
90
|
+
>
|
|
91
|
+
|
|
92
|
+
type DispatcherFor<
|
|
93
|
+
Paths extends object,
|
|
94
|
+
Path extends keyof Paths,
|
|
95
|
+
Method extends HttpMethod
|
|
96
|
+
> = Dispatcher<ResponsesForOperation<Paths, Path, Method>>
|
|
97
|
+
|
|
98
|
+
type RequestOptionsForOperation<
|
|
99
|
+
Paths extends object,
|
|
100
|
+
Path extends keyof Paths,
|
|
101
|
+
Method extends HttpMethod
|
|
102
|
+
> = RequestOptionsFor<OperationFor<Paths, Path, Method>>
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Type-safe API client with full request-side type enforcement
|
|
106
|
+
*
|
|
107
|
+
* **Key guarantees:**
|
|
108
|
+
* 1. GET only works on paths that have `get` method in schema
|
|
109
|
+
* 2. POST only works on paths that have `post` method in schema
|
|
110
|
+
* 3. Dispatcher type is derived from operation's responses
|
|
111
|
+
* 4. Request options (params/query/body) are derived from operation
|
|
112
|
+
*
|
|
113
|
+
* **Effect Channel Design:**
|
|
114
|
+
* - Success channel: `ApiSuccess<Responses>` - 2xx responses only
|
|
115
|
+
* - Error channel: `ApiFailure<Responses>` - HTTP errors (4xx, 5xx) + boundary errors
|
|
116
|
+
*
|
|
117
|
+
* @typeParam Paths - OpenAPI paths type from openapi-typescript
|
|
118
|
+
*
|
|
119
|
+
* @pure false - operations perform HTTP requests
|
|
120
|
+
* @invariant ∀ call: path ∈ PathsForMethod<Paths, method> ∧ options derived from operation
|
|
121
|
+
*/
|
|
122
|
+
export type StrictApiClient<Paths extends object> = {
|
|
123
|
+
/**
|
|
124
|
+
* Execute GET request
|
|
125
|
+
*
|
|
126
|
+
* @typeParam Path - Path that supports GET method (enforced at type level)
|
|
127
|
+
* @param path - API path with GET method
|
|
128
|
+
* @param dispatcher - Response dispatcher (must match operation responses)
|
|
129
|
+
* @param options - Request options (typed from operation)
|
|
130
|
+
* @returns Effect with 2xx in success channel, errors in error channel
|
|
131
|
+
*/
|
|
132
|
+
readonly GET: <Path extends PathsForMethod<Paths, "get">>(
|
|
133
|
+
path: Path,
|
|
134
|
+
dispatcher: DispatcherFor<Paths, Path, "get">,
|
|
135
|
+
options?: RequestOptionsForOperation<Paths, Path, "get">
|
|
136
|
+
) => RequestEffect<Paths, Path, "get">
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Execute POST request
|
|
140
|
+
*/
|
|
141
|
+
readonly POST: <Path extends PathsForMethod<Paths, "post">>(
|
|
142
|
+
path: Path,
|
|
143
|
+
dispatcher: DispatcherFor<Paths, Path, "post">,
|
|
144
|
+
options?: RequestOptionsForOperation<Paths, Path, "post">
|
|
145
|
+
) => RequestEffect<Paths, Path, "post">
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Execute PUT request
|
|
149
|
+
*/
|
|
150
|
+
readonly PUT: <Path extends PathsForMethod<Paths, "put">>(
|
|
151
|
+
path: Path,
|
|
152
|
+
dispatcher: DispatcherFor<Paths, Path, "put">,
|
|
153
|
+
options?: RequestOptionsForOperation<Paths, Path, "put">
|
|
154
|
+
) => RequestEffect<Paths, Path, "put">
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Execute DELETE request
|
|
158
|
+
*/
|
|
159
|
+
readonly DELETE: <Path extends PathsForMethod<Paths, "delete">>(
|
|
160
|
+
path: Path,
|
|
161
|
+
dispatcher: DispatcherFor<Paths, Path, "delete">,
|
|
162
|
+
options?: RequestOptionsForOperation<Paths, Path, "delete">
|
|
163
|
+
) => RequestEffect<Paths, Path, "delete">
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Execute PATCH request
|
|
167
|
+
*/
|
|
168
|
+
readonly PATCH: <Path extends PathsForMethod<Paths, "patch">>(
|
|
169
|
+
path: Path,
|
|
170
|
+
dispatcher: DispatcherFor<Paths, Path, "patch">,
|
|
171
|
+
options?: RequestOptionsForOperation<Paths, Path, "patch">
|
|
172
|
+
) => RequestEffect<Paths, Path, "patch">
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Execute HEAD request
|
|
176
|
+
*/
|
|
177
|
+
readonly HEAD: <Path extends PathsForMethod<Paths, "head">>(
|
|
178
|
+
path: Path,
|
|
179
|
+
dispatcher: DispatcherFor<Paths, Path, "head">,
|
|
180
|
+
options?: RequestOptionsForOperation<Paths, Path, "head">
|
|
181
|
+
) => RequestEffect<Paths, Path, "head">
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Execute OPTIONS request
|
|
185
|
+
*/
|
|
186
|
+
readonly OPTIONS: <Path extends PathsForMethod<Paths, "options">>(
|
|
187
|
+
path: Path,
|
|
188
|
+
dispatcher: DispatcherFor<Paths, Path, "options">,
|
|
189
|
+
options?: RequestOptionsForOperation<Paths, Path, "options">
|
|
190
|
+
) => RequestEffect<Paths, Path, "options">
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Type-safe API client with auto-dispatching (dispatcher is derived from path+method)
|
|
195
|
+
*
|
|
196
|
+
* **Key guarantees:**
|
|
197
|
+
* 1. GET only works on paths that have `get` method in schema
|
|
198
|
+
* 2. Dispatcher is looked up from provided dispatcher map by path+method
|
|
199
|
+
* 3. Request options (params/query/body) are derived from operation
|
|
200
|
+
*
|
|
201
|
+
* **Effect Channel Design:**
|
|
202
|
+
* - Success channel: `ApiSuccess<Responses>` - 2xx responses only
|
|
203
|
+
* - Error channel: `ApiFailure<Responses>` - HTTP errors (4xx, 5xx) + boundary errors
|
|
204
|
+
*
|
|
205
|
+
* @typeParam Paths - OpenAPI paths type from openapi-typescript
|
|
206
|
+
*
|
|
207
|
+
* @pure false - operations perform HTTP requests
|
|
208
|
+
* @invariant ∀ call: path ∈ PathsForMethod<Paths, method> ∧ dispatcherMap[path][method] defined
|
|
209
|
+
*/
|
|
210
|
+
export type StrictApiClientWithDispatchers<Paths extends object> = {
|
|
211
|
+
/**
|
|
212
|
+
* Execute GET request (dispatcher is inferred)
|
|
213
|
+
*/
|
|
214
|
+
readonly GET: <Path extends PathsForMethod<Paths, "get">>(
|
|
215
|
+
path: Path,
|
|
216
|
+
options?: RequestOptionsForOperation<Paths, Path, "get">
|
|
217
|
+
) => RequestEffect<Paths, Path, "get">
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Execute POST request (dispatcher is inferred)
|
|
221
|
+
*/
|
|
222
|
+
readonly POST: <Path extends PathsForMethod<Paths, "post">>(
|
|
223
|
+
path: Path,
|
|
224
|
+
options?: RequestOptionsForOperation<Paths, Path, "post">
|
|
225
|
+
) => RequestEffect<Paths, Path, "post">
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Execute PUT request (dispatcher is inferred)
|
|
229
|
+
*/
|
|
230
|
+
readonly PUT: <Path extends PathsForMethod<Paths, "put">>(
|
|
231
|
+
path: Path,
|
|
232
|
+
options?: RequestOptionsForOperation<Paths, Path, "put">
|
|
233
|
+
) => RequestEffect<Paths, Path, "put">
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Execute DELETE request (dispatcher is inferred)
|
|
237
|
+
*/
|
|
238
|
+
readonly DELETE: <Path extends PathsForMethod<Paths, "delete">>(
|
|
239
|
+
path: Path,
|
|
240
|
+
options?: RequestOptionsForOperation<Paths, Path, "delete">
|
|
241
|
+
) => RequestEffect<Paths, Path, "delete">
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Execute PATCH request (dispatcher is inferred)
|
|
245
|
+
*/
|
|
246
|
+
readonly PATCH: <Path extends PathsForMethod<Paths, "patch">>(
|
|
247
|
+
path: Path,
|
|
248
|
+
options?: RequestOptionsForOperation<Paths, Path, "patch">
|
|
249
|
+
) => RequestEffect<Paths, Path, "patch">
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Execute HEAD request (dispatcher is inferred)
|
|
253
|
+
*/
|
|
254
|
+
readonly HEAD: <Path extends PathsForMethod<Paths, "head">>(
|
|
255
|
+
path: Path,
|
|
256
|
+
options?: RequestOptionsForOperation<Paths, Path, "head">
|
|
257
|
+
) => RequestEffect<Paths, Path, "head">
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Execute OPTIONS request (dispatcher is inferred)
|
|
261
|
+
*/
|
|
262
|
+
readonly OPTIONS: <Path extends PathsForMethod<Paths, "options">>(
|
|
263
|
+
path: Path,
|
|
264
|
+
options?: RequestOptionsForOperation<Paths, Path, "options">
|
|
265
|
+
) => RequestEffect<Paths, Path, "options">
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Ergonomic API client where HTTP statuses (2xx + 4xx/5xx from schema)
|
|
270
|
+
* are returned in the success value channel.
|
|
271
|
+
*
|
|
272
|
+
* Boundary/protocol errors remain in the error channel.
|
|
273
|
+
* This removes the need for `Effect.either` when handling normal HTTP statuses.
|
|
274
|
+
*/
|
|
275
|
+
export type ClientEffect<Paths extends object> = {
|
|
276
|
+
readonly GET: <Path extends PathsForMethod<Paths, "get">>(
|
|
277
|
+
path: Path,
|
|
278
|
+
options?: RequestOptionsForOperation<Paths, Path, "get">
|
|
279
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "get">
|
|
280
|
+
|
|
281
|
+
readonly POST: <Path extends PathsForMethod<Paths, "post">>(
|
|
282
|
+
path: Path,
|
|
283
|
+
options?: RequestOptionsForOperation<Paths, Path, "post">
|
|
284
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "post">
|
|
285
|
+
|
|
286
|
+
readonly PUT: <Path extends PathsForMethod<Paths, "put">>(
|
|
287
|
+
path: Path,
|
|
288
|
+
options?: RequestOptionsForOperation<Paths, Path, "put">
|
|
289
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "put">
|
|
290
|
+
|
|
291
|
+
readonly DELETE: <Path extends PathsForMethod<Paths, "delete">>(
|
|
292
|
+
path: Path,
|
|
293
|
+
options?: RequestOptionsForOperation<Paths, Path, "delete">
|
|
294
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "delete">
|
|
295
|
+
|
|
296
|
+
readonly PATCH: <Path extends PathsForMethod<Paths, "patch">>(
|
|
297
|
+
path: Path,
|
|
298
|
+
options?: RequestOptionsForOperation<Paths, Path, "patch">
|
|
299
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "patch">
|
|
300
|
+
|
|
301
|
+
readonly HEAD: <Path extends PathsForMethod<Paths, "head">>(
|
|
302
|
+
path: Path,
|
|
303
|
+
options?: RequestOptionsForOperation<Paths, Path, "head">
|
|
304
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "head">
|
|
305
|
+
|
|
306
|
+
readonly OPTIONS: <Path extends PathsForMethod<Paths, "options">>(
|
|
307
|
+
path: Path,
|
|
308
|
+
options?: RequestOptionsForOperation<Paths, Path, "options">
|
|
309
|
+
) => RequestEffectWithHttpErrorsInSuccess<Paths, Path, "options">
|
|
310
|
+
}
|