@alepha/react 0.15.0 → 0.15.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 (81) hide show
  1. package/dist/auth/index.browser.js +603 -242
  2. package/dist/auth/index.browser.js.map +1 -1
  3. package/dist/auth/index.d.ts +6 -6
  4. package/dist/auth/index.d.ts.map +1 -1
  5. package/dist/auth/index.js +1296 -922
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/core/index.d.ts +128 -128
  8. package/dist/core/index.d.ts.map +1 -1
  9. package/dist/core/index.js +20 -20
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/form/index.d.ts +36 -36
  12. package/dist/form/index.d.ts.map +1 -1
  13. package/dist/form/index.js +15 -15
  14. package/dist/form/index.js.map +1 -1
  15. package/dist/head/index.browser.js +20 -0
  16. package/dist/head/index.browser.js.map +1 -1
  17. package/dist/head/index.d.ts +73 -65
  18. package/dist/head/index.d.ts.map +1 -1
  19. package/dist/head/index.js +20 -0
  20. package/dist/head/index.js.map +1 -1
  21. package/dist/i18n/index.d.ts +37 -37
  22. package/dist/i18n/index.d.ts.map +1 -1
  23. package/dist/i18n/index.js.map +1 -1
  24. package/dist/router/index.browser.js +605 -244
  25. package/dist/router/index.browser.js.map +1 -1
  26. package/dist/router/index.d.ts +539 -550
  27. package/dist/router/index.d.ts.map +1 -1
  28. package/dist/router/index.js +1296 -922
  29. package/dist/router/index.js.map +1 -1
  30. package/dist/websocket/index.d.ts +38 -38
  31. package/dist/websocket/index.d.ts.map +1 -1
  32. package/package.json +6 -6
  33. package/src/auth/__tests__/$auth.spec.ts +162 -147
  34. package/src/auth/index.ts +9 -3
  35. package/src/auth/services/ReactAuth.ts +15 -5
  36. package/src/core/hooks/useAction.ts +1 -2
  37. package/src/core/index.ts +4 -4
  38. package/src/form/errors/FormValidationError.ts +4 -6
  39. package/src/form/hooks/useFormState.ts +1 -1
  40. package/src/form/index.ts +1 -1
  41. package/src/form/services/FormModel.ts +31 -25
  42. package/src/head/helpers/SeoExpander.ts +2 -1
  43. package/src/head/hooks/useHead.spec.tsx +2 -2
  44. package/src/head/index.browser.ts +2 -2
  45. package/src/head/index.ts +4 -4
  46. package/src/head/interfaces/Head.ts +15 -3
  47. package/src/head/primitives/$head.ts +2 -5
  48. package/src/head/providers/BrowserHeadProvider.ts +55 -0
  49. package/src/head/providers/HeadProvider.ts +4 -1
  50. package/src/i18n/__tests__/integration.spec.tsx +1 -1
  51. package/src/i18n/components/Localize.spec.tsx +2 -2
  52. package/src/i18n/hooks/useI18n.browser.spec.tsx +2 -2
  53. package/src/i18n/index.ts +1 -1
  54. package/src/i18n/primitives/$dictionary.ts +1 -1
  55. package/src/i18n/providers/I18nProvider.spec.ts +1 -1
  56. package/src/i18n/providers/I18nProvider.ts +1 -1
  57. package/src/router/__tests__/page-head-browser.browser.spec.ts +5 -1
  58. package/src/router/__tests__/page-head.spec.ts +11 -7
  59. package/src/router/__tests__/seo-head.spec.ts +7 -3
  60. package/src/router/atoms/ssrManifestAtom.ts +2 -11
  61. package/src/router/components/ErrorViewer.tsx +626 -167
  62. package/src/router/components/Link.tsx +4 -2
  63. package/src/router/components/NestedView.tsx +7 -9
  64. package/src/router/components/NotFound.tsx +2 -2
  65. package/src/router/hooks/useQueryParams.ts +1 -1
  66. package/src/router/hooks/useRouter.ts +1 -1
  67. package/src/router/hooks/useRouterState.ts +1 -1
  68. package/src/router/index.browser.ts +10 -11
  69. package/src/router/index.shared.ts +7 -7
  70. package/src/router/index.ts +10 -7
  71. package/src/router/primitives/$page.browser.spec.tsx +6 -1
  72. package/src/router/primitives/$page.spec.tsx +7 -1
  73. package/src/router/primitives/$page.ts +5 -9
  74. package/src/router/providers/ReactBrowserProvider.ts +17 -6
  75. package/src/router/providers/ReactBrowserRouterProvider.ts +1 -1
  76. package/src/router/providers/ReactPageProvider.ts +4 -3
  77. package/src/router/providers/ReactServerProvider.ts +29 -37
  78. package/src/router/providers/ReactServerTemplateProvider.ts +300 -137
  79. package/src/router/providers/SSRManifestProvider.ts +17 -60
  80. package/src/router/services/ReactPageService.ts +4 -1
  81. package/src/router/services/ReactRouter.ts +6 -5
@@ -43,14 +43,14 @@ declare const ClientOnly: (props: PropsWithChildren<ClientOnlyProps>) => ReactNo
43
43
  */
44
44
  interface ErrorBoundaryProps {
45
45
  /**
46
- * Fallback React node to render when an error is caught.
47
- * If not provided, a default error message will be shown.
48
- */
46
+ * Fallback React node to render when an error is caught.
47
+ * If not provided, a default error message will be shown.
48
+ */
49
49
  fallback: (error: Error) => ReactNode;
50
50
  /**
51
- * Optional callback that receives the error and error info.
52
- * Use this to log errors to a monitoring service.
53
- */
51
+ * Optional callback that receives the error and error info.
52
+ * Use this to log errors to a monitoring service.
53
+ */
54
54
  onError?: (error: Error, info: ErrorInfo) => void;
55
55
  }
56
56
  /**
@@ -67,17 +67,23 @@ interface ErrorBoundaryState {
67
67
  declare class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBoundaryProps>, ErrorBoundaryState> {
68
68
  constructor(props: ErrorBoundaryProps);
69
69
  /**
70
- * Update state so the next render shows the fallback UI.
71
- */
70
+ * Update state so the next render shows the fallback UI.
71
+ */
72
72
  static getDerivedStateFromError(error: Error): ErrorBoundaryState;
73
73
  /**
74
- * Lifecycle method called when an error is caught.
75
- * You can log the error or perform side effects here.
76
- */
74
+ * Lifecycle method called when an error is caught.
75
+ * You can log the error or perform side effects here.
76
+ */
77
77
  componentDidCatch(error: Error, info: ErrorInfo): void;
78
78
  render(): ReactNode;
79
79
  }
80
80
  //#endregion
81
+ //#region ../../src/core/contexts/AlephaContext.d.ts
82
+ /**
83
+ * React context to provide the Alepha instance throughout the component tree.
84
+ */
85
+ declare const AlephaContext: react0.Context<Alepha | undefined>;
86
+ //#endregion
81
87
  //#region ../../src/core/contexts/AlephaProvider.d.ts
