@faasjs/react 8.0.0-beta.7 → 8.0.0-beta.9

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/dist/index.d.ts CHANGED
@@ -1,117 +1,838 @@
1
- import { BaseUrl, FaasBrowserClient, Options, Options as Options$1, Response, Response as Response$1, ResponseError, ResponseError as ResponseError$1, ResponseHeaders } from "@faasjs/browser";
2
1
  import * as react from "react";
3
2
  import { Component, ComponentProps, ComponentType, Dispatch, ErrorInfo, JSX, JSXElementConstructor, ReactElement, ReactNode, RefObject, SetStateAction } from "react";
4
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+ import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasActionUnionType as FaasActionUnionType$1, FaasData, FaasData as FaasData$1, FaasParams, FaasParams as FaasParams$1 } from "@faasjs/types";
5
5
 
6
- //#region ../types/src/index.d.ts
6
+ //#region src/generateId.d.ts
7
7
  /**
8
- * Interface for defining FaasJS actions.
8
+ * Generate random id with prefix
9
+ *
10
+ * @param prefix prefix of id
11
+ * @param length length of id without prefix, range is 8 ~ 18, default is 18
9
12
  *
10
13
  * @example
11
- * ```typescript
12
- * declare module '@faasjs/types' {
13
- * interface FaasActions {
14
- * demo: {
15
- * Params: {
16
- * key: string
17
- * }
18
- * Data: {
19
- * value: string
20
- * }
21
- * }
14
+ * ```ts
15
+ * generateId('prefix-') // prefix-1z3b4c5d6e
16
+ * ```
17
+ */
18
+ declare function generateId(prefix?: string, length?: number): string;
19
+ //#endregion
20
+ //#region src/browser.d.ts
21
+ /**
22
+ * Template literal type for URL strings that must end with a forward slash.
23
+ *
24
+ * Ensures that base URLs used in FaasJS requests always have a trailing '/' character,
25
+ * which is required for proper URL construction when appending action paths.
26
+ *
27
+ * @remarks
28
+ * - Type only accepts strings ending with '/' (e.g., 'https://api.example.com/', '/')
29
+ * - Strings without trailing '/' will fail TypeScript type checking
30
+ * - Used by FaasBrowserClient constructor and Options type
31
+ * - Ensures consistent URL formatting across the codebase
32
+ * - Throws Error at runtime if baseUrl doesn't end with '/'
33
+ *
34
+ * @see FaasBrowserClient for usage in client creation
35
+ * @see Options for usage in request options
36
+ */
37
+ type BaseUrl = `${string}/`;
38
+ /**
39
+ * Configuration options for FaasJS requests.
40
+ *
41
+ * Extends the standard RequestInit interface with FaasJS-specific options for
42
+ * customizing request behavior, adding request hooks, and overriding defaults.
43
+ *
44
+ * @remarks
45
+ * - Options can be provided at client creation (defaultOptions) or per-request
46
+ * - Per-request options override client default options
47
+ * - headers are merged: per-request headers override default headers
48
+ * - beforeRequest hook is called before the request is sent, allowing modification
49
+ * - Custom request function completely replaces the default fetch implementation
50
+ * - baseUrl in options overrides the client's baseUrl for this specific request
51
+ * - When stream is true, returns the native fetch Response instead of wrapped Response
52
+ *
53
+ * @property {Record<string, string>} [headers] - Default headers to include in all requests.
54
+ * Merged with client default headers, with per-request headers taking precedence.
55
+ * Common headers include Content-Type, Authorization, and custom application headers.
56
+ *
57
+ * @property {Function} [beforeRequest] - Async hook called before sending each request.
58
+ * Receives action, params, options, and headers, allowing modification before the request is sent.
59
+ * Useful for logging, authentication, adding timestamps, or modifying headers dynamically.
60
+ * Any changes to the headers object will affect the actual request.
61
+ *
62
+ * @property {Function} [request] - Custom request function to replace the default fetch.
63
+ * Allows using alternative HTTP clients like axios, XMLHttpRequest, or custom implementations.
64
+ * Receives the URL and parsed options, must return a Promise resolving to a Response object.
65
+ * When provided, this function is used instead of the native fetch API.
66
+ *
67
+ * @property {BaseUrl} [baseUrl] - Optional override for the base URL for this specific request.
68
+ * If provided, overrides the client's baseUrl. Must end with '/'.
69
+ * Useful for making requests to different endpoints or environments from the same client instance.
70
+ *
71
+ * @property {boolean} [stream] - Enable streaming mode for large responses.
72
+ * When true, returns the raw fetch Response object instead of a wrapped Response.
73
+ * Useful for processing large data incrementally or working with binary data streams.
74
+ * When false or undefined, returns a wrapped Response with automatic JSON parsing.
75
+ *
76
+ * @extends RequestInit
77
+ * @see FaasBrowserClient for client creation
78
+ * @see Response for response object structure
79
+ */
80
+ type Options = RequestInit & {
81
+ headers?: Record<string, string>; /** trigger before request */
82
+ beforeRequest?: ({
83
+ action,
84
+ params,
85
+ options,
86
+ headers
87
+ }: {
88
+ action: string;
89
+ params?: Record<string, any> | undefined;
90
+ options: Options;
91
+ headers: Record<string, string>;
92
+ }) => Promise<void>; /** custom request */
93
+ request?: <PathOrData extends FaasActionUnionType$1>(url: string, options: Options) => Promise<Response<FaasData$1<PathOrData>>>;
94
+ baseUrl?: BaseUrl;
95
+ stream?: boolean;
96
+ };
97
+ /**
98
+ * Simple key-value object for HTTP response headers.
99
+ *
100
+ * Represents headers as a plain object with string keys and string values.
101
+ * Used by Response, ResponseError, and Options types.
102
+ *
103
+ * @property {string} [key] - Dynamic string keys for header names (e.g., 'Content-Type', 'Authorization').
104
+ * Values must be strings. Multiple values for the same key are not supported.
105
+ *
106
+ * @remarks
107
+ * - Headers are case-insensitive in HTTP but stored with exact casing in this object
108
+ * - Common headers include: Content-Type, Authorization, X-Request-Id, X-Custom-Header
109
+ * - No support for multi-value headers (use comma-separated values instead)
110
+ * - Used in Response, ResponseError, and Options types
111
+ * - Simplified model compared to browser's Headers interface (no .get(), .set() methods)
112
+ *
113
+ * @see Response for usage in response objects
114
+ * @see ResponseError for usage in error objects
115
+ * @see Options for usage in request options
116
+ */
117
+ type ResponseHeaders = {
118
+ [key: string]: string;
119
+ };
120
+ /**
121
+ * Type definition for the FaasBrowserClient.action method.
122
+ *
123
+ * Defines the signature of the method used to make requests to FaasJS functions.
124
+ * Provides type-safe parameter and return value handling.
125
+ *
126
+ * @template PathOrData - The function path or data type for type safety
127
+ *
128
+ * @param {FaasAction<PathOrData>} action - The function path to call
129
+ * @param {FaasParams<PathOrData>} [params] - Optional parameters for the function
130
+ * @param {Options} [options] - Optional request options
131
+ *
132
+ * @returns {Promise<Response<FaasData<PathOrData>> | Response>} - A Promise resolving to a Response object
133
+ *
134
+ * @remarks
135
+ * - Used internally by FaasBrowserClient.action method
136
+ * - Provides type-safe action method signature
137
+ * - Return type includes both typed and untyped Response variants
138
+ * - Params are optional and can be undefined
139
+ * - Options override client defaults when provided
140
+ *
141
+ * @see FaasBrowserClient for the class that uses this type
142
+ * @see Response for the return type
143
+ * @see Options for the options parameter type
144
+ */
145
+ type FaasBrowserClientAction = <PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, params?: FaasParams$1<PathOrData>, options?: Options) => Promise<Response<FaasData$1<PathOrData>> | Response>;
146
+ /**
147
+ * Properties for creating a Response object.
148
+ *
149
+ * Defines the structure of response data that can be passed to the Response constructor
150
+ * or returned from mock handlers.
151
+ *
152
+ * @template T - The type of the data property for type-safe response creation
153
+ *
154
+ * @property {number} [status] - The HTTP status code for the response.
155
+ * Optional: defaults to 200 if data or body is provided, 204 otherwise.
156
+ *
157
+ * @property {ResponseHeaders} [headers] - The response headers as a key-value object.
158
+ * Optional: defaults to an empty object if not provided.
159
+ *
160
+ * @property {any} [body] - The raw response body as a string or object.
161
+ * Optional: if not provided, body is automatically populated from data using JSON.stringify.
162
+ *
163
+ * @property {T} [data] - The parsed JSON data to include in the response.
164
+ * Optional: contains the response payload when JSON data is provided.
165
+ *
166
+ * @remarks
167
+ * - All properties are optional
168
+ * - At least one of data or body should be provided for meaningful responses
169
+ * - The Response class automatically defaults status to 200 or 204 based on content
170
+ * - If data is provided without body, body is automatically JSON.stringify(data)
171
+ * - Used by Response constructor and mock handlers
172
+ *
173
+ * @see Response for the class that uses these properties
174
+ * @see ResponseErrorProps for error response properties
175
+ */
176
+ type ResponseProps<T = any> = {
177
+ status?: number;
178
+ headers?: ResponseHeaders;
179
+ body?: any;
180
+ data?: T;
181
+ };
182
+ /**
183
+ * Wrapper class for HTTP responses from FaasJS functions.
184
+ *
185
+ * Provides a consistent interface for handling server responses with status code, headers,
186
+ * body, and parsed data. Automatically handles JSON serialization and status code defaults.
187
+ *
188
+ * @template T - The type of the data property for type-safe response handling
189
+ *
190
+ * @property {number} status - The HTTP status code of the response.
191
+ * Defaults to 200 if data or body is provided, 204 if neither is present.
192
+ * @property {ResponseHeaders} headers - The response headers as a key-value object.
193
+ * Empty object if no headers were provided.
194
+ * @property {any} body - The raw response body as a string or object.
195
+ * If data is provided without body, body is automatically set to JSON.stringify(data).
196
+ * @property {T} [data] - The parsed JSON data from the response.
197
+ * Optional property that contains the response payload when JSON is provided.
198
+ *
199
+ * @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
200
+ * All properties are optional with sensible defaults.
201
+ *
202
+ * @remarks
203
+ * - status defaults to 200 if data or body is present, 204 otherwise
204
+ * - body is automatically populated from data if not explicitly provided
205
+ * - headers defaults to an empty object if not provided
206
+ * - Use generic type parameter T for type-safe data access
207
+ * - Commonly used as the return type from client.action() method
208
+ * - Can be used in mock handlers to return structured responses
209
+ * - The data property is optional and may be undefined for responses without data
210
+ *
211
+ * @example Create successful response with data
212
+ * ```ts
213
+ * const response = new Response({
214
+ * status: 200,
215
+ * data: {
216
+ * id: 123,
217
+ * name: 'John Doe'
22
218
  * }
219
+ * })
220
+ * console.log(response.status) // 200
221
+ * console.log(response.data.name) // 'John Doe'
222
+ * ```
223
+ *
224
+ * @example Create response with type safety
225
+ * ```ts
226
+ * interface User {
227
+ * id: number
228
+ * name: string
229
+ * email: string
23
230
  * }
231
+ *
232
+ * const response = new Response<User>({
233
+ * data: {
234
+ * id: 123,
235
+ * name: 'John',
236
+ * email: 'john@example.com'
237
+ * }
238
+ * })
239
+ * // TypeScript knows response.data.name is a string
240
+ * ```
241
+ *
242
+ * @example Create response with headers
243
+ * ```ts
244
+ * const response = new Response({
245
+ * status: 201,
246
+ * data: { created: true },
247
+ * headers: {
248
+ * 'Content-Type': 'application/json',
249
+ * 'X-Request-Id': 'req-123',
250
+ * 'X-Cache-Key': 'user-123'
251
+ * }
252
+ * })
253
+ * ```
254
+ *
255
+ * @example Create response with custom body
256
+ * ```ts
257
+ * const response = new Response({
258
+ * status: 200,
259
+ * body: JSON.stringify({ custom: 'format' }),
260
+ * headers: { 'Content-Type': 'application/json' }
261
+ * })
262
+ * ```
263
+ *
264
+ * @example Create empty response (204 No Content)
265
+ * ```ts
266
+ * const response = new Response()
267
+ * // status: 204, headers: {}, body: undefined, data: undefined
24
268
  * ```
269
+ *
270
+ * @example Create error response
271
+ * ```ts
272
+ * const response = new Response({
273
+ * status: 404,
274
+ * data: {
275
+ * error: {
276
+ * message: 'User not found',
277
+ * code: 'USER_NOT_FOUND'
278
+ * }
279
+ * }
280
+ * })
281
+ * ```
282
+ *
283
+ * @example Use in mock handler
284
+ * ```ts
285
+ * setMock(async (action, params) => {
286
+ * if (action === 'user') {
287
+ * return new Response({
288
+ * status: 200,
289
+ * data: { id: params.id, name: 'Mock User' }
290
+ * })
291
+ * }
292
+ * return new Response({ status: 404, data: { error: 'Not found' } })
293
+ * })
294
+ * ```
295
+ *
296
+ * @see ResponseProps for response property type
297
+ * @see ResponseError for error response handling
298
+ * @see FaasBrowserClient.action for method returning Response
25
299
  */
