@zerotal/client 1.6.3 → 1.7.0
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/api-surface.md +367 -0
- package/package.json +3 -2
package/api-surface.md
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# @zerotal/client — public API surface
|
|
2
|
+
|
|
3
|
+
<!-- AUTO-GENERATED by scripts/api-surface.ts. Do not edit by hand.
|
|
4
|
+
Run `bun run api:surface` to regenerate after an intentional API change. -->
|
|
5
|
+
|
|
6
|
+
## . `(./src/index.ts)`
|
|
7
|
+
|
|
8
|
+
class ApiClient = {
|
|
9
|
+
new <Routes extends ApiRouteMap>(config?: ApiClientConfig): ApiClient<Routes>
|
|
10
|
+
delete: <Path extends PathsFor<Routes, 'DELETE'>>(path: Path, params?: ParamRecord<Path & string>, options?: RequestOptions) => Promise<ResponseOf<Routes, 'DELETE', Path & string>>
|
|
11
|
+
get: <Path extends PathsFor<Routes, 'GET'>>(path: Path, params?: ParamRecord<Path & string>, options?: GetOptions<QueryOf<Routes, 'GET', Path & string>>) => Promise<ResponseOf<Routes, 'GET', Path & string>>
|
|
12
|
+
patch: <Path extends PathsFor<Routes, 'PATCH'>>(path: Path, body?: BodyOf<Routes, 'PATCH', Path & string>, options?: MutationOptions<QueryOf<Routes, 'PATCH', Path & string>>) => Promise<ResponseOf<Routes, 'PATCH', Path & string>>
|
|
13
|
+
post: <Path extends PathsFor<Routes, 'POST'>>(path: Path, body?: BodyOf<Routes, 'POST', Path & string>, options?: MutationOptions<QueryOf<Routes, 'POST', Path & string>>) => Promise<ResponseOf<Routes, 'POST', Path & string>>
|
|
14
|
+
put: <Path extends PathsFor<Routes, 'PUT'>>(path: Path, body?: BodyOf<Routes, 'PUT', Path & string>, options?: MutationOptions<QueryOf<Routes, 'PUT', Path & string>>) => Promise<ResponseOf<Routes, 'PUT', Path & string>>
|
|
15
|
+
setToken: (token: TokenSource | null) => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class ApiClientError = {
|
|
19
|
+
new (status: number, statusText: string, body: string, headers?: Headers): ApiClientError
|
|
20
|
+
readonly body: string
|
|
21
|
+
readonly code: string
|
|
22
|
+
readonly context?: Record<string, unknown> | undefined
|
|
23
|
+
readonly headers: Headers | undefined
|
|
24
|
+
readonly status: number
|
|
25
|
+
readonly statusText: string
|
|
26
|
+
retryAfterMs: number | null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class Channel = {
|
|
30
|
+
new (name: string, _socket: Socket): Channel
|
|
31
|
+
_dispatch: (frame: ServerFrame) => void
|
|
32
|
+
error: (cb: Listener) => Channel
|
|
33
|
+
listen: (event: string, cb: Listener) => Channel
|
|
34
|
+
readonly name: string
|
|
35
|
+
stopListening: (event: string, cb?: Listener) => Channel
|
|
36
|
+
subscribed: (cb: Listener) => Channel
|
|
37
|
+
unsubscribe: () => void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class CircuitBreaker = {
|
|
41
|
+
new (options?: CircuitBreakerOptions): CircuitBreaker
|
|
42
|
+
call: <T>(fn: () => Promise<T>) => Promise<T>
|
|
43
|
+
failures: number
|
|
44
|
+
reset: () => void
|
|
45
|
+
state: CircuitState
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class CircuitBreakerOpenError = {
|
|
49
|
+
new (): CircuitBreakerOpenError
|
|
50
|
+
readonly code: string
|
|
51
|
+
readonly context?: Record<string, unknown> | undefined
|
|
52
|
+
readonly status: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class ClientProvider = {
|
|
56
|
+
new (app: Application): ClientProvider
|
|
57
|
+
static dependsOn?: (new (app: Application) => ServiceProvider)[]
|
|
58
|
+
static environments: AppEnvironment[]
|
|
59
|
+
static priority?: number
|
|
60
|
+
static provides: readonly ['client']
|
|
61
|
+
devProcesses: () => DevProcessDefinition[]
|
|
62
|
+
doctorChecks: () => DoctorCheck[]
|
|
63
|
+
onBooted: () => Promise<void>
|
|
64
|
+
onBooting: () => Promise<void>
|
|
65
|
+
onRegister: () => void
|
|
66
|
+
onRequestProcessed: (_ctx: HttpContext) => Promise<void>
|
|
67
|
+
onRequestReceived: (_ctx: HttpContext) => Promise<void>
|
|
68
|
+
onResponseSent: (_ctx: HttpContext) => Promise<void>
|
|
69
|
+
onStarted: () => Promise<void>
|
|
70
|
+
onStarting: () => Promise<void>
|
|
71
|
+
onStopped: () => Promise<void>
|
|
72
|
+
onStopping: () => Promise<void>
|
|
73
|
+
replContext: () => Record<string, unknown>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class PresenceChannel = {
|
|
77
|
+
new (name: string, _socket: Socket): PresenceChannel
|
|
78
|
+
_dispatch: (frame: ServerFrame) => void
|
|
79
|
+
error: (cb: Listener) => PresenceChannel
|
|
80
|
+
here: (cb: (members: PresenceMember[]) => void) => PresenceChannel
|
|
81
|
+
joining: (cb: (member: PresenceMember) => void) => PresenceChannel
|
|
82
|
+
leaving: (cb: (member: PresenceMember) => void) => PresenceChannel
|
|
83
|
+
listen: (event: string, cb: Listener) => PresenceChannel
|
|
84
|
+
readonly name: string
|
|
85
|
+
stopListening: (event: string, cb?: Listener) => PresenceChannel
|
|
86
|
+
subscribed: (cb: Listener) => PresenceChannel
|
|
87
|
+
unsubscribe: () => void
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
class Socket = {
|
|
91
|
+
new (options?: SocketOptions): Socket
|
|
92
|
+
channel: (name: string) => Channel
|
|
93
|
+
channels: () => Channel[]
|
|
94
|
+
connect: () => void
|
|
95
|
+
disconnect: () => void
|
|
96
|
+
join: (name: string) => PresenceChannel
|
|
97
|
+
leave: (name: string) => void
|
|
98
|
+
leaveChannel: (wireName: string) => void
|
|
99
|
+
on: (state: SocketState, cb: (detail?: unknown) => void) => () => void
|
|
100
|
+
presence: (name: string) => PresenceChannel
|
|
101
|
+
private: (name: string) => Channel
|
|
102
|
+
socketId: () => string | null
|
|
103
|
+
state: SocketState
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class ValidationError = {
|
|
107
|
+
new (statusText: string, body: string, errors: Record<string, string[]>, validationMessage: string, headers?: Headers): ValidationError
|
|
108
|
+
all: () => Record<string, string[]>
|
|
109
|
+
fields: () => string[]
|
|
110
|
+
first: (field: string) => string | undefined
|
|
111
|
+
has: (field: string) => boolean
|
|
112
|
+
readonly body: string
|
|
113
|
+
readonly code: string
|
|
114
|
+
readonly context?: Record<string, unknown> | undefined
|
|
115
|
+
readonly errors: Record<string, string[]>
|
|
116
|
+
readonly headers: Headers | undefined
|
|
117
|
+
readonly status: number
|
|
118
|
+
readonly statusText: string
|
|
119
|
+
readonly validationMessage: string
|
|
120
|
+
retryAfterMs: number | null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const Client = ApiClient<Partial<Record<`GET ${string}` | `POST ${string}` | `PUT ${string}` | `PATCH ${string}` | `DELETE ${string}`, RouteShape>>>
|
|
124
|
+
|
|
125
|
+
function ClientConfig = (options?: Partial<ClientConfigShape>) => Partial<ClientConfigShape>
|
|
126
|
+
|
|
127
|
+
function createApiClient = <Routes extends ApiRouteMap>(config?: ApiClientConfig) => ApiClient<Routes>
|
|
128
|
+
|
|
129
|
+
interface ApiClientConfig = {
|
|
130
|
+
baseUrl?: string
|
|
131
|
+
circuitBreaker?: CircuitBreaker | CircuitBreakerOptions
|
|
132
|
+
csrf?: boolean | { cookie?: string; header?: string;}
|
|
133
|
+
headers?: Record<string, string>
|
|
134
|
+
onError?: (error: ApiClientError) => void | Promise<void>
|
|
135
|
+
onForbidden?: (error: ApiClientError) => void | Promise<void>
|
|
136
|
+
onRequest?: RequestInterceptor | RequestInterceptor[]
|
|
137
|
+
onResponse?: ResponseInterceptor | ResponseInterceptor[]
|
|
138
|
+
onUnauthorized?: (error: ApiClientError, retry: (headerOverrides?: Record<string, string>) => Promise<unknown>) => Promise<unknown> | void
|
|
139
|
+
retry?: number | RetryOptions
|
|
140
|
+
timeout?: number
|
|
141
|
+
token?: TokenSource
|
|
142
|
+
withCredentials?: boolean
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface CircuitBreakerOptions = {
|
|
146
|
+
isFailure?: (error: unknown) => boolean
|
|
147
|
+
resetTimeout?: number
|
|
148
|
+
threshold?: number
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ClientConfigShape = {
|
|
152
|
+
baseUrl?: string
|
|
153
|
+
circuitBreaker?: CircuitBreaker | CircuitBreakerOptions
|
|
154
|
+
csrf?: boolean | { cookie?: string; header?: string;}
|
|
155
|
+
headers?: Record<string, string>
|
|
156
|
+
onError?: (error: ApiClientError) => void | Promise<void>
|
|
157
|
+
onForbidden?: (error: ApiClientError) => void | Promise<void>
|
|
158
|
+
onRequest?: RequestInterceptor | RequestInterceptor[]
|
|
159
|
+
onResponse?: ResponseInterceptor | ResponseInterceptor[]
|
|
160
|
+
onUnauthorized?: (error: ApiClientError, retry: (headerOverrides?: Record<string, string>) => Promise<unknown>) => Promise<unknown> | void
|
|
161
|
+
retry?: number | RetryOptions
|
|
162
|
+
timeout?: number
|
|
163
|
+
token?: TokenSource
|
|
164
|
+
withCredentials?: boolean
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface GetOptions = {
|
|
168
|
+
headers?: Record<string, string>
|
|
169
|
+
init?: Omit<RequestInit, 'method' | 'headers' | 'body'>
|
|
170
|
+
meta?: (meta: ResponseMeta) => void
|
|
171
|
+
query?: Q
|
|
172
|
+
responseType?: 'text' | 'json' | 'auto' | 'blob' | 'arrayBuffer'
|
|
173
|
+
retry?: number | false | RetryOptions
|
|
174
|
+
signal?: AbortSignal
|
|
175
|
+
timeout?: number
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface MutationOptions = {
|
|
179
|
+
headers?: Record<string, string>
|
|
180
|
+
init?: Omit<RequestInit, 'method' | 'headers' | 'body'>
|
|
181
|
+
meta?: (meta: ResponseMeta) => void
|
|
182
|
+
params?: Record<string, string | number>
|
|
183
|
+
query?: Q
|
|
184
|
+
responseType?: 'text' | 'json' | 'auto' | 'blob' | 'arrayBuffer'
|
|
185
|
+
retry?: number | false | RetryOptions
|
|
186
|
+
signal?: AbortSignal
|
|
187
|
+
timeout?: number
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
interface PresenceMember = {
|
|
191
|
+
id: string | number
|
|
192
|
+
info: Record<string, unknown>
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface RequestConfig = {
|
|
196
|
+
body: BodyInit | undefined
|
|
197
|
+
headers: Record<string, string>
|
|
198
|
+
method: string
|
|
199
|
+
url: string
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
interface RequestOptions = {
|
|
203
|
+
headers?: Record<string, string>
|
|
204
|
+
init?: Omit<RequestInit, 'method' | 'headers' | 'body'>
|
|
205
|
+
meta?: (meta: ResponseMeta) => void
|
|
206
|
+
responseType?: 'text' | 'json' | 'auto' | 'blob' | 'arrayBuffer'
|
|
207
|
+
retry?: number | false | RetryOptions
|
|
208
|
+
signal?: AbortSignal
|
|
209
|
+
timeout?: number
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface ResponseContext = {
|
|
213
|
+
data: unknown
|
|
214
|
+
headers: Headers
|
|
215
|
+
request: RequestConfig
|
|
216
|
+
status: number
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
interface ResponseMeta = {
|
|
220
|
+
headers: Headers
|
|
221
|
+
status: number
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface RetryOptions = {
|
|
225
|
+
attempts?: number
|
|
226
|
+
backoff?: (attempt: number, retryAfterMs: number | null) => number
|
|
227
|
+
methods?: string[]
|
|
228
|
+
respectRetryAfter?: boolean
|
|
229
|
+
statuses?: number[]
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
interface RouteShape = {
|
|
233
|
+
body?: Record<string, unknown>
|
|
234
|
+
params?: Record<string, string | number>
|
|
235
|
+
query?: Record<string, string | number | boolean | undefined>
|
|
236
|
+
response?: unknown
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
interface SocketLike = {
|
|
240
|
+
close: (code?: number, reason?: string) => void
|
|
241
|
+
onclose: ((ev: { code?: number; reason?: string;}) => void) | null
|
|
242
|
+
onerror: ((ev: unknown) => void) | null
|
|
243
|
+
onmessage: ((ev: { data: unknown;}) => void) | null
|
|
244
|
+
onopen: ((ev: unknown) => void) | null
|
|
245
|
+
readyState: number
|
|
246
|
+
send: (data: string) => void
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
interface SocketOptions = {
|
|
250
|
+
WebSocket?: new (url: string) => SocketLike
|
|
251
|
+
auth?: { params?: Record<string, string>; headers?: Record<string, string>;}
|
|
252
|
+
authEndpoint?: string | false
|
|
253
|
+
autoConnect?: boolean
|
|
254
|
+
fetch?: typeof fetch
|
|
255
|
+
host?: string
|
|
256
|
+
maxReconnectDelay?: number
|
|
257
|
+
path?: string
|
|
258
|
+
pingInterval?: number
|
|
259
|
+
port?: string | number
|
|
260
|
+
reconnect?: boolean
|
|
261
|
+
reconnectDelay?: number
|
|
262
|
+
scheme?: 'ws' | 'wss'
|
|
263
|
+
url?: string
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
type ApiRouteMap = { [x: `GET ${string}`]: RouteShape | undefined; [x: `POST ${string}`]: RouteShape | undefined; [x: `PUT ${string}`]: RouteShape | undefined; [x: `PATCH ${string}`]: RouteShape | undefined; [x: `DELETE ${string}`]: RouteShape | undefined;}
|
|
267
|
+
|
|
268
|
+
type BodyOf = `${Method} ${Path}` extends keyof Routes ? Routes[`${Method} ${Path}`] extends { body: infer B;} ? B : Record<string, unknown> : Record<string, unknown>
|
|
269
|
+
|
|
270
|
+
type CircuitState = 'closed' | 'open' | 'half-open'
|
|
271
|
+
|
|
272
|
+
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
273
|
+
|
|
274
|
+
type ParamRecord = [PathParams<Path>] extends [never] ? undefined : { [K in PathParams<Path>]: string | number; }
|
|
275
|
+
|
|
276
|
+
type PathParams = Path extends `${string}{${infer Param}}${infer Tail}` ? Param | PathParams<Tail> : never
|
|
277
|
+
|
|
278
|
+
type PathsFor = { [K in keyof Routes & string]: K extends `${Method} ${infer Path}` ? Path : never; }[keyof Routes & string]
|
|
279
|
+
|
|
280
|
+
type QueryOf = `${Method} ${Path}` extends keyof Routes ? Routes[`${Method} ${Path}`] extends { query: infer Q;} ? Q : Record<string, string | number | boolean | undefined> : Record<string, string | number | boolean | undefined>
|
|
281
|
+
|
|
282
|
+
type RequestInterceptor = (config: RequestConfig) => RequestConfig | Promise<RequestConfig>
|
|
283
|
+
|
|
284
|
+
type ResponseInterceptor = (ctx: ResponseContext) => ResponseContext | Promise<ResponseContext>
|
|
285
|
+
|
|
286
|
+
type ResponseOf = `${Method} ${Path}` extends keyof Routes ? Routes[`${Method} ${Path}`] extends { response: infer R;} ? R : unknown : unknown
|
|
287
|
+
|
|
288
|
+
type SocketState = 'error' | 'connecting' | 'connected' | 'disconnected' | 'reconnecting'
|
|
289
|
+
|
|
290
|
+
type TokenSource = string | (() => string | null | undefined | Promise<string | null | undefined>)
|
|
291
|
+
|
|
292
|
+
## ./Socket `(./src/Socket.ts)`
|
|
293
|
+
|
|
294
|
+
class Channel = {
|
|
295
|
+
new (name: string, _socket: Socket): Channel
|
|
296
|
+
_dispatch: (frame: ServerFrame) => void
|
|
297
|
+
error: (cb: Listener) => Channel
|
|
298
|
+
listen: (event: string, cb: Listener) => Channel
|
|
299
|
+
readonly name: string
|
|
300
|
+
stopListening: (event: string, cb?: Listener) => Channel
|
|
301
|
+
subscribed: (cb: Listener) => Channel
|
|
302
|
+
unsubscribe: () => void
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
class PresenceChannel = {
|
|
306
|
+
new (name: string, _socket: Socket): PresenceChannel
|
|
307
|
+
_dispatch: (frame: ServerFrame) => void
|
|
308
|
+
error: (cb: Listener) => PresenceChannel
|
|
309
|
+
here: (cb: (members: PresenceMember[]) => void) => PresenceChannel
|
|
310
|
+
joining: (cb: (member: PresenceMember) => void) => PresenceChannel
|
|
311
|
+
leaving: (cb: (member: PresenceMember) => void) => PresenceChannel
|
|
312
|
+
listen: (event: string, cb: Listener) => PresenceChannel
|
|
313
|
+
readonly name: string
|
|
314
|
+
stopListening: (event: string, cb?: Listener) => PresenceChannel
|
|
315
|
+
subscribed: (cb: Listener) => PresenceChannel
|
|
316
|
+
unsubscribe: () => void
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
class Socket = {
|
|
320
|
+
new (options?: SocketOptions): Socket
|
|
321
|
+
channel: (name: string) => Channel
|
|
322
|
+
channels: () => Channel[]
|
|
323
|
+
connect: () => void
|
|
324
|
+
disconnect: () => void
|
|
325
|
+
join: (name: string) => PresenceChannel
|
|
326
|
+
leave: (name: string) => void
|
|
327
|
+
leaveChannel: (wireName: string) => void
|
|
328
|
+
on: (state: SocketState, cb: (detail?: unknown) => void) => () => void
|
|
329
|
+
presence: (name: string) => PresenceChannel
|
|
330
|
+
private: (name: string) => Channel
|
|
331
|
+
socketId: () => string | null
|
|
332
|
+
state: SocketState
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface PresenceMember = {
|
|
336
|
+
id: string | number
|
|
337
|
+
info: Record<string, unknown>
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
interface SocketLike = {
|
|
341
|
+
close: (code?: number, reason?: string) => void
|
|
342
|
+
onclose: ((ev: { code?: number; reason?: string;}) => void) | null
|
|
343
|
+
onerror: ((ev: unknown) => void) | null
|
|
344
|
+
onmessage: ((ev: { data: unknown;}) => void) | null
|
|
345
|
+
onopen: ((ev: unknown) => void) | null
|
|
346
|
+
readyState: number
|
|
347
|
+
send: (data: string) => void
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
interface SocketOptions = {
|
|
351
|
+
WebSocket?: new (url: string) => SocketLike
|
|
352
|
+
auth?: { params?: Record<string, string>; headers?: Record<string, string>;}
|
|
353
|
+
authEndpoint?: string | false
|
|
354
|
+
autoConnect?: boolean
|
|
355
|
+
fetch?: typeof fetch
|
|
356
|
+
host?: string
|
|
357
|
+
maxReconnectDelay?: number
|
|
358
|
+
path?: string
|
|
359
|
+
pingInterval?: number
|
|
360
|
+
port?: string | number
|
|
361
|
+
reconnect?: boolean
|
|
362
|
+
reconnectDelay?: number
|
|
363
|
+
scheme?: 'ws' | 'wss'
|
|
364
|
+
url?: string
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
type SocketState = 'error' | 'connecting' | 'connected' | 'disconnected' | 'reconnecting'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerotal/client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"maturity": "stable",
|
|
6
6
|
"private": false,
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"CHANGELOG.md",
|
|
16
|
+
"api-surface.md",
|
|
16
17
|
"src",
|
|
17
18
|
"!src/**/*.test.ts",
|
|
18
19
|
"!src/**/*.test.tsx",
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
"typecheck": "tsc --noEmit"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@zerotal/core": "1.
|
|
34
|
+
"@zerotal/core": "1.7.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"typescript": "^5.8.0"
|