tempest-react-sdk 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/bin/lib/openapi/generate.mjs +339 -0
- package/bin/lib/openapi/generate.pagination.test.mjs +86 -0
- package/bin/lib/openapi/generate.test.mjs +129 -0
- package/bin/lib/openapi/load.mjs +24 -0
- package/bin/lib/openapi/schema-to-zod.mjs +123 -0
- package/bin/lib/openapi/schema-to-zod.test.mjs +81 -0
- package/bin/tempest.mjs +84 -2
- package/dist/sw.cjs +1 -1
- package/dist/sw.cjs.map +1 -1
- package/dist/sw.d.ts +130 -0
- package/dist/sw.js +327 -61
- package/dist/sw.js.map +1 -1
- package/dist/tempest-react-sdk.cjs +3 -3
- package/dist/tempest-react-sdk.cjs.map +1 -1
- package/dist/tempest-react-sdk.d.ts +488 -1
- package/dist/tempest-react-sdk.js +2752 -2558
- package/dist/tempest-react-sdk.js.map +1 -1
- package/dist/vite.cjs +3 -1
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.ts +136 -0
- package/dist/vite.js +253 -34
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/template-pwa/index.html +1 -1
- package/template-pwa/package.json +3 -0
- package/template-pwa/public/manifest.webmanifest +6 -6
- package/template-pwa/src/main.tsx +17 -24
- package/template-pwa/src/sw.ts +44 -9
- package/template-pwa/vite.config.ts +21 -0
- package/template-pwa/public/icon-maskable.svg +0 -4
|
@@ -28,6 +28,7 @@ import { ForwardRefExoticComponent } from 'react';
|
|
|
28
28
|
import { HashRouter } from 'react-router-dom';
|
|
29
29
|
import { HTMLAttributes } from 'react';
|
|
30
30
|
import { ImgHTMLAttributes } from 'react';
|
|
31
|
+
import { InfiniteData } from '@tanstack/react-query';
|
|
31
32
|
import { InputEventHandler } from 'react';
|
|
32
33
|
import { InputHTMLAttributes } from 'react';
|
|
33
34
|
import { JSX } from 'react/jsx-runtime';
|
|
@@ -47,6 +48,7 @@ import { Path } from 'react-hook-form';
|
|
|
47
48
|
import { PersistOptions } from 'zustand/middleware';
|
|
48
49
|
import { PointerEventHandler } from 'react';
|
|
49
50
|
import { QueryClient } from '@tanstack/react-query';
|
|
51
|
+
import { QueryKey } from '@tanstack/react-query';
|
|
50
52
|
import { ReactElement } from 'react';
|
|
51
53
|
import { ReactEventHandler } from 'react';
|
|
52
54
|
import { ReactNode } from 'react';
|
|
@@ -77,10 +79,12 @@ import { UseFormProps } from 'react-hook-form';
|
|
|
77
79
|
import { UseFormRegister } from 'react-hook-form';
|
|
78
80
|
import { UseFormReturn } from 'react-hook-form';
|
|
79
81
|
import { useFormState } from 'react-hook-form';
|
|
82
|
+
import { UseInfiniteQueryOptions } from '@tanstack/react-query';
|
|
80
83
|
import { useLocation } from 'react-router-dom';
|
|
81
84
|
import { useMatch } from 'react-router-dom';
|
|
82
85
|
import { useNavigate } from 'react-router-dom';
|
|
83
86
|
import { useParams } from 'react-router-dom';
|
|
87
|
+
import { UseQueryOptions } from '@tanstack/react-query';
|
|
84
88
|
import { useRouteError } from 'react-router-dom';
|
|
85
89
|
import { useSearchParams } from 'react-router-dom';
|
|
86
90
|
import { useWatch } from 'react-hook-form';
|
|
@@ -157,6 +161,12 @@ export declare interface ApiClientConfig {
|
|
|
157
161
|
baseURL: string;
|
|
158
162
|
/** Returns the current bearer token (or null/undefined). Called per request. */
|
|
159
163
|
getToken?: () => string | null | undefined;
|
|
164
|
+
/**
|
|
165
|
+
* Per-request correlation id sent as the `X-Request-ID` header, matching the
|
|
166
|
+
* Tempest FastAPI SDK `RequestIDMiddleware`. Defaults to a generated id.
|
|
167
|
+
* Return an empty string to disable the header.
|
|
168
|
+
*/
|
|
169
|
+
requestId?: () => string;
|
|
160
170
|
/** Called on 401 responses. Use it to logout the user or trigger a refresh. */
|
|
161
171
|
onUnauthorized?: (response: Response) => void | Promise<void>;
|
|
162
172
|
/**
|
|
@@ -173,8 +183,26 @@ export declare interface ApiClientConfig {
|
|
|
173
183
|
}
|
|
174
184
|
|
|
175
185
|
export declare interface ApiError {
|
|
186
|
+
/** HTTP status code (0 for network failures). */
|
|
176
187
|
status: number;
|
|
188
|
+
/** Human-readable message — the backend envelope's `detail` (or `message`). */
|
|
177
189
|
detail: string;
|
|
190
|
+
/**
|
|
191
|
+
* Programmatic error code from the Tempest FastAPI SDK envelope (`code`),
|
|
192
|
+
* e.g. `"EMAIL_TAKEN"`. Lets callers branch without parsing `detail`.
|
|
193
|
+
*/
|
|
194
|
+
code?: string;
|
|
195
|
+
/**
|
|
196
|
+
* Correlation id echoed from the backend envelope's `details.request_id`
|
|
197
|
+
* (or the `X-Request-ID` response header). Pair it with `createLogger`.
|
|
198
|
+
*/
|
|
199
|
+
requestId?: string;
|
|
200
|
+
/**
|
|
201
|
+
* Seconds to wait before retrying, parsed from the `Retry-After` response
|
|
202
|
+
* header (commonly on `429`/`503`). Honored by {@link retry}.
|
|
203
|
+
*/
|
|
204
|
+
retryAfter?: number;
|
|
205
|
+
/** The raw parsed error body, when available. */
|
|
178
206
|
body?: unknown;
|
|
179
207
|
}
|
|
180
208
|
|
|
@@ -558,6 +586,23 @@ export declare const BREAKPOINTS: Record<Breakpoint, number>;
|
|
|
558
586
|
|
|
559
587
|
export { BrowserRouter }
|
|
560
588
|
|
|
589
|
+
/**
|
|
590
|
+
* Parse an error body + response into the Tempest {@link ApiError} envelope.
|
|
591
|
+
*
|
|
592
|
+
* Reads `detail`/`message`, the programmatic `code`, and the correlation id
|
|
593
|
+
* from `details.request_id` (falling back to the `X-Request-ID` header, then
|
|
594
|
+
* the id the client sent).
|
|
595
|
+
*
|
|
596
|
+
* @param status - HTTP status code.
|
|
597
|
+
* @param body - The parsed error body (object, string, or null).
|
|
598
|
+
* @param headers - The response headers (for the `X-Request-ID` fallback).
|
|
599
|
+
* @param sentRequestId - The id the client sent on the request, if any.
|
|
600
|
+
* @returns A fully-populated `ApiError`.
|
|
601
|
+
*/
|
|
602
|
+
export declare function buildApiError(status: number, body: unknown, headers?: Headers | {
|
|
603
|
+
get(name: string): string | null;
|
|
604
|
+
}, sentRequestId?: string): ApiError;
|
|
605
|
+
|
|
561
606
|
/**
|
|
562
607
|
* Primary action button with variants, sizes and a loading state that
|
|
563
608
|
* preserves layout via an absolutely-positioned spinner.
|
|
@@ -1259,6 +1304,17 @@ export declare interface CreateLoggerOptions {
|
|
|
1259
1304
|
*/
|
|
1260
1305
|
export declare function createOfflineStore<TItem, TKey extends string | number = string>(config: OfflineStoreConfig<TItem>): OfflineStore<TItem, TKey>;
|
|
1261
1306
|
|
|
1307
|
+
/**
|
|
1308
|
+
* Build a `206 Partial Content` response from a full one for an HTTP `Range`
|
|
1309
|
+
* request. Supports `bytes=start-end`, open-ended `bytes=start-` and suffix
|
|
1310
|
+
* `bytes=-suffixLength`. Returns the original response when there is no usable
|
|
1311
|
+
* `Range` header, or a `416` when the range is unsatisfiable.
|
|
1312
|
+
*
|
|
1313
|
+
* @param request The incoming request (its `Range` header drives the slice).
|
|
1314
|
+
* @param response The full (200) response to slice.
|
|
1315
|
+
*/
|
|
1316
|
+
export declare function createPartialResponse(request: Request, response: Response): Promise<Response>;
|
|
1317
|
+
|
|
1262
1318
|
/**
|
|
1263
1319
|
* Build a [[TelemetryAdapter]] backed by [`posthog-js`](https://posthog.com/docs/libraries/js).
|
|
1264
1320
|
* The PostHog client is supplied by the caller (not bundled).
|
|
@@ -1433,6 +1489,65 @@ export declare interface CreateStorePersistOptions<T> {
|
|
|
1433
1489
|
migrate?: PersistOptions<T, Partial<T>>["migrate"];
|
|
1434
1490
|
}
|
|
1435
1491
|
|
|
1492
|
+
/**
|
|
1493
|
+
* Turn-key auth preset wiring `createAuthStore` + `createRefreshQueue` +
|
|
1494
|
+
* `createApiClient` to the Tempest FastAPI SDK auth contract: login returns
|
|
1495
|
+
* `{ access_token, token_type }`, requests carry `Authorization: Bearer`, and a
|
|
1496
|
+
* `401` triggers a single deduplicated refresh + retry. Logout (or a failed
|
|
1497
|
+
* refresh) clears the session.
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* const auth = createTempestAuth<User, { email: string; password: string }>({
|
|
1501
|
+
* baseURL: import.meta.env.VITE_API_URL,
|
|
1502
|
+
* mePath: "/api/auth/me",
|
|
1503
|
+
* });
|
|
1504
|
+
*
|
|
1505
|
+
* await auth.login({ email, password }); // stores session, returns the user
|
|
1506
|
+
* const orders = await auth.api.get("/api/orders"); // sends the bearer token
|
|
1507
|
+
* auth.logout();
|
|
1508
|
+
*
|
|
1509
|
+
* @param options - The auth configuration.
|
|
1510
|
+
* @returns The store hook, a wired API client, and login/logout/refresh helpers.
|
|
1511
|
+
*/
|
|
1512
|
+
export declare function createTempestAuth<TUser, TCredentials = {
|
|
1513
|
+
email: string;
|
|
1514
|
+
password: string;
|
|
1515
|
+
}>(options: CreateTempestAuthOptions<TUser>): TempestAuth<TUser, TCredentials>;
|
|
1516
|
+
|
|
1517
|
+
export declare interface CreateTempestAuthOptions<TUser> {
|
|
1518
|
+
/** Base URL of the API. Required. */
|
|
1519
|
+
baseURL: string;
|
|
1520
|
+
/** Login route (`POST`). Default: `"/api/auth/login"`. */
|
|
1521
|
+
loginPath?: string;
|
|
1522
|
+
/** Refresh route (`POST`). Default: `"/api/auth/refresh"`. */
|
|
1523
|
+
refreshPath?: string;
|
|
1524
|
+
/** Optional current-user route (`GET`) called after login/refresh. */
|
|
1525
|
+
mePath?: string;
|
|
1526
|
+
/** Persist key for the store. Default: `"tempest-auth"`. */
|
|
1527
|
+
storeName?: string;
|
|
1528
|
+
/** Storage backend. Default: `"local"`. */
|
|
1529
|
+
storage?: "local" | "session";
|
|
1530
|
+
/** Send cookies (needed when the refresh token lives in an httpOnly cookie). */
|
|
1531
|
+
withCredentials?: boolean;
|
|
1532
|
+
/** Custom fetch implementation (testing / SSR). Defaults to `globalThis.fetch`. */
|
|
1533
|
+
fetcher?: typeof fetch;
|
|
1534
|
+
/**
|
|
1535
|
+
* Extract tokens from a login/refresh response. Default reads
|
|
1536
|
+
* `access_token` + `refresh_token`.
|
|
1537
|
+
*/
|
|
1538
|
+
parseTokens?: (data: unknown) => {
|
|
1539
|
+
token: string;
|
|
1540
|
+
refreshToken?: string;
|
|
1541
|
+
};
|
|
1542
|
+
/** Pull the user out of the login response, when the API embeds it. */
|
|
1543
|
+
parseUser?: (data: unknown) => TUser | null;
|
|
1544
|
+
/**
|
|
1545
|
+
* Build the refresh request body. Default sends `{ refresh_token }` when a
|
|
1546
|
+
* refresh token is stored, else `undefined` (cookie-based refresh).
|
|
1547
|
+
*/
|
|
1548
|
+
refreshBody?: (refreshToken: string | null) => unknown;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1436
1551
|
/**
|
|
1437
1552
|
* Open a WebSocket with automatic exponential-backoff reconnect, optional
|
|
1438
1553
|
* heartbeat pings, and typed JSON parsing.
|
|
@@ -1468,6 +1583,26 @@ export declare interface CreateWebSocketOptions<T> {
|
|
|
1468
1583
|
onStatusChange?: (status: WebSocketStatus) => void;
|
|
1469
1584
|
}
|
|
1470
1585
|
|
|
1586
|
+
/** Cursor-paginated response envelope (`CursorPaginationSchema[T]`). */
|
|
1587
|
+
export declare interface CursorPage<T> {
|
|
1588
|
+
/** The rows for this batch. */
|
|
1589
|
+
items: T[];
|
|
1590
|
+
/** Opaque cursor for the next batch, or null when exhausted. Pass it back verbatim. */
|
|
1591
|
+
next_cursor: string | null;
|
|
1592
|
+
/** Whether another batch exists. */
|
|
1593
|
+
has_more: boolean;
|
|
1594
|
+
/** Batch size used for this query. */
|
|
1595
|
+
limit: number;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
/** Cursor filter query params (`CursorPaginationFilterSchema`). */
|
|
1599
|
+
export declare interface CursorParams {
|
|
1600
|
+
cursor?: string | null;
|
|
1601
|
+
limit?: number;
|
|
1602
|
+
order_by?: string;
|
|
1603
|
+
ascending?: boolean;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1471
1606
|
/**
|
|
1472
1607
|
* Generic, typed list that renders a `<ul>` with one `<li>` per item.
|
|
1473
1608
|
*
|
|
@@ -1767,6 +1902,14 @@ export declare interface ElementSize {
|
|
|
1767
1902
|
height: number;
|
|
1768
1903
|
}
|
|
1769
1904
|
|
|
1905
|
+
/**
|
|
1906
|
+
* Build an empty {@link OffsetPage} — handy as `placeholderData`/`initialData`.
|
|
1907
|
+
*
|
|
1908
|
+
* @param pageSize - The page size to report (default 20).
|
|
1909
|
+
* @returns An empty offset page on page 1.
|
|
1910
|
+
*/
|
|
1911
|
+
export declare function emptyOffsetPage<T>(pageSize?: number): OffsetPage<T>;
|
|
1912
|
+
|
|
1770
1913
|
/** Centered "nothing here yet" placeholder with optional icon and CTA. */
|
|
1771
1914
|
export declare function EmptyState({ icon, title, description, action, className }: EmptyStateProps): JSX.Element;
|
|
1772
1915
|
|
|
@@ -2455,6 +2598,42 @@ export declare interface InputProps extends Omit<InputHTMLAttributes<HTMLInputEl
|
|
|
2455
2598
|
|
|
2456
2599
|
export declare type InputSize = "sm" | "md" | "lg";
|
|
2457
2600
|
|
|
2601
|
+
/**
|
|
2602
|
+
* Install the background-sync queue: on a failed mutating request, the request
|
|
2603
|
+
* is serialized to IndexedDB and a sync is registered; the original fetch still
|
|
2604
|
+
* rejects (so your app can show an offline state), and the request is replayed
|
|
2605
|
+
* later when the network returns.
|
|
2606
|
+
*/
|
|
2607
|
+
export declare function installBackgroundSync(options?: InstallBackgroundSyncOptions): void;
|
|
2608
|
+
|
|
2609
|
+
/**
|
|
2610
|
+
* Background-sync helper: queue failed mutating requests (POST/PUT/PATCH/DELETE)
|
|
2611
|
+
* while offline and replay them when connectivity returns. A dependency-free
|
|
2612
|
+
* take on Workbox's `BackgroundSyncPlugin`, backed by a tiny IndexedDB queue.
|
|
2613
|
+
*
|
|
2614
|
+
* Import inside your `sw.ts`. Uses the Background Sync API (`registration.sync`)
|
|
2615
|
+
* when available, and also replays opportunistically on the next request as a
|
|
2616
|
+
* fallback for browsers without it (e.g. Safari).
|
|
2617
|
+
*
|
|
2618
|
+
* @example
|
|
2619
|
+
* import { installBackgroundSync } from "tempest-react-sdk/sw";
|
|
2620
|
+
*
|
|
2621
|
+
* installBackgroundSync({ match: (url) => url.pathname.startsWith("/api/") });
|
|
2622
|
+
*/
|
|
2623
|
+
/** Options for {@link installBackgroundSync}. */
|
|
2624
|
+
export declare interface InstallBackgroundSyncOptions {
|
|
2625
|
+
/**
|
|
2626
|
+
* Which requests to queue on failure. A `RegExp` against the URL or a
|
|
2627
|
+
* predicate. Only non-`GET` requests are ever considered. Default: all
|
|
2628
|
+
* non-`GET` requests.
|
|
2629
|
+
*/
|
|
2630
|
+
match?: RegExp | ((url: URL, request: Request) => boolean);
|
|
2631
|
+
/** IndexedDB database name, also used as the sync tag. Default `tempest-bg-sync`. */
|
|
2632
|
+
queueName?: string;
|
|
2633
|
+
/** Drop queued requests older than this (minutes) on replay. Default `1440` (24h). */
|
|
2634
|
+
maxRetentionMinutes?: number;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2458
2637
|
/**
|
|
2459
2638
|
* Install a `notificationclick` handler that focuses an existing client when
|
|
2460
2639
|
* possible and falls back to opening a new window.
|
|
@@ -2466,6 +2645,32 @@ export declare interface InstallNotificationClickHandlerOptions {
|
|
|
2466
2645
|
resolveUrl?: (data: unknown) => string;
|
|
2467
2646
|
}
|
|
2468
2647
|
|
|
2648
|
+
/**
|
|
2649
|
+
* Precache the app shell at `install` and serve it offline:
|
|
2650
|
+
* - reads `precache-manifest.json` (emitted by `tempestPwaManifest()`),
|
|
2651
|
+
* - caches every listed URL under a versioned cache,
|
|
2652
|
+
* - on `activate`, deletes stale precache versions and claims open clients,
|
|
2653
|
+
* - on `fetch`, serves precached assets cache-first and falls back to the
|
|
2654
|
+
* `navigateFallback` document for offline navigations (SPA routing).
|
|
2655
|
+
*
|
|
2656
|
+
* Same-origin only. Register this LAST, after any {@link installRuntimeCache}.
|
|
2657
|
+
*/
|
|
2658
|
+
export declare function installPrecache(options?: InstallPrecacheOptions): void;
|
|
2659
|
+
|
|
2660
|
+
/** Options for {@link installPrecache}. */
|
|
2661
|
+
export declare interface InstallPrecacheOptions {
|
|
2662
|
+
/** URL of the manifest emitted by `tempestPwaManifest()`. Default `/precache-manifest.json`. */
|
|
2663
|
+
manifestUrl?: string;
|
|
2664
|
+
/** Cache name prefix; the manifest `version` is appended. Default `tempest-precache`. */
|
|
2665
|
+
cacheName?: string;
|
|
2666
|
+
/** App-shell document served for navigation requests offline. Default `/index.html`. */
|
|
2667
|
+
navigateFallback?: string;
|
|
2668
|
+
/** Navigation paths that should NOT use the fallback (e.g. `[/^\/api\//]`). */
|
|
2669
|
+
navigateFallbackDenylist?: RegExp[];
|
|
2670
|
+
/** Activate the new worker immediately after precaching. Default `true`. */
|
|
2671
|
+
skipWaiting?: boolean;
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2469
2674
|
/**
|
|
2470
2675
|
* Install a `push` event listener that parses the payload as JSON (with a
|
|
2471
2676
|
* plain-text fallback) and shows a notification.
|
|
@@ -2486,6 +2691,18 @@ export declare interface InstallPushHandlerOptions {
|
|
|
2486
2691
|
transform?: (payload: PushPayload) => PushPayload | null;
|
|
2487
2692
|
}
|
|
2488
2693
|
|
|
2694
|
+
/**
|
|
2695
|
+
* Install a `fetch` handler that resolves matching `GET` requests with the
|
|
2696
|
+
* given runtime strategies. Non-matching requests are left untouched (no
|
|
2697
|
+
* `respondWith`), so a later {@link installPrecache} can handle them.
|
|
2698
|
+
*
|
|
2699
|
+
* Register this BEFORE `installPrecache` so specific routes win over the
|
|
2700
|
+
* precache catch-all.
|
|
2701
|
+
*
|
|
2702
|
+
* @param routes Ordered rules; the first whose `match` passes handles the request.
|
|
2703
|
+
*/
|
|
2704
|
+
export declare function installRuntimeCache(routes: RuntimeRoute[]): void;
|
|
2705
|
+
|
|
2489
2706
|
/**
|
|
2490
2707
|
* Install a `message` listener that activates a waiting worker when the host
|
|
2491
2708
|
* app sends `{ type: "SKIP_WAITING" }`.
|
|
@@ -2494,6 +2711,23 @@ export declare function installSkipWaitingListener(): void;
|
|
|
2494
2711
|
|
|
2495
2712
|
export declare type InterpolationValues = Record<string, string | number>;
|
|
2496
2713
|
|
|
2714
|
+
/**
|
|
2715
|
+
* Type guard for the {@link ApiError} shape. Matches both {@link TempestApiError}
|
|
2716
|
+
* instances and plain objects carrying `status` + `detail`.
|
|
2717
|
+
*
|
|
2718
|
+
* @param error - The unknown value (typically a caught error).
|
|
2719
|
+
* @returns Whether `error` conforms to the `ApiError` contract.
|
|
2720
|
+
*/
|
|
2721
|
+
export declare function isApiError(error: unknown): error is ApiError;
|
|
2722
|
+
|
|
2723
|
+
/**
|
|
2724
|
+
* Type guard for a {@link CursorPage} envelope.
|
|
2725
|
+
*
|
|
2726
|
+
* @param value - The unknown value to test.
|
|
2727
|
+
* @returns Whether it carries `items` + `has_more` + a `next_cursor` key.
|
|
2728
|
+
*/
|
|
2729
|
+
export declare function isCursorPage<T = unknown>(value: unknown): value is CursorPage<T>;
|
|
2730
|
+
|
|
2497
2731
|
/**
|
|
2498
2732
|
* Type guard asserting a value is neither `null` nor `undefined`.
|
|
2499
2733
|
*
|
|
@@ -2543,6 +2777,14 @@ export declare function isJWTExpired(token: string, leewaySeconds?: number): boo
|
|
|
2543
2777
|
*/
|
|
2544
2778
|
export declare function isNumber(value: unknown): value is number;
|
|
2545
2779
|
|
|
2780
|
+
/**
|
|
2781
|
+
* Type guard for an {@link OffsetPage} envelope.
|
|
2782
|
+
*
|
|
2783
|
+
* @param value - The unknown value to test.
|
|
2784
|
+
* @returns Whether it carries `items` + `total` + `page` + `pages`.
|
|
2785
|
+
*/
|
|
2786
|
+
export declare function isOffsetPage<T = unknown>(value: unknown): value is OffsetPage<T>;
|
|
2787
|
+
|
|
2546
2788
|
/**
|
|
2547
2789
|
* Type guard asserting a value is a plain object literal.
|
|
2548
2790
|
*
|
|
@@ -2989,6 +3231,33 @@ export declare interface OfflineStoreConfig<TItem> {
|
|
|
2989
3231
|
ownerField?: keyof TItem & string;
|
|
2990
3232
|
}
|
|
2991
3233
|
|
|
3234
|
+
/** Offset-paginated response envelope (fastapi-pagination `Page[T]`). */
|
|
3235
|
+
export declare interface OffsetPage<T> {
|
|
3236
|
+
/** The rows for the current page. */
|
|
3237
|
+
items: T[];
|
|
3238
|
+
/** Total number of matching rows across all pages. */
|
|
3239
|
+
total: number;
|
|
3240
|
+
/** Current 1-based page number. */
|
|
3241
|
+
page: number;
|
|
3242
|
+
/** Total number of pages. */
|
|
3243
|
+
pages: number;
|
|
3244
|
+
/** Page size — fastapi-pagination emits `size`. */
|
|
3245
|
+
size?: number;
|
|
3246
|
+
/** Page size — some backends name it `page_size` instead. */
|
|
3247
|
+
page_size?: number;
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
/** Offset filter query params (fastapi-pagination / `BasePaginationFilterSchema`). */
|
|
3251
|
+
export declare interface OffsetParams {
|
|
3252
|
+
page?: number;
|
|
3253
|
+
/** Page size — fastapi-pagination convention. */
|
|
3254
|
+
size?: number;
|
|
3255
|
+
/** Page size — `page_size` convention. */
|
|
3256
|
+
page_size?: number;
|
|
3257
|
+
order_by?: string;
|
|
3258
|
+
ascending?: boolean;
|
|
3259
|
+
}
|
|
3260
|
+
|
|
2992
3261
|
/**
|
|
2993
3262
|
* Create a new object with the given `keys` removed from `obj`.
|
|
2994
3263
|
*
|
|
@@ -3587,6 +3856,13 @@ export declare interface RetryOptions {
|
|
|
3587
3856
|
initialDelay?: number;
|
|
3588
3857
|
/** Maximum delay between attempts. Default: 10_000. */
|
|
3589
3858
|
maxDelay?: number;
|
|
3859
|
+
/**
|
|
3860
|
+
* Honor a `Retry-After` hint on the thrown error (`error.retryAfter`, in
|
|
3861
|
+
* seconds — populated by {@link createApiClient} on `429`/`503`). When
|
|
3862
|
+
* present it overrides the exponential backoff for that attempt. The value
|
|
3863
|
+
* is capped at `maxDelay`. Default: true.
|
|
3864
|
+
*/
|
|
3865
|
+
respectRetryAfter?: boolean;
|
|
3590
3866
|
/**
|
|
3591
3867
|
* Return false to stop retrying for a specific error.
|
|
3592
3868
|
* Default: retry on any thrown error.
|
|
@@ -3635,6 +3911,51 @@ export declare type RouterKind = "browser" | "hash" | "memory";
|
|
|
3635
3911
|
|
|
3636
3912
|
export { Routes }
|
|
3637
3913
|
|
|
3914
|
+
/** A single runtime-caching rule, matched against each `GET` request. */
|
|
3915
|
+
export declare interface RuntimeRoute {
|
|
3916
|
+
/** A `RegExp` tested against the full URL, or a predicate over the parsed URL. */
|
|
3917
|
+
match: RegExp | ((url: URL, request: Request) => boolean);
|
|
3918
|
+
/** How to resolve a match. */
|
|
3919
|
+
strategy: RuntimeStrategy;
|
|
3920
|
+
/** Cache bucket name for this route. */
|
|
3921
|
+
cacheName: string;
|
|
3922
|
+
/** Trim the cache to at most this many entries (FIFO) after each write. */
|
|
3923
|
+
maxEntries?: number;
|
|
3924
|
+
/** Treat a cached response older than this (seconds) as a miss. */
|
|
3925
|
+
maxAgeSeconds?: number;
|
|
3926
|
+
/** For `network-first`: fall back to cache after this timeout (seconds). */
|
|
3927
|
+
networkTimeoutSeconds?: number;
|
|
3928
|
+
/**
|
|
3929
|
+
* Serve HTTP `Range` requests (206 Partial Content) by slicing the cached
|
|
3930
|
+
* full response. Enable for audio/video so seeking works offline. The full
|
|
3931
|
+
* resource is cached once (the `Range` header is stripped before caching).
|
|
3932
|
+
*/
|
|
3933
|
+
rangeRequests?: boolean;
|
|
3934
|
+
}
|
|
3935
|
+
|
|
3936
|
+
/**
|
|
3937
|
+
* Service-worker caching helpers — a small, dependency-free subset of what
|
|
3938
|
+
* Workbox provides: precaching of the build's app shell (so the app launches
|
|
3939
|
+
* offline) plus runtime caching strategies for fonts, APIs and images.
|
|
3940
|
+
*
|
|
3941
|
+
* Import these inside your own `sw.ts`. They run in the service-worker global
|
|
3942
|
+
* scope, not the main thread. Pair `installPrecache` with the
|
|
3943
|
+
* `tempestPwaManifest()` Vite plugin (from `tempest-react-sdk/vite`), which
|
|
3944
|
+
* emits the `precache-manifest.json` this reads at install time.
|
|
3945
|
+
*
|
|
3946
|
+
* @example
|
|
3947
|
+
* /// <reference lib="webworker" />
|
|
3948
|
+
* import { installRuntimeCache, installPrecache } from "tempest-react-sdk/sw";
|
|
3949
|
+
*
|
|
3950
|
+
* // Register specific routes FIRST so they win over the precache catch-all.
|
|
3951
|
+
* installRuntimeCache([
|
|
3952
|
+
* { match: /\/api\//, strategy: "network-first", cacheName: "api", maxAgeSeconds: 300 },
|
|
3953
|
+
* ]);
|
|
3954
|
+
* installPrecache();
|
|
3955
|
+
*/
|
|
3956
|
+
/** Caching strategy for a runtime route. Mirrors the common Workbox trio. */
|
|
3957
|
+
export declare type RuntimeStrategy = "cache-first" | "network-first" | "stale-while-revalidate";
|
|
3958
|
+
|
|
3638
3959
|
/**
|
|
3639
3960
|
* Apply `env(safe-area-inset-*)` padding so content avoids iOS notch /
|
|
3640
3961
|
* Android navbar / device chrome. Wrap the outermost container of pages
|
|
@@ -4192,6 +4513,46 @@ export declare interface TelemetryUser {
|
|
|
4192
4513
|
traits?: Record<string, unknown>;
|
|
4193
4514
|
}
|
|
4194
4515
|
|
|
4516
|
+
/**
|
|
4517
|
+
* Error thrown by {@link createApiClient} / {@link uploadWithProgress} on a
|
|
4518
|
+
* non-2xx response. Mirrors the Tempest FastAPI SDK error envelope
|
|
4519
|
+
* (`{ detail, code, details.request_id }`) so callers get a typed `code` and a
|
|
4520
|
+
* `requestId` for log correlation, while still being a real `Error` (stack
|
|
4521
|
+
* trace, `instanceof Error`).
|
|
4522
|
+
*
|
|
4523
|
+
* @example
|
|
4524
|
+
* try {
|
|
4525
|
+
* await api.post("/users", { body });
|
|
4526
|
+
* } catch (err) {
|
|
4527
|
+
* if (isApiError(err) && err.code === "EMAIL_TAKEN") {
|
|
4528
|
+
* showFieldError("email", err.detail);
|
|
4529
|
+
* }
|
|
4530
|
+
* }
|
|
4531
|
+
*/
|
|
4532
|
+
export declare class TempestApiError extends Error implements ApiError {
|
|
4533
|
+
readonly status: number;
|
|
4534
|
+
readonly detail: string;
|
|
4535
|
+
readonly code?: string;
|
|
4536
|
+
readonly requestId?: string;
|
|
4537
|
+
readonly body?: unknown;
|
|
4538
|
+
constructor(init: ApiError);
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4541
|
+
export declare interface TempestAuth<TUser, TCredentials> {
|
|
4542
|
+
/** The persisted Zustand auth store hook (compatible with `<AuthGuard>`). */
|
|
4543
|
+
useAuthStore: ReturnType<typeof createAuthStore<TUser>>;
|
|
4544
|
+
/** A `createApiClient` wired with bearer auth + 401 → refresh → retry. */
|
|
4545
|
+
api: ApiClient;
|
|
4546
|
+
/** Authenticate, store the session, and resolve the user (or null). */
|
|
4547
|
+
login: (credentials: TCredentials) => Promise<TUser | null>;
|
|
4548
|
+
/** Clear the session (and the stored refresh token). */
|
|
4549
|
+
logout: () => void;
|
|
4550
|
+
/** Refresh the access token (deduplicated across concurrent callers). */
|
|
4551
|
+
refresh: () => Promise<void>;
|
|
4552
|
+
/** The current access token, or null. */
|
|
4553
|
+
getToken: () => string | null;
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4195
4556
|
/**
|
|
4196
4557
|
* A single declarative route node. Mirrors React Router's nested `<Route>`
|
|
4197
4558
|
* model but adds first-class `lazy` (code-split with retry) and `guard`
|
|
@@ -4224,6 +4585,16 @@ export declare interface TempestRouteObject {
|
|
|
4224
4585
|
caseSensitive?: boolean;
|
|
4225
4586
|
}
|
|
4226
4587
|
|
|
4588
|
+
/** The token envelope returned by a Tempest FastAPI SDK login/refresh route. */
|
|
4589
|
+
export declare interface TempestTokenResponse {
|
|
4590
|
+
/** The bearer access token. */
|
|
4591
|
+
access_token: string;
|
|
4592
|
+
/** Token type — always `"bearer"` for the SDK. */
|
|
4593
|
+
token_type?: string;
|
|
4594
|
+
/** Optional refresh token (when the API returns it in the body, not a cookie). */
|
|
4595
|
+
refresh_token?: string;
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4227
4598
|
/**
|
|
4228
4599
|
* Multi-line text input. Mirrors the {@link Input} API for label/helper/error.
|
|
4229
4600
|
*/
|
|
@@ -4545,7 +4916,7 @@ export declare interface UploadProgressEvent {
|
|
|
4545
4916
|
*
|
|
4546
4917
|
* `fetch` cannot report upload progress in browsers, so this helper falls
|
|
4547
4918
|
* back to `XMLHttpRequest`. It mirrors the error contract used by
|
|
4548
|
-
* {@link createApiClient}: non-2xx responses
|
|
4919
|
+
* {@link createApiClient}: non-2xx responses reject with a `TempestApiError`.
|
|
4549
4920
|
*
|
|
4550
4921
|
* @returns The parsed JSON response, or the raw text when the response is not JSON.
|
|
4551
4922
|
*/
|
|
@@ -4566,6 +4937,11 @@ export declare interface UploadWithProgressOptions {
|
|
|
4566
4937
|
signal?: AbortSignal;
|
|
4567
4938
|
/** Override the JSON parser. Defaults to `JSON.parse`. */
|
|
4568
4939
|
parser?: (raw: string) => unknown;
|
|
4940
|
+
/**
|
|
4941
|
+
* Per-request correlation id sent as `X-Request-ID` (Tempest convention).
|
|
4942
|
+
* Defaults to a generated id. Return an empty string to disable.
|
|
4943
|
+
*/
|
|
4944
|
+
requestId?: () => string;
|
|
4569
4945
|
}
|
|
4570
4946
|
|
|
4571
4947
|
/**
|
|
@@ -4680,6 +5056,52 @@ export declare interface UseClipboardResult {
|
|
|
4680
5056
|
reset: () => void;
|
|
4681
5057
|
}
|
|
4682
5058
|
|
|
5059
|
+
/**
|
|
5060
|
+
* Cursor-pagination hook over TanStack Query's `useInfiniteQuery` for the
|
|
5061
|
+
* Tempest `CursorPaginationSchema` envelope
|
|
5062
|
+
* (`{ items, next_cursor, has_more, limit }`).
|
|
5063
|
+
*
|
|
5064
|
+
* The opaque `next_cursor` is fed straight back as the next page param; the
|
|
5065
|
+
* loop stops when `has_more` is false (or `next_cursor` is null).
|
|
5066
|
+
*
|
|
5067
|
+
* @example
|
|
5068
|
+
* const feed = useCursorQuery<Post>({
|
|
5069
|
+
* queryKey: ["feed"],
|
|
5070
|
+
* limit: 30,
|
|
5071
|
+
* queryFn: (params) => postsService.listPosts(params),
|
|
5072
|
+
* });
|
|
5073
|
+
* // feed.items, feed.fetchNextPage(), feed.hasNextPage
|
|
5074
|
+
*/
|
|
5075
|
+
export declare function useCursorQuery<T>(options: UseCursorQueryOptions<T>): UseCursorQueryResult<T>;
|
|
5076
|
+
|
|
5077
|
+
export declare interface UseCursorQueryOptions<T> extends Omit<UseInfiniteQueryOptions<CursorPage<T>, Error, InfiniteData<CursorPage<T>, string | null>, QueryKey, string | null>, "queryKey" | "queryFn" | "initialPageParam" | "getNextPageParam"> {
|
|
5078
|
+
/** Base query key — `limit`/sort is appended for cache isolation. */
|
|
5079
|
+
queryKey: QueryKey;
|
|
5080
|
+
/** Fetcher receiving the cursor params; return the backend envelope. */
|
|
5081
|
+
queryFn: (params: CursorParams) => Promise<CursorPage<T>> | CursorPage<T>;
|
|
5082
|
+
/** Batch size sent as `limit`. Default: 20. */
|
|
5083
|
+
limit?: number;
|
|
5084
|
+
/** Initial `order_by`. */
|
|
5085
|
+
orderBy?: string;
|
|
5086
|
+
/** Initial `ascending`. Default: false. */
|
|
5087
|
+
ascending?: boolean;
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
export declare interface UseCursorQueryResult<T> {
|
|
5091
|
+
/** All rows fetched so far, flattened across batches. */
|
|
5092
|
+
items: T[];
|
|
5093
|
+
/** The raw batches, in fetch order. */
|
|
5094
|
+
pages: CursorPage<T>[];
|
|
5095
|
+
hasNextPage: boolean;
|
|
5096
|
+
isLoading: boolean;
|
|
5097
|
+
isFetchingNextPage: boolean;
|
|
5098
|
+
error: Error | null;
|
|
5099
|
+
/** Fetch the next batch (no-op when exhausted). */
|
|
5100
|
+
fetchNextPage: () => void;
|
|
5101
|
+
/** Refetch from the first batch. */
|
|
5102
|
+
refetch: () => void;
|
|
5103
|
+
}
|
|
5104
|
+
|
|
4683
5105
|
/**
|
|
4684
5106
|
* Debounce a fast-changing value. Returns the latest value once `delay` ms
|
|
4685
5107
|
* have elapsed without further changes.
|
|
@@ -4965,6 +5387,71 @@ export declare interface UseOAuthCallbackResult<T> {
|
|
|
4965
5387
|
*/
|
|
4966
5388
|
export declare function useOnline(): boolean;
|
|
4967
5389
|
|
|
5390
|
+
/**
|
|
5391
|
+
* Offset-pagination hook over TanStack Query for the fastapi-pagination /
|
|
5392
|
+
* Tempest envelope (`{ items, total, page, size, pages }`).
|
|
5393
|
+
*
|
|
5394
|
+
* It owns the page state, sends `page` + the size param (`size` by default,
|
|
5395
|
+
* or `page_size` via `sizeParam`) plus optional `order_by`/`ascending` to your
|
|
5396
|
+
* fetcher, keeps the previous page visible while the next loads, and derives
|
|
5397
|
+
* `hasNext`/`hasPrev`/`pageCount`.
|
|
5398
|
+
*
|
|
5399
|
+
* @example
|
|
5400
|
+
* const users = usePaginatedQuery<User>({
|
|
5401
|
+
* queryKey: ["users"],
|
|
5402
|
+
* pageSize: 25,
|
|
5403
|
+
* queryFn: (params) => usersService.listUsers(params),
|
|
5404
|
+
* });
|
|
5405
|
+
* // users.items, users.next(), users.hasNext, users.pageCount
|
|
5406
|
+
*/
|
|
5407
|
+
export declare function usePaginatedQuery<T>(options: UsePaginatedQueryOptions<T>): UsePaginatedQueryResult<T>;
|
|
5408
|
+
|
|
5409
|
+
export declare interface UsePaginatedQueryOptions<T> extends Omit<UseQueryOptions<OffsetPage<T>, Error, OffsetPage<T>, QueryKey>, "queryKey" | "queryFn"> {
|
|
5410
|
+
/** Base query key — the current page/sort is appended for cache isolation. */
|
|
5411
|
+
queryKey: QueryKey;
|
|
5412
|
+
/** Fetcher receiving the offset params; return the backend envelope. */
|
|
5413
|
+
queryFn: (params: OffsetParams) => Promise<OffsetPage<T>> | OffsetPage<T>;
|
|
5414
|
+
/** Initial 1-based page. Default: 1. */
|
|
5415
|
+
initialPage?: number;
|
|
5416
|
+
/** Page size. Default: 20. */
|
|
5417
|
+
pageSize?: number;
|
|
5418
|
+
/**
|
|
5419
|
+
* Query-param name for the page size. fastapi-pagination uses `"size"`
|
|
5420
|
+
* (default); SDK `BasePaginationFilterSchema` configs may use `"page_size"`.
|
|
5421
|
+
*/
|
|
5422
|
+
sizeParam?: "size" | "page_size";
|
|
5423
|
+
/** Initial `order_by` (only sent when set). */
|
|
5424
|
+
orderBy?: string;
|
|
5425
|
+
/** Initial `ascending` (only sent when `orderBy` is set). Default: false. */
|
|
5426
|
+
ascending?: boolean;
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
export declare interface UsePaginatedQueryResult<T> {
|
|
5430
|
+
/** The current page envelope, or undefined while the first load is pending. */
|
|
5431
|
+
page: OffsetPage<T> | undefined;
|
|
5432
|
+
/** The rows of the current page (empty array while pending). */
|
|
5433
|
+
items: T[];
|
|
5434
|
+
/** Current 1-based page number (controlled by the hook). */
|
|
5435
|
+
pageNumber: number;
|
|
5436
|
+
/** Total page count from the last successful response. */
|
|
5437
|
+
pageCount: number;
|
|
5438
|
+
/** Total row count from the last successful response. */
|
|
5439
|
+
total: number;
|
|
5440
|
+
hasNext: boolean;
|
|
5441
|
+
hasPrev: boolean;
|
|
5442
|
+
isLoading: boolean;
|
|
5443
|
+
isFetching: boolean;
|
|
5444
|
+
error: Error | null;
|
|
5445
|
+
/** Jump to a specific 1-based page (clamped to >= 1). */
|
|
5446
|
+
setPage: (page: number) => void;
|
|
5447
|
+
/** Go to the next page when available. */
|
|
5448
|
+
next: () => void;
|
|
5449
|
+
/** Go to the previous page when available. */
|
|
5450
|
+
prev: () => void;
|
|
5451
|
+
/** Refetch the current page. */
|
|
5452
|
+
refetch: () => void;
|
|
5453
|
+
}
|
|
5454
|
+
|
|
4968
5455
|
/**
|
|
4969
5456
|
* Manage page/size state for paginated lists. Reset goes back to page 1
|
|
4970
5457
|
* without touching the page size.
|