26
- interface FaasActions {
27
- /**
28
- * Internal placeholder to keep this interface visible in generated docs.
29
- */
30
- faasjsActionsPlaceholder?: {
31
- Params: Record<string, any>;
32
- Data: Record<string, any>;
33
- };
300
+ declare class Response<T = any> {
301
+ readonly status: number;
302
+ readonly headers: ResponseHeaders;
303
+ readonly body: any;
304
+ readonly data?: T;
305
+ constructor(props?: ResponseProps<T>);
34
306
  }
307
+ type ResponseErrorProps = {
308
+ message: string; /** @default 500 */
309
+ status?: number; /** @default {} */
310
+ headers?: ResponseHeaders; /** @default { error: Error(message) } */
311
+ body?: any;
312
+ originalError?: Error;
313
+ };
35
314
  /**
36
- * Infer all action paths declared in {@link FaasActions}.
37
- */
38
- type FaasActionPaths = Exclude<Extract<keyof FaasActions, string>, 'faasjsActionsPlaceholder'>;
39
- /**
40
- * Union type accepted by action helpers.
315
+ * Custom error class for handling HTTP response errors from FaasJS requests.
316
+ *
317
+ * Extends the built-in Error class to provide additional information about failed requests,
318
+ * including HTTP status code, response headers, response body, and the original error.
319
+ *
320
+ * @class ResponseError
321
+ * @extends {Error}
322
+ *
323
+ * @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
324
+ * @property {ResponseHeaders} headers - The response headers from the failed request.
325
+ * @property {any} body - The response body containing error details or the original error if available.
326
+ * @property {Error} [originalError] - The original Error object if this ResponseError was created from another Error.
327
+ *
328
+ * @param {string | Error | ResponseErrorProps} data - The error message, an Error object, or a ResponseErrorProps object.
329
+ * @param {Omit<ResponseErrorProps, 'message' | 'originalError'>} [options] - Additional options for the error (status, headers, body).
330
+ *
331
+ * @example Basic error with message
332
+ * ```ts
333
+ * throw new ResponseError('User not found')
334
+ * // or inside action method:
335
+ * catch (error) {
336
+ * throw new ResponseError(error.message)
337
+ * }
338
+ * ```
339
+ *
340
+ * @example Error from existing Error
341
+ * ```ts
342
+ * try {
343
+ * await someOperation()
344
+ * } catch (error) {
345
+ * throw new ResponseError(error, {
346
+ * status: 500,
347
+ * headers: { 'X-Error-Type': 'internal' }
348
+ * })
349
+ * }
350
+ * ```
351
+ *
352
+ * @example Error with complete response details
353
+ * ```ts
354
+ * throw new ResponseError({
355
+ * message: 'Validation failed',
356
+ * status: 400,
357
+ * headers: { 'X-Error-Code': 'VALIDATION_ERROR' },
358
+ * body: {
359
+ * error: {
360
+ * message: 'Validation failed',
361
+ * fields: ['email', 'password']
362
+ * }
363
+ * }
364
+ * })
365
+ * ```
366
+ *
367
+ * @example Handling ResponseError in client
368
+ * ```ts
369
+ * try {
370
+ * const response = await client.action('user', { id: 123 })
371
+ * console.log(response.data)
372
+ * } catch (error) {
373
+ * if (error instanceof ResponseError) {
374
+ * console.error(`Request failed: ${error.message}`)
375
+ * console.error(`Status: ${error.status}`)
376
+ * if (error.body) {
377
+ * console.error('Error details:', error.body)
378
+ * }
379
+ * if (error.headers['X-Request-Id']) {
380
+ * console.error('Request ID:', error.headers['X-Request-Id'])
381
+ * }
382
+ * }
383
+ * }
384
+ * ```
385
+ *
386
+ * @example Throwing ResponseError from mock
387
+ * ```ts
388
+ * setMock(async (action, params) => {
389
+ * if (action === 'login') {
390
+ * if (!params.email || !params.password) {
391
+ * throw new ResponseError({
392
+ * message: 'Email and password are required',
393
+ * status: 400,
394
+ * body: { error: 'missing_fields' }
395
+ * })
396
+ * }
397
+ * return { data: { token: 'abc123' } }
398
+ * }
399
+ * })
400
+ * ```
401
+ *
402
+ * @remarks
403
+ * - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
404
+ * - The error message from server responses is extracted from body.error.message if available
405
+ * - When created from an Error object, the original error is preserved in the originalError property
406
+ * - The status property defaults to 500 if not explicitly provided
407
+ * - Use instanceof ResponseError to distinguish FaasJS errors from other JavaScript errors
408
+ * - The body property can contain structured error information from the server response
409
+ *
410
+ * @see FaasBrowserClient.action for how ResponseError is thrown in requests
411
+ * @see ResponseProps for the structure of response data
412
+ * @see setMock for mocking errors in tests
41
413
  */
42
- type FaasActionUnionType = FaasActionPaths | Record<string, any> | string;
414
+ declare class ResponseError extends Error {
415
+ readonly status: number;
416
+ readonly headers: ResponseHeaders;
417
+ readonly body: any;
418
+ readonly originalError?: Error;
419
+ constructor(msg: string | Error, options?: Omit<ResponseErrorProps, 'message' | 'originalError'>);
420
+ constructor(props: ResponseErrorProps);
421
+ }
43
422
  /**
44
- * Infer the action path type.
423
+ * Mock handler function type for testing FaasJS requests.
45
424
  *
46
- * Returns the original type when `T` is a known action path,
47
- * otherwise falls back to `string`.
425
+ * Defines the signature for functions that can mock API requests during testing.
426
+ * Mock handlers receive request parameters and return simulated responses or errors.
48
427
  *
49
- * @example
50
- * ```typescript
51
- * type A = FaasAction<'demo'> // 'demo'
52
- * type B = FaasAction<number> // string
428
+ * @param {string} action - The function path/action being requested (e.g., 'user', 'data/list').
429
+ * Converted to lowercase by the client before being passed to the handler.
430
+ *
431
+ * @param {Record<string, any> | undefined} params - The parameters passed to the action.
432
+ * May be undefined if the action was called without parameters.
433
+ * Parameters are passed as a plain object (already JSON-serialized if needed).
434
+ *
435
+ * @param {Options} options - The full request options including headers, beforeRequest hook, and other config.
436
+ * Includes X-FaasJS-Request-Id header in the headers object.
437
+ * Contains merged client defaults and per-request options.
438
+ *
439
+ * @returns {Promise<ResponseProps> | Promise<void> | Promise<Error>} - A Promise resolving to:
440
+ * - ResponseProps: Mock response data (status, headers, body, data)
441
+ * - void: Returns an empty response (204 No Content)
442
+ * - Error: Throws ResponseError when returning an Error object
443
+ *
444
+ * @remarks
445
+ * - Used by setMock() function to mock API calls during tests
446
+ * - Affects all FaasBrowserClient instances when set globally
447
+ * - Can return different responses based on action or params
448
+ * - Returning an Error object causes the action() method to reject with ResponseError
449
+ * - Async function - must return a Promise
450
+ * - Receives the fully merged options including default headers
451
+ *
452
+ * @example Basic mock returning data
453
+ * ```ts
454
+ * setMock(async (action, params, options) => {
455
+ * if (action === 'user') {
456
+ * return {
457
+ * status: 200,
458
+ * data: { id: params.id, name: 'Mock User' }
459
+ * }
460
+ * }
461
+ * return { status: 404, data: { error: 'Not found' } }
462
+ * })
463
+ * ```
464
+ *
465
+ * @example Conditional mock based on parameters
466
+ * ```ts
467
+ * setMock(async (action, params) => {
468
+ * if (action === 'login') {
469
+ * if (params.email === 'admin@example.com' && params.password === 'admin') {
470
+ * return { data: { token: 'admin-token', role: 'admin' } }
471
+ * }
472
+ * return { status: 401, data: { error: 'Invalid credentials' } }
473
+ * }
474
+ * })
475
+ * ```
476
+ *
477
+ * @example Throwing error from mock
478
+ * ```ts
479
+ * setMock(async (action) => {
480
+ * if (action === 'protected') {
481
+ * return new Error('Unauthorized access')
482
+ * // This will be wrapped in ResponseError and thrown
483
+ * }
484
+ * })
53
485
  * ```
486
+ *
487
+ * @example Returning void for empty response
488
+ * ```ts
489
+ * setMock(async (action) => {
490
+ * if (action === 'delete') {
491
+ * // Return void for 204 No Content
492
+ * return
493
+ * }
494
+ * return { data: { success: true } }
495
+ * })
496
+ * ```
497
+ *
498
+ * @see setMock for setting up mock handlers
499
+ * @see ResponseProps for response structure
500
+ * @see ResponseError for error handling
54
501
  */
55
- type FaasAction<T = any> = T extends FaasActionPaths ? T : string;
502
+ type MockHandler = (action: string, params: Record<string, any> | undefined, options: Options) => Promise<ResponseProps> | Promise<void> | Promise<Error>;
56
503
  /**
57
- * Infer params type by action path.
504
+ * Set global mock handler for testing. Mock affects all FaasBrowserClient instances.
58
505
  *
59
- * @example
60
- * ```typescript
61
- * type DemoParams = FaasParams<'demo'>
506
+ * @param handler - Mock handler, can be:
507
+ * - MockHandler function: receives (action, params, options) and returns response data
508
+ * - ResponseProps object: static response data
509
+ * - Response instance: pre-configured Response object
510
+ * - null or undefined: clear mock
511
+ *
512
+ * @example Use MockHandler function
513
+ * ```ts
514
+ * setMock(async (action, params, options) => {
515
+ * if (action === 'user') {
516
+ * return { data: { name: 'John' } }
517
+ * }
518
+ * return { status: 404, data: { error: 'Not found' } }
519
+ * })
520
+ *
521
+ * const response = await client.action('user')
522
+ * ```
523
+ *
524
+ * @example Use ResponseProps object
525
+ * ```ts
526
+ * setMock({
527
+ * status: 200,
528
+ * data: { result: 'success' },
529
+ * headers: { 'X-Custom': 'value' }
530
+ * })
531
+ * ```
532
+ *
533
+ * @example Use Response instance
534
+ * ```ts
535
+ * setMock(new Response({
536
+ * status: 200,
537
+ * data: { result: 'success' }
538
+ * }))
539
+ * ```
540
+ *
541
+ * @example Clear mock
542
+ * ```ts
543
+ * setMock(null)
544
+ * // or
545
+ * setMock(undefined)
546
+ * ```
547
+ *
548
+ * @example Handle errors
549
+ * ```ts
550
+ * setMock(async () => {
551
+ * throw new Error('Internal error')
552
+ * })
553
+ * // This will reject with ResponseError
62
554
  * ```
63
555
  */
64
- type FaasParams<T = any> = T extends FaasActionPaths ? FaasActions[T]['Params'] : Record<string, any>;
556
+ declare function setMock(handler: MockHandler | ResponseProps | Response | null): void;
65
557
  /**
66
- * Infer response data type by action path.
558
+ * Browser client for FaasJS - provides HTTP client functionality for making API requests from web applications.
67
559
  *
68
- * If `T` is already a plain object type, it is returned directly.
560
+ * @template PathOrData - Type parameter extending FaasActionUnionType for type-safe requests
69
561
  *
70
- * @example
71
- * ```typescript
72
- * type DemoData = FaasData<'demo'>
73
- * type CustomData = FaasData<{ value: number }> // { value: number }
562
+ * Features:
563
+ * - Type-safe API requests with TypeScript support
564
+ * - Built-in mock support for testing
565
+ * - Custom request function support
566
+ * - Request/response hooks (beforeRequest)
567
+ * - Automatic error handling with ResponseError
568
+ * - Streaming support for large responses
569
+ * - Multiple instance support with unique IDs
570
+ *
571
+ * @remarks
572
+ * - All requests are POST requests by default
573
+ * - Automatically adds X-FaasJS-Request-Id header for request tracking
574
+ * - baseUrl must end with '/' (will throw Error if not)
575
+ * - Supports global mock via setMock() for testing all instances
576
+ *
577
+ * @example Basic usage
578
+ * ```ts
579
+ * import { FaasBrowserClient } from '@faasjs/react'
580
+ *
581
+ * const client = new FaasBrowserClient('http://localhost:8080/')
582
+ * const response = await client.action('func', { key: 'value' })
583
+ * console.log(response.data)
74
584
  * ```
585
+ *
586
+ * @example With custom headers and options
587
+ * ```ts
588
+ * const client = new FaasBrowserClient('https://api.example.com/', {
589
+ * headers: { 'X-API-Key': 'secret' },
590
+ * beforeRequest: async ({ action, params, headers }) => {
591
+ * console.log(`Calling ${action} with params:`, params)
592
+ * }
593
+ * })
594
+ * ```
595
+ *
596
+ * @example Multiple instances
597
+ * ```ts
598
+ * const apiClient = new FaasBrowserClient('https://api.example.com/')
599
+ * const localClient = new FaasBrowserClient('http://localhost:3000/')
600
+ *
601
+ * const apiData = await apiClient.action('users')
602
+ * const localData = await localClient.action('data')
603
+ * ```
604
+ *
605
+ * @example Error handling
606
+ * ```ts
607
+ * const client = new FaasBrowserClient('https://api.example.com/')
608
+ *
609
+ * try {
610
+ * const response = await client.action('user', { id: 123 })
611
+ * console.log(response.data)
612
+ * } catch (error) {
613
+ * if (error instanceof ResponseError) {
614
+ * console.error(`Request failed: ${error.message}`, error.status)
615
+ * } else {
616
+ * console.error('Unexpected error:', error)
617
+ * }
618
+ * }
619
+ * ```
620
+ *
621
+ * @throws {Error} When baseUrl does not end with '/'
622
+ *
623
+ * @see setMock for testing support
624
+ * @see ResponseError for error handling
75
625
  */
76
- type FaasData<T = any> = T extends FaasActionPaths ? FaasActions[T]['Data'] : T extends Record<string, any> ? T : Record<string, any>;
626
+ declare class FaasBrowserClient {
627
+ readonly id: string;
628
+ baseUrl: BaseUrl;
629
+ defaultOptions: Options;
630
+ /**
631
+ * Creates a new FaasBrowserClient instance.
632
+ *
633
+ * @param baseUrl - Base URL for all API requests. Must end with '/'. Defaults to '/' for relative requests.
634
+ * @throws {Error} If baseUrl does not end with '/'
635
+ * @param options - Configuration options for the client.
636
+ * Supports default headers, beforeRequest hook, custom request function,
637
+ * baseUrl override, and streaming mode.
638
+ *
639
+ * @example Basic initialization
640
+ * ```ts
641
+ * const client = new FaasBrowserClient('/')
642
+ * ```
643
+ *
644
+ * @example With API endpoint
645
+ * ```ts
646
+ * const client = new FaasBrowserClient('https://api.example.com/')
647
+ * ```
648
+ *
649
+ * @example With custom headers
650
+ * ```ts
651
+ * const client = new FaasBrowserClient('https://api.example.com/', {
652
+ * headers: {
653
+ * 'Authorization': 'Bearer token123',
654
+ * 'X-Custom-Header': 'value'
655
+ * }
656
+ * })
657
+ * ```
658
+ *
659
+ * @example With beforeRequest hook
660
+ * ```ts
661
+ * const client = new FaasBrowserClient('https://api.example.com/', {
662
+ * beforeRequest: async ({ action, params, headers }) => {
663
+ * console.log(`Requesting ${action}`, params)
664
+ * // Modify headers before request
665
+ * headers['X-Timestamp'] = Date.now().toString()
666
+ * }
667
+ * })
668
+ * ```
669
+ *
670
+ * @example With custom request function
671
+ * ```ts
672
+ * import axios from 'axios'
673
+ *
674
+ * const client = new FaasBrowserClient('/', {
675
+ * request: async (url, options) => {
676
+ * const response = await axios.post(url, options.body, {
677
+ * headers: options.headers
678
+ * })
679
+ * return new Response({
680
+ * status: response.status,
681
+ * headers: response.headers,
682
+ * data: response.data
683
+ * })
684
+ * }
685
+ * })
686
+ * ```
687
+ *
688
+ * @throws {Error} When baseUrl does not end with '/'
689
+ */
690
+ constructor(baseUrl?: BaseUrl, options?: Options);
691
+ /**
692
+ * Makes a request to a FaasJS function.
693
+ *
694
+ * @template PathOrData - The function path or data type for type safety
695
+ * @param action - The function path to call. Converted to lowercase when constructing the URL.
696
+ * Must be a non-empty string.
697
+ * @param params - The parameters to send to the function. Will be serialized as JSON.
698
+ * Optional if the function accepts no parameters.
699
+ * @param options - Optional request options that override client defaults.
700
+ * Supports headers, beforeRequest hook, custom request function, baseUrl override, and streaming mode.
701
+ *
702
+ * @returns A Promise that resolves to a Response object containing status, headers, body, and data.
703
+ * The data property is typed based on the PathOrData generic parameter.
704
+ *
705
+ * @throws {Error} When action is not provided or is empty
706
+ * @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
707
+ * @throws {NetworkError} When network request fails
708
+ *
709
+ * @remarks
710
+ * - All requests are POST requests by default
711
+ * - Action path is automatically converted to lowercase
712
+ * - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
713
+ * - Headers are merged from client defaults and request options (request options take precedence)
714
+ * - If a global mock is set via setMock(), it will be used instead of making real requests
715
+ * - If a custom request function is provided in options, it will be used instead of fetch
716
+ * - When stream option is true, returns the native fetch Response instead of a wrapped Response
717
+ * - Response body is automatically parsed as JSON when possible
718
+ * - Server errors (body.error) are automatically converted to ResponseError
719
+ *
720
+ * @example Basic request
721
+ * ```ts
722
+ * const response = await client.action('user', { id: 123 })
723
+ * console.log(response.data)
724
+ * ```
725
+ *
726
+ * @example With no parameters
727
+ * ```ts
728
+ * const response = await client.action('status')
729
+ * console.log(response.data.status)
730
+ * ```
731
+ *
732
+ * @example With custom options
733
+ * ```ts
734
+ * const response = await client.action('data', {
735
+ * limit: 10,
736
+ * offset: 0
737
+ * }, {
738
+ * headers: { 'X-Custom-Header': 'value' }
739
+ * })
740
+ * ```
741
+ *
742
+ * @example Streaming large response
743
+ * ```ts
744
+ * const response = await client.action('stream', {
745
+ * format: 'json'
746
+ * }, {
747
+ * stream: true
748
+ * })
749
+ * // response is native fetch Response with streaming support
750
+ * const reader = response.body.getReader()
751
+ * ```
752
+ *
753
+ * @example With type safety
754
+ * ```ts
755
+ * interface UserData {
756
+ * id: number
757
+ * name: string
758
+ * email: string
759
+ * }
760
+ *
761
+ * const response = await client.action<{
762
+ * action: 'user'
763
+ * params: { id: number }
764
+ * data: UserData
765
+ * }>('user', { id: 123 })
766
+ * console.log(response.data.name) // TypeScript knows it's a string
767
+ * ```
768
+ *
769
+ * @example Handling errors
770
+ * ```ts
771
+ * try {
772
+ * const response = await client.action('user', { id: 123 })
773
+ * console.log(response.data)
774
+ * } catch (error) {
775
+ * if (error instanceof ResponseError) {
776
+ * console.error(`Server error: ${error.message}`, error.status)
777
+ * if (error.data) console.error('Error details:', error.data)
778
+ * } else {
779
+ * console.error('Network error:', error)
780
+ * }
781
+ * }
782
+ * ```
783
+ *
784
+ * @example Chaining requests
785
+ * ```ts
786
+ * const userId = await client.action('createUser', {
787
+ * name: 'John',
788
+ * email: 'john@example.com'
789
+ * })
790
+ *
791
+ * const profile = await client.action('getProfile', {
792
+ * userId: userId.data.id
793
+ * })
794
+ * ```
795
+ */
796
+ action<PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, params?: FaasParams$1<PathOrData>, options?: Options): Promise<Response<FaasData$1<PathOrData>>>;
797
+ }
77
798
  //#endregion
