@intrig/plugin-react 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.swcrc +29 -0
  2. package/README.md +7 -0
  3. package/eslint.config.mjs +19 -0
  4. package/package.json +25 -0
  5. package/project.json +29 -0
  6. package/rollup.config.cjs +54 -0
  7. package/rollup.config.mjs +33 -0
  8. package/src/index.ts +2 -0
  9. package/src/lib/code-generator.ts +79 -0
  10. package/src/lib/get-endpoint-documentation.ts +35 -0
  11. package/src/lib/get-schema-documentation.ts +11 -0
  12. package/src/lib/internal-types.ts +15 -0
  13. package/src/lib/plugin-react.ts +22 -0
  14. package/src/lib/templates/context.template.ts +74 -0
  15. package/src/lib/templates/docs/__snapshots__/async-hook.spec.ts.snap +889 -0
  16. package/src/lib/templates/docs/__snapshots__/download-hook.spec.ts.snap +1445 -0
  17. package/src/lib/templates/docs/__snapshots__/react-hook.spec.ts.snap +1371 -0
  18. package/src/lib/templates/docs/__snapshots__/sse-hook.spec.ts.snap +2008 -0
  19. package/src/lib/templates/docs/async-hook.spec.ts +92 -0
  20. package/src/lib/templates/docs/async-hook.ts +226 -0
  21. package/src/lib/templates/docs/download-hook.spec.ts +182 -0
  22. package/src/lib/templates/docs/download-hook.ts +170 -0
  23. package/src/lib/templates/docs/react-hook.spec.ts +97 -0
  24. package/src/lib/templates/docs/react-hook.ts +323 -0
  25. package/src/lib/templates/docs/schema.ts +105 -0
  26. package/src/lib/templates/docs/sse-hook.spec.ts +207 -0
  27. package/src/lib/templates/docs/sse-hook.ts +221 -0
  28. package/src/lib/templates/extra.template.ts +198 -0
  29. package/src/lib/templates/index.template.ts +14 -0
  30. package/src/lib/templates/intrigMiddleware.template.ts +21 -0
  31. package/src/lib/templates/logger.template.ts +67 -0
  32. package/src/lib/templates/media-type-utils.template.ts +191 -0
  33. package/src/lib/templates/network-state.template.ts +702 -0
  34. package/src/lib/templates/packageJson.template.ts +63 -0
  35. package/src/lib/templates/provider/__tests__/provider-templates.spec.ts +209 -0
  36. package/src/lib/templates/provider/axios-config.template.ts +49 -0
  37. package/src/lib/templates/provider/hooks.template.ts +240 -0
  38. package/src/lib/templates/provider/interfaces.template.ts +72 -0
  39. package/src/lib/templates/provider/intrig-provider-stub.template.ts +73 -0
  40. package/src/lib/templates/provider/intrig-provider.template.ts +185 -0
  41. package/src/lib/templates/provider/main.template.ts +48 -0
  42. package/src/lib/templates/provider/reducer.template.ts +50 -0
  43. package/src/lib/templates/provider/status-trap.template.ts +80 -0
  44. package/src/lib/templates/provider.template.ts +698 -0
  45. package/src/lib/templates/source/controller/method/asyncFunctionHook.template.ts +196 -0
  46. package/src/lib/templates/source/controller/method/clientIndex.template.ts +38 -0
  47. package/src/lib/templates/source/controller/method/download.template.ts +256 -0
  48. package/src/lib/templates/source/controller/method/params.template.ts +31 -0
  49. package/src/lib/templates/source/controller/method/requestHook.template.ts +220 -0
  50. package/src/lib/templates/source/type/typeTemplate.ts +257 -0
  51. package/src/lib/templates/swcrc.template.ts +25 -0
  52. package/src/lib/templates/tsconfig.template.ts +37 -0
  53. package/src/lib/templates/type-utils.template.ts +28 -0
  54. package/tsconfig.json +13 -0
  55. package/tsconfig.lib.json +20 -0