82
88
  interface AlephaProviderProps {
83
89
  children: ReactNode;
@@ -91,12 +97,6 @@ interface AlephaProviderProps {
91
97
  */
92
98
  declare const AlephaProvider: (props: AlephaProviderProps) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react0.ReactPortal | react0.ReactElement<unknown, string | react0.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime0.JSX.Element | null | undefined;
93
99
  //#endregion
94
- //#region ../../src/core/contexts/AlephaContext.d.ts
95
- /**
96
- * React context to provide the Alepha instance throughout the component tree.
97
- */
98
- declare const AlephaContext: react0.Context<Alepha | undefined>;
99
- //#endregion
100
100
  //#region ../../src/core/hooks/useAction.d.ts
101
101
  /**
102
102
  * Hook for handling async actions with automatic error handling and event emission.
@@ -209,126 +209,126 @@ declare function useAction<Args extends any[], Result = void>(options: UseAction
209
209
  */
210
210
  interface ActionContext {
211
211
  /**
212
- * AbortSignal that can be passed to fetch or other async operations.
213
- * The signal will be aborted when:
214
- * - The component unmounts
215
- * - A new action is triggered (cancels previous)
216
- * - The cancel() method is called
217
- *
218
- * @example
219
- * ```tsx
220
- * const action = useAction({
221
- * handler: async (url, { signal }) => {
222
- * const response = await fetch(url, { signal });
223
- * return response.json();
224
- * }
225
- * }, []);
226
- * ```
227
- */
212
+ * AbortSignal that can be passed to fetch or other async operations.
213
+ * The signal will be aborted when:
214
+ * - The component unmounts
215
+ * - A new action is triggered (cancels previous)
216
+ * - The cancel() method is called
217
+ *
218
+ * @example
219
+ * ```tsx
220
+ * const action = useAction({
221
+ * handler: async (url, { signal }) => {
222
+ * const response = await fetch(url, { signal });
223
+ * return response.json();
224
+ * }
225
+ * }, []);
226
+ * ```
227
+ */
228
228
  signal: AbortSignal;
229
229
  }
230
230
  interface UseActionOptions<Args extends any[] = any[], Result = any> {
231
231
  /**
232
- * The async action handler function.
233
- * Receives the action arguments plus an ActionContext as the last parameter.
234
- */
232
+ * The async action handler function.
233
+ * Receives the action arguments plus an ActionContext as the last parameter.
234
+ */
235
235
  handler: (...args: [...Args, ActionContext]) => Async<Result>;
236
236
  /**
237
- * Custom error handler. If provided, prevents default error re-throw.
238
- */
237
+ * Custom error handler. If provided, prevents default error re-throw.
238
+ */
239
239
  onError?: (error: Error) => void | Promise<void>;
240
240
  /**
241
- * Custom success handler.
242
- */
241
+ * Custom success handler.
242
+ */
243
243
  onSuccess?: (result: Result) => void | Promise<void>;
244
244
  /**
245
- * Optional identifier for this action (useful for debugging/analytics)
246
- */
245
+ * Optional identifier for this action (useful for debugging/analytics)
246
+ */
247
247
  id?: string;
248
248
  name?: string;
249
249
  /**
250
- * Debounce delay in milliseconds. If specified, the action will only execute
251
- * after the specified delay has passed since the last call. Useful for search inputs
252
- * or other high-frequency events.
253
- *
254
- * @example
255
- * ```tsx
256
- * // Execute search 300ms after user stops typing
257
- * const search = useAction({ handler: search, debounce: 300 }, [])
258
- * ```
259
- */
250
+ * Debounce delay in milliseconds. If specified, the action will only execute
251
+ * after the specified delay has passed since the last call. Useful for search inputs
252
+ * or other high-frequency events.
253
+ *
254
+ * @example
255
+ * ```tsx
256
+ * // Execute search 300ms after user stops typing
257
+ * const search = useAction({ handler: search, debounce: 300 }, [])
258
+ * ```
259
+ */
260
260
  debounce?: number;
261
261
  /**
262
- * If true, the action will be executed once when the component mounts.
263
- *
264
- * @example
265
- * ```tsx
266
- * const fetchData = useAction({
267
- * handler: async () => await api.getData(),
268
- * runOnInit: true
269
- * }, []);
270
- * ```
271
- */
262
+ * If true, the action will be executed once when the component mounts.
263
+ *
264
+ * @example
265
+ * ```tsx
266
+ * const fetchData = useAction({
267
+ * handler: async () => await api.getData(),
268
+ * runOnInit: true
269
+ * }, []);
270
+ * ```
271
+ */
272
272
  runOnInit?: boolean;
273
273
  /**
274
- * If specified, the action will be executed periodically at the given interval.
275
- * The interval is specified as a DurationLike value (number in ms, Duration object, or [number, unit] tuple).
276
- *
277
- * @example
278
- * ```tsx
279
- * // Run every 5 seconds
280
- * const poll = useAction({
281
- * handler: async () => await api.poll(),
282
- * runEvery: 5000
283
- * }, []);
284
- * ```
285
- *
286
- * @example
287
- * ```tsx
288
- * // Run every 1 minute
289
- * const poll = useAction({
290
- * handler: async () => await api.poll(),
291
- * runEvery: [1, 'minute']
292
- * }, []);
293
- * ```
294
- */
274
+ * If specified, the action will be executed periodically at the given interval.
275
+ * The interval is specified as a DurationLike value (number in ms, Duration object, or [number, unit] tuple).
276
+ *
277
+ * @example
278
+ * ```tsx
279
+ * // Run every 5 seconds
280
+ * const poll = useAction({
281
+ * handler: async () => await api.poll(),
282
+ * runEvery: 5000
283
+ * }, []);
284
+ * ```
285
+ *
286
+ * @example
287
+ * ```tsx
288
+ * // Run every 1 minute
289
+ * const poll = useAction({
290
+ * handler: async () => await api.poll(),
291
+ * runEvery: [1, 'minute']
292
+ * }, []);
293
+ * ```
294
+ */
295
295
  runEvery?: DurationLike;
296
296
  }
297
297
  interface UseActionReturn<Args extends any[], Result> {
298
298
  /**
299
- * Execute the action with the provided arguments.
300
- *
301
- * @example
302
- * ```tsx
303
- * const action = useAction({ handler: async (data) => { ... } }, []);
304
- * action.run(data);
305
- * ```
306
- */
299
+ * Execute the action with the provided arguments.
300
+ *
301
+ * @example
302
+ * ```tsx
303
+ * const action = useAction({ handler: async (data) => { ... } }, []);
304
+ * action.run(data);
305
+ * ```
306
+ */
307
307
  run: (...args: Args) => Promise<Result | undefined>;
308
308
  /**
309
- * Loading state - true when action is executing.
310
- */
309
+ * Loading state - true when action is executing.
310
+ */
311
311
  loading: boolean;
312
312
  /**
313
- * Error state - contains error if action failed, undefined otherwise.
314
- */
313
+ * Error state - contains error if action failed, undefined otherwise.
314
+ */
315
315
  error?: Error;
316
316
  /**
317
- * Cancel any pending debounced action or abort the current in-flight request.
318
- *
319
- * @example
320
- * ```tsx
321
- * const action = useAction({ ... }, []);
322
- *
323
- * <button onClick={action.cancel} disabled={!action.loading}>
324
- * Cancel
325
- * </button>
326
- * ```
327
- */
317
+ * Cancel any pending debounced action or abort the current in-flight request.
318
+ *
319
+ * @example
320
+ * ```tsx
321
+ * const action = useAction({ ... }, []);
322
+ *
323
+ * <button onClick={action.cancel} disabled={!action.loading}>
324
+ * Cancel
325
+ * </button>
326
+ * ```
327
+ */
328
328
  cancel: () => void;
329
329
  /**
330
- * The result data from the last successful action execution.
331
- */
330
+ * The result data from the last successful action execution.
331
+ */
332
332
  result?: Result;
333
333
  }
334
334
  //#endregion
@@ -347,6 +347,14 @@ interface UseActionReturn<Args extends any[], Result> {
347
347
  */
348
348
  declare const useAlepha: () => Alepha;
349
349
  //#endregion
350
+ //#region ../../src/core/hooks/useClient.d.ts
351
+ /**
352
+ * Hook to get a virtual client for the specified scope.
353
+ *
354
+ * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.
355
+ */
356
+ declare const useClient: <T extends object>(scope?: ClientScope) => HttpVirtualClient<T>;
357
+ //#endregion
350
358
  //#region ../../src/core/hooks/useEvents.d.ts
351
359
  /**
352
360
  * Allow subscribing to multiple Alepha events. See {@link Hooks} for available events.
@@ -381,14 +389,6 @@ type UseEvents = { [T in keyof Hooks]?: Hook<T> | ((payload: Hooks[T]) => Async<
381
389
  */
382
390
  declare const useInject: <T extends object>(service: Service<T>) => T;
383
391
  //#endregion
384
- //#region ../../src/core/hooks/useClient.d.ts
385
- /**
386
- * Hook to get a virtual client for the specified scope.
387
- *
388
- * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.
389
- */
390
- declare const useClient: <T extends object>(scope?: ClientScope) => HttpVirtualClient<T>;
391
- //#endregion
392
392
  //#region ../../src/core/hooks/useStore.d.ts
393
393
  /**
394
394
  * Hook to access and mutate the Alepha state.
@@ -401,34 +401,34 @@ type UseStoreReturn<T> = [T, (value: T) => void];
401
401
  declare module "alepha" {
402
402
  interface Hooks {
403
403
  /**
404
- * Fires when a user action is starting.
405
- * Action can be a form submission, a route transition, or a custom action.
406
- */
404
+ * Fires when a user action is starting.
405
+ * Action can be a form submission, a route transition, or a custom action.
406
+ */
407
407
  "react:action:begin": {
408
408
  type: string;
409
409
  id?: string;
410
410
  };
411
411
  /**
412
- * Fires when a user action has succeeded.
413
- * Action can be a form submission, a route transition, or a custom action.
414
- */
412
+ * Fires when a user action has succeeded.
413
+ * Action can be a form submission, a route transition, or a custom action.
414
+ */
415
415
  "react:action:success": {
416
416
  type: string;
417
417
  id?: string;
418
418
  };
419
419
  /**
420
- * Fires when a user action has failed.
421
- * Action can be a form submission, a route transition, or a custom action.
422
- */
420
+ * Fires when a user action has failed.
421
+ * Action can be a form submission, a route transition, or a custom action.
422
+ */
423
423
  "react:action:error": {
424
424
  type: string;
425
425
  id?: string;
426
426
  error: Error;
427
427
  };
428
428
  /**
429
- * Fires when a user action has completed, regardless of success or failure.
430
- * Action can be a form submission, a route transition, or a custom action.
431
- */
429
+ * Fires when a user action has completed, regardless of success or failure.
430
+ * Action can be a form submission, a route transition, or a custom action.
431
+ */
432
432
  "react:action:end": {
433
433
  type: string;
434
434
  id?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/core/components/ClientOnly.tsx","../../src/core/components/ErrorBoundary.tsx","../../src/core/contexts/AlephaProvider.tsx","../../src/core/contexts/AlephaContext.ts","../../src/core/hooks/useAction.ts","../../src/core/hooks/useAlepha.ts","../../src/core/hooks/useEvents.ts","../../src/core/hooks/useInject.ts","../../src/core/hooks/useClient.ts","../../src/core/hooks/useStore.ts","../../src/core/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/core/components/ClientOnly.tsx","../../src/core/components/ErrorBoundary.tsx","../../src/core/contexts/AlephaContext.ts","../../src/core/contexts/AlephaProvider.tsx","../../src/core/hooks/useAction.ts","../../src/core/hooks/useAlepha.ts","../../src/core/hooks/useClient.ts","../../src/core/hooks/useEvents.ts","../../src/core/hooks/useInject.ts","../../src/core/hooks/useStore.ts","../../src/core/index.ts"],"mappings":"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"}
@@ -276,27 +276,27 @@ function useAction(options, deps) {
276
276
  id: options.id
277
277
  });
278
278
  try {
279
- const result$1 = await options.handler(...args, { signal: abortController.signal });
280
- setResult(result$1);
279
+ const result = await options.handler(...args, { signal: abortController.signal });
280
+ setResult(result);
281
281
  if (!isMountedRef.current || abortController.signal.aborted) return;
282
282
  await alepha.events.emit("react:action:success", {
283
283
  type: "custom",
284
284
  id: options.id
285
285
  });
286
- if (options.onSuccess) await options.onSuccess(result$1);
287
- return result$1;
286
+ if (options.onSuccess) await options.onSuccess(result);
287
+ return result;
288
288
  } catch (err) {
289
289
  if (err instanceof Error && err.name === "AbortError") return;
290
290
  if (!isMountedRef.current) return;
291
- const error$1 = err;
292
- setError(error$1);
291
+ const error = err;
292
+ setError(error);
293
293
  await alepha.events.emit("react:action:error", {
294
294
  type: "custom",
295
295
  id: options.id,
296
- error: error$1
296
+ error
297
297
  });
298
- if (options.onError) await options.onError(error$1);
299
- else throw error$1;
298
+ if (options.onError) await options.onError(error);
299
+ else throw error;
300
300
  } finally {
301
301
  isExecutingRef.current = false;
302
302
  setLoading(false);
@@ -359,6 +359,17 @@ function useAction(options, deps) {
359
359
  };
360
360
  }
361
361
 
362
+ //#endregion
363
+ //#region ../../src/core/hooks/useClient.ts
364
+ /**
365
+ * Hook to get a virtual client for the specified scope.
366
+ *
367
+ * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.
368
+ */
369
+ const useClient = (scope) => {
370
+ return useInject(LinkProvider).client(scope);
371
+ };
372
+
362
373
  //#endregion
363
374
  //#region ../../src/core/hooks/useEvents.ts
364
375
  /**
@@ -396,17 +407,6 @@ const useEvents = (opts, deps) => {
396
407
  }, deps);
397
408
  };
398
409
 
399
- //#endregion
400
- //#region ../../src/core/hooks/useClient.ts
401
- /**
402
- * Hook to get a virtual client for the specified scope.
403
- *
404
- * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.
405
- */
406
- const useClient = (scope) => {
407
- return useInject(LinkProvider).client(scope);
408
- };
409
-
410
410
  //#endregion
411
411
  //#region ../../src/core/hooks/useStore.ts
412
412
  function useStore(target, defaultValue) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["result","error"],"sources":["../../src/core/components/ClientOnly.tsx","../../src/core/components/ErrorBoundary.tsx","../../src/core/contexts/AlephaContext.ts","../../src/core/contexts/AlephaProvider.tsx","../../src/core/hooks/useAlepha.ts","../../src/core/hooks/useInject.ts","../../src/core/hooks/useAction.ts","../../src/core/hooks/useEvents.ts","../../src/core/hooks/useClient.ts","../../src/core/hooks/useStore.ts","../../src/core/index.ts"],"sourcesContent":["import {\n type PropsWithChildren,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface ClientOnlyProps {\n fallback?: ReactNode;\n disabled?: boolean;\n}\n\n/**\n * A small utility component that renders its children only on the client side.\n *\n * Optionally, you can provide a fallback React node that will be rendered.\n *\n * You should use this component when\n * - you have code that relies on browser-specific APIs\n * - you want to avoid server-side rendering for a specific part of your application\n * - you want to prevent pre-rendering of a component\n *\n * @example\n * ```tsx\n * import { ClientOnly } from \"@alepha/react\";\n *\n * const MyComponent = () => {\n * // Avoids SSR issues with Date API\n * return (\n * <ClientOnly>\n * {new Date().toLocaleTimeString()}\n * </ClientOnly>\n * );\n * }\n * ```\n */\nconst ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => setMounted(true), []);\n\n if (props.disabled) {\n return props.children;\n }\n\n return mounted ? props.children : props.fallback;\n};\n\nexport default ClientOnly;\n","import React, {\n type ErrorInfo,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\n\n/**\n * Props for the ErrorBoundary component.\n */\nexport interface ErrorBoundaryProps {\n /**\n * Fallback React node to render when an error is caught.\n * If not provided, a default error message will be shown.\n */\n fallback: (error: Error) => ReactNode;\n\n /**\n * Optional callback that receives the error and error info.\n * Use this to log errors to a monitoring service.\n */\n onError?: (error: Error, info: ErrorInfo) => void;\n}\n\n/**\n * State of the ErrorBoundary component.\n */\ninterface ErrorBoundaryState {\n error?: Error;\n}\n\n/**\n * A reusable error boundary for catching rendering errors in any part of the React component tree.\n *\n * It's already included in the Alepha React framework when using page or layout components.\n */\nexport class ErrorBoundary extends React.Component<\n PropsWithChildren<ErrorBoundaryProps>,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = {};\n }\n\n /**\n * Update state so the next render shows the fallback UI.\n */\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return {\n error,\n };\n }\n\n /**\n * Lifecycle method called when an error is caught.\n * You can log the error or perform side effects here.\n */\n componentDidCatch(error: Error, info: ErrorInfo): void {\n if (this.props.onError) {\n this.props.onError(error, info);\n }\n }\n\n render(): ReactNode {\n if (this.state.error) {\n return this.props.fallback(this.state.error);\n }\n\n return this.props.children;\n }\n}\n\nexport default ErrorBoundary;\n","import type { Alepha } from \"alepha\";\nimport { createContext } from \"react\";\n\n/**\n * React context to provide the Alepha instance throughout the component tree.\n */\nexport const AlephaContext = createContext<Alepha | undefined>(undefined);\n","import { Alepha } from \"alepha\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { AlephaContext } from \"./AlephaContext.ts\";\n\nexport interface AlephaProviderProps {\n children: ReactNode;\n onError: (error: Error) => ReactNode;\n onLoading: () => ReactNode;\n}\n\n/**\n * AlephaProvider component to initialize and provide Alepha instance to the app.\n *\n * This isn't recommended for apps using `@alepha/react/router`, as Router will handle this for you.\n */\nexport const AlephaProvider = (props: AlephaProviderProps) => {\n const alepha = useMemo(() => Alepha.create(), []);\n\n const [started, setStarted] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n useEffect(() => {\n alepha\n .start()\n .then(() => setStarted(true))\n .catch((err) => setError(err));\n }, [alepha]);\n\n if (error) {\n return props.onError(error);\n }\n\n if (!started) {\n return props.onLoading();\n }\n\n return (\n <AlephaContext.Provider value={alepha}>\n {props.children}\n </AlephaContext.Provider>\n );\n};\n","import { type Alepha, AlephaError } from \"alepha\";\nimport { useContext } from \"react\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\n\n/**\n * Main Alepha hook.\n *\n * It provides access to the Alepha instance within a React component.\n *\n * With Alepha, you can access the core functionalities of the framework:\n *\n * - alepha.state() for state management\n * - alepha.inject() for dependency injection\n * - alepha.events.emit() for event handling\n * etc...\n */\nexport const useAlepha = (): Alepha => {\n const alepha = useContext(AlephaContext);\n if (!alepha) {\n throw new AlephaError(\n \"Hook 'useAlepha()' must be used within an AlephaContext.Provider\",\n );\n }\n\n return alepha;\n};\n","import type { Service } from \"alepha\";\nimport { useMemo } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to inject a service instance.\n * It's a wrapper of `useAlepha().inject(service)` with a memoization.\n */\nexport const useInject = <T extends object>(service: Service<T>): T => {\n const alepha = useAlepha();\n return useMemo(() => alepha.inject(service), []);\n};\n","import {\n DateTimeProvider,\n type DurationLike,\n type Interval,\n type Timeout,\n} from \"alepha/datetime\";\nimport {\n type DependencyList,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useInject } from \"./useInject.ts\";\nimport type { Async } from \"alepha\";\n\n/**\n * Hook for handling async actions with automatic error handling and event emission.\n *\n * By default, prevents concurrent executions - if an action is running and you call it again,\n * the second call will be ignored. Use `debounce` option to delay execution instead.\n *\n * Emits lifecycle events:\n * - `react:action:begin` - When action starts\n * - `react:action:success` - When action completes successfully\n * - `react:action:error` - When action throws an error\n * - `react:action:end` - Always emitted at the end\n *\n * @example Basic usage\n * ```tsx\n * const action = useAction({\n * handler: async (data) => {\n * await api.save(data);\n * }\n * }, []);\n *\n * <button onClick={() => action.run(data)} disabled={action.loading}>\n * Save\n * </button>\n * ```\n *\n * @example With debounce (search input)\n * ```tsx\n * const search = useAction({\n * handler: async (query: string) => {\n * await api.search(query);\n * },\n * debounce: 300 // Wait 300ms after last call\n * }, []);\n *\n * <input onChange={(e) => search.run(e.target.value)} />\n * ```\n *\n * @example Run on component mount\n * ```tsx\n * const fetchData = useAction({\n * handler: async () => {\n * const data = await api.getData();\n * return data;\n * },\n * runOnInit: true // Runs once when component mounts\n * }, []);\n * ```\n *\n * @example Run periodically (polling)\n * ```tsx\n * const pollStatus = useAction({\n * handler: async () => {\n * const status = await api.getStatus();\n * return status;\n * },\n * runEvery: 5000 // Run every 5 seconds\n * }, []);\n *\n * // Or with duration tuple\n * const pollStatus = useAction({\n * handler: async () => {\n * const status = await api.getStatus();\n * return status;\n * },\n * runEvery: [30, 'seconds'] // Run every 30 seconds\n * }, []);\n * ```\n *\n * @example With AbortController\n * ```tsx\n * const fetch = useAction({\n * handler: async (url, { signal }) => {\n * const response = await fetch(url, { signal });\n * return response.json();\n * }\n * }, []);\n * // Automatically cancelled on unmount or when new request starts\n * ```\n *\n * @example With error handling\n * ```tsx\n * const deleteAction = useAction({\n * handler: async (id: string) => {\n * await api.delete(id);\n * },\n * onError: (error) => {\n * if (error.code === 'NOT_FOUND') {\n * // Custom error handling\n * }\n * }\n * }, []);\n *\n * {deleteAction.error && <div>Error: {deleteAction.error.message}</div>}\n * ```\n *\n * @example Global error handling\n * ```tsx\n * // In your root app setup\n * alepha.events.on(\"react:action:error\", ({ error }) => {\n * toast.danger(error.message);\n * Sentry.captureException(error);\n * });\n * ```\n */\nexport function useAction<Args extends any[], Result = void>(\n options: UseActionOptions<Args, Result>,\n deps: DependencyList,\n): UseActionReturn<Args, Result> {\n const alepha = useAlepha();\n const dateTimeProvider = useInject(DateTimeProvider);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n const [result, setResult] = useState<Result | undefined>();\n const isExecutingRef = useRef(false);\n const debounceTimerRef = useRef<Timeout | undefined>(undefined);\n const abortControllerRef = useRef<AbortController | undefined>(undefined);\n const isMountedRef = useRef(true);\n const intervalRef = useRef<Interval | undefined>(undefined);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n\n // clear debounce timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n\n // clear interval\n if (intervalRef.current) {\n dateTimeProvider.clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n\n // abort in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = undefined;\n }\n };\n }, []);\n\n const executeAction = useCallback(\n async (...args: Args): Promise<Result | undefined> => {\n // Prevent concurrent executions\n if (isExecutingRef.current) {\n return;\n }\n\n // Abort previous request if still running\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n\n // Create new AbortController for this request\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n isExecutingRef.current = true;\n setLoading(true);\n setError(undefined);\n\n await alepha.events.emit(\"react:action:begin\", {\n type: \"custom\",\n id: options.id,\n });\n\n try {\n // Pass abort signal as last argument to handler\n const result = await options.handler(...args, {\n signal: abortController.signal,\n } as any);\n\n // TODO: it should be after onSuccess?\n setResult(result as Result);\n\n // Only update state if still mounted and not aborted\n if (!isMountedRef.current || abortController.signal.aborted) {\n return;\n }\n\n await alepha.events.emit(\"react:action:success\", {\n type: \"custom\",\n id: options.id,\n });\n\n if (options.onSuccess) {\n await options.onSuccess(result);\n }\n\n\n return result;\n } catch (err) {\n // Ignore abort errors\n if (err instanceof Error && err.name === \"AbortError\") {\n return;\n }\n\n // Only update state if still mounted\n if (!isMountedRef.current) {\n return;\n }\n\n const error = err as Error;\n setError(error);\n\n await alepha.events.emit(\"react:action:error\", {\n type: \"custom\",\n id: options.id,\n error,\n });\n\n if (options.onError) {\n await options.onError(error);\n } else {\n // Re-throw if no custom error handler\n throw error;\n }\n } finally {\n isExecutingRef.current = false;\n setLoading(false);\n\n await alepha.events.emit(\"react:action:end\", {\n type: \"custom\",\n id: options.id,\n });\n\n // Clean up abort controller\n if (abortControllerRef.current === abortController) {\n abortControllerRef.current = undefined;\n }\n }\n },\n [...deps, options.id, options.onError, options.onSuccess],\n );\n\n const handler = useCallback(\n async (...args: Args): Promise<Result | undefined> => {\n if (options.debounce) {\n // clear existing timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n }\n\n // Set new timer\n return new Promise((resolve) => {\n debounceTimerRef.current = dateTimeProvider.createTimeout(\n async () => {\n const result = await executeAction(...args);\n resolve(result);\n },\n options.debounce ?? 0,\n );\n });\n }\n\n return executeAction(...args);\n },\n [executeAction, options.debounce],\n );\n\n const cancel = useCallback(() => {\n // clear debounce timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n\n // abort in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = undefined;\n }\n\n // reset state\n if (isMountedRef.current) {\n isExecutingRef.current = false;\n setLoading(false);\n }\n }, []);\n\n // Run action on mount if runOnInit is true\n useEffect(() => {\n if (options.runOnInit) {\n handler(...([] as any));\n }\n }, deps);\n\n // Run action periodically if runEvery is specified\n useEffect(() => {\n if (!options.runEvery) {\n return;\n }\n\n // Set up interval\n intervalRef.current = dateTimeProvider.createInterval(\n () => handler(...([] as any)),\n options.runEvery,\n true,\n );\n\n // cleanup on unmount or when runEvery changes\n return () => {\n if (intervalRef.current) {\n dateTimeProvider.clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n };\n }, [handler, options.runEvery]);\n\n return {\n run: handler,\n loading,\n error,\n cancel,\n result,\n };\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Context object passed as the last argument to action handlers.\n * Contains an AbortSignal that can be used to cancel the request.\n */\nexport interface ActionContext {\n /**\n * AbortSignal that can be passed to fetch or other async operations.\n * The signal will be aborted when:\n * - The component unmounts\n * - A new action is triggered (cancels previous)\n * - The cancel() method is called\n *\n * @example\n * ```tsx\n * const action = useAction({\n * handler: async (url, { signal }) => {\n * const response = await fetch(url, { signal });\n * return response.json();\n * }\n * }, []);\n * ```\n */\n signal: AbortSignal;\n}\n\nexport interface UseActionOptions<Args extends any[] = any[], Result = any> {\n /**\n * The async action handler function.\n * Receives the action arguments plus an ActionContext as the last parameter.\n */\n handler: (...args: [...Args, ActionContext]) => Async<Result>;\n\n /**\n * Custom error handler. If provided, prevents default error re-throw.\n */\n onError?: (error: Error) => void | Promise<void>;\n\n /**\n * Custom success handler.\n */\n onSuccess?: (result: Result) => void | Promise<void>;\n\n /**\n * Optional identifier for this action (useful for debugging/analytics)\n */\n id?: string;\n\n name?: string;\n\n /**\n * Debounce delay in milliseconds. If specified, the action will only execute\n * after the specified delay has passed since the last call. Useful for search inputs\n * or other high-frequency events.\n *\n * @example\n * ```tsx\n * // Execute search 300ms after user stops typing\n * const search = useAction({ handler: search, debounce: 300 }, [])\n * ```\n */\n debounce?: number;\n\n /**\n * If true, the action will be executed once when the component mounts.\n *\n * @example\n * ```tsx\n * const fetchData = useAction({\n * handler: async () => await api.getData(),\n * runOnInit: true\n * }, []);\n * ```\n */\n runOnInit?: boolean;\n\n /**\n * If specified, the action will be executed periodically at the given interval.\n * The interval is specified as a DurationLike value (number in ms, Duration object, or [number, unit] tuple).\n *\n * @example\n * ```tsx\n * // Run every 5 seconds\n * const poll = useAction({\n * handler: async () => await api.poll(),\n * runEvery: 5000\n * }, []);\n * ```\n *\n * @example\n * ```tsx\n * // Run every 1 minute\n * const poll = useAction({\n * handler: async () => await api.poll(),\n * runEvery: [1, 'minute']\n * }, []);\n * ```\n */\n runEvery?: DurationLike;\n}\n\nexport interface UseActionReturn<Args extends any[], Result> {\n /**\n * Execute the action with the provided arguments.\n *\n * @example\n * ```tsx\n * const action = useAction({ handler: async (data) => { ... } }, []);\n * action.run(data);\n * ```\n */\n run: (...args: Args) => Promise<Result | undefined>;\n\n /**\n * Loading state - true when action is executing.\n */\n loading: boolean;\n\n /**\n * Error state - contains error if action failed, undefined otherwise.\n */\n error?: Error;\n\n /**\n * Cancel any pending debounced action or abort the current in-flight request.\n *\n * @example\n * ```tsx\n * const action = useAction({ ... }, []);\n *\n * <button onClick={action.cancel} disabled={!action.loading}>\n * Cancel\n * </button>\n * ```\n */\n cancel: () => void;\n\n /**\n * The result data from the last successful action execution.\n */\n result?: Result;\n}\n","import type { Async, Hook, Hooks } from \"alepha\";\nimport { type DependencyList, useEffect } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Allow subscribing to multiple Alepha events. See {@link Hooks} for available events.\n *\n * useEvents is fully typed to ensure correct event callback signatures.\n *\n * @example\n * ```tsx\n * useEvents(\n * {\n * \"react:transition:begin\": (ev) => {\n * console.log(\"Transition began to:\", ev.to);\n * },\n * \"react:transition:error\": {\n * priority: \"first\",\n * callback: (ev) => {\n * console.error(\"Transition error:\", ev.error);\n * },\n * },\n * },\n * [],\n * );\n * ```\n */\nexport const useEvents = (opts: UseEvents, deps: DependencyList) => {\n const alepha = useAlepha();\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const subs: Function[] = [];\n for (const [name, hook] of Object.entries(opts)) {\n subs.push(alepha.events.on(name as any, hook as any));\n }\n\n return () => {\n for (const clear of subs) {\n clear();\n }\n };\n }, deps);\n};\n\ntype UseEvents = {\n [T in keyof Hooks]?: Hook<T> | ((payload: Hooks[T]) => Async<void>);\n};\n","import {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"alepha/server/links\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Hook to get a virtual client for the specified scope.\n *\n * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.\n */\nexport const useClient = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return useInject(LinkProvider).client<T>(scope);\n};\n","import type { State, Static, TAtomObject } from \"alepha\";\nimport { Atom } from \"alepha\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to access and mutate the Alepha state.\n */\nfunction useStore<T extends TAtomObject>(\n target: Atom<T>,\n defaultValue?: Static<T>,\n): UseStoreReturn<Static<T>>;\nfunction useStore<Key extends keyof State>(\n target: Key,\n defaultValue?: State[Key],\n): UseStoreReturn<State[Key]>;\nfunction useStore(target: any, defaultValue?: any): any {\n const alepha = useAlepha();\n\n useMemo(() => {\n if (defaultValue != null && alepha.store.get(target) == null) {\n alepha.store.set(target, defaultValue);\n }\n }, [defaultValue]);\n\n const [state, setState] = useState(alepha.store.get(target));\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const key = target instanceof Atom ? target.key : target;\n\n return alepha.events.on(\"state:mutate\", (ev) => {\n if (ev.key === key) {\n setState(ev.value);\n }\n });\n }, []);\n\n return [\n state,\n (value: any) => {\n alepha.store.set(target, value);\n },\n ] as const;\n}\n\nexport type UseStoreReturn<T> = [T, (value: T) => void];\n\nexport { useStore };\n","import { $module } from \"alepha\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport { default as ClientOnly } from \"./components/ClientOnly.tsx\";\nexport type * from \"./components/ClientOnly.tsx\";\nexport { default as ErrorBoundary } from \"./components/ErrorBoundary.tsx\";\nexport type * from \"./components/ErrorBoundary.tsx\";\nexport * from \"./contexts/AlephaProvider.tsx\";\nexport * from \"./contexts/AlephaContext.ts\";\nexport * from \"./hooks/useAction.ts\";\nexport * from \"./hooks/useAlepha.ts\";\nexport * from \"./hooks/useEvents.ts\";\nexport * from \"./hooks/useInject.ts\";\nexport * from \"./hooks/useClient.ts\";\nexport * from \"./hooks/useStore.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Fires when a user action is starting.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:begin\": {\n type: string;\n id?: string;\n };\n /**\n * Fires when a user action has succeeded.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:success\": {\n type: string;\n id?: string;\n };\n /**\n * Fires when a user action has failed.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:error\": {\n type: string;\n id?: string;\n error: Error;\n };\n /**\n * Fires when a user action has completed, regardless of success or failure.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:end\": {\n type: string;\n id?: string;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.\n *\n * The React module enables building modern React applications using the `$page` primitive on class properties.\n * It delivers seamless server-side rendering, automatic code splitting, and client-side navigation with full\n * type safety and schema validation for route parameters and data.\n *\n * @see {@link $page}\n * @module alepha.react\n */\nexport const AlephaReact = $module({\n name: \"alepha.react.core\",\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/core/components/ClientOnly.tsx","../../src/core/components/ErrorBoundary.tsx","../../src/core/contexts/AlephaContext.ts","../../src/core/contexts/AlephaProvider.tsx","../../src/core/hooks/useAlepha.ts","../../src/core/hooks/useInject.ts","../../src/core/hooks/useAction.ts","../../src/core/hooks/useClient.ts","../../src/core/hooks/useEvents.ts","../../src/core/hooks/useStore.ts","../../src/core/index.ts"],"sourcesContent":["import {\n type PropsWithChildren,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface ClientOnlyProps {\n fallback?: ReactNode;\n disabled?: boolean;\n}\n\n/**\n * A small utility component that renders its children only on the client side.\n *\n * Optionally, you can provide a fallback React node that will be rendered.\n *\n * You should use this component when\n * - you have code that relies on browser-specific APIs\n * - you want to avoid server-side rendering for a specific part of your application\n * - you want to prevent pre-rendering of a component\n *\n * @example\n * ```tsx\n * import { ClientOnly } from \"@alepha/react\";\n *\n * const MyComponent = () => {\n * // Avoids SSR issues with Date API\n * return (\n * <ClientOnly>\n * {new Date().toLocaleTimeString()}\n * </ClientOnly>\n * );\n * }\n * ```\n */\nconst ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => setMounted(true), []);\n\n if (props.disabled) {\n return props.children;\n }\n\n return mounted ? props.children : props.fallback;\n};\n\nexport default ClientOnly;\n","import React, {\n type ErrorInfo,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\n\n/**\n * Props for the ErrorBoundary component.\n */\nexport interface ErrorBoundaryProps {\n /**\n * Fallback React node to render when an error is caught.\n * If not provided, a default error message will be shown.\n */\n fallback: (error: Error) => ReactNode;\n\n /**\n * Optional callback that receives the error and error info.\n * Use this to log errors to a monitoring service.\n */\n onError?: (error: Error, info: ErrorInfo) => void;\n}\n\n/**\n * State of the ErrorBoundary component.\n */\ninterface ErrorBoundaryState {\n error?: Error;\n}\n\n/**\n * A reusable error boundary for catching rendering errors in any part of the React component tree.\n *\n * It's already included in the Alepha React framework when using page or layout components.\n */\nexport class ErrorBoundary extends React.Component<\n PropsWithChildren<ErrorBoundaryProps>,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = {};\n }\n\n /**\n * Update state so the next render shows the fallback UI.\n */\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return {\n error,\n };\n }\n\n /**\n * Lifecycle method called when an error is caught.\n * You can log the error or perform side effects here.\n */\n componentDidCatch(error: Error, info: ErrorInfo): void {\n if (this.props.onError) {\n this.props.onError(error, info);\n }\n }\n\n render(): ReactNode {\n if (this.state.error) {\n return this.props.fallback(this.state.error);\n }\n\n return this.props.children;\n }\n}\n\nexport default ErrorBoundary;\n","import type { Alepha } from \"alepha\";\nimport { createContext } from \"react\";\n\n/**\n * React context to provide the Alepha instance throughout the component tree.\n */\nexport const AlephaContext = createContext<Alepha | undefined>(undefined);\n","import { Alepha } from \"alepha\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { AlephaContext } from \"./AlephaContext.ts\";\n\nexport interface AlephaProviderProps {\n children: ReactNode;\n onError: (error: Error) => ReactNode;\n onLoading: () => ReactNode;\n}\n\n/**\n * AlephaProvider component to initialize and provide Alepha instance to the app.\n *\n * This isn't recommended for apps using `@alepha/react/router`, as Router will handle this for you.\n */\nexport const AlephaProvider = (props: AlephaProviderProps) => {\n const alepha = useMemo(() => Alepha.create(), []);\n\n const [started, setStarted] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n useEffect(() => {\n alepha\n .start()\n .then(() => setStarted(true))\n .catch((err) => setError(err));\n }, [alepha]);\n\n if (error) {\n return props.onError(error);\n }\n\n if (!started) {\n return props.onLoading();\n }\n\n return (\n <AlephaContext.Provider value={alepha}>\n {props.children}\n </AlephaContext.Provider>\n );\n};\n","import { type Alepha, AlephaError } from \"alepha\";\nimport { useContext } from \"react\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\n\n/**\n * Main Alepha hook.\n *\n * It provides access to the Alepha instance within a React component.\n *\n * With Alepha, you can access the core functionalities of the framework:\n *\n * - alepha.state() for state management\n * - alepha.inject() for dependency injection\n * - alepha.events.emit() for event handling\n * etc...\n */\nexport const useAlepha = (): Alepha => {\n const alepha = useContext(AlephaContext);\n if (!alepha) {\n throw new AlephaError(\n \"Hook 'useAlepha()' must be used within an AlephaContext.Provider\",\n );\n }\n\n return alepha;\n};\n","import type { Service } from \"alepha\";\nimport { useMemo } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to inject a service instance.\n * It's a wrapper of `useAlepha().inject(service)` with a memoization.\n */\nexport const useInject = <T extends object>(service: Service<T>): T => {\n const alepha = useAlepha();\n return useMemo(() => alepha.inject(service), []);\n};\n","import type { Async } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n type Interval,\n type Timeout,\n} from \"alepha/datetime\";\nimport {\n type DependencyList,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Hook for handling async actions with automatic error handling and event emission.\n *\n * By default, prevents concurrent executions - if an action is running and you call it again,\n * the second call will be ignored. Use `debounce` option to delay execution instead.\n *\n * Emits lifecycle events:\n * - `react:action:begin` - When action starts\n * - `react:action:success` - When action completes successfully\n * - `react:action:error` - When action throws an error\n * - `react:action:end` - Always emitted at the end\n *\n * @example Basic usage\n * ```tsx\n * const action = useAction({\n * handler: async (data) => {\n * await api.save(data);\n * }\n * }, []);\n *\n * <button onClick={() => action.run(data)} disabled={action.loading}>\n * Save\n * </button>\n * ```\n *\n * @example With debounce (search input)\n * ```tsx\n * const search = useAction({\n * handler: async (query: string) => {\n * await api.search(query);\n * },\n * debounce: 300 // Wait 300ms after last call\n * }, []);\n *\n * <input onChange={(e) => search.run(e.target.value)} />\n * ```\n *\n * @example Run on component mount\n * ```tsx\n * const fetchData = useAction({\n * handler: async () => {\n * const data = await api.getData();\n * return data;\n * },\n * runOnInit: true // Runs once when component mounts\n * }, []);\n * ```\n *\n * @example Run periodically (polling)\n * ```tsx\n * const pollStatus = useAction({\n * handler: async () => {\n * const status = await api.getStatus();\n * return status;\n * },\n * runEvery: 5000 // Run every 5 seconds\n * }, []);\n *\n * // Or with duration tuple\n * const pollStatus = useAction({\n * handler: async () => {\n * const status = await api.getStatus();\n * return status;\n * },\n * runEvery: [30, 'seconds'] // Run every 30 seconds\n * }, []);\n * ```\n *\n * @example With AbortController\n * ```tsx\n * const fetch = useAction({\n * handler: async (url, { signal }) => {\n * const response = await fetch(url, { signal });\n * return response.json();\n * }\n * }, []);\n * // Automatically cancelled on unmount or when new request starts\n * ```\n *\n * @example With error handling\n * ```tsx\n * const deleteAction = useAction({\n * handler: async (id: string) => {\n * await api.delete(id);\n * },\n * onError: (error) => {\n * if (error.code === 'NOT_FOUND') {\n * // Custom error handling\n * }\n * }\n * }, []);\n *\n * {deleteAction.error && <div>Error: {deleteAction.error.message}</div>}\n * ```\n *\n * @example Global error handling\n * ```tsx\n * // In your root app setup\n * alepha.events.on(\"react:action:error\", ({ error }) => {\n * toast.danger(error.message);\n * Sentry.captureException(error);\n * });\n * ```\n */\nexport function useAction<Args extends any[], Result = void>(\n options: UseActionOptions<Args, Result>,\n deps: DependencyList,\n): UseActionReturn<Args, Result> {\n const alepha = useAlepha();\n const dateTimeProvider = useInject(DateTimeProvider);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n const [result, setResult] = useState<Result | undefined>();\n const isExecutingRef = useRef(false);\n const debounceTimerRef = useRef<Timeout | undefined>(undefined);\n const abortControllerRef = useRef<AbortController | undefined>(undefined);\n const isMountedRef = useRef(true);\n const intervalRef = useRef<Interval | undefined>(undefined);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n\n // clear debounce timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n\n // clear interval\n if (intervalRef.current) {\n dateTimeProvider.clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n\n // abort in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = undefined;\n }\n };\n }, []);\n\n const executeAction = useCallback(\n async (...args: Args): Promise<Result | undefined> => {\n // Prevent concurrent executions\n if (isExecutingRef.current) {\n return;\n }\n\n // Abort previous request if still running\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n\n // Create new AbortController for this request\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n\n isExecutingRef.current = true;\n setLoading(true);\n setError(undefined);\n\n await alepha.events.emit(\"react:action:begin\", {\n type: \"custom\",\n id: options.id,\n });\n\n try {\n // Pass abort signal as last argument to handler\n const result = await options.handler(...args, {\n signal: abortController.signal,\n } as any);\n\n // TODO: it should be after onSuccess?\n setResult(result as Result);\n\n // Only update state if still mounted and not aborted\n if (!isMountedRef.current || abortController.signal.aborted) {\n return;\n }\n\n await alepha.events.emit(\"react:action:success\", {\n type: \"custom\",\n id: options.id,\n });\n\n if (options.onSuccess) {\n await options.onSuccess(result);\n }\n\n return result;\n } catch (err) {\n // Ignore abort errors\n if (err instanceof Error && err.name === \"AbortError\") {\n return;\n }\n\n // Only update state if still mounted\n if (!isMountedRef.current) {\n return;\n }\n\n const error = err as Error;\n setError(error);\n\n await alepha.events.emit(\"react:action:error\", {\n type: \"custom\",\n id: options.id,\n error,\n });\n\n if (options.onError) {\n await options.onError(error);\n } else {\n // Re-throw if no custom error handler\n throw error;\n }\n } finally {\n isExecutingRef.current = false;\n setLoading(false);\n\n await alepha.events.emit(\"react:action:end\", {\n type: \"custom\",\n id: options.id,\n });\n\n // Clean up abort controller\n if (abortControllerRef.current === abortController) {\n abortControllerRef.current = undefined;\n }\n }\n },\n [...deps, options.id, options.onError, options.onSuccess],\n );\n\n const handler = useCallback(\n async (...args: Args): Promise<Result | undefined> => {\n if (options.debounce) {\n // clear existing timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n }\n\n // Set new timer\n return new Promise((resolve) => {\n debounceTimerRef.current = dateTimeProvider.createTimeout(\n async () => {\n const result = await executeAction(...args);\n resolve(result);\n },\n options.debounce ?? 0,\n );\n });\n }\n\n return executeAction(...args);\n },\n [executeAction, options.debounce],\n );\n\n const cancel = useCallback(() => {\n // clear debounce timer\n if (debounceTimerRef.current) {\n dateTimeProvider.clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = undefined;\n }\n\n // abort in-flight request\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = undefined;\n }\n\n // reset state\n if (isMountedRef.current) {\n isExecutingRef.current = false;\n setLoading(false);\n }\n }, []);\n\n // Run action on mount if runOnInit is true\n useEffect(() => {\n if (options.runOnInit) {\n handler(...([] as any));\n }\n }, deps);\n\n // Run action periodically if runEvery is specified\n useEffect(() => {\n if (!options.runEvery) {\n return;\n }\n\n // Set up interval\n intervalRef.current = dateTimeProvider.createInterval(\n () => handler(...([] as any)),\n options.runEvery,\n true,\n );\n\n // cleanup on unmount or when runEvery changes\n return () => {\n if (intervalRef.current) {\n dateTimeProvider.clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n };\n }, [handler, options.runEvery]);\n\n return {\n run: handler,\n loading,\n error,\n cancel,\n result,\n };\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Context object passed as the last argument to action handlers.\n * Contains an AbortSignal that can be used to cancel the request.\n */\nexport interface ActionContext {\n /**\n * AbortSignal that can be passed to fetch or other async operations.\n * The signal will be aborted when:\n * - The component unmounts\n * - A new action is triggered (cancels previous)\n * - The cancel() method is called\n *\n * @example\n * ```tsx\n * const action = useAction({\n * handler: async (url, { signal }) => {\n * const response = await fetch(url, { signal });\n * return response.json();\n * }\n * }, []);\n * ```\n */\n signal: AbortSignal;\n}\n\nexport interface UseActionOptions<Args extends any[] = any[], Result = any> {\n /**\n * The async action handler function.\n * Receives the action arguments plus an ActionContext as the last parameter.\n */\n handler: (...args: [...Args, ActionContext]) => Async<Result>;\n\n /**\n * Custom error handler. If provided, prevents default error re-throw.\n */\n onError?: (error: Error) => void | Promise<void>;\n\n /**\n * Custom success handler.\n */\n onSuccess?: (result: Result) => void | Promise<void>;\n\n /**\n * Optional identifier for this action (useful for debugging/analytics)\n */\n id?: string;\n\n name?: string;\n\n /**\n * Debounce delay in milliseconds. If specified, the action will only execute\n * after the specified delay has passed since the last call. Useful for search inputs\n * or other high-frequency events.\n *\n * @example\n * ```tsx\n * // Execute search 300ms after user stops typing\n * const search = useAction({ handler: search, debounce: 300 }, [])\n * ```\n */\n debounce?: number;\n\n /**\n * If true, the action will be executed once when the component mounts.\n *\n * @example\n * ```tsx\n * const fetchData = useAction({\n * handler: async () => await api.getData(),\n * runOnInit: true\n * }, []);\n * ```\n */\n runOnInit?: boolean;\n\n /**\n * If specified, the action will be executed periodically at the given interval.\n * The interval is specified as a DurationLike value (number in ms, Duration object, or [number, unit] tuple).\n *\n * @example\n * ```tsx\n * // Run every 5 seconds\n * const poll = useAction({\n * handler: async () => await api.poll(),\n * runEvery: 5000\n * }, []);\n * ```\n *\n * @example\n * ```tsx\n * // Run every 1 minute\n * const poll = useAction({\n * handler: async () => await api.poll(),\n * runEvery: [1, 'minute']\n * }, []);\n * ```\n */\n runEvery?: DurationLike;\n}\n\nexport interface UseActionReturn<Args extends any[], Result> {\n /**\n * Execute the action with the provided arguments.\n *\n * @example\n * ```tsx\n * const action = useAction({ handler: async (data) => { ... } }, []);\n * action.run(data);\n * ```\n */\n run: (...args: Args) => Promise<Result | undefined>;\n\n /**\n * Loading state - true when action is executing.\n */\n loading: boolean;\n\n /**\n * Error state - contains error if action failed, undefined otherwise.\n */\n error?: Error;\n\n /**\n * Cancel any pending debounced action or abort the current in-flight request.\n *\n * @example\n * ```tsx\n * const action = useAction({ ... }, []);\n *\n * <button onClick={action.cancel} disabled={!action.loading}>\n * Cancel\n * </button>\n * ```\n */\n cancel: () => void;\n\n /**\n * The result data from the last successful action execution.\n */\n result?: Result;\n}\n","import {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"alepha/server/links\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Hook to get a virtual client for the specified scope.\n *\n * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.\n */\nexport const useClient = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return useInject(LinkProvider).client<T>(scope);\n};\n","import type { Async, Hook, Hooks } from \"alepha\";\nimport { type DependencyList, useEffect } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Allow subscribing to multiple Alepha events. See {@link Hooks} for available events.\n *\n * useEvents is fully typed to ensure correct event callback signatures.\n *\n * @example\n * ```tsx\n * useEvents(\n * {\n * \"react:transition:begin\": (ev) => {\n * console.log(\"Transition began to:\", ev.to);\n * },\n * \"react:transition:error\": {\n * priority: \"first\",\n * callback: (ev) => {\n * console.error(\"Transition error:\", ev.error);\n * },\n * },\n * },\n * [],\n * );\n * ```\n */\nexport const useEvents = (opts: UseEvents, deps: DependencyList) => {\n const alepha = useAlepha();\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const subs: Function[] = [];\n for (const [name, hook] of Object.entries(opts)) {\n subs.push(alepha.events.on(name as any, hook as any));\n }\n\n return () => {\n for (const clear of subs) {\n clear();\n }\n };\n }, deps);\n};\n\ntype UseEvents = {\n [T in keyof Hooks]?: Hook<T> | ((payload: Hooks[T]) => Async<void>);\n};\n","import type { State, Static, TAtomObject } from \"alepha\";\nimport { Atom } from \"alepha\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to access and mutate the Alepha state.\n */\nfunction useStore<T extends TAtomObject>(\n target: Atom<T>,\n defaultValue?: Static<T>,\n): UseStoreReturn<Static<T>>;\nfunction useStore<Key extends keyof State>(\n target: Key,\n defaultValue?: State[Key],\n): UseStoreReturn<State[Key]>;\nfunction useStore(target: any, defaultValue?: any): any {\n const alepha = useAlepha();\n\n useMemo(() => {\n if (defaultValue != null && alepha.store.get(target) == null) {\n alepha.store.set(target, defaultValue);\n }\n }, [defaultValue]);\n\n const [state, setState] = useState(alepha.store.get(target));\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const key = target instanceof Atom ? target.key : target;\n\n return alepha.events.on(\"state:mutate\", (ev) => {\n if (ev.key === key) {\n setState(ev.value);\n }\n });\n }, []);\n\n return [\n state,\n (value: any) => {\n alepha.store.set(target, value);\n },\n ] as const;\n}\n\nexport type UseStoreReturn<T> = [T, (value: T) => void];\n\nexport { useStore };\n","import { $module } from \"alepha\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type * from \"./components/ClientOnly.tsx\";\nexport { default as ClientOnly } from \"./components/ClientOnly.tsx\";\nexport type * from \"./components/ErrorBoundary.tsx\";\nexport { default as ErrorBoundary } from \"./components/ErrorBoundary.tsx\";\nexport * from \"./contexts/AlephaContext.ts\";\nexport * from \"./contexts/AlephaProvider.tsx\";\nexport * from \"./hooks/useAction.ts\";\nexport * from \"./hooks/useAlepha.ts\";\nexport * from \"./hooks/useClient.ts\";\nexport * from \"./hooks/useEvents.ts\";\nexport * from \"./hooks/useInject.ts\";\nexport * from \"./hooks/useStore.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Fires when a user action is starting.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:begin\": {\n type: string;\n id?: string;\n };\n /**\n * Fires when a user action has succeeded.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:success\": {\n type: string;\n id?: string;\n };\n /**\n * Fires when a user action has failed.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:error\": {\n type: string;\n id?: string;\n error: Error;\n };\n /**\n * Fires when a user action has completed, regardless of success or failure.\n * Action can be a form submission, a route transition, or a custom action.\n */\n \"react:action:end\": {\n type: string;\n id?: string;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.\n *\n * The React module enables building modern React applications using the `$page` primitive on class properties.\n * It delivers seamless server-side rendering, automatic code splitting, and client-side navigation with full\n * type safety and schema validation for route parameters and data.\n *\n * @see {@link $page}\n * @module alepha.react\n */\nexport const AlephaReact = $module({\n name: \"alepha.react.core\",\n});\n"],"mappings":"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"}