78
799
  //#region src/FaasDataWrapper.d.ts
79
800
  /**
80
801
  * Injects FaasData props.
81
802
  */
82
- type FaasDataInjection<PathOrData extends FaasActionUnionType = any> = {
83
- action: FaasAction<PathOrData>;
84
- params: FaasParams<PathOrData>;
803
+ type FaasDataInjection<PathOrData extends FaasActionUnionType$1 = any> = {
804
+ action: FaasAction$1<PathOrData>;
805
+ params: FaasParams$1<PathOrData>;
85
806
  loading: boolean;
86
807
  reloadTimes: number;
87
- data: FaasData<PathOrData>;
808
+ data: FaasData$1<PathOrData>;
88
809
  error: any;
89
- promise: Promise<Response$1<FaasData<PathOrData>>>;
810
+ promise: Promise<Response<FaasData$1<PathOrData>>>;
90
811
  /**
91
812
  * Reloads data with new or existing parameters.
92
813
  *
93
814
  * **Note**: It will sets skip to false before loading data.
94
815
  */
95
- reload(params?: Record<string, any>): Promise<FaasData<PathOrData>>;
96
- setData: React.Dispatch<React.SetStateAction<FaasData<PathOrData>>>;
816
+ reload(params?: Record<string, any>): Promise<FaasData$1<PathOrData>>;
817
+ setData: React.Dispatch<React.SetStateAction<FaasData$1<PathOrData>>>;
97
818
  setLoading: React.Dispatch<React.SetStateAction<boolean>>;
98
- setPromise: React.Dispatch<React.SetStateAction<Promise<Response$1<FaasData<PathOrData>>>>>;
819
+ setPromise: React.Dispatch<React.SetStateAction<Promise<Response<FaasData$1<PathOrData>>>>>;
99
820
  setError: React.Dispatch<React.SetStateAction<any>>;
100
821
  };
101
- type FaasDataWrapperProps<PathOrData extends FaasActionUnionType> = {
822
+ type FaasDataWrapperProps<PathOrData extends FaasActionUnionType$1> = {
102
823
  render?(args: FaasDataInjection<PathOrData>): JSX.Element | JSX.Element[];
103
824
  children?: React.ReactElement<Partial<FaasDataInjection<PathOrData>>>;
104
825
  fallback?: JSX.Element | false;
105
- action: FaasAction<PathOrData>;
106
- params?: FaasParams<PathOrData>;
826
+ action: FaasAction$1<PathOrData>;
827
+ params?: FaasParams$1<PathOrData>;
107
828
  onDataChange?(args: FaasDataInjection<PathOrData>): void; /** use custom data, should work with setData */
108
- data?: FaasData<PathOrData>; /** use custom setData, should work with data */
109
- setData?: React.Dispatch<React.SetStateAction<FaasData<PathOrData>>>;
829
+ data?: FaasData$1<PathOrData>; /** use custom setData, should work with data */
830
+ setData?: React.Dispatch<React.SetStateAction<FaasData$1<PathOrData>>>;
110
831
  baseUrl?: BaseUrl;
111
832
  ref?: React.Ref<FaasDataWrapperRef<PathOrData>>;
112
833
  };
113
- type FaasDataWrapperRef<PathOrData extends FaasActionUnionType = any> = FaasDataInjection<PathOrData>;
114
- declare const FaasDataWrapper: <PathOrData extends FaasActionUnionType = any>(props: FaasDataWrapperProps<PathOrData> & react.RefAttributes<FaasDataWrapperRef<PathOrData>>) => React.ReactElement | null;
834
+ type FaasDataWrapperRef<PathOrData extends FaasActionUnionType$1 = any> = FaasDataInjection<PathOrData>;
835
+ declare const FaasDataWrapper: <PathOrData extends FaasActionUnionType$1 = any>(props: FaasDataWrapperProps<PathOrData> & react.RefAttributes<FaasDataWrapperRef<PathOrData>>) => React.ReactElement | null;
115
836
  /**
116
837
  * HOC to wrap a component with FaasDataWrapper
117
838
  *
@@ -120,7 +841,7 @@ declare const FaasDataWrapper: <PathOrData extends FaasActionUnionType = any>(pr
120
841
  * const MyComponent = withFaasData(({ data }) => <div>{data.name}</div>, { action: 'test', params: { a: 1 } })
121
842
  * ```
122
843
  */
123
- declare function withFaasData<PathOrData extends FaasActionUnionType, TComponentProps extends Required<FaasDataInjection<PathOrData>> = Required<FaasDataInjection<PathOrData>>>(Component: React.FC<TComponentProps>, faasProps: FaasDataWrapperProps<PathOrData>): React.FC<Omit<TComponentProps, keyof FaasDataInjection<PathOrData>> & Record<string, any>>;
844
+ declare function withFaasData<PathOrData extends FaasActionUnionType$1, TComponentProps extends Required<FaasDataInjection<PathOrData>> = Required<FaasDataInjection<PathOrData>>>(Component: React.FC<TComponentProps>, faasProps: FaasDataWrapperProps<PathOrData>): React.FC<Omit<TComponentProps, keyof FaasDataInjection<PathOrData>> & Record<string, any>>;
124
845
  //#endregion
125
846
  //#region src/faas.d.ts
126
847
  /**
@@ -137,19 +858,19 @@ declare function withFaasData<PathOrData extends FaasActionUnionType, TComponent
137
858
  * })
138
859
  * ```
139
860
  */
140
- declare function faas<PathOrData extends FaasActionUnionType>(action: FaasAction<PathOrData>, params: FaasParams<PathOrData>, options?: Options$1): Promise<Response$1<FaasData<PathOrData>>>;
861
+ declare function faas<PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, params: FaasParams$1<PathOrData>, options?: Options): Promise<Response<FaasData$1<PathOrData>>>;
141
862
  //#endregion
142
863
  //#region src/useFaas.d.ts
143
- type useFaasOptions<PathOrData extends FaasActionUnionType> = {
144
- params?: FaasParams<PathOrData>;
145
- data?: FaasData<PathOrData>;
146
- setData?: React.Dispatch<React.SetStateAction<FaasData<PathOrData>>>;
864
+ type useFaasOptions<PathOrData extends FaasActionUnionType$1> = {
865
+ params?: FaasParams$1<PathOrData>;
866
+ data?: FaasData$1<PathOrData>;
867
+ setData?: React.Dispatch<React.SetStateAction<FaasData$1<PathOrData>>>;
147
868
  /**
148
869
  * If skip is true, the request will not be sent.
149
870
  *
150
871
  * However, you can still use reload to send the request.
151
872
  */
152
- skip?: boolean | ((params: FaasParams<PathOrData>) => boolean); /** Send the last request after milliseconds */
873
+ skip?: boolean | ((params: FaasParams$1<PathOrData>) => boolean); /** Send the last request after milliseconds */
153
874
  debounce?: number;
154
875
  baseUrl?: BaseUrl;
155
876
  };
@@ -168,13 +889,13 @@ type useFaasOptions<PathOrData extends FaasActionUnionType> = {
168
889
  * }
169
890
  * ```
170
891
  */
171
- declare function useFaas<PathOrData extends FaasActionUnionType>(action: FaasAction<PathOrData>, defaultParams: FaasParams<PathOrData>, options?: useFaasOptions<PathOrData>): FaasDataInjection<PathOrData>;
892
+ declare function useFaas<PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, defaultParams: FaasParams$1<PathOrData>, options?: useFaasOptions<PathOrData>): FaasDataInjection<PathOrData>;
172
893
  //#endregion
173
894
  //#region src/client.d.ts
174
- type OnError = (action: string, params: Record<string, any>) => (res: ResponseError$1) => Promise<void>;
895
+ type OnError = (action: string, params: Record<string, any>) => (res: ResponseError) => Promise<void>;
175
896
  type FaasReactClientOptions = {
176
897
  /** @default `/` */baseUrl?: BaseUrl;
177
- options?: Options$1;
898
+ options?: Options;
178
899
  /**
179
900
  * @example
180
901
  * ```ts
@@ -250,7 +971,7 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
250
971
  static displayName: string;
251
972
  constructor(props: ErrorBoundaryProps);
252
973
  componentDidCatch(error: Error, info: ErrorInfo): void;
253
- render(): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null;
974
+ render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime0.JSX.Element | null;
254
975
  }
255
976
  //#endregion
256
977
  //#region src/equal.d.ts
@@ -547,7 +1268,7 @@ declare function OptionalWrapper({
547
1268
  Wrapper,
548
1269
  wrapperProps,
549
1270
  children
550
- }: OptionalWrapperProps): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
1271
+ }: OptionalWrapperProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime0.JSX.Element | null | undefined;
551
1272
  declare namespace OptionalWrapper {
552
1273
  var displayName: string;
553
1274
  }