@@ -0,0 +1,889 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`reactAsyncFunctionHookDocs > snapshot — path params only (no request body) 1`] = `
4
+ "# Intrig Async Hooks — Quick Guide
5
+
6
+ ## Copy-paste starter (fast lane)
7
+
8
+ ### 1) Hook import
9
+
10
+ \`\`\`ts
11
+ import { useVerifyUserByIdAsync } from "@intrig/react/users/{id}/client";
12
+ \`\`\`
13
+
14
+ ### 2) Create an instance
15
+
16
+ \`\`\`ts
17
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
18
+ \`\`\`
19
+
20
+ ### 3) Call it (awaitable)
21
+
22
+ \`\`\`ts
23
+ // body?, params? — pass what your endpoint needs (order: body, params)
24
+ await verifyUserById(verifyUserByIdParams);
25
+ \`\`\`
26
+
27
+ Async hooks are for one-off, low-friction calls (e.g., validations, submissions). They return an **awaitable function** plus an **abort** function. No NetworkState.
28
+
29
+ ---
30
+
31
+ ## TL;DR (copy–paste)
32
+
33
+ \`\`\`tsx
34
+ import { useVerifyUserByIdAsync } from "@intrig/react/users/{id}/client";
35
+ import { useCallback, useEffect } from "react";
36
+
37
+ export default function Example() {
38
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
39
+
40
+ const run = useCallback(async () => {
41
+ try {
42
+ const result = await verifyUserById(verifyUserByIdParams);
43
+ // do something with result
44
+ console.log(result);
45
+ } catch (e) {
46
+ // request failed or was aborted
47
+ console.error(e);
48
+ }
49
+ }, [verifyUserById]);
50
+
51
+ // Optional: abort on unmount
52
+ useEffect(() => abortVerifyUserById, [abortVerifyUserById]);
53
+
54
+ return <button onClick={run}>Call</button>;
55
+ }
56
+ \`\`\`
57
+
58
+ ### Optional types (if generated by your build)
59
+
60
+ \`\`\`ts
61
+ import type { VerifyUserByIdParams } from "@intrig/react/users/{id}/VerifyUserById.params";
62
+ import type { VerifyUserByIdResponseBody } from "@intrig/react/users/{id}/VerifyUserById.response";
63
+ \`\`\`
64
+
65
+ ---
66
+
67
+ ## Hook API
68
+
69
+ \`\`\`ts
70
+ // Prefer concrete types if your build emits them:
71
+ // import type { VerifyUserByIdResponseBody } from '@intrig/react/users/{id}/VerifyUserById.response';
72
+ // import type { VerifyUserByIdParams } from '@intrig/react/users/{id}/VerifyUserById.params';
73
+
74
+ type VerifyUserByIdData = unknown; // replace with VerifyUserByIdResponseBody if generated
75
+ type VerifyUserByIdRequest = {
76
+ body?: unknown;
77
+ params?: VerifyUserByIdParams;
78
+ };
79
+
80
+ // Signature (shape shown; return type depends on your endpoint)
81
+ declare function useVerifyUserByIdAsync(): [
82
+ (
83
+ body?: VerifyUserByIdRequest["body"],
84
+ params?: VerifyUserByIdRequest["params"],
85
+ ) => Promise<VerifyUserByIdData>,
86
+ () => void, // abort
87
+ ];
88
+ \`\`\`
89
+
90
+ ### Why async hooks?
91
+
92
+ - **No state machine:** just \`await\` the result.
93
+ - **Great for validations & submits:** uniqueness checks, field-level checks, updates.
94
+ - **Abortable:** cancel in-flight work on demand.
95
+
96
+ ---
97
+
98
+ ## Usage Patterns
99
+
100
+ ### 1) Simple try/catch (recommended)
101
+
102
+ \`\`\`tsx
103
+ const [verifyUserById] = useVerifyUserByIdAsync();
104
+
105
+ try {
106
+ const res = await verifyUserById(verifyUserByIdParams);
107
+ // use res
108
+ } catch (e) {
109
+ // network error or abort
110
+ }
111
+ \`\`\`
112
+
113
+ <details><summary>Description</summary>
114
+ <p><strong>Use when</strong> you just need the value or an error. Ideal for validators, uniqueness checks, or quick lookups.</p>
115
+ </details>
116
+
117
+ ### 2) Abort on unmount (safe cleanup)
118
+
119
+ \`\`\`tsx
120
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
121
+
122
+ useEffect(() => abortVerifyUserById, [abortVerifyUserById]);
123
+ \`\`\`
124
+
125
+ <details><summary>Description</summary>
126
+ <p><strong>Use when</strong> the component may unmount while a request is in-flight (route changes, conditional UI).</p>
127
+ </details>
128
+
129
+ ### 3) Debounced validation (e.g., on input change)
130
+
131
+ \`\`\`tsx
132
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
133
+
134
+ const onChange = useMemo(() => {
135
+ let t: any;
136
+ return (value: string) => {
137
+ clearTimeout(t);
138
+ t = setTimeout(async () => {
139
+ try {
140
+ // Optionally abort before firing a new request
141
+ abortVerifyUserById();
142
+ await verifyUserById(/* body from value */, verifyUserByIdParams);
143
+ } catch {}
144
+ }, 250);
145
+ };
146
+ }, [verifyUserById, abortVerifyUserById]);
147
+ \`\`\`
148
+
149
+ <details><summary>Description</summary>
150
+ <p><strong>Use when</strong> validating as the user types. Debounce to reduce chatter; consider <code>abortVerifyUserById()</code> before firing a new call.</p>
151
+ </details>
152
+
153
+ ### 4) Guard against races (latest-only)
154
+
155
+ \`\`\`tsx
156
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
157
+
158
+ const latestOnly = async () => {
159
+ abortVerifyUserById();
160
+ return verifyUserById(verifyUserByIdParams);
161
+ };
162
+ \`\`\`
163
+
164
+ <details><summary>Description</summary>
165
+ <p><strong>Use when</strong> only the most recent call should win (search suggestions, live filters).</p>
166
+ </details>
167
+
168
+ ---
169
+
170
+ ## Full example
171
+
172
+ \`\`\`tsx
173
+ import { useVerifyUserByIdAsync } from "@intrig/react/users/{id}/client";
174
+ import { useCallback } from "react";
175
+
176
+ function MyComponent() {
177
+ const [verifyUserById, abortVerifyUserById] = useVerifyUserByIdAsync();
178
+
179
+ const run = useCallback(async () => {
180
+ try {
181
+ const data = await verifyUserById(verifyUserByIdParams);
182
+ alert(JSON.stringify(data));
183
+ } catch (e) {
184
+ console.error("Call failed/aborted", e);
185
+ }
186
+ }, [verifyUserById]);
187
+
188
+ return (
189
+ <>
190
+ <button onClick={run}>Call remote</button>
191
+ <button onClick={abortVerifyUserById}>Abort</button>
192
+ </>
193
+ );
194
+ }
195
+ \`\`\`
196
+
197
+ ---
198
+
199
+ ## Gotchas & Tips
200
+
201
+ - **No \`NetworkState\`:** async hooks return a Promise, not a state machine.
202
+ - **Abort:** always available; call it to cancel the latest in-flight request.
203
+ - **Errors:** wrap calls with \`try/catch\` to handle network failures or abort errors.
204
+ - **Debounce & throttle:** combine with timers to cut down chatter for typeahead/validators.
205
+ - **Types:** prefer generated \`VerifyUserByIdResponseBody\` and \`VerifyUserByIdParams\` if your build emits them.
206
+
207
+ ---
208
+
209
+ ## Reference: Minimal cheat sheet
210
+
211
+ \`\`\`ts
212
+ const [fn, abort] = useVerifyUserByIdAsync();
213
+ await fn(verifyUserByIdParams);
214
+ abort(); // optional
215
+ \`\`\`
216
+ "
217
+ `;
218
+
219
+ exports[`reactAsyncFunctionHookDocs > snapshot — request body and path params 1`] = `
220
+ "# Intrig Async Hooks — Quick Guide
221
+
222
+ ## Copy-paste starter (fast lane)
223
+
224
+ ### 1) Hook import
225
+
226
+ \`\`\`ts
227
+ import { useRecalculateUserScoreAsync } from "@intrig/react/users/{id}/client";
228
+ \`\`\`
229
+
230
+ ### 2) Create an instance
231
+
232
+ \`\`\`ts
233
+ const [recalculateUserScore, abortRecalculateUserScore] =
234
+ useRecalculateUserScoreAsync();
235
+ \`\`\`
236
+
237
+ ### 3) Call it (awaitable)
238
+
239
+ \`\`\`ts
240
+ // body?, params? — pass what your endpoint needs (order: body, params)
241
+ await recalculateUserScore(
242
+ recalculateUserScoreRequest,
243
+ recalculateUserScoreParams,
244
+ );
245
+ \`\`\`
246
+
247
+ Async hooks are for one-off, low-friction calls (e.g., validations, submissions). They return an **awaitable function** plus an **abort** function. No NetworkState.
248
+
249
+ ---
250
+
251
+ ## TL;DR (copy–paste)
252
+
253
+ \`\`\`tsx
254
+ import { useRecalculateUserScoreAsync } from "@intrig/react/users/{id}/client";
255
+ import { useCallback, useEffect } from "react";
256
+
257
+ export default function Example() {
258
+ const [recalculateUserScore, abortRecalculateUserScore] =
259
+ useRecalculateUserScoreAsync();
260
+
261
+ const run = useCallback(async () => {
262
+ try {
263
+ const result = await recalculateUserScore(
264
+ recalculateUserScoreRequest,
265
+ recalculateUserScoreParams,
266
+ );
267
+ // do something with result
268
+ console.log(result);
269
+ } catch (e) {
270
+ // request failed or was aborted
271
+ console.error(e);
272
+ }
273
+ }, [recalculateUserScore]);
274
+
275
+ // Optional: abort on unmount
276
+ useEffect(() => abortRecalculateUserScore, [abortRecalculateUserScore]);
277
+
278
+ return <button onClick={run}>Call</button>;
279
+ }
280
+ \`\`\`
281
+
282
+ ### Optional types (if generated by your build)
283
+
284
+ \`\`\`ts
285
+ import type { RecalculateUserScoreRequest } from "@intrig/react/demo_api/components/schemas/RecalculateUserScoreRequest";
286
+ import type { RecalculateUserScoreParams } from "@intrig/react/users/{id}/RecalculateUserScore.params";
287
+ import type { RecalculateUserScoreResponseBody } from "@intrig/react/users/{id}/RecalculateUserScore.response";
288
+ \`\`\`
289
+
290
+ ---
291
+
292
+ ## Hook API
293
+
294
+ \`\`\`ts
295
+ // Prefer concrete types if your build emits them:
296
+ // import type { RecalculateUserScoreResponseBody } from '@intrig/react/users/{id}/RecalculateUserScore.response';
297
+ // import type { RecalculateUserScoreParams } from '@intrig/react/users/{id}/RecalculateUserScore.params';
298
+
299
+ type RecalculateUserScoreData = unknown; // replace with RecalculateUserScoreResponseBody if generated
300
+ type RecalculateUserScoreRequest = {
301
+ body?: RecalculateUserScoreRequest;
302
+ params?: RecalculateUserScoreParams;
303
+ };
304
+
305
+ // Signature (shape shown; return type depends on your endpoint)
306
+ declare function useRecalculateUserScoreAsync(): [
307
+ (
308
+ body?: RecalculateUserScoreRequest["body"],
309
+ params?: RecalculateUserScoreRequest["params"],
310
+ ) => Promise<RecalculateUserScoreData>,
311
+ () => void, // abort
312
+ ];
313
+ \`\`\`
314
+
315
+ ### Why async hooks?
316
+
317
+ - **No state machine:** just \`await\` the result.
318
+ - **Great for validations & submits:** uniqueness checks, field-level checks, updates.
319
+ - **Abortable:** cancel in-flight work on demand.
320
+
321
+ ---
322
+
323
+ ## Usage Patterns
324
+
325
+ ### 1) Simple try/catch (recommended)
326
+
327
+ \`\`\`tsx
328
+ const [recalculateUserScore] = useRecalculateUserScoreAsync();
329
+
330
+ try {
331
+ const res = await recalculateUserScore(
332
+ recalculateUserScoreRequest,
333
+ recalculateUserScoreParams,
334
+ );
335
+ // use res
336
+ } catch (e) {
337
+ // network error or abort
338
+ }
339
+ \`\`\`
340
+
341
+ <details><summary>Description</summary>
342
+ <p><strong>Use when</strong> you just need the value or an error. Ideal for validators, uniqueness checks, or quick lookups.</p>
343
+ </details>
344
+
345
+ ### 2) Abort on unmount (safe cleanup)
346
+
347
+ \`\`\`tsx
348
+ const [recalculateUserScore, abortRecalculateUserScore] =
349
+ useRecalculateUserScoreAsync();
350
+
351
+ useEffect(() => abortRecalculateUserScore, [abortRecalculateUserScore]);
352
+ \`\`\`
353
+
354
+ <details><summary>Description</summary>
355
+ <p><strong>Use when</strong> the component may unmount while a request is in-flight (route changes, conditional UI).</p>
356
+ </details>
357
+
358
+ ### 3) Debounced validation (e.g., on input change)
359
+
360
+ \`\`\`tsx
361
+ const [recalculateUserScore, abortRecalculateUserScore] =
362
+ useRecalculateUserScoreAsync();
363
+
364
+ const onChange = useMemo(() => {
365
+ let t: any;
366
+ return (recalculateUserScoreRequest: RecalculateUserScoreRequest) => {
367
+ clearTimeout(t);
368
+ t = setTimeout(async () => {
369
+ try {
370
+ // Optionally abort before firing a new request
371
+ abortRecalculateUserScore();
372
+ await recalculateUserScore(
373
+ recalculateUserScoreRequest,
374
+ recalculateUserScoreParams,
375
+ );
376
+ } catch {}
377
+ }, 250);
378
+ };
379
+ }, [recalculateUserScore, abortRecalculateUserScore]);
380
+ \`\`\`
381
+
382
+ <details><summary>Description</summary>
383
+ <p><strong>Use when</strong> validating as the user types. Debounce to reduce chatter; consider <code>abortRecalculateUserScore()</code> before firing a new call.</p>
384
+ </details>
385
+
386
+ ### 4) Guard against races (latest-only)
387
+
388
+ \`\`\`tsx
389
+ const [recalculateUserScore, abortRecalculateUserScore] =
390
+ useRecalculateUserScoreAsync();
391
+
392
+ const latestOnly = async () => {
393
+ abortRecalculateUserScore();
394
+ return recalculateUserScore(
395
+ recalculateUserScoreRequest,
396
+ recalculateUserScoreParams,
397
+ );
398
+ };
399
+ \`\`\`
400
+
401
+ <details><summary>Description</summary>
402
+ <p><strong>Use when</strong> only the most recent call should win (search suggestions, live filters).</p>
403
+ </details>
404
+
405
+ ---
406
+
407
+ ## Full example
408
+
409
+ \`\`\`tsx
410
+ import { useRecalculateUserScoreAsync } from "@intrig/react/users/{id}/client";
411
+ import { useCallback } from "react";
412
+
413
+ function MyComponent() {
414
+ const [recalculateUserScore, abortRecalculateUserScore] =
415
+ useRecalculateUserScoreAsync();
416
+
417
+ const run = useCallback(async () => {
418
+ try {
419
+ const data = await recalculateUserScore(
420
+ recalculateUserScoreRequest,
421
+ recalculateUserScoreParams,
422
+ );
423
+ alert(JSON.stringify(data));
424
+ } catch (e) {
425
+ console.error("Call failed/aborted", e);
426
+ }
427
+ }, [recalculateUserScore]);
428
+
429
+ return (
430
+ <>
431
+ <button onClick={run}>Call remote</button>
432
+ <button onClick={abortRecalculateUserScore}>Abort</button>
433
+ </>
434
+ );
435
+ }
436
+ \`\`\`
437
+
438
+ ---
439
+
440
+ ## Gotchas & Tips
441
+
442
+ - **No \`NetworkState\`:** async hooks return a Promise, not a state machine.
443
+ - **Abort:** always available; call it to cancel the latest in-flight request.
444
+ - **Errors:** wrap calls with \`try/catch\` to handle network failures or abort errors.
445
+ - **Debounce & throttle:** combine with timers to cut down chatter for typeahead/validators.
446
+ - **Types:** prefer generated \`RecalculateUserScoreResponseBody\` and \`RecalculateUserScoreParams\` if your build emits them.
447
+
448
+ ---
449
+
450
+ ## Reference: Minimal cheat sheet
451
+
452
+ \`\`\`ts
453
+ const [fn, abort] = useRecalculateUserScoreAsync();
454
+ await fn(recalculateUserScoreRequest, recalculateUserScoreParams);
455
+ abort(); // optional
456
+ \`\`\`
457
+ "
458
+ `;
459
+
460
+ exports[`reactAsyncFunctionHookDocs > snapshot — request body only (no path params) 1`] = `
461
+ "# Intrig Async Hooks — Quick Guide
462
+
463
+ ## Copy-paste starter (fast lane)
464
+
465
+ ### 1) Hook import
466
+
467
+ \`\`\`ts
468
+ import { useCheckPasswordStrengthAsync } from "@intrig/react/security/client";
469
+ \`\`\`
470
+
471
+ ### 2) Create an instance
472
+
473
+ \`\`\`ts
474
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
475
+ useCheckPasswordStrengthAsync();
476
+ \`\`\`
477
+
478
+ ### 3) Call it (awaitable)
479
+
480
+ \`\`\`ts
481
+ // body?, params? — pass what your endpoint needs (order: body, params)
482
+ await checkPasswordStrength(checkPasswordStrengthRequest);
483
+ \`\`\`
484
+
485
+ Async hooks are for one-off, low-friction calls (e.g., validations, submissions). They return an **awaitable function** plus an **abort** function. No NetworkState.
486
+
487
+ ---
488
+
489
+ ## TL;DR (copy–paste)
490
+
491
+ \`\`\`tsx
492
+ import { useCheckPasswordStrengthAsync } from "@intrig/react/security/client";
493
+ import { useCallback, useEffect } from "react";
494
+
495
+ export default function Example() {
496
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
497
+ useCheckPasswordStrengthAsync();
498
+
499
+ const run = useCallback(async () => {
500
+ try {
501
+ const result = await checkPasswordStrength(checkPasswordStrengthRequest);
502
+ // do something with result
503
+ console.log(result);
504
+ } catch (e) {
505
+ // request failed or was aborted
506
+ console.error(e);
507
+ }
508
+ }, [checkPasswordStrength]);
509
+
510
+ // Optional: abort on unmount
511
+ useEffect(() => abortCheckPasswordStrength, [abortCheckPasswordStrength]);
512
+
513
+ return <button onClick={run}>Call</button>;
514
+ }
515
+ \`\`\`
516
+
517
+ ### Optional types (if generated by your build)
518
+
519
+ \`\`\`ts
520
+ import type { CheckPasswordStrengthRequest } from "@intrig/react/demo_api/components/schemas/CheckPasswordStrengthRequest";
521
+ import type { CheckPasswordStrengthResponseBody } from "@intrig/react/security/CheckPasswordStrength.response";
522
+ \`\`\`
523
+
524
+ ---
525
+
526
+ ## Hook API
527
+
528
+ \`\`\`ts
529
+ // Prefer concrete types if your build emits them:
530
+ // import type { CheckPasswordStrengthResponseBody } from '@intrig/react/security/CheckPasswordStrength.response';
531
+ //
532
+
533
+ type CheckPasswordStrengthData = unknown; // replace with CheckPasswordStrengthResponseBody if generated
534
+ type CheckPasswordStrengthRequest = {
535
+ body?: CheckPasswordStrengthRequest;
536
+ params?: unknown;
537
+ };
538
+
539
+ // Signature (shape shown; return type depends on your endpoint)
540
+ declare function useCheckPasswordStrengthAsync(): [
541
+ (
542
+ body?: CheckPasswordStrengthRequest["body"],
543
+ params?: CheckPasswordStrengthRequest["params"],
544
+ ) => Promise<CheckPasswordStrengthData>,
545
+ () => void, // abort
546
+ ];
547
+ \`\`\`
548
+
549
+ ### Why async hooks?
550
+
551
+ - **No state machine:** just \`await\` the result.
552
+ - **Great for validations & submits:** uniqueness checks, field-level checks, updates.
553
+ - **Abortable:** cancel in-flight work on demand.
554
+
555
+ ---
556
+
557
+ ## Usage Patterns
558
+
559
+ ### 1) Simple try/catch (recommended)
560
+
561
+ \`\`\`tsx
562
+ const [checkPasswordStrength] = useCheckPasswordStrengthAsync();
563
+
564
+ try {
565
+ const res = await checkPasswordStrength(checkPasswordStrengthRequest);
566
+ // use res
567
+ } catch (e) {
568
+ // network error or abort
569
+ }
570
+ \`\`\`
571
+
572
+ <details><summary>Description</summary>
573
+ <p><strong>Use when</strong> you just need the value or an error. Ideal for validators, uniqueness checks, or quick lookups.</p>
574
+ </details>
575
+
576
+ ### 2) Abort on unmount (safe cleanup)
577
+
578
+ \`\`\`tsx
579
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
580
+ useCheckPasswordStrengthAsync();
581
+
582
+ useEffect(() => abortCheckPasswordStrength, [abortCheckPasswordStrength]);
583
+ \`\`\`
584
+
585
+ <details><summary>Description</summary>
586
+ <p><strong>Use when</strong> the component may unmount while a request is in-flight (route changes, conditional UI).</p>
587
+ </details>
588
+
589
+ ### 3) Debounced validation (e.g., on input change)
590
+
591
+ \`\`\`tsx
592
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
593
+ useCheckPasswordStrengthAsync();
594
+
595
+ const onChange = useMemo(() => {
596
+ let t: any;
597
+ return (checkPasswordStrengthRequest: CheckPasswordStrengthRequest) => {
598
+ clearTimeout(t);
599
+ t = setTimeout(async () => {
600
+ try {
601
+ // Optionally abort before firing a new request
602
+ abortCheckPasswordStrength();
603
+ await checkPasswordStrength(checkPasswordStrengthRequest /* params? */);
604
+ } catch {}
605
+ }, 250);
606
+ };
607
+ }, [checkPasswordStrength, abortCheckPasswordStrength]);
608
+ \`\`\`
609
+
610
+ <details><summary>Description</summary>
611
+ <p><strong>Use when</strong> validating as the user types. Debounce to reduce chatter; consider <code>abortCheckPasswordStrength()</code> before firing a new call.</p>
612
+ </details>
613
+
614
+ ### 4) Guard against races (latest-only)
615
+
616
+ \`\`\`tsx
617
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
618
+ useCheckPasswordStrengthAsync();
619
+
620
+ const latestOnly = async () => {
621
+ abortCheckPasswordStrength();
622
+ return checkPasswordStrength(checkPasswordStrengthRequest);
623
+ };
624
+ \`\`\`
625
+
626
+ <details><summary>Description</summary>
627
+ <p><strong>Use when</strong> only the most recent call should win (search suggestions, live filters).</p>
628
+ </details>
629
+
630
+ ---
631
+
632
+ ## Full example
633
+
634
+ \`\`\`tsx
635
+ import { useCheckPasswordStrengthAsync } from "@intrig/react/security/client";
636
+ import { useCallback } from "react";
637
+
638
+ function MyComponent() {
639
+ const [checkPasswordStrength, abortCheckPasswordStrength] =
640
+ useCheckPasswordStrengthAsync();
641
+
642
+ const run = useCallback(async () => {
643
+ try {
644
+ const data = await checkPasswordStrength(checkPasswordStrengthRequest);
645
+ alert(JSON.stringify(data));
646
+ } catch (e) {
647
+ console.error("Call failed/aborted", e);
648
+ }
649
+ }, [checkPasswordStrength]);
650
+
651
+ return (
652
+ <>
653
+ <button onClick={run}>Call remote</button>
654
+ <button onClick={abortCheckPasswordStrength}>Abort</button>
655
+ </>
656
+ );
657
+ }
658
+ \`\`\`
659
+
660
+ ---
661
+
662
+ ## Gotchas & Tips
663
+
664
+ - **No \`NetworkState\`:** async hooks return a Promise, not a state machine.
665
+ - **Abort:** always available; call it to cancel the latest in-flight request.
666
+ - **Errors:** wrap calls with \`try/catch\` to handle network failures or abort errors.
667
+ - **Debounce & throttle:** combine with timers to cut down chatter for typeahead/validators.
668
+ - **Types:** prefer generated \`CheckPasswordStrengthResponseBody\` and \`...Params\` if your build emits them.
669
+
670
+ ---
671
+
672
+ ## Reference: Minimal cheat sheet
673
+
674
+ \`\`\`ts
675
+ const [fn, abort] = useCheckPasswordStrengthAsync();
676
+ await fn(checkPasswordStrengthRequest);
677
+ abort(); // optional
678
+ \`\`\`
679
+ "
680
+ `;
681
+
682
+ exports[`reactAsyncFunctionHookDocs > snapshot — simple REST descriptor (no body, no path params) 1`] = `
683
+ "# Intrig Async Hooks — Quick Guide
684
+
685
+ ## Copy-paste starter (fast lane)
686
+
687
+ ### 1) Hook import
688
+
689
+ \`\`\`ts
690
+ import { useValidateUsernameAsync } from "@intrig/react/users/client";
691
+ \`\`\`
692
+
693
+ ### 2) Create an instance
694
+
695
+ \`\`\`ts
696
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
697
+ \`\`\`
698
+
699
+ ### 3) Call it (awaitable)
700
+
701
+ \`\`\`ts
702
+ // body?, params? — pass what your endpoint needs (order: body, params)
703
+ await validateUsername();
704
+ \`\`\`
705
+
706
+ Async hooks are for one-off, low-friction calls (e.g., validations, submissions). They return an **awaitable function** plus an **abort** function. No NetworkState.
707
+
708
+ ---
709
+
710
+ ## TL;DR (copy–paste)
711
+
712
+ \`\`\`tsx
713
+ import { useValidateUsernameAsync } from "@intrig/react/users/client";
714
+ import { useCallback, useEffect } from "react";
715
+
716
+ export default function Example() {
717
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
718
+
719
+ const run = useCallback(async () => {
720
+ try {
721
+ const result = await validateUsername();
722
+ // do something with result
723
+ console.log(result);
724
+ } catch (e) {
725
+ // request failed or was aborted
726
+ console.error(e);
727
+ }
728
+ }, [validateUsername]);
729
+
730
+ // Optional: abort on unmount
731
+ useEffect(() => abortValidateUsername, [abortValidateUsername]);
732
+
733
+ return <button onClick={run}>Call</button>;
734
+ }
735
+ \`\`\`
736
+
737
+ ---
738
+
739
+ ## Hook API
740
+
741
+ \`\`\`ts
742
+ // Prefer concrete types if your build emits them:
743
+ // import type { ValidateUsernameResponseBody } from '@intrig/react/users/ValidateUsername.response';
744
+ //
745
+
746
+ type ValidateUsernameData = unknown; // replace with ValidateUsernameResponseBody if generated
747
+ type ValidateUsernameRequest = {
748
+ body?: unknown;
749
+ params?: unknown;
750
+ };
751
+
752
+ // Signature (shape shown; return type depends on your endpoint)
753
+ declare function useValidateUsernameAsync(): [
754
+ (
755
+ body?: ValidateUsernameRequest["body"],
756
+ params?: ValidateUsernameRequest["params"],
757
+ ) => Promise<ValidateUsernameData>,
758
+ () => void, // abort
759
+ ];
760
+ \`\`\`
761
+
762
+ ### Why async hooks?
763
+
764
+ - **No state machine:** just \`await\` the result.
765
+ - **Great for validations & submits:** uniqueness checks, field-level checks, updates.
766
+ - **Abortable:** cancel in-flight work on demand.
767
+
768
+ ---
769
+
770
+ ## Usage Patterns
771
+
772
+ ### 1) Simple try/catch (recommended)
773
+
774
+ \`\`\`tsx
775
+ const [validateUsername] = useValidateUsernameAsync();
776
+
777
+ try {
778
+ const res = await validateUsername();
779
+ // use res
780
+ } catch (e) {
781
+ // network error or abort
782
+ }
783
+ \`\`\`
784
+
785
+ <details><summary>Description</summary>
786
+ <p><strong>Use when</strong> you just need the value or an error. Ideal for validators, uniqueness checks, or quick lookups.</p>
787
+ </details>
788
+
789
+ ### 2) Abort on unmount (safe cleanup)
790
+
791
+ \`\`\`tsx
792
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
793
+
794
+ useEffect(() => abortValidateUsername, [abortValidateUsername]);
795
+ \`\`\`
796
+
797
+ <details><summary>Description</summary>
798
+ <p><strong>Use when</strong> the component may unmount while a request is in-flight (route changes, conditional UI).</p>
799
+ </details>
800
+
801
+ ### 3) Debounced validation (e.g., on input change)
802
+
803
+ \`\`\`tsx
804
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
805
+
806
+ const onChange = useMemo(() => {
807
+ let t: any;
808
+ return (value: string) => {
809
+ clearTimeout(t);
810
+ t = setTimeout(async () => {
811
+ try {
812
+ // Optionally abort before firing a new request
813
+ abortValidateUsername();
814
+ await validateUsername(/* body from value */, /* params? */);
815
+ } catch {}
816
+ }, 250);
817
+ };
818
+ }, [validateUsername, abortValidateUsername]);
819
+ \`\`\`
820
+
821
+ <details><summary>Description</summary>
822
+ <p><strong>Use when</strong> validating as the user types. Debounce to reduce chatter; consider <code>abortValidateUsername()</code> before firing a new call.</p>
823
+ </details>
824
+
825
+ ### 4) Guard against races (latest-only)
826
+
827
+ \`\`\`tsx
828
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
829
+
830
+ const latestOnly = async () => {
831
+ abortValidateUsername();
832
+ return validateUsername();
833
+ };
834
+ \`\`\`
835
+
836
+ <details><summary>Description</summary>
837
+ <p><strong>Use when</strong> only the most recent call should win (search suggestions, live filters).</p>
838
+ </details>
839
+
840
+ ---
841
+
842
+ ## Full example
843
+
844
+ \`\`\`tsx
845
+ import { useValidateUsernameAsync } from "@intrig/react/users/client";
846
+ import { useCallback } from "react";
847
+
848
+ function MyComponent() {
849
+ const [validateUsername, abortValidateUsername] = useValidateUsernameAsync();
850
+
851
+ const run = useCallback(async () => {
852
+ try {
853
+ const data = await validateUsername();
854
+ alert(JSON.stringify(data));
855
+ } catch (e) {
856
+ console.error("Call failed/aborted", e);
857
+ }
858
+ }, [validateUsername]);
859
+
860
+ return (
861
+ <>
862
+ <button onClick={run}>Call remote</button>
863
+ <button onClick={abortValidateUsername}>Abort</button>
864
+ </>
865
+ );
866
+ }
867
+ \`\`\`
868
+
869
+ ---
870
+
871
+ ## Gotchas & Tips
872
+
873
+ - **No \`NetworkState\`:** async hooks return a Promise, not a state machine.
874
+ - **Abort:** always available; call it to cancel the latest in-flight request.
875
+ - **Errors:** wrap calls with \`try/catch\` to handle network failures or abort errors.
876
+ - **Debounce & throttle:** combine with timers to cut down chatter for typeahead/validators.
877
+ - **Types:** prefer generated \`ValidateUsernameResponseBody\` and \`...Params\` if your build emits them.
878
+
879
+ ---
880
+
881
+ ## Reference: Minimal cheat sheet
882
+
883
+ \`\`\`ts
884
+ const [fn, abort] = useValidateUsernameAsync();
885
+ await fn();
886
+ abort(); // optional
887
+ \`\`\`
888
+ "
889
+ `;