@aiquants/daily-report 0.21.0 → 0.22.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.
- package/README.md +53 -9
- package/dist/client.d.mts +24 -13
- package/dist/client.d.ts +24 -13
- package/dist/client.js +5 -5
- package/dist/client.mjs +5 -5
- package/dist/{sse-schema-DCxpdETM.d.mts → ids-stream-BnM6L-Sk.d.ts} +42 -2
- package/dist/{sse-schema-DoQw8_om.d.ts → ids-stream-DCuiaTit.d.mts} +42 -2
- package/dist/index.d.mts +3 -30
- package/dist/index.d.ts +3 -30
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.d.mts +11 -3
- package/dist/server.d.ts +11 -3
- package/dist/server.js +4 -15
- package/dist/server.mjs +4 -15
- package/dist/styles/daily-report.standalone.css +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ External projects:
|
|
|
25
25
|
pnpm add @aiquants/daily-report react react-dom react-router drizzle-orm zod
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
`react` / `react-dom` / `react-router` / `drizzle-orm` / `zod` are **peer dependencies**. Build / test: `pnpm run build` (tsup → dist) / `pnpm run test` (vitest).
|
|
28
|
+
`react` / `react-dom` / `react-router` / `drizzle-orm` / `zod` are **peer dependencies**. `@aiquants/sse` (the SSE wire contract, server response helpers and the reopening client) is a regular **dependency**: it arrives transitively, so consumers do not declare it. Build / test: `pnpm run build` (tsup → dist) / `pnpm run test` (vitest).
|
|
29
29
|
|
|
30
30
|
### Tailwind CSS
|
|
31
31
|
|
|
@@ -156,7 +156,7 @@ createDailyReportServer({
|
|
|
156
156
|
- **How it reaches the service**: the resolved set is wrapped in a `DailyReportViewerScope` and passed as the **first** argument of every gated service method.
|
|
157
157
|
The class is nominal (it holds a private field), so `{ visible: null }`, `{ ...scope, visible: null }` and `new DailyReportViewerScope(...)` are all type errors — the only ways to obtain one are `DailyReportViewerScope.restrictTo(tokens)` — which accepts `readonly string[]` only, so it cannot be handed a nullish value and quietly widen — and `DailyReportViewerScope.unrestricted(auditReason)`.
|
|
158
158
|
Because a bare `null` is not spellable as a visibility value, `grep -rn "DailyReportViewerScope.unrestricted("` enumerates every unfiltered read in a codebase, each carrying a written reason.
|
|
159
|
-
- **Performance**: the port is called once per request on the critical path (cache keys incorporate the resolved set), so keep it fast — cache grants per session/user with a short TTL (≤ 60s). A live SSE connection re-resolves on
|
|
159
|
+
- **Performance**: the port is called once per request on the critical path (cache keys incorporate the resolved set), so keep it fast — cache grants per session/user with a short TTL (≤ 60s). A live SSE connection re-resolves on a dedicated 60 s timer (independent of the heartbeat) to bound how long a revoked grant keeps streaming; that call passes `reason: "refresh"` and reuses the connection's original `Request`, so a cache keyed on request identity **must** be bypassed when `reason === "refresh"` or the re-check silently returns the stale set.
|
|
160
160
|
- **SSE latency**: because a live connection re-resolves periodically, a grant change (in either direction) takes effect for the stream within ~60s. Events dropped before a widening are not replayed; the next read (which re-resolves per request) restores them.
|
|
161
161
|
|
|
162
162
|
### Comment visibility
|
|
@@ -211,6 +211,7 @@ export default function Route() {
|
|
|
211
211
|
user={user}
|
|
212
212
|
userId={userId}
|
|
213
213
|
config={{
|
|
214
|
+
onSessionExpired: () => navigate(0), // Required: the host decides the navigation on session expiry
|
|
214
215
|
renderHeader: ({ title, annotation }) => <YourHeader title={title} annotation={annotation} />,
|
|
215
216
|
showDevControls: import.meta.env.DEV, // Toggle SSE subscriptions, etc.
|
|
216
217
|
draftLabelName: "Draft", // Label name for draft states (matches target DB; not tied to locale)
|
|
@@ -227,6 +228,8 @@ export default function Route() {
|
|
|
227
228
|
}
|
|
228
229
|
```
|
|
229
230
|
|
|
231
|
+
`config` is **required** and so is its `onSessionExpired` port (omitting it is a type error, TS2741; a non-function throws a `TypeError` at render). The package never navigates by itself: when the session is gone — the SSE stream ends with `auth-required`, or the ids stream answers 401 / 403 — it calls `onSessionExpired()` exactly once per occurrence and stops. A typical host reloads the route (`navigate(0)`) so its own loader redirects to the login page. `DailyReportConfigProvider` takes the same required `config`; outside a provider, the default configuration's `onSessionExpired` throws.
|
|
232
|
+
|
|
230
233
|
`DailyReportPage` is layout-agnostic (header rendering via `renderHeader` slot, error boundaries/footer control managed by the app). For fine-grained usage, `DailyReportActionProvider`, `DailyReportResolvedContent`, `useDailyReportDetail`, etc. can be imported individually.
|
|
231
234
|
|
|
232
235
|
Mutation failures (save / publish / delete / comment) are surfaced through an error seam: inject `config.onError(info: DailyReportErrorInfo)` to route them into your own toast/notification system, or omit it to use the package's built-in `role="alert"` banner (auto-dismiss + manual close). Failures on a continuation that resolves after a no-reload user switch are suppressed. If you compose `DailyReportActionProvider` yourself instead of using `DailyReportPage`, wrap it in `DailyReportErrorProvider` (both are exported from `@aiquants/daily-report/client`) so `onError` / the banner work.
|
|
@@ -403,7 +406,7 @@ first), `DAILY_REPORT_LABEL_CATALOGS` (the frozen catalogs), `resolveDailyReport
|
|
|
403
406
|
| `streamRetrying` | stream badge (reconnecting) | `(1234)` → Reconnecting... (1,234 received) | `(1234)` → 再接続中... (1,234 件受信済) |
|
|
404
407
|
| `reportLoadFailed` | detail load failure (side pane, DetailList card) | `(12345)` → Failed to load report 12,345. | `(12345)` → 日報 12,345 の読み込みに失敗しました。 |
|
|
405
408
|
| `reportSummaryLoadFailed` | list card load failure | `(12345)` → Failed to load the summary of report 12,345. | `(12345)` → 日報 12,345 の概要読み込みに失敗しました。 |
|
|
406
|
-
| `interviewerWithAffiliation` | interviewer chip | `("Sato", "Acme")` → Sato (Acme) | `("佐藤", "
|
|
409
|
+
| `interviewerWithAffiliation` | interviewer chip | `("Sato", "Acme")` → Sato (Acme) | `("佐藤", "山田商事")` → 佐藤 (山田商事) |
|
|
407
410
|
| `operationFailed` | error banner / `DailyReportErrorInfo.message` | `("update")` → Failed to save the report. Please try again later. | `("update")` → 日報の保存に失敗しました。時間をおいて再度お試しください。 |
|
|
408
411
|
|
|
409
412
|
#### Migrating from 0.20.x (breaking changes in 0.21.0)
|
|
@@ -418,7 +421,7 @@ first), `DAILY_REPORT_LABEL_CATALOGS` (the frozen catalogs), `resolveDailyReport
|
|
|
418
421
|
wording except four values aligned with the shared `@aiquants` vocabulary: `treeComingSoon`
|
|
419
422
|
(`ツリーは現在準備中です`), `resizeHandle` (`日報一覧と詳細ペインの境界のサイズ変更ハンドル`),
|
|
420
423
|
`unknownUser` (`不明なユーザー`, formerly `"Unknown"` / `不明`) and `interviewerWithAffiliation`
|
|
421
|
-
(half-width parentheses: `佐藤 (
|
|
424
|
+
(half-width parentheses: `佐藤 (山田商事)`).
|
|
422
425
|
2. **`config.fieldLabels` → `config.labels`** (the same 21 keys). The type `DailyReportFieldLabels`
|
|
423
426
|
and the value `defaultDailyReportFieldLabels` are removed; use `DailyReportLabels` /
|
|
424
427
|
`DAILY_REPORT_LABEL_CATALOGS[locale]`. A leftover `fieldLabels` key throws a `RangeError` at
|
|
@@ -525,13 +528,54 @@ export default defineConfig({
|
|
|
525
528
|
|
|
526
529
|
1. Mutation services publish to Redis Stream (`daily-report:sse-stream`) in sequence: `invalidate -> epoch increment -> SSE publish`.
|
|
527
530
|
2. `DailyReportSseReader` uses a single blocking `xRead` loop to fan-out events to all SSE connections (eliminating per-connection Redis TCP connections).
|
|
528
|
-
3. `sse.loader`
|
|
529
|
-
4. On the client, `useDailyReportSseConnection`
|
|
531
|
+
3. `sse.loader` is built on `@aiquants/sse/server` (`createSseResponse`, `terminalStreamResponse`, `startSseHeartbeat`, `readLastEventId`). Its responses carry only `SSE_RESPONSE_HEADERS` plus the forwarded `Set-Cookie` (no `Connection` or other hop-by-hop header, which HTTP/2 forbids). `recipientRawUserId` is filtered server-side and removed before transmission to prevent internal ID leaks. Catch-up and live entries pass through the same filters (recipient, source-type visibility, comment redaction).
|
|
532
|
+
4. On the client, `useDailyReportSseConnection` runs on `useReopeningEventSource` (`@aiquants/sse/react`): full-jitter backoff from 2 s to 30 s, the failure count reset only after 30 s of healthy open, one native browser reconnect (which carries the cursor in the `Last-Event-ID` header), and a stale watch of 45 s (three heartbeat periods).
|
|
533
|
+
The action context correlates optimistic updates with SSE echoes using `clientTempId`, and exposes the connection status as `sseStatus` (`DailyReportSseConnectionStatus`: the reopening status, or `{ kind: "resyncing" }` while a `resync-required` waits for a fresh ids anchor).
|
|
534
|
+
|
|
535
|
+
### SSE wire contract
|
|
536
|
+
|
|
537
|
+
Stop signals are **in-band**: the server answers 200 and writes `retry: 86400000` before one named terminal event, so a client that does not listen for the event (an older bundle) reconnects at most once a day instead of in a loop. A non-200 response is reserved for a misconfigured endpoint.
|
|
538
|
+
|
|
539
|
+
| Server-side situation | Response | Client (`useDailyReportSseConnection`) |
|
|
540
|
+
| --- | --- | --- |
|
|
541
|
+
| Not authenticated | 200, `retry: 86400000` → `event: auth-required` (`Set-Cookie` forwarded) | terminated; calls `config.onSessionExpired()` once; never reconnects |
|
|
542
|
+
| Authenticated but no internal user | 200, `retry: 86400000` → `event: forbidden` | terminated; no navigation (a reload cannot fix it); visible through `sseStatus` |
|
|
543
|
+
| Unknown endpoint | 404 | treated as retryable; backoff up to 30 s |
|
|
544
|
+
| Unexpected error before the stream starts (for example the internal-user lookup fails) | 500 with the body `Internal Server Error` (no error detail), `Set-Cookie` forwarded | treated as retryable; backoff up to 30 s |
|
|
545
|
+
| Malformed cursor | 200, `retry: 86400000` → `event: resync-required` | rereads the ids (server cache bypassed) and reopens from the new anchor |
|
|
546
|
+
| Cursor older than the oldest retained entry (the stream is trimmed with `MAXLEN ~ streamMaxLen`) | 200, `connected` → heartbeat → `retry: 86400000` → `event: resync-required` → end | same as above |
|
|
547
|
+
| The start of a catch-up page is trimmed away before the page is read | 200, the entries delivered so far → `retry: 86400000` → `event: resync-required` → end | same as above |
|
|
548
|
+
| Empty stream, or a cursor inside the retained window or in the future | 200, `connected` → heartbeat → catch-up (every entry) → live | continues |
|
|
549
|
+
| Redis failure during the catch-up | the body ends (`producer-failed`) | one native reconnect with `Last-Event-ID`, then the utility's own backoff; the cursor is kept |
|
|
550
|
+
|
|
551
|
+
- **Resume cursor**: `readLastEventId` reads the `Last-Event-ID` header first, then the `lastEventId` query parameter (`DAILY_REPORT_SSE_CURSOR_PARAM`). The browser's own reconnect reuses the URL it opened with (a stale query) but sends a fresh header, so the header is always the newer value. A cursor must be a Redis stream id of the form `<ms>-<seq>` with 1–15 digits per part (`isDailyReportSseStreamId`); anything else is answered with `resync-required`. The client URL-encodes the cursor.
|
|
552
|
+
- **`connected` frame**: `data: {"type":"connected"}` with `id:` set to the resume position (the cursor, or the newest entry at connect time when there is no cursor). On the cursor path it is written before any Redis round trip.
|
|
553
|
+
The same frame is used as an anchor-only frame for entries the viewer's filters drop (addressed to another user, or a source type the viewer cannot see), so the client's cursor keeps advancing without receiving their content.
|
|
554
|
+
Without it, a tab whose visible traffic is quiet while other users' read / star updates flow would keep an old cursor, and its next reconnect would fall outside the retained window (`resync-required`, then an ids rescan that bypasses the server cache).
|
|
555
|
+
- **Catch-up**: entries after the cursor are read in pages of 1,000 (`xRange` is inclusive, so each page skips its start id) until the stream end; every entry is delivered. When a page does not start with its start id, the oldest retained entry is read again: if it is newer than the start id, the range after it may have been trimmed, so the connection ends with `resync-required` instead of silently skipping it (a cursor that is simply not an entry id inside the retained window continues).
|
|
556
|
+
- **Ids on the wire only increase**: live entries that arrive during the catch-up are queued, not written. The catch-up stops in front of the first queued entry (the fan-out reader delivers every entry after it in order), then the queue is written in id order and later live entries are written as they arrive. Writing a live entry first would let a disconnect move the client's resume position past catch-up entries it never received, and an older `report-update` would overwrite a newer one on the client.
|
|
557
|
+
- **Heartbeat**: `startSseHeartbeat` writes a jittered `retry:` (2,000–10,000 ms), an immediate named `event: heartbeat` (`data: {"serverTime":<ms>}`, no `id:`), then one every 15 s (`DAILY_REPORT_SSE_HEARTBEAT_MS`). Named events are ignored by `onmessage`, so old bundles are unaffected.
|
|
558
|
+
- **Stream anchor (`streamAnchor`)**: the ids stream carries the newest SSE entry id on its first authoritative line
|
|
559
|
+
(the line with `total`, or the short-circuit line when the whole data set fits in the fast first page; never on a
|
|
560
|
+
provisional line). The service reads it inside the cached fetcher **before** the SQL, so every cache path (bucket hit,
|
|
561
|
+
joining an in-flight fetch, refresh-ahead) returns an array that already reflects every update up to the anchor. The
|
|
562
|
+
SSE hook does not connect until an anchor arrives and then uses it as the first cursor, which closes the gap between
|
|
563
|
+
loading the ids and opening the stream. `null` means "position unknown" (empty stream, no redis, read failure): the
|
|
564
|
+
hook then opens without a cursor and the server starts from the newest entry at connect time.
|
|
565
|
+
- **Delivery is idempotent**: an anchor can be up to one ids-cache TTL old; replaying from it is safe because `report-*` messages upsert and `comment-add` is matched by comment id.
|
|
566
|
+
- **A resync that gives up is retried**: after `resync-required` the hook asks the ids session for a rescan (`resyncDailyReportIdsStream()`) and does not reconnect until an anchor newer than the one it had arrives. When that rescan gives up (the ids phase stays `complete` with an `error`, which happens after repeated failures during an outage), the hook asks again after a full-jitter backoff from 2 s to 30 s while SSE is enabled, until an anchor arrives. An initial ids scan that ends in `failed` is left to the page's manual retry.
|
|
530
567
|
|
|
531
568
|
## API Surface (Summary)
|
|
532
569
|
|
|
533
|
-
- **server**: `createDailyReportServer` / `createDailyReportService` / `createDailyReportHandlers` / `defineDailyReportSchema` / `DailyReportSseReader` / `SqlResultCache` / `transformJsonArray` / `jsonResponseWithETag` / `generateETag` / `isStreamIdLte`
|
|
534
|
-
- **client**: `DailyReportPage` / `DailyReportResolvedContent` / `DailyReportList` / `DailyReportDetailList` /
|
|
535
|
-
|
|
570
|
+
- **server**: `createDailyReportServer` / `createDailyReportService` (`getDailyReportIdsByExternalId` returns `{ items, streamAnchor }`; `readSseStreamAnchor`) / `createDailyReportHandlers` / `DAILY_REPORT_SSE_VISIBILITY_REFRESH_MS` / `DAILY_REPORT_SSE_CATCH_UP_BATCH` / `defineDailyReportSchema` / `DailyReportSseReader` / `SqlResultCache` / `transformJsonArray` / `jsonResponseWithETag` / `generateETag` / `isStreamIdLte`
|
|
571
|
+
- **client**: `DailyReportPage` / `DailyReportResolvedContent` / `DailyReportList` / `DailyReportDetailList` /
|
|
572
|
+
`DailyReportActionProvider` / `useDailyReportActionContext` (`sseStatus`) / `useDailyReportDetail` /
|
|
573
|
+
`useDailyReportPrefetch` / `useDailyReportComments` / `useDailyReportSseConnection` (returns
|
|
574
|
+
`DailyReportSseConnectionStatus`) / `useDailyReportIdsStream` (state carries `streamAnchor`) /
|
|
575
|
+
`resyncDailyReportIdsStream` / `DailyReportIdsStreamStatus` / `DailyReportIdsStreamClient` (`resync()`) /
|
|
576
|
+
`DailyReportConfigProvider` / `useDailyReportConfig` / `defaultDailyReportClientConfig` / `resolveDailyReportLabels` /
|
|
577
|
+
`DAILY_REPORT_LABEL_CATALOGS` / `DAILY_REPORT_LABEL_KEYS` / `createDailyReportClientLoader` /
|
|
578
|
+
`dailyReportShouldRevalidate`
|
|
579
|
+
- **shared**: `DailyReportItem` / `DailyReportDetail` / `DailyReportUser` / `dailyReportSseMessageSchema` (8 discriminated union types) / `DAILY_REPORT_SSE_TERMINAL_EVENTS` / `DAILY_REPORT_SSE_HEARTBEAT_MS` / `DAILY_REPORT_SSE_CURSOR_PARAM` / `isDailyReportSseStreamId` / `DailyReportSseStreamAnchor` / `normalizeBusinessDateKey` / `mergeComments(legacyComments, modernComments, currentUserId, unknownAuthorName)`
|
|
536
580
|
|
|
537
581
|
MIT
|
package/dist/client.d.mts
CHANGED
|
@@ -2,7 +2,8 @@ import * as react from "react";
|
|
|
2
2
|
import { RefObject, ReactNode, Context } from "react";
|
|
3
3
|
import { ScrollBarThumbOverlayRenderProps, VirtualScrollLocale, VirtualScrollLabels, ScrollPaneInertiaOptions, ScrollBarTapCircleOptions } from "@aiquants/virtualscroll";
|
|
4
4
|
import { D as DailyReportAttachmentSummary, a as DailyReportItem, b as DailyReportDetail, c as DailyReportUser } from "./types-CqgYQgbH.mjs";
|
|
5
|
-
import { U as UIComment, D as DailyReportSseMessage } from "./
|
|
5
|
+
import { U as UIComment, D as DailyReportSseTerminalEvent, a as DailyReportSseMessage, b as DailyReportSseStreamAnchor } from "./ids-stream-DCuiaTit.mjs";
|
|
6
|
+
import { UseReopeningEventSourceResult } from "@aiquants/sse/react";
|
|
6
7
|
import { ShouldRevalidateFunction } from "react-router";
|
|
7
8
|
import "zod";
|
|
8
9
|
declare const BusinessDayThumbOverlay: ({ orientation, thumbCenter, label, isDragging, isTapScrollActive, isWheelScrollActive }: ScrollBarThumbOverlayRenderProps & {
|
|
@@ -282,15 +283,17 @@ type DailyReportClientConfig = {
|
|
|
282
283
|
renderHeader: (props: DailyReportHeaderProps) => ReactNode;
|
|
283
284
|
showDevControls: boolean;
|
|
284
285
|
onError?: (info: DailyReportErrorInfo) => void;
|
|
286
|
+
onSessionExpired: () => void;
|
|
285
287
|
};
|
|
286
|
-
type DailyReportClientConfigInput = Partial<Omit<DailyReportClientConfig, "locale" | "labels">> & {
|
|
288
|
+
type DailyReportClientConfigInput = Partial<Omit<DailyReportClientConfig, "locale" | "labels" | "onSessionExpired">> & {
|
|
287
289
|
locale?: DailyReportLocale;
|
|
288
290
|
labels?: DailyReportLabelOverrides;
|
|
291
|
+
onSessionExpired: () => void;
|
|
289
292
|
};
|
|
290
293
|
type DailyReportClientConfigDefaults = Readonly<Pick<DailyReportClientConfig, "apiBasePath" | "ssePath" | "draftLabelName" | "renderHeader" | "showDevControls">>;
|
|
291
294
|
declare const defaultDailyReportClientConfig: DailyReportClientConfigDefaults;
|
|
292
295
|
declare const DailyReportConfigProvider: ({ config, children }: {
|
|
293
|
-
config
|
|
296
|
+
config: DailyReportClientConfigInput;
|
|
294
297
|
children: ReactNode;
|
|
295
298
|
}) => react.JSX.Element;
|
|
296
299
|
declare const useDailyReportConfig: () => DailyReportClientConfig;
|
|
@@ -300,7 +303,7 @@ declare const DailyReportLoading: () => react.JSX.Element;
|
|
|
300
303
|
type DailyReportPageProps = {
|
|
301
304
|
user?: DailyReportUser;
|
|
302
305
|
userId?: string | null;
|
|
303
|
-
config
|
|
306
|
+
config: DailyReportClientConfigInput;
|
|
304
307
|
};
|
|
305
308
|
declare const DailyReportPage: ({ config, ...rest }: DailyReportPageProps) => react.JSX.Element;
|
|
306
309
|
type DailyReportResolvedContentProps = {
|
|
@@ -311,6 +314,16 @@ type UnreadIndicatorProps = {
|
|
|
311
314
|
className?: string;
|
|
312
315
|
};
|
|
313
316
|
declare const UnreadIndicator: ({ className }: UnreadIndicatorProps) => react.JSX.Element;
|
|
317
|
+
type DailyReportSseConnectionStatus = UseReopeningEventSourceResult<DailyReportSseTerminalEvent>["status"] | {
|
|
318
|
+
readonly kind: "resyncing";
|
|
319
|
+
};
|
|
320
|
+
type UseDailyReportSseConnectionOptions = {
|
|
321
|
+
isSseEnabled: boolean;
|
|
322
|
+
onMessage: (payload: Exclude<DailyReportSseMessage, {
|
|
323
|
+
type: "connected";
|
|
324
|
+
}>) => void;
|
|
325
|
+
};
|
|
326
|
+
declare const useDailyReportSseConnection: ({ isSseEnabled, onMessage }: UseDailyReportSseConnectionOptions) => DailyReportSseConnectionStatus;
|
|
314
327
|
type DailyReportActionContextType = {
|
|
315
328
|
user?: DailyReportUser;
|
|
316
329
|
pendingAddCommentIds: React.MutableRefObject<Map<number, Map<number, string>>>;
|
|
@@ -322,6 +335,7 @@ type DailyReportActionContextType = {
|
|
|
322
335
|
items: DailyReportItem[];
|
|
323
336
|
isSseEnabled: boolean;
|
|
324
337
|
toggleSse: () => void;
|
|
338
|
+
sseStatus: DailyReportSseConnectionStatus;
|
|
325
339
|
addComment: (reportHubId: number, content: string, businessDate: string) => Promise<void>;
|
|
326
340
|
deleteComment: (reportHubId: number, commentId: number, businessDate: string) => Promise<void>;
|
|
327
341
|
toggleStar: (reportHubId: number, isStarred: boolean, businessDate: string) => Promise<void>;
|
|
@@ -420,13 +434,6 @@ declare const useDailyReportComments: (report: DailyReportDetail | null, user: U
|
|
|
420
434
|
setPendingDeleteId: react.Dispatch<react.SetStateAction<string | number | null>>;
|
|
421
435
|
resolvedIdMap: Map<number, number>;
|
|
422
436
|
};
|
|
423
|
-
type UseDailyReportSseConnectionOptions = {
|
|
424
|
-
isSseEnabled: boolean;
|
|
425
|
-
onMessage: (payload: Exclude<DailyReportSseMessage, {
|
|
426
|
-
type: "connected";
|
|
427
|
-
}>) => void;
|
|
428
|
-
};
|
|
429
|
-
declare const useDailyReportSseConnection: ({ isSseEnabled, onMessage }: UseDailyReportSseConnectionOptions) => void;
|
|
430
437
|
type UseDynamicViewportHeightOptions = {
|
|
431
438
|
enableMutationObserver?: boolean;
|
|
432
439
|
bottomGap?: number;
|
|
@@ -456,6 +463,7 @@ type DailyReportIdsStreamState = {
|
|
|
456
463
|
hasCompletedOnce: boolean;
|
|
457
464
|
completedAt: number | null;
|
|
458
465
|
error: Error | null;
|
|
466
|
+
streamAnchor: DailyReportSseStreamAnchor | null;
|
|
459
467
|
};
|
|
460
468
|
type DailyReportIdsStreamClientOptions = {
|
|
461
469
|
apiBasePath?: string;
|
|
@@ -480,6 +488,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
480
488
|
private readonly itemMap;
|
|
481
489
|
private readonly listeners;
|
|
482
490
|
private state;
|
|
491
|
+
private streamAnchorRevision;
|
|
483
492
|
private lastCursor;
|
|
484
493
|
private lastSnapshot;
|
|
485
494
|
private consecutiveFailures;
|
|
@@ -503,6 +512,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
503
512
|
refresh(options?: {
|
|
504
513
|
forceRefresh?: boolean;
|
|
505
514
|
}): void;
|
|
515
|
+
resync(): void;
|
|
506
516
|
applyExternalUpsert(item: DailyReportItem): void;
|
|
507
517
|
applyExternalRemoval(reportHubId: number): void;
|
|
508
518
|
dispose(): void;
|
|
@@ -511,6 +521,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
511
521
|
private streamOnce;
|
|
512
522
|
private readWithStallGuard;
|
|
513
523
|
private absorbChunkLine;
|
|
524
|
+
private absorbStreamAnchor;
|
|
514
525
|
private publishItems;
|
|
515
526
|
private schedulePublishItems;
|
|
516
527
|
private cancelScheduledPublishItems;
|
|
@@ -518,7 +529,6 @@ declare class DailyReportIdsStreamClient {
|
|
|
518
529
|
private buildStreamUrl;
|
|
519
530
|
private waitBeforeRetry;
|
|
520
531
|
}
|
|
521
|
-
declare const reloadDocument: () => void;
|
|
522
532
|
declare const ensureDailyReportIdsStreamSession: (options: {
|
|
523
533
|
apiBasePath?: string;
|
|
524
534
|
userKey: string | null;
|
|
@@ -531,6 +541,7 @@ declare const primeDailyReportIdsStreamSession: () => void;
|
|
|
531
541
|
declare const upsertDailyReportIdsStreamItem: (item: DailyReportItem) => void;
|
|
532
542
|
declare const removeDailyReportIdsStreamItem: (reportHubId: number) => void;
|
|
533
543
|
declare const retryDailyReportIdsStream: () => void;
|
|
544
|
+
declare const resyncDailyReportIdsStream: () => void;
|
|
534
545
|
declare const refreshDailyReportIdsStream: (options?: {
|
|
535
546
|
forceRefresh?: boolean;
|
|
536
547
|
}) => void;
|
|
@@ -557,4 +568,4 @@ declare const CONTENT_DRAG_POINTER_INPUTS: readonly [
|
|
|
557
568
|
"pen",
|
|
558
569
|
"touch"
|
|
559
570
|
];
|
|
560
|
-
export { BusinessDayThumbOverlay, CONTENT_DRAG_POINTER_INPUTS, DAILY_REPORT_FETCH_DEBOUNCE_MS, DAILY_REPORT_LABEL_CATALOGS, DAILY_REPORT_LABEL_KEYS, DEFAULT_ITEM_HEIGHT, type DailyReportActionContextType, DailyReportActionProvider, DailyReportAttachmentIndicator, DailyReportAttachmentList, DailyReportCache, type DailyReportClientConfig, type DailyReportClientConfigDefaults, type DailyReportClientConfigInput, DailyReportCommentForm, DailyReportCommentList, DailyReportConfigProvider, DailyReportDetailList, type DailyReportDetailListScrollRestore, type DailyReportDetailResource, DailyReportEditForm, type DailyReportErrorInfo, DailyReportErrorProvider, type DailyReportHeaderProps, DailyReportIdsStreamClient, type DailyReportIdsStreamClientOptions, type DailyReportIdsStreamPhase, type DailyReportIdsStreamState, DailyReportIdsStreamStatus, type DailyReportLabelOverrides, type DailyReportLabels, DailyReportList, DailyReportLoadError, DailyReportLoading, type DailyReportLocale, type DailyReportOperation, DailyReportPage, type DailyReportPageProps, DailyReportPostedComment, DailyReportResolvedContent, EMPTY_DETAIL, EMPTY_ITEM, FAST_SCROLL_INERTIA_OPTIONS, FAST_SCROLL_WHEEL_MULTIPLIER, ITEM_CONTAINER_HEIGHT, ITEM_VERTICAL_PADDING, MAX_PREVIEW_LINES, PREFETCH_LOOKAHEAD, PREFETCH_MAX_DATES, SCROLL_BAR_WIDTH, SSE_INITIAL_CONNECT_DEFER_MS, type SourceTypeConfig, TAP_SCROLL_CIRCLE_OPTIONS, UnreadIndicator, VIRTUAL_SCROLL_OVERSCAN_COUNT, WHEEL_RESET_TIMEOUT_MS, acquireMutationLock, applyBroadcastReportUpdate, applyDailyReportServerUpdates, bootstrapDailyReportIdsStreamSession, clearDailyReportCache, createDailyReportClientLoader, dailyReportShouldRevalidate, defaultDailyReportClientConfig, deleteDailyReportCache, ensureDailyReportIdsStreamSession, getCachedReport, getDailyReportIdsStreamSessionUserKey, primeDailyReportIdsStreamSession, refreshDailyReportIdsStream, registerRecentDeletion, releaseMutationLock,
|
|
571
|
+
export { BusinessDayThumbOverlay, CONTENT_DRAG_POINTER_INPUTS, DAILY_REPORT_FETCH_DEBOUNCE_MS, DAILY_REPORT_LABEL_CATALOGS, DAILY_REPORT_LABEL_KEYS, DEFAULT_ITEM_HEIGHT, type DailyReportActionContextType, DailyReportActionProvider, DailyReportAttachmentIndicator, DailyReportAttachmentList, DailyReportCache, type DailyReportClientConfig, type DailyReportClientConfigDefaults, type DailyReportClientConfigInput, DailyReportCommentForm, DailyReportCommentList, DailyReportConfigProvider, DailyReportDetailList, type DailyReportDetailListScrollRestore, type DailyReportDetailResource, DailyReportEditForm, type DailyReportErrorInfo, DailyReportErrorProvider, type DailyReportHeaderProps, DailyReportIdsStreamClient, type DailyReportIdsStreamClientOptions, type DailyReportIdsStreamPhase, type DailyReportIdsStreamState, DailyReportIdsStreamStatus, type DailyReportLabelOverrides, type DailyReportLabels, DailyReportList, DailyReportLoadError, DailyReportLoading, type DailyReportLocale, type DailyReportOperation, DailyReportPage, type DailyReportPageProps, DailyReportPostedComment, DailyReportResolvedContent, type DailyReportSseConnectionStatus, EMPTY_DETAIL, EMPTY_ITEM, FAST_SCROLL_INERTIA_OPTIONS, FAST_SCROLL_WHEEL_MULTIPLIER, ITEM_CONTAINER_HEIGHT, ITEM_VERTICAL_PADDING, MAX_PREVIEW_LINES, PREFETCH_LOOKAHEAD, PREFETCH_MAX_DATES, SCROLL_BAR_WIDTH, SSE_INITIAL_CONNECT_DEFER_MS, type SourceTypeConfig, TAP_SCROLL_CIRCLE_OPTIONS, UnreadIndicator, type UseDailyReportSseConnectionOptions, VIRTUAL_SCROLL_OVERSCAN_COUNT, WHEEL_RESET_TIMEOUT_MS, acquireMutationLock, applyBroadcastReportUpdate, applyDailyReportServerUpdates, bootstrapDailyReportIdsStreamSession, clearDailyReportCache, createDailyReportClientLoader, dailyReportShouldRevalidate, defaultDailyReportClientConfig, deleteDailyReportCache, ensureDailyReportIdsStreamSession, getCachedReport, getDailyReportIdsStreamSessionUserKey, primeDailyReportIdsStreamSession, refreshDailyReportIdsStream, registerRecentDeletion, releaseMutationLock, removeDailyReportIdsStreamItem, resetDailyReportIdsStreamSessionForTesting, resolveDailyReportLabels, resolveSourceTypeConfig, resyncDailyReportIdsStream, retryDailyReportIdsStream, subscribeCacheReady, updateDailyReportCache, upsertDailyReportIdsStreamItem, useAnimatedNumber, useDailyReportActionContext, useDailyReportComments, useDailyReportConfig, useDailyReportDetail, useDailyReportErrorSurface, useDailyReportIdsStream, useDailyReportPrefetch, useDailyReportSseConnection, useDynamicViewportHeight, writeCache };
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import * as react from "react";
|
|
|
2
2
|
import { RefObject, ReactNode, Context } from "react";
|
|
3
3
|
import { ScrollBarThumbOverlayRenderProps, VirtualScrollLocale, VirtualScrollLabels, ScrollPaneInertiaOptions, ScrollBarTapCircleOptions } from "@aiquants/virtualscroll";
|
|
4
4
|
import { D as DailyReportAttachmentSummary, a as DailyReportItem, b as DailyReportDetail, c as DailyReportUser } from "./types-CqgYQgbH.js";
|
|
5
|
-
import { U as UIComment, D as DailyReportSseMessage } from "./
|
|
5
|
+
import { U as UIComment, D as DailyReportSseTerminalEvent, a as DailyReportSseMessage, b as DailyReportSseStreamAnchor } from "./ids-stream-BnM6L-Sk.js";
|
|
6
|
+
import { UseReopeningEventSourceResult } from "@aiquants/sse/react";
|
|
6
7
|
import { ShouldRevalidateFunction } from "react-router";
|
|
7
8
|
import "zod";
|
|
8
9
|
declare const BusinessDayThumbOverlay: ({ orientation, thumbCenter, label, isDragging, isTapScrollActive, isWheelScrollActive }: ScrollBarThumbOverlayRenderProps & {
|
|
@@ -282,15 +283,17 @@ type DailyReportClientConfig = {
|
|
|
282
283
|
renderHeader: (props: DailyReportHeaderProps) => ReactNode;
|
|
283
284
|
showDevControls: boolean;
|
|
284
285
|
onError?: (info: DailyReportErrorInfo) => void;
|
|
286
|
+
onSessionExpired: () => void;
|
|
285
287
|
};
|
|
286
|
-
type DailyReportClientConfigInput = Partial<Omit<DailyReportClientConfig, "locale" | "labels">> & {
|
|
288
|
+
type DailyReportClientConfigInput = Partial<Omit<DailyReportClientConfig, "locale" | "labels" | "onSessionExpired">> & {
|
|
287
289
|
locale?: DailyReportLocale;
|
|
288
290
|
labels?: DailyReportLabelOverrides;
|
|
291
|
+
onSessionExpired: () => void;
|
|
289
292
|
};
|
|
290
293
|
type DailyReportClientConfigDefaults = Readonly<Pick<DailyReportClientConfig, "apiBasePath" | "ssePath" | "draftLabelName" | "renderHeader" | "showDevControls">>;
|
|
291
294
|
declare const defaultDailyReportClientConfig: DailyReportClientConfigDefaults;
|
|
292
295
|
declare const DailyReportConfigProvider: ({ config, children }: {
|
|
293
|
-
config
|
|
296
|
+
config: DailyReportClientConfigInput;
|
|
294
297
|
children: ReactNode;
|
|
295
298
|
}) => react.JSX.Element;
|
|
296
299
|
declare const useDailyReportConfig: () => DailyReportClientConfig;
|
|
@@ -300,7 +303,7 @@ declare const DailyReportLoading: () => react.JSX.Element;
|
|
|
300
303
|
type DailyReportPageProps = {
|
|
301
304
|
user?: DailyReportUser;
|
|
302
305
|
userId?: string | null;
|
|
303
|
-
config
|
|
306
|
+
config: DailyReportClientConfigInput;
|
|
304
307
|
};
|
|
305
308
|
declare const DailyReportPage: ({ config, ...rest }: DailyReportPageProps) => react.JSX.Element;
|
|
306
309
|
type DailyReportResolvedContentProps = {
|
|
@@ -311,6 +314,16 @@ type UnreadIndicatorProps = {
|
|
|
311
314
|
className?: string;
|
|
312
315
|
};
|
|
313
316
|
declare const UnreadIndicator: ({ className }: UnreadIndicatorProps) => react.JSX.Element;
|
|
317
|
+
type DailyReportSseConnectionStatus = UseReopeningEventSourceResult<DailyReportSseTerminalEvent>["status"] | {
|
|
318
|
+
readonly kind: "resyncing";
|
|
319
|
+
};
|
|
320
|
+
type UseDailyReportSseConnectionOptions = {
|
|
321
|
+
isSseEnabled: boolean;
|
|
322
|
+
onMessage: (payload: Exclude<DailyReportSseMessage, {
|
|
323
|
+
type: "connected";
|
|
324
|
+
}>) => void;
|
|
325
|
+
};
|
|
326
|
+
declare const useDailyReportSseConnection: ({ isSseEnabled, onMessage }: UseDailyReportSseConnectionOptions) => DailyReportSseConnectionStatus;
|
|
314
327
|
type DailyReportActionContextType = {
|
|
315
328
|
user?: DailyReportUser;
|
|
316
329
|
pendingAddCommentIds: React.MutableRefObject<Map<number, Map<number, string>>>;
|
|
@@ -322,6 +335,7 @@ type DailyReportActionContextType = {
|
|
|
322
335
|
items: DailyReportItem[];
|
|
323
336
|
isSseEnabled: boolean;
|
|
324
337
|
toggleSse: () => void;
|
|
338
|
+
sseStatus: DailyReportSseConnectionStatus;
|
|
325
339
|
addComment: (reportHubId: number, content: string, businessDate: string) => Promise<void>;
|
|
326
340
|
deleteComment: (reportHubId: number, commentId: number, businessDate: string) => Promise<void>;
|
|
327
341
|
toggleStar: (reportHubId: number, isStarred: boolean, businessDate: string) => Promise<void>;
|
|
@@ -420,13 +434,6 @@ declare const useDailyReportComments: (report: DailyReportDetail | null, user: U
|
|
|
420
434
|
setPendingDeleteId: react.Dispatch<react.SetStateAction<string | number | null>>;
|
|
421
435
|
resolvedIdMap: Map<number, number>;
|
|
422
436
|
};
|
|
423
|
-
type UseDailyReportSseConnectionOptions = {
|
|
424
|
-
isSseEnabled: boolean;
|
|
425
|
-
onMessage: (payload: Exclude<DailyReportSseMessage, {
|
|
426
|
-
type: "connected";
|
|
427
|
-
}>) => void;
|
|
428
|
-
};
|
|
429
|
-
declare const useDailyReportSseConnection: ({ isSseEnabled, onMessage }: UseDailyReportSseConnectionOptions) => void;
|
|
430
437
|
type UseDynamicViewportHeightOptions = {
|
|
431
438
|
enableMutationObserver?: boolean;
|
|
432
439
|
bottomGap?: number;
|
|
@@ -456,6 +463,7 @@ type DailyReportIdsStreamState = {
|
|
|
456
463
|
hasCompletedOnce: boolean;
|
|
457
464
|
completedAt: number | null;
|
|
458
465
|
error: Error | null;
|
|
466
|
+
streamAnchor: DailyReportSseStreamAnchor | null;
|
|
459
467
|
};
|
|
460
468
|
type DailyReportIdsStreamClientOptions = {
|
|
461
469
|
apiBasePath?: string;
|
|
@@ -480,6 +488,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
480
488
|
private readonly itemMap;
|
|
481
489
|
private readonly listeners;
|
|
482
490
|
private state;
|
|
491
|
+
private streamAnchorRevision;
|
|
483
492
|
private lastCursor;
|
|
484
493
|
private lastSnapshot;
|
|
485
494
|
private consecutiveFailures;
|
|
@@ -503,6 +512,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
503
512
|
refresh(options?: {
|
|
504
513
|
forceRefresh?: boolean;
|
|
505
514
|
}): void;
|
|
515
|
+
resync(): void;
|
|
506
516
|
applyExternalUpsert(item: DailyReportItem): void;
|
|
507
517
|
applyExternalRemoval(reportHubId: number): void;
|
|
508
518
|
dispose(): void;
|
|
@@ -511,6 +521,7 @@ declare class DailyReportIdsStreamClient {
|
|
|
511
521
|
private streamOnce;
|
|
512
522
|
private readWithStallGuard;
|
|
513
523
|
private absorbChunkLine;
|
|
524
|
+
private absorbStreamAnchor;
|
|
514
525
|
private publishItems;
|
|
515
526
|
private schedulePublishItems;
|
|
516
527
|
private cancelScheduledPublishItems;
|
|
@@ -518,7 +529,6 @@ declare class DailyReportIdsStreamClient {
|
|
|
518
529
|
private buildStreamUrl;
|
|
519
530
|
private waitBeforeRetry;
|
|
520
531
|
}
|
|
521
|
-
declare const reloadDocument: () => void;
|
|
522
532
|
declare const ensureDailyReportIdsStreamSession: (options: {
|
|
523
533
|
apiBasePath?: string;
|
|
524
534
|
userKey: string | null;
|
|
@@ -531,6 +541,7 @@ declare const primeDailyReportIdsStreamSession: () => void;
|
|
|
531
541
|
declare const upsertDailyReportIdsStreamItem: (item: DailyReportItem) => void;
|
|
532
542
|
declare const removeDailyReportIdsStreamItem: (reportHubId: number) => void;
|
|
533
543
|
declare const retryDailyReportIdsStream: () => void;
|
|
544
|
+
declare const resyncDailyReportIdsStream: () => void;
|
|
534
545
|
declare const refreshDailyReportIdsStream: (options?: {
|
|
535
546
|
forceRefresh?: boolean;
|
|
536
547
|
}) => void;
|
|
@@ -557,4 +568,4 @@ declare const CONTENT_DRAG_POINTER_INPUTS: readonly [
|
|
|
557
568
|
"pen",
|
|
558
569
|
"touch"
|
|
559
570
|
];
|
|
560
|
-
export { BusinessDayThumbOverlay, CONTENT_DRAG_POINTER_INPUTS, DAILY_REPORT_FETCH_DEBOUNCE_MS, DAILY_REPORT_LABEL_CATALOGS, DAILY_REPORT_LABEL_KEYS, DEFAULT_ITEM_HEIGHT, type DailyReportActionContextType, DailyReportActionProvider, DailyReportAttachmentIndicator, DailyReportAttachmentList, DailyReportCache, type DailyReportClientConfig, type DailyReportClientConfigDefaults, type DailyReportClientConfigInput, DailyReportCommentForm, DailyReportCommentList, DailyReportConfigProvider, DailyReportDetailList, type DailyReportDetailListScrollRestore, type DailyReportDetailResource, DailyReportEditForm, type DailyReportErrorInfo, DailyReportErrorProvider, type DailyReportHeaderProps, DailyReportIdsStreamClient, type DailyReportIdsStreamClientOptions, type DailyReportIdsStreamPhase, type DailyReportIdsStreamState, DailyReportIdsStreamStatus, type DailyReportLabelOverrides, type DailyReportLabels, DailyReportList, DailyReportLoadError, DailyReportLoading, type DailyReportLocale, type DailyReportOperation, DailyReportPage, type DailyReportPageProps, DailyReportPostedComment, DailyReportResolvedContent, EMPTY_DETAIL, EMPTY_ITEM, FAST_SCROLL_INERTIA_OPTIONS, FAST_SCROLL_WHEEL_MULTIPLIER, ITEM_CONTAINER_HEIGHT, ITEM_VERTICAL_PADDING, MAX_PREVIEW_LINES, PREFETCH_LOOKAHEAD, PREFETCH_MAX_DATES, SCROLL_BAR_WIDTH, SSE_INITIAL_CONNECT_DEFER_MS, type SourceTypeConfig, TAP_SCROLL_CIRCLE_OPTIONS, UnreadIndicator, VIRTUAL_SCROLL_OVERSCAN_COUNT, WHEEL_RESET_TIMEOUT_MS, acquireMutationLock, applyBroadcastReportUpdate, applyDailyReportServerUpdates, bootstrapDailyReportIdsStreamSession, clearDailyReportCache, createDailyReportClientLoader, dailyReportShouldRevalidate, defaultDailyReportClientConfig, deleteDailyReportCache, ensureDailyReportIdsStreamSession, getCachedReport, getDailyReportIdsStreamSessionUserKey, primeDailyReportIdsStreamSession, refreshDailyReportIdsStream, registerRecentDeletion, releaseMutationLock,
|
|
571
|
+
export { BusinessDayThumbOverlay, CONTENT_DRAG_POINTER_INPUTS, DAILY_REPORT_FETCH_DEBOUNCE_MS, DAILY_REPORT_LABEL_CATALOGS, DAILY_REPORT_LABEL_KEYS, DEFAULT_ITEM_HEIGHT, type DailyReportActionContextType, DailyReportActionProvider, DailyReportAttachmentIndicator, DailyReportAttachmentList, DailyReportCache, type DailyReportClientConfig, type DailyReportClientConfigDefaults, type DailyReportClientConfigInput, DailyReportCommentForm, DailyReportCommentList, DailyReportConfigProvider, DailyReportDetailList, type DailyReportDetailListScrollRestore, type DailyReportDetailResource, DailyReportEditForm, type DailyReportErrorInfo, DailyReportErrorProvider, type DailyReportHeaderProps, DailyReportIdsStreamClient, type DailyReportIdsStreamClientOptions, type DailyReportIdsStreamPhase, type DailyReportIdsStreamState, DailyReportIdsStreamStatus, type DailyReportLabelOverrides, type DailyReportLabels, DailyReportList, DailyReportLoadError, DailyReportLoading, type DailyReportLocale, type DailyReportOperation, DailyReportPage, type DailyReportPageProps, DailyReportPostedComment, DailyReportResolvedContent, type DailyReportSseConnectionStatus, EMPTY_DETAIL, EMPTY_ITEM, FAST_SCROLL_INERTIA_OPTIONS, FAST_SCROLL_WHEEL_MULTIPLIER, ITEM_CONTAINER_HEIGHT, ITEM_VERTICAL_PADDING, MAX_PREVIEW_LINES, PREFETCH_LOOKAHEAD, PREFETCH_MAX_DATES, SCROLL_BAR_WIDTH, SSE_INITIAL_CONNECT_DEFER_MS, type SourceTypeConfig, TAP_SCROLL_CIRCLE_OPTIONS, UnreadIndicator, type UseDailyReportSseConnectionOptions, VIRTUAL_SCROLL_OVERSCAN_COUNT, WHEEL_RESET_TIMEOUT_MS, acquireMutationLock, applyBroadcastReportUpdate, applyDailyReportServerUpdates, bootstrapDailyReportIdsStreamSession, clearDailyReportCache, createDailyReportClientLoader, dailyReportShouldRevalidate, defaultDailyReportClientConfig, deleteDailyReportCache, ensureDailyReportIdsStreamSession, getCachedReport, getDailyReportIdsStreamSessionUserKey, primeDailyReportIdsStreamSession, refreshDailyReportIdsStream, registerRecentDeletion, releaseMutationLock, removeDailyReportIdsStreamItem, resetDailyReportIdsStreamSessionForTesting, resolveDailyReportLabels, resolveSourceTypeConfig, resyncDailyReportIdsStream, retryDailyReportIdsStream, subscribeCacheReady, updateDailyReportCache, upsertDailyReportIdsStreamItem, useAnimatedNumber, useDailyReportActionContext, useDailyReportComments, useDailyReportConfig, useDailyReportDetail, useDailyReportErrorSurface, useDailyReportIdsStream, useDailyReportPrefetch, useDailyReportSseConnection, useDynamicViewportHeight, writeCache };
|