@rdlabo/ionic-angular-kit 0.0.3 → 0.0.4

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.
@@ -0,0 +1,767 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, EnvironmentProviders, OnInit } from '@angular/core';
3
+ import { ModalOptions, ToastOptions } from '@ionic/angular/standalone';
4
+ import { RouterStateSnapshot, UrlTree, CanActivateFn } from '@angular/router';
5
+ import { Observable } from 'rxjs';
6
+ import { HttpRequest, HttpResponse, HttpErrorResponse, HttpEvent, HttpInterceptorFn } from '@angular/common/http';
7
+ import { ImpactStyle } from '@capacitor/haptics';
8
+
9
+ /**
10
+ * Thin, typed wrapper around `@ionic/storage-angular`.
11
+ *
12
+ * Starts `create()` exactly once and stores the resulting ready Promise. Every operation awaits
13
+ * that Promise before touching the underlying store, so calls made before initialization completes
14
+ * are queued rather than dropped.
15
+ *
16
+ * @remarks
17
+ * A naive wrapper that reads the store synchronously would silently no-op (or throw) when invoked
18
+ * before `create()` resolves, losing early writes. Awaiting the one-time ready Promise on every
19
+ * operation removes that race without forcing callers to coordinate initialization themselves.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * constructor(private readonly storage: KitStorageService) {}
24
+ *
25
+ * async ngOnInit(): Promise<void> {
26
+ * await this.storage.set('token', 'abc123');
27
+ * const token = await this.storage.get<string>('token');
28
+ * }
29
+ * ```
30
+ */
31
+ declare class KitStorageService {
32
+ #private;
33
+ /**
34
+ * Persist a value under the given key.
35
+ *
36
+ * @typeParam T - type of the value being stored
37
+ * @param key - key to store the value under
38
+ * @param value - value to persist; overwrites any existing value for the key
39
+ * @returns a Promise that resolves once the value has been written
40
+ * @example
41
+ * ```ts
42
+ * await storage.set('user', { id: 1, name: 'Ada' });
43
+ * ```
44
+ */
45
+ set<T>(key: string, value: T): Promise<void>;
46
+ /**
47
+ * Read the value stored under the given key.
48
+ *
49
+ * @typeParam T - expected type of the stored value
50
+ * @param key - key to read
51
+ * @returns the stored value, or `null` when the key is absent
52
+ * @example
53
+ * ```ts
54
+ * const user = await storage.get<{ id: number }>('user');
55
+ * ```
56
+ */
57
+ get<T>(key: string): Promise<T | null>;
58
+ /**
59
+ * Remove the value stored under the given key.
60
+ *
61
+ * @param key - key to remove; a no-op when the key is absent
62
+ * @returns a Promise that resolves once the key has been removed
63
+ */
64
+ remove(key: string): Promise<void>;
65
+ /**
66
+ * Remove every key/value pair from the store.
67
+ *
68
+ * @returns a Promise that resolves once the store has been emptied
69
+ */
70
+ clear(): Promise<void>;
71
+ /**
72
+ * List every key currently present in the store.
73
+ *
74
+ * @returns an array of all stored keys
75
+ */
76
+ keys(): Promise<string[]>;
77
+ static ɵfac: i0.ɵɵFactoryDeclaration<KitStorageService, never>;
78
+ static ɵprov: i0.ɵɵInjectableDeclaration<KitStorageService>;
79
+ }
80
+
81
+ /**
82
+ * User-visible button labels consumed by `KitOverlayController`.
83
+ *
84
+ * @remarks
85
+ * The kit deliberately ships no i18n strings of its own and has no hard dependency on
86
+ * `@angular/localize`. The consuming application always provides these labels: multilingual apps
87
+ * pass `$localize`-resolved strings, single-language apps pass plain literals.
88
+ */
89
+ interface KitLabels {
90
+ /** Text for the "close" button used by alerts and toasts. */
91
+ readonly close: string;
92
+ /** Text for the "cancel" button used by confirmation alerts. */
93
+ readonly cancel: string;
94
+ }
95
+ /**
96
+ * Overlay configuration injected via `provideKitOverlay()`.
97
+ *
98
+ * @remarks
99
+ * All fields are required; the consuming application must supply a complete configuration.
100
+ */
101
+ interface KitOverlayConfig {
102
+ /** Button labels used across the overlays presented by `KitOverlayController`. */
103
+ readonly labels: KitLabels;
104
+ }
105
+ /**
106
+ * Injection token carrying the {@link KitOverlayConfig} for `KitOverlayController`.
107
+ *
108
+ * @remarks
109
+ * Provide it through {@link provideKitOverlay} rather than registering it directly.
110
+ */
111
+ declare const KIT_OVERLAY_CONFIG: InjectionToken<KitOverlayConfig>;
112
+ /**
113
+ * Wire `KitOverlayController` into the application by providing its button labels.
114
+ *
115
+ * @param config - overlay configuration, including the button labels to inject
116
+ * @returns environment providers to add to the application's provider list
117
+ * @example
118
+ * ```ts
119
+ * bootstrapApplication(AppComponent, {
120
+ * providers: [
121
+ * provideKitOverlay({ labels: { close: $localize`Close`, cancel: $localize`Cancel` } }),
122
+ * ],
123
+ * });
124
+ * ```
125
+ */
126
+ declare const provideKitOverlay: (config: KitOverlayConfig) => EnvironmentProviders;
127
+
128
+ /**
129
+ * Options for {@link KitOverlayController.presentModal}.
130
+ *
131
+ * @remarks
132
+ * Extends Ionic's `ModalOptions` but omits `component` and `componentProps`, which are passed as
133
+ * dedicated arguments instead.
134
+ */
135
+ interface KitModalPresentOptions extends Omit<ModalOptions, 'component' | 'componentProps'> {
136
+ /**
137
+ * When `true`, expand the sheet to its maximum breakpoint while the native keyboard is shown.
138
+ *
139
+ * @remarks
140
+ * Only has an effect on native platforms; ignored on the web.
141
+ */
142
+ watchKeyboard?: boolean;
143
+ }
144
+ /**
145
+ * Options for {@link KitOverlayController.alertClose}.
146
+ */
147
+ interface KitAlertCloseOptions {
148
+ /** Alert header text. */
149
+ header: string;
150
+ /** Alert body message. */
151
+ message: string;
152
+ /** Optional alert sub-header text shown beneath the header. */
153
+ subHeader?: string;
154
+ }
155
+ /**
156
+ * Options for {@link KitOverlayController.alertConfirm}.
157
+ *
158
+ * @remarks
159
+ * Extends {@link KitAlertCloseOptions} with the confirm-button text.
160
+ */
161
+ interface KitAlertConfirmOptions extends KitAlertCloseOptions {
162
+ /**
163
+ * Text for the OK (confirm) button.
164
+ *
165
+ * @remarks
166
+ * Action-specific, so it is supplied by the caller rather than taken from the shared labels.
167
+ */
168
+ okText: string;
169
+ }
170
+ /**
171
+ * Ergonomic wrapper that consolidates Ionic's overlay controllers (Modal / Toast / Alert).
172
+ *
173
+ * @remarks
174
+ * Folds the repetitive create → present → onDidDismiss sequence into single calls and returns the
175
+ * relevant result directly. It holds no application-specific policy such as navigation; compose
176
+ * those concerns on the consuming side.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * constructor(private readonly overlay: KitOverlayController) {}
181
+ *
182
+ * async edit(): Promise<void> {
183
+ * const result = await this.overlay.presentModal<EditResult>(EditPage, { id: 1 });
184
+ * if (result) {
185
+ * await this.overlay.presentToast({ message: 'Saved' });
186
+ * }
187
+ * }
188
+ * ```
189
+ */
190
+ declare class KitOverlayController {
191
+ #private;
192
+ /**
193
+ * Present a modal and resolve with the data passed to its dismissal.
194
+ *
195
+ * @typeParam O - type of the data returned when the modal is dismissed
196
+ * @param component - the component to render inside the modal
197
+ * @param componentProps - props to pass to the modal component
198
+ * @param options - additional modal options, including {@link KitModalPresentOptions.watchKeyboard}
199
+ * @returns the dismiss data, or `undefined` when the modal is dismissed without data
200
+ * @example
201
+ * ```ts
202
+ * const data = await overlay.presentModal<{ saved: boolean }>(EditPage, { id: 1 }, { watchKeyboard: true });
203
+ * ```
204
+ */
205
+ presentModal<O = unknown>(component: ModalOptions['component'], componentProps?: ModalOptions['componentProps'], options?: KitModalPresentOptions): Promise<O | undefined>;
206
+ /**
207
+ * Present a toast using kit defaults that the caller may override.
208
+ *
209
+ * @remarks
210
+ * Defaults to a top position, a 2000ms duration, a vertical swipe gesture, and a close button
211
+ * from the configured labels; any of these can be overridden via `options`. Presenting a toast
212
+ * also triggers light native haptic feedback as an intentional kit UX choice.
213
+ *
214
+ * @param options - Ionic toast options that override the kit defaults
215
+ * @returns the presented toast element
216
+ * @example
217
+ * ```ts
218
+ * await overlay.presentToast({ message: 'Copied to clipboard' });
219
+ * ```
220
+ */
221
+ presentToast(options: ToastOptions): Promise<HTMLIonToastElement>;
222
+ /**
223
+ * Present a notification alert with a single "close" button and wait for it to be dismissed.
224
+ *
225
+ * @param options - alert content (header, message, optional sub-header)
226
+ * @returns a Promise that resolves once the alert has been dismissed
227
+ * @example
228
+ * ```ts
229
+ * await overlay.alertClose({ header: 'Done', message: 'Your changes were saved.' });
230
+ * ```
231
+ */
232
+ alertClose(options: KitAlertCloseOptions): Promise<void>;
233
+ /**
234
+ * Present a confirmation alert with cancel and OK buttons.
235
+ *
236
+ * @param options - alert content plus the OK button text via {@link KitAlertConfirmOptions.okText}
237
+ * @returns `true` when the user presses OK, `false` otherwise (cancel or backdrop dismissal)
238
+ * @example
239
+ * ```ts
240
+ * const ok = await overlay.alertConfirm({
241
+ * header: 'Delete item?',
242
+ * message: 'This cannot be undone.',
243
+ * okText: 'Delete',
244
+ * });
245
+ * if (ok) {
246
+ * await remove();
247
+ * }
248
+ * ```
249
+ */
250
+ alertConfirm(options: KitAlertConfirmOptions): Promise<boolean>;
251
+ static ɵfac: i0.ɵɵFactoryDeclaration<KitOverlayController, never>;
252
+ static ɵprov: i0.ɵɵInjectableDeclaration<KitOverlayController>;
253
+ }
254
+
255
+ /**
256
+ * Content for {@link KitReloadAlertController.present}.
257
+ */
258
+ interface KitReloadAlertOptions {
259
+ /** Alert header text. */
260
+ header: string;
261
+ /** Alert body message. */
262
+ message: string;
263
+ /**
264
+ * Text for the reload (confirm) button, e.g. "リフレッシュ".
265
+ *
266
+ * @remarks
267
+ * Action-specific, so it is supplied by the caller rather than taken from the shared labels.
268
+ * The cancel button uses the configured {@link KitLabels.cancel}.
269
+ */
270
+ okText: string;
271
+ }
272
+ /**
273
+ * The fleet's canonical "network error → offer to reload" alert, as a stateful controller.
274
+ *
275
+ * @remarks
276
+ * Consolidates the good-UX variant that had drifted across the fleet into one behavior:
277
+ *
278
+ * - **De-dup** — never stacks; a second {@link present} while an alert is already shown is a no-op.
279
+ * - **Backdrop lock** — `backdropDismiss: false`, so a critical network error can't be dismissed by
280
+ * an accidental backdrop tap; the user consciously chooses cancel or reload.
281
+ * - **Auto-dismiss on reconnect** — the presented alert is tracked, so {@link dismiss} (called from a
282
+ * later successful response) clears a now-stale error alert instead of leaving it on screen.
283
+ * - **Reload on confirm** — the confirm button calls `location.reload()`.
284
+ *
285
+ * All user-facing text is supplied by the caller so the kit stays free of any hardcoded i18n; the
286
+ * cancel button reuses {@link KitOverlayConfig.labels}. Because it performs navigation
287
+ * (`location.reload()`) and holds state, it is a dedicated controller rather than part of
288
+ * {@link KitOverlayController}, which stays free of navigation policy.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * // In an HTTP interceptor:
293
+ * const reload = inject(KitReloadAlertController);
294
+ * // ...on a network-class error while connected:
295
+ * await reload.present({ header: 'ネットワークエラー', message: `…(${status})`, okText: 'リフレッシュ' });
296
+ * // ...on any later successful response:
297
+ * await reload.dismiss();
298
+ * ```
299
+ */
300
+ declare class KitReloadAlertController {
301
+ #private;
302
+ /**
303
+ * Present the reload alert, unless one is already on screen.
304
+ *
305
+ * @param options - alert content plus the reload-button text
306
+ * @returns a Promise that resolves once the alert has been presented (or immediately if suppressed)
307
+ */
308
+ present(options: KitReloadAlertOptions): Promise<void>;
309
+ /**
310
+ * Dismiss the tracked reload alert if one is showing.
311
+ *
312
+ * @remarks
313
+ * Typically called from a later successful response so a stale "network error" alert clears once
314
+ * connectivity is restored. A no-op when nothing is showing.
315
+ *
316
+ * @returns a Promise that resolves once the alert has been dismissed (or immediately if none)
317
+ */
318
+ dismiss(): Promise<void>;
319
+ static ɵfac: i0.ɵɵFactoryDeclaration<KitReloadAlertController, never>;
320
+ static ɵprov: i0.ɵɵInjectableDeclaration<KitReloadAlertController>;
321
+ }
322
+
323
+ /**
324
+ * Work around iOS `ion-input` autofill values not propagating to the Angular form model.
325
+ *
326
+ * On iOS, when the browser autofills an `ion-input` (for example a saved password), the value
327
+ * is written to the underlying native `<input>` element but the corresponding `change` event is
328
+ * not forwarded to the host `ion-input`, so the Angular form control (and `ngModel`) never sees
329
+ * the autofilled value. This directive listens for the first `change` event on the inner input
330
+ * element and mirrors its value back onto the host element, restoring two-way binding.
331
+ *
332
+ * Apply it to any `ion-input` that participates in a form and may be autofilled by attaching the
333
+ * `rdlaboAutofill` attribute.
334
+ *
335
+ * @remarks
336
+ * The directive is a no-op on every platform other than iOS, where the value already propagates
337
+ * correctly. A short timeout is used because `ion-input` creates its inner `<input>` element
338
+ * asynchronously after the host element is initialized.
339
+ *
340
+ * @example
341
+ * ```html
342
+ * <ion-input rdlaboAutofill type="password" [(ngModel)]="password"></ion-input>
343
+ * ```
344
+ */
345
+ declare class KitAutofillDirective implements OnInit {
346
+ #private;
347
+ constructor();
348
+ /**
349
+ * Register the iOS autofill workaround once the directive is initialized.
350
+ *
351
+ * Returns immediately on non-iOS platforms. On iOS, after a short delay it attaches a one-shot,
352
+ * passive `change` listener to the inner `<input>` element that `ion-input` renders, copying the
353
+ * autofilled value back onto the host element so the Angular form model stays in sync. Any error
354
+ * while locating the inner input (for example if the element is not yet present) is swallowed.
355
+ *
356
+ * @returns Nothing.
357
+ */
358
+ ngOnInit(): void;
359
+ static ɵfac: i0.ɵɵFactoryDeclaration<KitAutofillDirective, never>;
360
+ static ɵdir: i0.ɵɵDirectiveDeclaration<KitAutofillDirective, "[rdlaboAutofill]", never, {}, {}, never, never, true, never>;
361
+ }
362
+
363
+ /**
364
+ * Discriminated set of authentication states the guards react to.
365
+ *
366
+ * @remarks
367
+ * The application is responsible for emitting these values through {@link KitAuthConfig.authState}.
368
+ * An application that does not use a value (for example email confirmation) simply never emits it.
369
+ *
370
+ * - `user` — fully authenticated and verified.
371
+ * - `confirm` — awaiting email confirmation.
372
+ * - `required` — not authenticated.
373
+ * - `anonymous` — signed in anonymously; the user can still be guided toward full registration.
374
+ */
375
+ type KitAuthState = 'user' | 'confirm' | 'required' | 'anonymous';
376
+ /**
377
+ * Redirect targets (route paths) used by the guards when access is denied.
378
+ *
379
+ * @remarks
380
+ * Every field is required and must be provided per application, because the guards have no
381
+ * knowledge of the host application's route layout.
382
+ */
383
+ interface KitAuthRedirects {
384
+ /** Used by {@link kitRequiredUnauthorizedGuard}: where to navigate when the user is already authenticated (`user`). */
385
+ readonly whenAuthorized: string;
386
+ /** Used by {@link kitRequiredUnauthorizedGuard}: where to navigate when the user is awaiting email confirmation (`confirm`). */
387
+ readonly whenConfirming: string;
388
+ /** Used by {@link kitRequireConfirmingGuard}: where to navigate when the state is not `confirm`. */
389
+ readonly whenNotConfirming: string;
390
+ /** Used by {@link kitRequireAuthorizedGuard}: where to navigate when the state is not `user` and the fallback is not allowed. */
391
+ readonly whenUnauthorized: string;
392
+ }
393
+ /**
394
+ * Configuration consumed by the authentication guards, injected through {@link provideKitAuth}.
395
+ *
396
+ * @remarks
397
+ * All members are required. The hooks let the host application plug its own auth service and
398
+ * navigation policy into the otherwise fixed guard control flow.
399
+ */
400
+ interface KitAuthConfig {
401
+ /**
402
+ * Source of the current authentication state.
403
+ *
404
+ * @remarks
405
+ * Typically backed by the application's own auth service (for example `AuthService.isAuth()`).
406
+ *
407
+ * @returns A stream of {@link KitAuthState} values.
408
+ */
409
+ authState(): Observable<KitAuthState>;
410
+ /**
411
+ * Application-specific work that runs in {@link kitRequireAuthorizedGuard} after the state is confirmed to be `user`.
412
+ *
413
+ * @remarks
414
+ * Typical responsibilities include token login, permission checks, terms-of-service acceptance,
415
+ * or restoring a previously requested redirect.
416
+ *
417
+ * @param state - The router state snapshot of the route being activated.
418
+ * @returns `true` to allow activation, or a `UrlTree` to perform a custom redirect.
419
+ */
420
+ onAuthorized(state: RouterStateSnapshot): Promise<boolean | UrlTree>;
421
+ /**
422
+ * Fallback that runs in {@link kitRequireAuthorizedGuard} when the state is `required` (not authenticated).
423
+ *
424
+ * @remarks
425
+ * For example, attempt an anonymous sign-in and allow the route. Applications that do not need
426
+ * this should pass `async () => false` to fall through to the default redirect.
427
+ *
428
+ * @param state - The router state snapshot of the route being activated.
429
+ * @returns `true` to allow activation, a `UrlTree` for a custom redirect, or `false` to use the default redirect.
430
+ */
431
+ onUnauthenticated(state: RouterStateSnapshot): Promise<boolean | UrlTree>;
432
+ /** Redirect targets used by the guards. */
433
+ redirects: KitAuthRedirects;
434
+ }
435
+ /**
436
+ * Injection token that carries the {@link KitAuthConfig} to the authentication guards.
437
+ */
438
+ declare const KIT_AUTH_CONFIG: InjectionToken<KitAuthConfig>;
439
+ /**
440
+ * Wire the authentication guard configuration into the application's dependency injection.
441
+ *
442
+ * @remarks
443
+ * The factory runs inside an injection context, so it may call `inject()` (for example
444
+ * `inject(AuthService)`) to build the configuration.
445
+ *
446
+ * @param configFactory - Factory that returns the {@link KitAuthConfig} for the application.
447
+ * @returns Environment providers to add to the application bootstrap.
448
+ *
449
+ * @example
450
+ * ```ts
451
+ * provideKitAuth(() => {
452
+ * const auth = inject(AuthService);
453
+ * return {
454
+ * authState: () => auth.isAuth(),
455
+ * onAuthorized: async () => true,
456
+ * onUnauthenticated: async () => false,
457
+ * redirects: {
458
+ * whenAuthorized: '/',
459
+ * whenConfirming: '/auth/confirm',
460
+ * whenNotConfirming: '/auth/signin',
461
+ * whenUnauthorized: 'auth',
462
+ * },
463
+ * };
464
+ * });
465
+ * ```
466
+ */
467
+ declare const provideKitAuth: (configFactory: () => KitAuthConfig) => EnvironmentProviders;
468
+ /**
469
+ * Guard that requires the user to be unauthenticated (for example sign-in or sign-up pages).
470
+ *
471
+ * @remarks
472
+ * Allows the `required` and `anonymous` states (an anonymous user is permitted to proceed to a
473
+ * registration page). An authenticated user (`user`) is sent to `whenAuthorized`, and a user
474
+ * awaiting confirmation (`confirm`) is sent to `whenConfirming`.
475
+ *
476
+ * @returns A stream emitting `true` to allow activation, or `false` after triggering a redirect.
477
+ *
478
+ * @example
479
+ * ```ts
480
+ * const routes: Routes = [{ path: 'signin', component: SigninPage, canActivate: [kitRequiredUnauthorizedGuard] }];
481
+ * ```
482
+ */
483
+ declare const kitRequiredUnauthorizedGuard: CanActivateFn;
484
+ /**
485
+ * Guard that requires the user to be awaiting email confirmation (`confirm`).
486
+ *
487
+ * @remarks
488
+ * Any other state triggers a redirect: an `anonymous` user is sent to the authenticated area
489
+ * (`whenAuthorized`), and every remaining state is sent to `whenNotConfirming`.
490
+ *
491
+ * @returns A stream emitting `true` to allow activation, or `false` after triggering a redirect.
492
+ *
493
+ * @example
494
+ * ```ts
495
+ * const routes: Routes = [{ path: 'confirm', component: ConfirmPage, canActivate: [kitRequireConfirmingGuard] }];
496
+ * ```
497
+ */
498
+ declare const kitRequireConfirmingGuard: CanActivateFn;
499
+ /**
500
+ * Guard that requires the user to be fully authenticated (`user`).
501
+ *
502
+ * @remarks
503
+ * - `user` — runs {@link KitAuthConfig.onAuthorized} (token login, permission checks, and so on).
504
+ * - `anonymous` — allowed as-is, for applications that permit anonymous browsing.
505
+ * - `required` / `confirm` — runs {@link KitAuthConfig.onUnauthenticated}; if it resolves to `false`,
506
+ * the user is redirected to `whenUnauthorized`.
507
+ *
508
+ * @param _route - The activated route snapshot (unused).
509
+ * @param state - The router state snapshot, forwarded to the configuration hooks.
510
+ * @returns A stream emitting the activation result: `true`, a `UrlTree`, or `false` after a redirect.
511
+ *
512
+ * @example
513
+ * ```ts
514
+ * const routes: Routes = [{ path: 'home', component: HomePage, canActivate: [kitRequireAuthorizedGuard] }];
515
+ * ```
516
+ */
517
+ declare const kitRequireAuthorizedGuard: CanActivateFn;
518
+
519
+ /**
520
+ * Configuration that customizes the behavior of {@link kitAuthInterceptor}, injected through {@link provideKitHttp}.
521
+ *
522
+ * @remarks
523
+ * The interceptor fixes the retry policy (up to 2 retries with a linearly increasing backoff, plus immediate
524
+ * throw on `401` and on every {@link NON_RETRYABLE_STATUSES | non-retryable status}) and the overall
525
+ * control flow. Only the hooks below are application-specific.
526
+ *
527
+ * Only {@link KitHttpConfig.getAuthHeaders} is required — it has no safe default. Every other hook is
528
+ * optional and defaults to a no-op (or `{}` / `false` / `null` as appropriate), so an app configures
529
+ * only the behavior that actually differs from the canonical baseline.
530
+ */
531
+ interface KitHttpConfig {
532
+ /**
533
+ * Produce authentication and metadata headers for the outgoing request.
534
+ *
535
+ * @param request - The outgoing request about to be sent.
536
+ * @returns A map of header names to values, resolved asynchronously.
537
+ */
538
+ getAuthHeaders(request: HttpRequest<unknown>): Promise<Record<string, string>>;
539
+ /**
540
+ * Produce additional headers for the outgoing request.
541
+ *
542
+ * @remarks
543
+ * Optional; defaults to adding no extra headers.
544
+ *
545
+ * @param request - The outgoing request about to be sent.
546
+ * @returns A map of header names to values; return `{}` when none are needed.
547
+ */
548
+ buildExtraHeaders?(request: HttpRequest<unknown>): Record<string, string>;
549
+ /**
550
+ * Called for every successful response that completed an actual network round trip.
551
+ *
552
+ * @remarks
553
+ * Responses synthesized by {@link KitHttpConfig.offlineFallback} are produced after `catchError`
554
+ * and therefore never reach this hook, so it observes genuine successes only. A typical use is to
555
+ * reset an "offline" flag once connectivity is restored. Optional; defaults to a no-op.
556
+ *
557
+ * @param event - The successful `HttpResponse`.
558
+ */
559
+ onResponse?(event: HttpResponse<unknown>): void;
560
+ /**
561
+ * Decide whether to pass the request straight through, skipping auth, retry, and error handling.
562
+ *
563
+ * @remarks
564
+ * Useful for external URLs such as S3 or a CDN. Optional; defaults to `false` (never bypass).
565
+ *
566
+ * @param request - The outgoing request.
567
+ * @returns `true` to bypass the interceptor pipeline.
568
+ */
569
+ bypass?(request: HttpRequest<unknown>): boolean;
570
+ /**
571
+ * Provide an offline short-circuit when a request fails.
572
+ *
573
+ * @remarks
574
+ * Returning a non-null observable replaces the error with that response (for example a queued
575
+ * offline result). Optional; defaults to `null` (no fallback, normal error handling proceeds).
576
+ *
577
+ * @param request - The request that failed (after headers were applied).
578
+ * @param error - The error response that triggered the fallback.
579
+ * @returns A replacement event stream, or `null` for no fallback.
580
+ */
581
+ offlineFallback?(request: HttpRequest<unknown>, error: HttpErrorResponse): Observable<HttpEvent<unknown>> | null;
582
+ /**
583
+ * Side effect to run on a `401` response (for example an expired token).
584
+ *
585
+ * @remarks
586
+ * Optional; defaults to a no-op.
587
+ *
588
+ * @param request - The request that received the `401`.
589
+ */
590
+ onUnauthorized?(request: HttpRequest<unknown>): void;
591
+ /**
592
+ * Side effect to run on a `403` response (a permission error).
593
+ *
594
+ * @remarks
595
+ * Optional; defaults to a no-op.
596
+ *
597
+ * @param request - The request that received the `403`.
598
+ */
599
+ onForbidden?(request: HttpRequest<unknown>): void;
600
+ /**
601
+ * UX hook for network-originated errors while the device is connected.
602
+ *
603
+ * @remarks
604
+ * Optional; defaults to a no-op. The kit ships {@link KitReloadAlertController} as the fleet's
605
+ * canonical implementation of this hook (with auto-dismiss on reconnect via `onResponse`).
606
+ *
607
+ * @param status - The HTTP status code, or a string descriptor for non-HTTP failures.
608
+ * @returns Optionally a promise to await before continuing.
609
+ */
610
+ onNetworkError?(status: number | string): Promise<void> | void;
611
+ /**
612
+ * UX hook for `400` / `500` responses that carry a server-provided message.
613
+ *
614
+ * @remarks
615
+ * Optional; defaults to a no-op.
616
+ *
617
+ * @param message - The message extracted from the error body.
618
+ */
619
+ onServerError?(message: string): void;
620
+ }
621
+ /**
622
+ * Injection token that carries the {@link KitHttpConfig} to {@link kitAuthInterceptor}.
623
+ */
624
+ declare const KIT_HTTP_CONFIG: InjectionToken<KitHttpConfig>;
625
+ /**
626
+ * Wire the {@link kitAuthInterceptor} configuration into the application's dependency injection.
627
+ *
628
+ * @remarks
629
+ * Register the interceptor itself separately via `provideHttpClient(withInterceptors([kitAuthInterceptor]))`.
630
+ * The factory runs inside an injection context, so it may call `inject()`.
631
+ *
632
+ * @param configFactory - Factory that returns the {@link KitHttpConfig} for the application.
633
+ * @returns Environment providers to add to the application bootstrap.
634
+ *
635
+ * @example
636
+ * ```ts
637
+ * bootstrapApplication(AppComponent, {
638
+ * providers: [
639
+ * provideHttpClient(withInterceptors([kitAuthInterceptor])),
640
+ * provideKitHttp(() => {
641
+ * const auth = inject(AuthService);
642
+ * const reload = inject(KitReloadAlertController);
643
+ * return {
644
+ * // Only getAuthHeaders is required; every other hook is optional and defaults to a no-op.
645
+ * getAuthHeaders: async () => ({ Authorization: `Bearer ${await auth.token()}` }),
646
+ * onUnauthorized: () => auth.signOut(),
647
+ * onNetworkError: (status) =>
648
+ * reload.present({ header: 'Network error', message: `Reload? (${status})`, okText: 'Reload' }),
649
+ * onResponse: () => void reload.dismiss(),
650
+ * };
651
+ * }),
652
+ * ],
653
+ * });
654
+ * ```
655
+ */
656
+ declare const provideKitHttp: (configFactory: () => KitHttpConfig) => EnvironmentProviders;
657
+ /**
658
+ * Canonical functional HTTP interceptor that applies authentication, retries, and error handling.
659
+ *
660
+ * @remarks
661
+ * Behavior, driven by the injected {@link KitHttpConfig}:
662
+ *
663
+ * 1. Requests for which `bypass` returns `true` are forwarded untouched.
664
+ * 2. Otherwise the headers from `getAuthHeaders` and `buildExtraHeaders` are merged onto a cloned request.
665
+ * 3. Failed requests are retried up to 2 times with a linearly increasing backoff of `500ms * (retryCount + 5)`,
666
+ * except that `401` and any {@link NON_RETRYABLE_STATUSES | non-retryable status}
667
+ * (`400`, `403`, `404`, `418`, `500`, `502`) are thrown immediately without retrying.
668
+ * 4. On error, `offlineFallback` is consulted first; otherwise `401` calls `onUnauthorized`, `403`
669
+ * calls `onForbidden`, network-class failures (anything other than `400`/`500`) call
670
+ * `onNetworkError` when the device is connected, and `400`/`500` responses carrying a body
671
+ * message call `onServerError`.
672
+ *
673
+ * @param request - The outgoing request.
674
+ * @param next - The next handler in the interceptor chain.
675
+ * @returns A stream of HTTP events for the (possibly modified, retried, or replaced) request.
676
+ *
677
+ * @example
678
+ * ```ts
679
+ * provideHttpClient(withInterceptors([kitAuthInterceptor]));
680
+ * ```
681
+ */
682
+ declare const kitAuthInterceptor: HttpInterceptorFn;
683
+
684
+ /**
685
+ * Trigger native haptic impact feedback.
686
+ *
687
+ * Delegates to `@capacitor/haptics` `Haptics.impact()` when running on a native platform. On the
688
+ * web (or any non-native platform) it is a no-op and resolves without doing anything.
689
+ *
690
+ * @remarks
691
+ * This haptic side effect was previously bundled implicitly into toast/modal presentation. It has
692
+ * been decoupled into this explicit function so callers opt in to the feedback deliberately, rather
693
+ * than receiving it as a hidden side effect of presenting UI.
694
+ *
695
+ * @param style - The impact intensity to play. Defaults to {@link ImpactStyle.Light}.
696
+ * @returns A promise that resolves once the feedback has been requested (immediately on the web).
697
+ * @example
698
+ * ```ts
699
+ * import { ImpactStyle } from '@capacitor/haptics';
700
+ *
701
+ * // Light tap (default)
702
+ * await kitImpact();
703
+ *
704
+ * // Stronger feedback, e.g. on a confirming action
705
+ * await kitImpact(ImpactStyle.Heavy);
706
+ * ```
707
+ */
708
+ declare const kitImpact: (style?: ImpactStyle) => Promise<void>;
709
+
710
+ /**
711
+ * Merge a newly fetched page of items into an existing list by id, keeping the result sorted.
712
+ *
713
+ * Items are merged by the numeric `key` field. On a duplicate `key` the item from `arrayNew` wins
714
+ * and replaces the one in `arrayOld`. Old items whose `key` falls *inside* the window spanned by
715
+ * `arrayNew` (between its first and last `key`) are dropped, since the freshly fetched page is the
716
+ * authoritative copy of that window; old items *outside* the window are kept. The merged items are
717
+ * finally sorted by `key`, ascending or descending according to `order`.
718
+ *
719
+ * The algorithm is:
720
+ * 1. If both inputs are empty, return an empty array.
721
+ * 2. Read the first (`lead`) and last (`last`) `key` values of `arrayNew` as the bounds of the
722
+ * page's window. Keep the old items whose `key` lies *outside* that window (at or beyond the
723
+ * extremes) and drop those strictly inside it, handling both a high-to-low page (`lead > last`)
724
+ * and a low-to-high page (`lead < last`). A single-value page (`lead === last`) keeps all old items.
725
+ * 3. Remove old items whose `key` already exists in `arrayNew` (new wins on duplicates).
726
+ * 4. Concatenate `arrayNew` with the surviving old items and sort by `key` in the requested
727
+ * direction.
728
+ *
729
+ * @remarks
730
+ * Designed for infinite-scroll / paginated list merging, where each fetched page may overlap the
731
+ * previously held items and the server returns a contiguous, ordered window of records. The `key`
732
+ * field is treated as a number for range comparison and sorting.
733
+ *
734
+ * @typeParam T - Element type of both arrays. Its `key` property must be a numeric value.
735
+ * @param arrayOld - The previously accumulated list. May be empty or nullish-safe (empty when falsy).
736
+ * @param arrayNew - The newly fetched page of items; its `key` range defines the window that its own
737
+ * items replace, and its items take precedence on duplicates.
738
+ * @param key - The property of `T` used as the unique, numeric id for matching, range filtering, and sorting.
739
+ * @param order - Sort direction by `key`: `'ASC'` for ascending or `'DESC'` for descending. Defaults to `'DESC'`.
740
+ * @returns A new array containing `arrayNew` merged with the out-of-window, non-duplicate old items, sorted by `key`.
741
+ * @example
742
+ * ```ts
743
+ * interface Post {
744
+ * id: number;
745
+ * title: string;
746
+ * }
747
+ *
748
+ * const loaded: Post[] = [
749
+ * { id: 30, title: 'c' },
750
+ * { id: 20, title: 'b' },
751
+ * { id: 10, title: 'a' },
752
+ * ];
753
+ * const nextPage: Post[] = [
754
+ * { id: 20, title: 'b (updated)' },
755
+ * { id: 15, title: 'a.5' },
756
+ * ];
757
+ *
758
+ * // Descending merge: id 30 lies above the new page's [15, 20] window so it is kept; id 20 is
759
+ * // inside the window and is replaced by the new value; id 10 lies below the window and is kept.
760
+ * const merged = arrayConcatById(loaded, nextPage, 'id', 'DESC');
761
+ * // => [{ id: 30, title: 'c' }, { id: 20, title: 'b (updated)' }, { id: 15, title: 'a.5' }, { id: 10, title: 'a' }]
762
+ * ```
763
+ */
764
+ declare const arrayConcatById: <T>(arrayOld: T[], arrayNew: T[], key: keyof T, order?: "ASC" | "DESC") => T[];
765
+
766
+ export { KIT_AUTH_CONFIG, KIT_HTTP_CONFIG, KIT_OVERLAY_CONFIG, KitAutofillDirective, KitOverlayController, KitReloadAlertController, KitStorageService, arrayConcatById, kitAuthInterceptor, kitImpact, kitRequireAuthorizedGuard, kitRequireConfirmingGuard, kitRequiredUnauthorizedGuard, provideKitAuth, provideKitHttp, provideKitOverlay };
767
+ export type { KitAlertCloseOptions, KitAlertConfirmOptions, KitAuthConfig, KitAuthRedirects, KitAuthState, KitHttpConfig, KitLabels, KitModalPresentOptions, KitOverlayConfig, KitReloadAlertOptions };