@@ -766,4 +1487,4 @@ declare function usePrevious<T = any>(value: T): T | undefined;
766
1487
  */
767
1488
  declare function useStateRef<T = any>(initialValue?: T): [T | null, Dispatch<SetStateAction<T | null>>, RefObject<T | null>];
768
1489
  //#endregion
769
- export { ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang, type FormProps, FormRule, FormRules, InferFormInputProps, InferFormRulesOptions, InferRuleOption, OnError, OptionalWrapper, OptionalWrapperProps, type Options, type Response, type ResponseError, type ResponseHeaders, StateSetters, StatesWithSetters, UseFaasStreamOptions, UseFaasStreamResult, createSplittingContext, equal, faas, getClient, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasOptions, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };
1490
+ export { BaseUrl, ErrorBoundary, ErrorBoundaryProps, ErrorChildrenProps, type FaasAction, type FaasActionUnionType, FaasBrowserClient, FaasBrowserClientAction, type FaasData, FaasDataInjection, FaasDataWrapper, FaasDataWrapperProps, FaasDataWrapperRef, type FaasParams, FaasReactClient, FaasReactClientInstance, FaasReactClientOptions, FormContainer as Form, type FormButtonElementProps, FormContextProps, FormContextProvider, FormDefaultElements, FormDefaultLang, FormDefaultRules, FormDefaultRulesOptions, FormElementTypes, FormInput, type FormInputElementProps, FormInputProps, FormItem, FormItemName, FormItemProps, type FormLabelElementProps, FormLang, type FormProps, FormRule, FormRules, InferFormInputProps, InferFormRulesOptions, InferRuleOption, MockHandler, OnError, OptionalWrapper, OptionalWrapperProps, Options, Response, ResponseError, ResponseErrorProps, ResponseHeaders, ResponseProps, StateSetters, StatesWithSetters, UseFaasStreamOptions, UseFaasStreamResult, createSplittingContext, equal, faas, generateId, getClient, setMock, useConstant, useEqualCallback, useEqualEffect, useEqualMemo, useEqualMemoize, useFaas, useFaasOptions, useFaasStream, useFormContext, usePrevious, useSplittingState, useStateRef, validValues, withFaasData };