@aiquants/enrichment-react-router 0.1.1 → 0.2.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 CHANGED
@@ -6,8 +6,233 @@ React Router (v7 / v8) adapter and turnkey operations console for Storage AI Enr
6
6
 
7
7
  `@aiquants/enrichment-react-router` encapsulates the full administrative lifecycle of enterprise knowledge indexing, RAG pipelines, graph stores, vector indices, and peripheral database health inspection into a single mountable route.
8
8
 
9
+ ## Prerequisites
10
+
11
+ - Node.js >= 18.0.0 (`engines`); the `react-router` peer sets the effective floor: >= 20.0.0 for React Router 7, higher for some 8.x releases (8.3.0 requires >= 22.22.0)
12
+ - React >= 19.0.0 and React DOM >= 19.0.0 (peer dependencies)
13
+ - React Router 7 or 8 (`react-router` `^7.0.0 || ^8.0.0`, peer dependency)
14
+ - `zod` `^3.25.0` (peer dependency; the route action validates form payloads with it)
15
+ - `@aiquants/authz-core`, `@aiquants/console-ui`, `@aiquants/enrichment-core`, `@aiquants/enrichment-react`, `@aiquants/governance-core` and `@aiquants/governance-react` (peer dependencies)
16
+
9
17
  ## Installation
10
18
 
11
19
  ```bash
12
- pnpm add @aiquants/enrichment-react-router
20
+ pnpm add @aiquants/enrichment-react-router @aiquants/authz-core @aiquants/console-ui @aiquants/enrichment-core @aiquants/enrichment-react @aiquants/governance-core @aiquants/governance-react 'zod@^3.25.0'
21
+ ```
22
+
23
+ React, React DOM and React Router come from the host application. `zod` carries the peer range because a bare `zod` installs the registry's `latest` tag, which is outside `^3.25.0`.
24
+
25
+ ## Usage
26
+
27
+ ```tsx
28
+ import { createStorageAdminApp } from "@aiquants/enrichment-react-router"
29
+
30
+ const app = createStorageAdminApp({ store, requireUser, requirePermission, resolveTenantId, authorizeIngest, canReadIntegrityFindings, canUpdateKnowledge })
31
+
32
+ export const loader = app.loader
33
+ export const action = app.action
34
+
35
+ export default function StorageAdminRoute() {
36
+ return (
37
+ <app.View
38
+ onSearch={runMetadataSearch}
39
+ loadIntegrityOverview={loadIntegrityOverview}
40
+ loadIntegrityFindings={loadIntegrityFindings}
41
+ policyConflicts={POLICY_CONFLICT_HOST}
42
+ documentAuthority={DOCUMENT_AUTHORITY_HOST}
43
+ onRefreshIngestQueue={refreshIngestQueue}
44
+ onLoadDocumentRuns={loadDocumentRuns}
45
+ onCompareVariants={compareVariants}
46
+ />
47
+ )
48
+ }
49
+ ```
50
+
51
+ Pass the host functions and host objects as module constants. A new identity re-reads nothing on the audit, policy conflict and ledger cards: they read the functions through refs and key their reads on what they read (a query, a pair's id), never on the host. `graphTraversal` is the exception: its relationship types are re-read when it changes (below).
52
+
53
+ ## The host ports (`CreateStorageAdminAppOptions`)
54
+
55
+ Every port below except the two optional settings of the last row is required, so a host that forgets one fails to compile instead of serving the console unguarded. A judgment port (`canReadIntegrityFindings`, `canUpdateKnowledge`) answers a refusal with `false`; a throw fails the loader (and the action that asks it), as a throw of `requirePermission` other than `AuthzDeniedError` does.
56
+
57
+ | Port | Returns | Notes |
58
+ | --- | --- | --- |
59
+ | `store` | `StorageAdminStore` | The reads and writes below. |
60
+ | `requireUser(request)` | `Promise<StorageAdminOperator \| null>` | The operator (below); `null` without a session. |
61
+ | `requirePermission(request, { resourceKey, action })` | `Promise<unknown>` | Throws `AuthzDeniedError` to refuse. The loader asks `read`, the action asks `update`, for `resourceKey` (default `storage_admin`). |
62
+ | `resolveTenantId(request)` | `string \| Promise<string>` | The tenant every read and write acts in. There is no default tenant: the tenant is the isolation axis. |
63
+ | `canReadIntegrityFindings(request)` | `Promise<boolean>` | Whether the operator may read every document (a file read scoped to no rows and no columns). The integrity audit's findings name documents, so the findings cells and the repair are offered only when it is `true`; the action refuses a `REPAIR` start with `FORBIDDEN` before calling the store when it is `false`. The host's findings route should use the same judgment. |
64
+ | `canUpdateKnowledge(request)` | `Promise<boolean>` | Whether the operator may write the document-authority ledger and decide policy conflicts: `true` exactly when the host would answer this operator's policy conflict summary with `viewer.canDecide` `true` (compute both from one function, so the ledger and the conflict queue never disagree). It is a permission, not a deployment state: a deployment that disables knowledge writes still answers `true`, and its write routes refuse with `DEPLOYMENT_DISABLED`, which the cards state. The loader answers it, so the ledger's first render (and a server render) already knows it. |
65
+ | `authorizeIngest(request, payload)` | `Promise<string \| null>` | The ingest refusal in the operator's words, or `null` to allow. |
66
+ | `healthProbeOptions?` / `resourceKey?` | | Optional probe settings and the permission resource key. |
67
+
68
+ ## The store contract (`StorageAdminStore`)
69
+
70
+ The host implements one object and injects it through `createStorageAdminApp`. Beyond the configuration, governance and health reads, the store owns:
71
+
72
+ | Method | Returns | Notes |
73
+ | --- | --- | --- |
74
+ | `getPipelineStepMetrics(tenantId)` | `readonly PipelineStepMetric[]` | One aggregate per (`documentKind`, `stepKey`) over the newest `pipelineStepMetricWindow` records of that pair (`@aiquants/enrichment-core`); `documentKind` is the kind of the run the records belong to. Read from the step table, never measured in process. The loader checks every entry against `PipelineStepMetricSchema` and throws (naming the method and each issue) when one is not a metric — one without `documentKind` included — or when a pair appears twice, because the flow figure shows the first match and would silently drop the second. |
75
+ | `pipelineStepMetricWindow` (property) | `number` | How many of the newest records per (`documentKind`, `stepKey`) each metric aggregates: the same constant the aggregation query uses. The loader throws, before it queries anything, when it is not a positive safe integer. |
76
+ | `getRecentPipelineRuns(tenantId)` | `readonly PipelineRunSummary[]` | The tenant's most recent runs, newest first, **without their steps**. The loader checks every entry against `PipelineRunSummarySchema` and throws (naming the method and each issue) when one is not a summary — a `steps` key included, because a full `PipelineRunRecord` is assignable to the summary type and would otherwise ship every step to the browser on each load. |
77
+ | `getStrategyVariants(tenantId)` | `readonly StrategyVariant[]` | `{ strategyId, variantKey, label, embeddingModel, domainKey }`, one per `tm_enrichment_strategy` row the tenant can see (its own rows and the `SYSTEM` rows). `strategyId` is the identity: every domain has its own `default` row, so a variant key repeats across domains. |
78
+ | `getEnrichmentStrategies(tenantId)` | `EnrichmentStrategyRow[]` | The per-domain strategies. Also the one source of the domain list the ingest console and the classification-rule editor offer (`{ key: domainKey, label: domainLabel }`, distinct, in board order). |
79
+ | `retryAllFailedSyncItems(tenantId, actor?, accessToken?)` | `RetryAllFailedResult` | `{ requeued, skipped: { metadataId, reason }[] }` — every row the retry left where it was is named, so the console never reports an all-clear over skipped rows. |
80
+ | `readIntegrityAuditOverview(tenantId)` | `IntegrityAuditOverview` | The integrity audit's overview read from the recorded runs (`@aiquants/enrichment-core`): the database's clock (`readAt`), the last completed run with its quantities, the active run, a newer unsuccessful run. No store is measured. The loader checks the answer against `IntegrityAuditOverviewSchema` and catches this read alone: a throw or a contract violation becomes the overview's own failure (`integrityAudit`), and the rest of the console is still drawn. A thrown error's message is that failure's reason, shipped in the loader data and shown to the operator as given, so throw only sentences an operator may read: log a database driver's error (its message can carry the query and its parameters) and throw your own sentence; keep the core's range sentences (`assertSystemParameterInRange`). |
81
+ | `startIntegrityRun(tenantId, mode, basisRunUid, accessToken)` | `IntegrityCommandReply` | Starts a `SCAN` (`basisRunUid` `null`) or a `REPAIR` (the basis scan's UID) upstream in the operator's name; the token is required. Answers `{ ok: true, runUid }` or `{ ok: false, status, errorCode }` (the upstream status and business code; no upstream wording). A throw is answered `UPSTREAM_FAILED` without a status and its cause is discarded (the package has no logger and shows no upstream wording), so the store logs a failure it throws for. |
82
+ | `cancelIntegrityRun(tenantId, runUid, accessToken)` | `IntegrityCommandReply` | Cancels a run (or closes one whose heartbeat stopped), answered like the start. |
83
+ | `getCircuitBreakerStatus()` | `Record<string, CircuitBreakerState>` | The search path's breakers (`vector` / `graph`). Only the search reads and feeds them, so only the search workbench is given them; the pipeline figure is not. |
84
+ | `getSystemParameters(tenantId)` | `SystemParameter[]` | The `value` arrives already in the type `data_type` names: `boolean` for `bool`, `number` for `int` / `float`, `string` for `string` / `json`. The store owns the conversion from stored text. |
85
+
86
+ The store reads no single run and no document history: the history panel reads through the injected `onLoadDocumentRuns` (below), whose route and authorization belong to the host.
87
+
88
+ ## The operator (`StorageAdminOperator`)
89
+
90
+ `requireUser(request)` is required and resolves `Promise<StorageAdminOperator | null>`: `null` when the request carries no session, otherwise the operator the request acts for.
91
+
92
+ | Field | Type | Meaning |
93
+ | --- | --- | --- |
94
+ | `email` | `string` | The address every write of the action is attributed to (`updated_by`, and the `actor` argument of the store's writes). An `id` or a display name is not an identity the audit trail can be read back through, so there is no other field to fall back on. |
95
+ | `accessToken` | `string \| null` | The operator's OAuth access token, forwarded unchanged to the store calls that take one (`retrySyncItem`, `retryAllFailedSyncItems`, `startIntegrityRun`, `cancelIntegrityRun`, `ingestDocument`, `inspectFileUri`). `null` when the session holds no token the upstream services accept — a mock or test session included; the package knows no host's mock values, so the host answers `null` for them, and a start or cancel is then refused with `FORBIDDEN` without calling the store. `""` is not a token: the action throws. |
96
+
97
+ The host maps its own session profile onto these two fields (for a Google session profile, `email` is `emails[0].value`). The package reads nothing else from the session and never probes the host's object, so a profile that does not carry `email` and `accessToken` does not type-check as an operator.
98
+
99
+ ```ts
100
+ import type { StorageAdminOperator } from "@aiquants/enrichment-react-router"
101
+
102
+ const requireUser = async (request: Request): Promise<StorageAdminOperator | null> => {
103
+ const session = await readSession(request)
104
+ if (session === null) return null
105
+ return { email: session.emails[0].value, accessToken: isUsableAccessToken(session.accessToken) ? session.accessToken : null }
106
+ }
13
107
  ```
108
+
109
+ ## Loader data
110
+
111
+ `StorageAdminLoaderData` carries, in addition to the configuration, governance, health and audit sections:
112
+
113
+ - `pipelineStepMetrics` — the step aggregates above, one per (`documentKind`, `stepKey`); the pipeline flow viewer draws its per-step figures from these and from nothing else, showing only the selected kind's own entry (a kind without one reads 未測定, never another kind's numbers).
114
+ - `pipelineStepMetricWindow` — the store's `pipelineStepMetricWindow`, passed to `PipelineFlowViewer` as `metricSampleWindow` so the figure states the window its numbers cover.
115
+ - `circuitBreakerStatus` — the search breakers above, passed to `MetadataSearchWorkbench` only.
116
+ - `recentPipelineRuns` — the run summaries above, listed under the flow viewer.
117
+ - `displayTimeZone` — the IANA time zone every recorded instant is written in, resolved on the server (`Intl.DateTimeFormat().resolvedOptions().timeZone`).
118
+ The view sets the console root's time zone from it (`ConsoleUiRoot` of `@aiquants/console-ui`, `locale="ja"`, `formatLocale="ja-JP"`, test id `storage-admin-console-ui`, its announcer `storage-admin-console-ui-announcer`), and every card reads the zone from the root — no card takes it as a prop — so the server-rendered page and the hydrated one print the same string.
119
+ `SyncStatusMonitor`'s `failedSyncItems[].failed_at` must therefore be ISO 8601 instants with an explicit offset, or `null`.
120
+ - `integrityAudit` — `ResourceOutcome<IntegrityAuditOverview>` (`@aiquants/console-ui/core`): the store's overview, or `{ ok: false, status: null, reason }` when that one read failed.
121
+ - `canReadIntegrityFindings` / `canUpdateKnowledge` — the two host judgments above, answered per request.
122
+ - `strategyVariants` — the variants above, offered by the model-comparison workbench.
123
+ - `enrichmentStrategies` — the strategies above; the domain options are derived from them in the view.
124
+ - `systemParameters` — the typed parameters above.
125
+
126
+ Every timestamp the host ships in loader data or in `onLoadDocumentRuns` (`startedAt`, `finishedAt`, `createdAt`, `lastStartedAt`, `checkedAt`, and `failedSyncItems[].failed_at` when not `null`) must be an ISO 8601 instant with an explicit offset (`Z` or `±hh:mm`), as `Date.prototype.toISOString()` writes it: `@aiquants/enrichment-react`'s `RecordedInstant` throws `RangeError` for anything else rather than guess the zone. The integrity audit's instants are checked by the core's contract where the loader reads them.
127
+
128
+ ## Route action validation
129
+
130
+ Before any intent is acted on, the action refuses the request as a whole:
131
+
132
+ | Condition | Answer |
133
+ | --- | --- |
134
+ | `requireUser` resolves `null` | `401 { error: "認証が必要です。" }` |
135
+ | The operator's `email` is empty or only whitespace | `403 { error: "操作者を特定できないため設定を変更できません。" }` |
136
+ | The operator's `accessToken` is `""` | Throws `Error` (a host error: answer `null` for a session without a usable token); it propagates to the route's error boundary and nothing is written. |
137
+ | `requirePermission` throws `AuthzDeniedError` for `update` | `403 { error: "権限がありません。" }`, except that a `start_integrity_run` / `cancel_integrity_run` is refused on the audit card: `403 { failure }` with `FORBIDDEN` and no status (below). Only this refusal reads the form, to choose the answer; a request the gate admits is read after the gate. A refused body that is not a form (JSON, or none) names no intent and gets the same `403 { error }`. Any other error `requirePermission` throws propagates. |
138
+
139
+ The loader throws `Response` `401` (`認証が必要です。`) when `requireUser` resolves `null`, and `403` (`権限がありません。`) when `requirePermission` throws `AuthzDeniedError` for `read`.
140
+
141
+ Each intent then answers `{ success: true, ... }` or refuses with `{ error }`:
142
+
143
+ | Intent | Refused with | Refused when |
144
+ | --- | --- | --- |
145
+ | `refresh_health` | — | Never; answers `{ success: true, refreshed: true }` (the revalidated loader re-probes). |
146
+ | `update_enrichment_strategy` | `400` | `stage` is not a canonical enrichment stage key; `strategyId` or `domainId` is not a positive safe integer; the store throws (its message is the `error`). |
147
+ | `toggle_flag` | `400` | `flagKey` is empty or is not one of the tenant's flags reported by `getFeatureFlags`. |
148
+ | `update_confidentiality_policy` | `400` | `confidentialityLevel` or `capability` is not a canonical value; `allowCloudProvider` is `'true'` for a capability that sends nothing outside the deployment. |
149
+ | `save_transcription_term` | `400` | `term` is blank; `boost` is present but not a finite number greater than zero (absent defers to the service); `id` is present but not a positive safe integer (absent means a new row); the store throws (e.g. the row belongs to another tenant or no longer exists; its message is the `error`). |
150
+ | `save_transcription_reference` | `400` | `fileUri` is blank; `id` is present but not a positive safe integer; the store throws (e.g. a URI the host's document-URI rule refuses; its message is the `error`). |
151
+ | `update_parameter` | `400` | `paramKey` is empty or is not one of the tenant's parameters, or `paramValue` is not readable as the parameter's `data_type` (`bool`: `'true'` / `'false'`; `int`: an integer literal within the safe range; `float`: a finite number; `json`: valid JSON), or the core's range table (`assertSystemParameterInRange` of `@aiquants/enrichment-core`) bounds the key and the value lies outside it (`<key> は <min>〜<max> の整数で指定してください。`). The raw string is passed to the store on success. |
152
+ | `update_prompt` | `400` | `payload` is not valid JSON; `templateKey` is empty; `payload` is not `{ templateText: string; modelName: string; temperature: number; maxOutputTokens: number; responseSchema?: object \| string \| null; endpointBaseUrl: string \| null }` (unknown keys refused); the store throws. |
153
+ | `reorder_rules` | `400` | `orderedRuleIds` is not valid JSON, or is not a non-empty array of distinct positive safe integers. |
154
+ | `retry_job` | `400` | `fileId` is empty; the store throws. |
155
+ | `retry_all_failed` | `400` | The store throws. Success answers `{ success, requeued, skipped }`. |
156
+ | `start_integrity_run` | `400` / failure | `400 { error }` unless the form is `mode=SCAN` without `basisRunUid` or `mode=REPAIR` with a UUID `basisRunUid`. Success answers `{ success, runUid }`. A failure answers `{ failure }` (below). |
157
+ | `cancel_integrity_run` | `400` / failure | `400 { error }` unless `runUid` is a UUID. Success answers `{ success, runUid }`. A failure answers `{ failure }` (below). |
158
+ | `resolve_entity` | `400` | `entityId` is empty or `action` is neither `merge` nor `promote`; the store throws. |
159
+ | `ingest_document` | `400` / `403` | `400` when `payload` is absent or empty, is not valid JSON, or is refused (not an object; `fileUri` absent, not a string, or blank; `confidentialityLevel` absent or not one of `PUBLIC`, `INTERNAL`, `DEPARTMENT`, `CONFIDENTIAL`, `RESTRICTED`; `departmentId` present but neither an integer nor `null` — an absent `departmentId` is accepted), and when the store throws. `403` when the host's `authorizeIngest(request, payload)` returns a refusal (the refusal is the `error`). Success answers `{ success, result }`. |
160
+ | `inspect_uri` | `400` / `501` | `400` when `fileUri` is blank, the store throws, or the inspection's `fileSize` is not a non-negative safe integer (the count rule the ingest console draws it with; the `error` names `fileSize`, so a broken size never reaches the console as a value); `501` when the store implements no `inspectFileUri`. Success answers `{ success, inspection }`. |
161
+ | any other value | `400` | `Unknown intent: <intent>`. |
162
+
163
+ A start or cancel failure is `{ failure }`, an `IntegrityCommandFailure` of `@aiquants/enrichment-core` that the core's contract admits:
164
+ `FORBIDDEN` without a status when `requirePermission` refuses `update`, when the operator holds no access token, or for a `REPAIR` when `canReadIntegrityFindings` answers `false` (the store is not called);
165
+ the store's `{ ok: false, status, errorCode }` mapped to the command's own vocabulary by `integrityCommandFailureCodeOf(command, status, errorCode)`;
166
+ `UPSTREAM_FAILED` without a status when the store throws (its cause is discarded; the store logs it) or answers something that is not a reply.
167
+ The response's HTTP status states the failure: the status the core's code table (`INTEGRITY_COMMAND_CODES`) gives the code, and 502 for `UPSTREAM_FAILED`, the one code the table has no row for;
168
+ not being a success, it keeps a router from re-reading its loader by default, and the view re-reads exactly after the failures that outdate the overview (`integrityFailureNeedsOverviewReread` of `@aiquants/governance-react`).
169
+
170
+ Store failures are caught and answered as `400 { error }` only where the table says "the store throws". In `toggle_flag`, `update_confidentiality_policy`, `update_parameter` and `reorder_rules` a store failure — like a failure of `resolveTenantId`, of `authorizeIngest`, or of reading the form — propagates out of the action to the route's error boundary.
171
+
172
+ ## Styling contract
173
+
174
+ - **Borders name their style.** Every Tailwind border-width utility in this package's sources (`border`, `border-b`, …) sits in the same class list as `border-solid`, and every `divide-x` / `divide-y` next to `divide-solid`, so the console draws its borders under any host — including one whose base layer sets `border-style: none` on every element (e.g. `* { @apply border-none }`).
175
+ `tests/borderStyleContract.spec.ts` scans every string literal in `src/` and fails on a width without its style; `@aiquants/enrichment-react` holds the same rule, and `@aiquants/governance-react` draws its borders with inline `border: 1px solid …`.
176
+ - **One card-title scale.** Every card title (`h2`) on every tab — this package's 直近の実行 and the panels of `@aiquants/enrichment-react` and `@aiquants/governance-react` alike — is 16 px bold; the view test checks each tab.
177
+
178
+ ## View props (`StorageAdminConsoleViewProps`)
179
+
180
+ A host read answers every failure it can describe as an outcome. The reads whose failure the view itself shows (`loadIntegrityOverview`, `onLoadDocumentRuns`, `onBrowseGraphNodes`) settle even when the function breaks that contract: a rejection or a synchronous throw is shown as a failed read whose reason is the error's message, so no control stays busy and no panel stays loading. The ingest queue's refresh shows no failure: a failed round keeps the rows and the next round reads again.
181
+
182
+ | Prop | Required | Purpose |
183
+ | --- | --- | --- |
184
+ | `onSearch: MetadataSearchRunner` | yes | Runs a metadata search. The workbench is the first tab and cannot be hidden, so the host must supply the runner; this package names no route. |
185
+ | `loadIntegrityOverview: IntegrityOverviewLoader` | yes | `(signal) => Promise<ResourceOutcome<IntegrityAuditOverview>>` — the same overview the store reads, through the host's own route. The view polls it while a run is active, reads it once on every return to the tab while an overview is shown, and calls it from the reload of a failed first read. |
186
+ | `loadIntegrityFindings: IntegrityFindingsLoader` | yes | `(query, signal) => Promise<ResourceOutcome<IntegrityFindingPage>>` — a page of one cell's findings, for the audit card's findings inspector. |
187
+ | `policyConflicts: PolicyConflictHost` | yes | The summary, the list's pages, a pair's detail, the decision and the detection (`@aiquants/governance-react`); reads answer `ResourceOutcome`, the decision and the detection `CommandOutcome` with the core's rejection body. |
188
+ | `documentAuthority: DocumentAuthorityHost` | yes | The ledger's pages, the unregistered candidates, the replaceable rows and the command (`CommandOutcome` with the core's rejection body). |
189
+ | `onRefreshIngestQueue?: IngestQueueRefresher` | no | Refetches the ingest queue while an ingestion runs. Forwarded on both the connected and the `data`-prop path. |
190
+ | `graphTraversal?: GraphTraversalHost` | no | `{ run: GraphTraversalRunner; listRelationshipTypes: GraphRelationshipTypesReader }` — graph traversal and the relationship types it may follow, supplied together; the traversal form is absent without it. `listRelationshipTypes` answers the deployment's offer (`{ ok: true, relationshipTypes }`, e.g. from the governance backend's `POST /ai/governance/admin/kg/relationship-types`, or `{ ok: false, reason }`); the form offers exactly those types, says why nothing can be traversed when the offer is empty, and re-reads when the function changes — keep the object stable (a module constant). A traversal that names no type follows the whole offer. `run` hands the backend's rows over unchanged (`label`, `from_label`, `to_label` included): the result map names each node by label and identifier, so an `Entity` and a `File` with the same identifier stay two nodes, and offers only `Entity` nodes as the next start. |
191
+ | `onBrowseGraphNodes?` | no | Reads one page of a label's nodes; the index is absent without it. |
192
+ | `onSimulateGovernance?: SimulationRunner` | no | Governance dry run; the dry-run console is absent without it. |
193
+ | `onLoadDocumentRuns?: DocumentRunsLoader` | no | `(metadataId, signal) => Promise<ResourceOutcome<readonly PipelineRunRecord[]>>` — every recorded run of one document, with steps, **newest first**, read with the caller's tenant (an empty `value` is a document with no run). A failed read's `reason` is shown inside `処理履歴を読めませんでした (<reason>)。`, so answer it as a short phrase without a final 。 (e.g. `HTTP 503 で拒まれました`). The panel aborts the read (`signal`) when it opens another document or closes. Without it the history panel, the 詳細 button on each recent run and the 履歴 button on each ingest row are all absent. |
194
+ | `onCompareVariants?: ModelComparisonRunner` | no | Runs a side-by-side search over two strategy rows (`ComparisonInput.strategyIds`, answered per `strategyId`); the model-comparison workbench (below the search workbench) is absent without it. A search that could not run should be answered as `{ ok: false, reason }` (the reason is shown as given); a rejection is shown as a failure too and clears the previous outcome. |
195
+ | `data?` / `fetcher?` / `integrityFetcher?` / `renderHeader?` | no | Overrides for tests and special mounts (`integrityFetcher` carries the audit card's start and cancel only). The view is mounted under a data router in every case: it re-reads the route's loader (`useRevalidator`) after a start or cancel failure that outdates the overview, and an injected `data` does not receive that re-read. |
196
+
197
+ ## Tabs
198
+
199
+ `?tab=` selects the panel: `search`, `ingest`, `pipeline`, `knowledge-graph`, `parameters`, `prompts`, `knowledge-authority`, `data-retention`. An unknown value falls back to the first tab. The tablist is named 運用管理コンソールの画面.
200
+ Only the selected panel is mounted, so leaving a tab discards what was typed there and not sent — the ledger's and the conflict queue's drafts included (the cards cannot tell being hidden from being removed; an answer that arrives after its card left says the input was discarded).
201
+
202
+ - Layout: the tablist folds by the width of its own frame (`@container`), never by the viewport, since a pinned side menu narrows the console's box without the viewport knowing.
203
+ Two columns by default, four from a 41.5rem frame, and one row of equal columns from an 82rem frame.
204
+ The thresholds come from the ingest label's second phrase (`取り込み & メタ生成`, 135.1 px at 14 px): it is the only phrase that must fit on one line for its label to stay within two lines (a single-phrase label breaks at its spaces into two lines anyway). So in four columns and in one row no label takes more than two lines, and only the narrowest two-column frame lets the ingest label take three.
205
+ In each folded layout the last tab spans the columns its row lacks, so the rectangle closes; in the single row it returns to one column.
206
+ - Labels are written as phrases: a trigger keeps each phrase whole (`break-keep`) and breaks only at a space or between phrases (`<wbr>`), so no label splits inside a katakana word or leaves one character alone on its second line; a phrase wider than its trigger still wraps (`wrap-anywhere`) instead of overflowing. No word is wider than the narrowest trigger (126 px at 14 px). `権威台帳 & 規程衝突` is one phrase, so it breaks at its spaces.
207
+
208
+ - `pipeline` (パイプライン & 接続状態) draws, in order, `PipelineFlowViewer`, the 直近の実行 table, `EnrichmentStrategyBoard` and `InfrastructureHealthMonitor`.
209
+ - `PipelineFlowViewer` draws the document-kind flows with the tenant's feature flags laid over each step's effective gate policy for that flow, and, for the selected step, the selected kind's own metric with its window (`metricSampleWindow` = `pipelineStepMetricWindow`).
210
+ - It is not given the circuit breakers: they belong to the search path, which the pipeline never consults, so a breaker opened by failed searches is never drawn on the projection step.
211
+ - The 直近の実行 table lists `recentPipelineRuns`: document, kind, trigger, attempt, status, failed step, started / finished, requester.
212
+ - It writes the status badge (`PIPELINE_RUN_STATUS_PRESENTATION[pipelineRunPresentationKey(run)]`, so a failed run with a scheduled retry reads 失敗 (再試行予定)), the trigger (`PIPELINE_TRIGGER_LABELS`, the raw value kept in `data-trigger`) and the times (`@aiquants/enrichment-react`'s `RecordedInstant` / `FinishedInstant`, written in the console root's time zone, which the view sets from `displayTimeZone`) exactly as the history panel and the ingest queue do.
213
+ - Its horizontal scroller is a containing block (`relative`), so the visually hidden header of the button column cannot widen the page at narrow widths.
214
+ - Headers, run / document ids, kind, trigger, attempt, times and the 詳細 button never wrap (`whitespace-nowrap`); only the failed step and the requester (`wrap-anywhere`) wrap, so a squeezed table breaks long values instead of splitting 詳細 or きっかけ mid-word.
215
+ - The document history panel (`PipelineRunInspector`) opens above the panels and stays open across tabs.
216
+ - A recent run's 詳細 opens that run's document with that run selected. An ingest row's 履歴 opens the document's whole history and selects the newest run once it is read — also for a row with no recorded run, which the panel then states as a neutral `role="status"` note.
217
+ - The panel reads through `onLoadDocumentRuns`, shows `処理履歴を読めませんでした (<reason>)。` when the read fails, rejects or throws (for a rejection or a throw the reason is the error's message), and ignores a read that settles after it was closed or another document was opened.
218
+ - An entry point's run stays selected even when the history does not list it (the panel says so); the newest run is never substituted for it.
219
+ - Re-targeting keeps the one panel mounted. Every open from outside the panel (a 詳細 or 履歴 press, including one that names the run already shown) bumps the panel's `openRequest`, so focus moves to its heading each time; a load settling on the newest run does not move focus.
220
+ - On 閉じる or Escape focus returns to the entry point that opened the panel most recently; when that element has left the page (its tab panel was switched away), the panel's `returnFocusFallback` hands focus to the active tab's button.
221
+ - A history holding a provenance string with nothing to read (any string a step's report carries, such as `provider` or `model`) — empty, or only white space of JavaScript's and Python's `\s` — is shown as a failure naming the run, the step and the field (`処理履歴の記録に読めない来歴の値があります (実行 <id> の段 <sequence> の <field>)。`, not wrapped in the failed-read sentence), and its runs are not handed to the panel (the panel's measured text slot would refuse it while rendering and take the console with it).
222
+ - `search` draws `MetadataSearchWorkbench` and, when `onCompareVariants` is supplied, `ModelComparisonWorkbench`, keyed by `strategyId`, with each variant labelled `<domainKey> / <variantKey> (<embeddingModel>)`.
223
+ - `knowledge-authority` (権威台帳 & 規程衝突) draws `DocumentAuthorityRegistry` (its `canUpdate` is the loader's `canUpdateKnowledge`) and then `PolicyConflictQueue`. The view keeps a policy conflict revision: the ledger's `onPolicyConflictsChanged` advances it, and the queue re-reads its summary, its first page and the open detail in place when it changes.
224
+ - `data-retention` (データ保持 & 整合性監査) draws `TriStoreIntegrityAudit`, then `PolicyConflictSummaryCard` (its `knowledgeTabLabel` is the knowledge-authority tab's label, and its link switches to that tab and moves focus to it), then the bulk-retry notice and the `SyncStatusMonitor` / `QdrantStorageCard` grid.
225
+ - The overview is kept last-good: the loader's answer, every poll and the reload are applied in arrival order through the console foundation's `keepLastGood`, so an overview once shown stays through later failures, which show only `更新に失敗しました (<reason>)。`. A success whose `readAt` is strictly earlier than the shown one (the core's `isStrictlyEarlier`, which compares every fractional digit across offsets) is dropped.
226
+ - Until an overview has been shown, a card titled `Tri-Store データ整合性監査` (`audit-overview-failed`) holds the console foundation's `ResourceFailed` (`audit-overview-failed-resource`): `監査の概況を読めませんでした (<reason>)。` with `再読み込み`, or for a 403 only `監査の概況を閲覧する権限がありません。`. Besides the loader's next answer, the reload is the only way back (neither the polling nor a return to the tab reads without an overview); focus that was on `再読み込み` moves to the audit card's heading on success, or to this card's heading when the reload answers 403.
227
+ - While the shown overview has an active run, the tab is shown and the document is visible, the overview is re-read every 2 s (`INTEGRITY_RUN_POLL_MS`), or every 10 s while the run's heartbeat is stale; a hidden document or another tab stops the polling and aborts the read in flight. The polling stops when a read shows the run ended, and when a re-read is refused (401 / 403: repeating it would only repeat the refusal; the shown overview stays with `更新に失敗しました (<reason>)。`).
228
+ - Whenever the tab is shown and the document visible again after either was not — the first visit to the tab after the console mounted on another included — the overview is read once at once, with or without an active run: the card, mounted again with the tab, counts its age label from `readAt` plus the time since its own mount, and a successful read corrects the time away. A failed read leaves the relative age short by the time away, while the absolute 最終測定 time and `更新に失敗しました (<reason>)。` stay correct. A mount on the tab itself reads nothing: the loader has just answered.
229
+ - The audit card's start (`start_integrity_run`) and cancel (`cancel_integrity_run`) go through a fetcher of their own (`integrityFetcher`), so a sync retry on the same tab never aborts them, nor they a retry (React Router aborts a fetcher's earlier submission when it submits again); the card is told which one is in flight. The console's alert states the `{ error }` of whichever fetcher settled last.
230
+ A failure the action answers as `{ failure }` — the `storage_admin:update` refusal included — reaches the card as `{ failure, occurrence }`, never the console's error alert (the occurrence advances with every failure, so a repeated failure is announced again).
231
+ The session and operator gates (no session, a blank `email`) and a malformed form answer `{ error }` in the console's alert, as for every intent. Any answer without a failure clears the card's, and so does leaving the tab, so a failure is announced once: one that settled while another tab was shown is shown when the operator returns. After a failure that outdates the overview the view re-reads the loader.
232
+ - The route must re-read its loader after a successful start or cancel: that re-read is how the new run appears and the polling begins. React Router's default `shouldRevalidate` does; a host that skips the re-read for intents without a loader effect must not list these two.
233
+
234
+ The console derives its in-flight and settled state from the fetcher: `isRetrying` / `isResolving` follow the intent in flight, rows skipped by `retry_all_failed` are listed in a `retry-all-skipped` notice, and the transcription-adaptation saves return a promise that settles with the submission (rejecting with the action's `error`), so the board keeps its inputs on refusal.
235
+
236
+ ## Health probes
237
+
238
+ `checkAllSystemHealth` probes Qdrant, Neo4j, Redis, SQL Server and the backend API on every load. Each probe measures its response time with the monotonic clock (`performance.now()`) in whole milliseconds, so a wall clock that steps back never yields a negative or fractional `latencyMs` (`@aiquants/enrichment-react` refuses one while rendering). A version or a string detail the probe could not read — absent, not a string, or holding nothing to read (`probeText`) — is `null`; no stand-in word and no empty string is reported as a value the probe read.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var Q=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var Se=(t,e)=>{for(var o in e)Q(t,o,{get:e[o],enumerable:!0})},be=(t,e,o,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of fe(e))!ye.call(t,i)&&i!==o&&Q(t,i,{get:()=>e[i],enumerable:!(s=ge(e,i))||s.enumerable});return t};var he=t=>be(Q({},"__esModule",{value:!0}),t);var ke={};Se(ke,{StorageAdminConsoleView:()=>$,checkAllSystemHealth:()=>J,checkBackendApiHealth:()=>le,checkNeo4jHealth:()=>ie,checkQdrantHealth:()=>se,checkRedisHealth:()=>ae,checkSqlServerHealth:()=>oe,createStorageAdminApp:()=>Ce,createStorageAdminServer:()=>W});module.exports=he(ke);var F=require("@aiquants/enrichment-core"),R=require("@aiquants/enrichment-react"),v=require("@aiquants/governance-react"),T=require("react"),j=require("react-router"),c=require("react/jsx-runtime"),X="tab",L=[{key:"search",label:"\u30E1\u30BF\u30C7\u30FC\u30BF\u691C\u7D22\u30EF\u30FC\u30AF\u30D9\u30F3\u30C1"},{key:"ingest",label:"\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u53D6\u308A\u8FBC\u307F & \u30E1\u30BF\u751F\u6210"},{key:"rag-pipeline",label:"RAG \u5B9F\u884C\u57FA\u76E4 & \u63A5\u7D9A\u72B6\u614B"},{key:"knowledge-graph",label:"\u30CA\u30EC\u30C3\u30B8\u30B0\u30E9\u30D5\u63A2\u7D22"},{key:"parameters",label:"\u30E2\u30C7\u30EB & \u30D1\u30E9\u30E1\u30FC\u30BF\u8A2D\u5B9A"},{key:"prompts",label:"\u30D7\u30ED\u30F3\u30D7\u30C8 & \u30C9\u30E9\u30A4\u30E9\u30F3"},{key:"data-retention",label:"\u30C7\u30FC\u30BF\u4FDD\u6301 & \u6574\u5408\u6027\u76E3\u67FB"}];function ve(t){return t!==null&&L.some(e=>e.key===t)}var Re={state:"idle",formData:null,data:null,submit:()=>Promise.resolve()};function ee({data:t,fetcher:e,renderHeader:o,onTraverseGraph:s,onBrowseGraphNodes:i,onSimulateGovernance:n,onRefreshIngestQueue:a}){let[l,p]=(0,T.useState)(null),[m,f]=(0,T.useState)(null),[y,b]=(0,T.useState)(!1),d=(0,T.useCallback)((r,S)=>{i!==void 0&&(b(!0),i(r,S).then(h=>{b(!1),f(h.ok?null:h.reason),h.ok&&p(h.page)}))},[i]),[k,E]=(0,j.useSearchParams)(),P=k.get(X),g=ve(P)?P:L[0].key,N=r=>{E(S=>{let h=new URLSearchParams(S);return h.set(X,r),h},{replace:!1,preventScrollReset:!0})},x=we(t.recentIngestItems,a,g==="ingest"),u=x===t.recentIngestItems?t:{...t,recentIngestItems:x===void 0?void 0:[...x]},w=(0,T.useRef)({}),I=(r,S)=>{let h=L.length-1,_;if(r.key==="ArrowRight"||r.key==="ArrowDown")_=S===h?0:S+1;else if(r.key==="ArrowLeft"||r.key==="ArrowUp")_=S===0?h:S-1;else if(r.key==="Home")_=0;else if(r.key==="End")_=h;else return;r.preventDefault();let U=L[_].key;N(U),w.current[U]?.focus()},O={...u.featureFlags};if(e.formData&&e.formData.get("intent")==="toggle_flag"){let r=String(e.formData.get("flagKey")??""),S=String(e.formData.get("enabled")??"")==="true";r&&(O[r]=S)}let D=e.data?.error,K=e.data&&"inspection"in e.data?e.data.inspection:void 0,q=e.state!=="idle"&&e.formData?.get("intent")==="inspect_uri",G=e.state!=="idle"&&e.formData?.get("intent")==="ingest_document";return(0,c.jsxs)("div",{className:"container mx-auto space-y-6 p-6 font-sans text-slate-900","data-testid":"storage-admin-console",children:[D&&(0,c.jsx)("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4 font-medium text-red-700 text-sm shadow-sm",role:"alert","data-testid":"storage-admin-error-alert",children:D}),o?o({title:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406",tenantId:u.tenantId}):(0,c.jsxs)("header",{className:"flex flex-col justify-between gap-2 border-slate-200 border-b pb-4 md:flex-row md:items-center",children:[(0,c.jsxs)("div",{children:[(0,c.jsx)("h1",{className:"font-bold text-2xl tracking-tight",children:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406"}),(0,c.jsxs)("p",{className:"mt-1 text-slate-500 text-sm",children:["\u30C6\u30CA\u30F3\u30C8: ",(0,c.jsx)("code",{className:"font-semibold text-slate-800",children:u.tenantId})," | \u5168\u30B7\u30B9\u30C6\u30E0\u72B6\u614B\u30FB\u30D1\u30E9\u30E1\u30FC\u30BF\u5236\u5FA1\u30FB\u6574\u5408\u6027\u76E3\u67FB"]})]}),(0,c.jsx)("div",{className:"flex items-center gap-2",children:(0,c.jsxs)("button",{type:"button","data-testid":"header-health-status-button",onClick:()=>N("rag-pipeline"),className:"inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 font-medium text-slate-700 text-xs transition-colors hover:bg-slate-100",children:[(0,c.jsx)("span",{className:`h-2 w-2 rounded-full ${u.systemHealth.allHealthy?"bg-emerald-500":"bg-amber-500"}`}),(0,c.jsxs)("span",{children:["\u5468\u8FBA\u6A5F\u80FD: ",u.systemHealth.allHealthy?"\u5168\u30B5\u30FC\u30D3\u30B9\u6B63\u5E38":"\u63A5\u7D9A\u8981\u78BA\u8A8D"]})]})})]}),(0,c.jsxs)("div",{className:"w-full space-y-6",children:[(0,c.jsx)("div",{className:"grid w-full grid-cols-2 gap-1 rounded-xl bg-slate-100 p-1 md:grid-cols-8",role:"tablist","aria-label":"Storage Administration Console Tabs",children:L.map((r,S)=>{let h=g===r.key;return(0,c.jsx)("button",{id:`tab-${r.key}`,type:"button",role:"tab",ref:_=>{w.current[r.key]=_},"aria-selected":h,"aria-controls":`panel-${r.key}`,tabIndex:h?0:-1,"data-testid":`tab-trigger-${r.key}`,onKeyDown:_=>I(_,S),onClick:()=>N(r.key),className:`rounded-lg px-3 py-2.5 text-center font-medium text-sm transition-all ${h?"bg-white text-slate-900 shadow-sm":"text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"}`,children:r.label},r.key)})}),g==="search"&&(0,c.jsx)("div",{role:"tabpanel",id:"panel-search","aria-labelledby":"tab-search",className:"space-y-6","data-testid":"tab-content-search",children:(0,c.jsx)(R.MetadataSearchWorkbench,{tenantId:u.tenantId,circuitBreakerStatus:u.circuitBreakerStatus})}),g==="ingest"&&(0,c.jsx)("div",{role:"tabpanel",id:"panel-ingest","aria-labelledby":"tab-ingest",className:"space-y-6","data-testid":"tab-content-ingest",children:(0,c.jsx)(R.DocumentIngestConsole,{tenantId:u.tenantId,policies:u.confidentialityPolicies,recentItems:u.recentIngestItems,inspectionResult:K,isInspecting:q,isSubmitting:G,onInspectUri:r=>{e.submit({intent:"inspect_uri",fileUri:r},{method:"post"})},onIngestDocument:r=>{e.submit({intent:"ingest_document",payload:JSON.stringify(r)},{method:"post"})},onRetryItem:r=>{e.submit({intent:"retry_job",fileId:String(r)},{method:"post"})}})}),g==="rag-pipeline"&&(0,c.jsxs)("div",{role:"tabpanel",id:"panel-rag-pipeline","aria-labelledby":"tab-rag-pipeline",className:"space-y-6","data-testid":"tab-content-rag-pipeline",children:[(0,c.jsx)(R.RAGPipelineGraphViewer,{pipelineConfig:u.pipelineConfig,circuitBreakerStatus:u.circuitBreakerStatus,stageMetrics:u.stageMetrics}),(0,c.jsx)(R.EnrichmentStrategyBoard,{strategies:u.enrichmentStrategies,featureFlags:u.featureFlags,isUpdating:e.state!=="idle",onToggleStage:(r,S,h)=>e.submit({intent:"update_enrichment_strategy",strategyId:String(r.id),domainId:String(r.domainId),stage:S,enabled:String(h)},{method:"post"})}),(0,c.jsx)(R.InfrastructureHealthMonitor,{health:u.systemHealth,isRefreshing:e.state!=="idle",onRefresh:()=>e.submit({intent:"refresh_health"},{method:"post"})})]}),g==="knowledge-graph"&&(0,c.jsxs)("div",{role:"tabpanel",id:"panel-knowledge-graph","aria-labelledby":"tab-knowledge-graph",className:"space-y-6","data-testid":"tab-content-knowledge-graph",children:[(0,c.jsx)(R.OntologyStatusCard,{tenantId:u.tenantId,ontologyStatus:u.ontologyStatus}),(0,c.jsx)(v.KnowledgeGraphExplorer,{topologyMaxLabels:F.GRAPH_INDEX_LIMITS.topologyLabels.default,schema:u.graphSchema,tenantId:u.tenantId,unresolvedEntities:u.unresolvedEntities,onTraverse:s,onBrowseLabel:i===void 0?void 0:d,nodeIndexPage:l,nodeIndexFailure:m,isNodeIndexLoading:y,onResolveEntity:(r,S)=>{e.submit({intent:"resolve_entity",entityId:r,action:S},{method:"post"})}})]}),g==="parameters"&&(0,c.jsxs)("div",{role:"tabpanel",id:"panel-parameters","aria-labelledby":"tab-parameters",className:"space-y-6","data-testid":"tab-content-parameters",children:[(0,c.jsxs)("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[(0,c.jsx)(v.FeatureFlagBoard,{flags:O,isUpdating:e.state!=="idle",onToggleFlag:(r,S)=>{e.submit({intent:"toggle_flag",flagKey:r,enabled:String(S)},{method:"post"})}}),(0,c.jsx)(v.ClassificationRuleEditor,{rules:u.classificationRules,consultedBy:u.classificationRuleConsumer,onReorderRules:r=>{e.submit({intent:"reorder_rules",orderedRuleIds:JSON.stringify(r)},{method:"post"})}})]}),u.policiesMissingDestination.length>0&&(0,c.jsxs)("div",{"data-testid":"policies-missing-destination",role:"alert",style:{padding:"10px 12px",borderRadius:"6px",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"12px"},children:[(0,c.jsx)("strong",{children:"\u6B21\u306E\u533A\u5206\u30FB\u6A5F\u80FD\u306F\u5B9F\u884C\u6642\u306B\u5931\u6557\u3057\u307E\u3059\u3002"})," \u53C2\u7167\u3059\u308B\u30D7\u30ED\u30F3\u30D7\u30C8\u884C\u306B\u5B9B\u5148\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",(0,c.jsx)("ul",{style:{margin:"6px 0 0",paddingInlineStart:"18px"},children:u.policiesMissingDestination.map(r=>(0,c.jsxs)("li",{"data-testid":`missing-destination-${r.confidentialityLevel}-${r.capability}`,children:[r.confidentialityLevel," / ",r.capability," \u2192 ",r.promptKey," (",r.modelProvider,") \u306E ",(0,c.jsx)("code",{children:"extra_params.base_url"})]},`${r.confidentialityLevel}:${r.capability}`))}),(0,c.jsx)("span",{style:{display:"block",marginTop:"4px",fontSize:"11px"},children:"\u5B9B\u5148\u3092\u8A2D\u5B9A\u3057\u3066\u3082\u3001\u305D\u306E\u30DB\u30B9\u30C8\u304C\u914D\u5099\u5185\u3068\u3057\u3066\u767B\u9332\u3055\u308C\u3066\u3044\u306A\u3051\u308C\u3070\u62D2\u5426\u3055\u308C\u307E\u3059\u3002"})]}),(0,c.jsx)(v.ConfidentialityPolicyBoard,{policies:u.confidentialityPolicies,promptKeys:u.promptTemplates.map(r=>r.template_key),isUpdating:e.state!=="idle",onChangePolicy:r=>{e.submit({intent:"update_confidentiality_policy",confidentialityLevel:r.confidentialityLevel,capability:r.capability,isEnabled:String(r.isEnabled),allowCloudProvider:String(r.allowCloudProvider),promptKey:r.promptKey??""},{method:"post"})}}),(0,c.jsx)(v.TranscriptionAdaptationBoard,{vocabulary:u.transcriptionVocabulary,references:u.transcriptionReferences,unresolvedUris:u.unresolvedReferenceUris,isUpdating:e.state!=="idle",onSaveTerm:r=>{e.submit({intent:"save_transcription_term",id:r.id===null?"":String(r.id),term:r.term,reading:r.reading??"",boost:r.boost===null?"":String(r.boost),domainKey:r.domainKey??"",isActive:String(r.isActive)},{method:"post"})},onSaveReference:r=>{e.submit({intent:"save_transcription_reference",id:r.id===null?"":String(r.id),fileUri:r.fileUri,domainKey:r.domainKey??"",isActive:String(r.isActive)},{method:"post"})}}),(0,c.jsx)(v.SystemParameterTable,{parameters:u.systemParameters,onSaveParameter:(r,S)=>{e.submit({intent:"update_parameter",paramKey:r,paramValue:String(S)},{method:"post"})}})]}),g==="prompts"&&(0,c.jsxs)("div",{role:"tabpanel",id:"panel-prompts","aria-labelledby":"tab-prompts",className:"space-y-6","data-testid":"tab-content-prompts",children:[(0,c.jsx)(v.PromptTemplateConsole,{templates:u.promptTemplates,isSaving:e.state!=="idle",onSaveTemplate:r=>{e.submit({intent:"update_prompt",templateKey:r.template_key,payload:JSON.stringify({templateText:r.template_text,modelName:r.model_name,temperature:r.temperature,maxOutputTokens:r.max_output_tokens,responseSchema:r.response_schema,endpointBaseUrl:r.endpoint_base_url??null})},{method:"post"})}}),(0,c.jsx)(v.GovernanceDryRunConsole,{onSimulate:n})]}),g==="data-retention"&&(0,c.jsxs)("div",{role:"tabpanel",id:"panel-data-retention","aria-labelledby":"tab-data-retention",className:"space-y-6","data-testid":"tab-content-data-retention",children:[(0,c.jsx)(v.TriStoreIntegrityAudit,{auditData:u.triStoreAuditData,onTriggerReconcile:()=>{e.submit({intent:"reconcile"},{method:"post"})}}),(0,c.jsxs)("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[(0,c.jsx)(R.SyncStatusMonitor,{counts:u.syncCounts,totalFiles:u.totalFiles,failedItems:u.failedSyncItems,onRetryItem:r=>{e.submit({intent:"retry_job",fileId:String(r)},{method:"post"})},onRetryAll:()=>{e.submit({intent:"retry_all_failed"},{method:"post"})}}),(0,c.jsx)(R.QdrantStorageCard,{collections:u.qdrantCollections.collections,probeFailure:u.qdrantCollections.probe_failure,health:{healthy:u.systemHealth.services.qdrant.status==="connected",latency_ms:u.systemHealth.services.qdrant.latencyMs}})]})]})]})]})}var Ie=new Set(F.EnrichmentSyncStatusSchema.options.filter(t=>t!=="SYNCED"&&!t.startsWith("FAILED"))),Z=2e3;function we(t,e,o){let[s,i]=(0,T.useState)(null),n=(0,T.useRef)(e);n.current=e;let a=(0,T.useRef)(t);a.current!==t&&(a.current=t,s!==null&&i(null));let l=s??t,p=l?.some(m=>Ie.has(m.syncStatus))===!0;return(0,T.useEffect)(()=>{if(!(o&&p&&n.current))return;let m=!1,f,y=async()=>{let b=n.current;if(!(m||!b)){try{let d=await b();if(m)return;i(d)}catch{if(m)return}f=setTimeout(y,Z)}};return f=setTimeout(y,Z),()=>{m=!0,f!==void 0&&clearTimeout(f)}},[p,o]),l}function Te(t){let e=(0,j.useLoaderData)(),o=(0,j.useFetcher)(),s=t.data??e,i=t.fetcher??o;return s?(0,c.jsx)(ee,{data:s,fetcher:i,onRefreshIngestQueue:t.onRefreshIngestQueue,renderHeader:t.renderHeader,onTraverseGraph:t.onTraverseGraph,onBrowseGraphNodes:t.onBrowseGraphNodes,onSimulateGovernance:t.onSimulateGovernance}):(0,c.jsx)("div",{className:"p-8 text-center text-slate-500","data-testid":"storage-admin-loading",children:"\u30C7\u30FC\u30BF\u8AAD\u307F\u8FBC\u307F\u4E2D..."})}function $(t={}){return t.data?(0,c.jsx)(ee,{data:t.data,fetcher:t.fetcher??Re,renderHeader:t.renderHeader,onTraverseGraph:t.onTraverseGraph,onBrowseGraphNodes:t.onBrowseGraphNodes,onSimulateGovernance:t.onSimulateGovernance}):(0,c.jsx)(Te,{...t})}var Y=require("@aiquants/authz-core"),ce=require("@aiquants/enrichment-core"),C=require("@aiquants/governance-core");function A(t){if(typeof globalThis<"u"&&"process"in globalThis)return globalThis.process?.env?.[t]}function H(t,e){let o=t?.trim();if(!o)throw new Error(`${e} is not configured; this probe will not guess an endpoint to send credentials to.`);return o}function te(t,e,o){let s=t??(e?.trim()?Number(e):Number.NaN);if(!Number.isInteger(s)||s<=0||s>65535)throw new Error(`${o} is not configured with a valid port; this probe will not guess one.`);return s}function ne(t,e){if(t!==void 0)return t;let o=e?.trim().toLowerCase();if(!(o===void 0||o===""))return o==="1"||o==="true"||o==="yes"||o==="on"}function re(t){let e=t.trim().split("://",1)[0]?.toLowerCase();if(e&&t.includes("://"))return e.endsWith("s")||e.includes("+s")}function Pe(t){let o=(t.split("://").pop()??"").split("/",1)[0]??"",s=o.split(":").pop();if(!s||s===o)return;let i=Number(s);return Number.isInteger(i)&&i>0&&i<=65535?i:void 0}async function V(t,e){let o;try{return await Promise.race([t,new Promise((s,i)=>{o=setTimeout(()=>i(new Error(`Probe timed out after ${e}ms`)),e)})])}finally{o!==void 0&&clearTimeout(o)}}async function se(t){let e=t?.qdrantApiKey??A("QDRANT_API_KEY")??"",o=t?.timeoutMs??3e3,s=Date.now(),i="";try{i=H(t?.qdrantUrl??A("QDRANT_URL"),"QDRANT_URL");let n={};e&&(n["api-key"]=e);let[a,l]=await Promise.all([fetch(`${i}/`,{headers:n,signal:AbortSignal.timeout(o)}),fetch(`${i}/collections`,{headers:n,signal:AbortSignal.timeout(o)})]);if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText} (/collections)`);let p=await a.json(),m=Date.now()-s,y=(await l.json()).result?.collections?.length??0;return{serviceName:"Qdrant",category:"vector",status:"connected",version:p.version??"unknown",endpoint:i,latencyMs:m,details:{engine:p.title??"qdrant",collectionsCount:y,restPort:Pe(i)??null,tls:re(i)??null}}}catch(n){let a=Date.now()-s,l=n instanceof Error?n.message:String(n);return{serviceName:"Qdrant",category:"vector",status:"error",version:null,endpoint:i,latencyMs:a,details:{},errorMessage:l}}}async function ie(t){let e=t?.timeoutMs??3e3,o=Date.now(),s=t?.neo4jBoltUri??A("NEO4J_URI")??"";try{let i=t?.graphReader;if(!i)throw new Error("Graph reader not configured");let n=t?.tenantId,[a,l]=await Promise.all([V(i("CALL dbms.components() YIELD versions, edition RETURN versions[0] AS version, edition",{}),e),V(n?i("MATCH (n {tenantId: $tenantId}) RETURN count(n) AS node_count",{tenantId:n}):i("RETURN null AS node_count",{}),e)]);if(!a.ok)throw new Error(a.reason);if(!l.ok)throw new Error(l.reason);let[p,m]=a.rows[0]??[],f=l.rows[0]?.[0],y=Date.now()-o;return{serviceName:"Neo4j",category:"graph",status:"connected",version:typeof p=="string"?p:"unknown",endpoint:s,latencyMs:y,details:{edition:typeof m=="string"?m:"unknown",boltUri:s,nodeCount:typeof f=="number"?f:null,tls:re(s)??null}}}catch(i){let n=Date.now()-o,a=i instanceof Error?i.message:String(i);return{serviceName:"Neo4j",category:"graph",status:"error",version:null,endpoint:s,latencyMs:n,details:{},errorMessage:a}}}async function ae(t){let e=Date.now(),o="",s=ne(t?.redisTls,A("REDIS_TLS")),i=Number.NaN;try{let n=t?.redisClient;if(!n)throw new Error("Redis client not configured");let a=H(t?.redisHost??A("REDIS_HOST"),"REDIS_HOST");i=te(t?.redisPort,A("REDIS_PORT"),"REDIS_PORT"),o=`${s===!1?"redis":"rediss"}://${a}:${i}`,await n.ping();let p=(await n.info("server")).match(/redis_version:([^\r\n]+)/),m=p?p[1]:"unknown",f=null;if(typeof n.dbSize=="function")try{f=await n.dbSize()}catch{f=null}let y=Date.now()-e;return{serviceName:"Redis",category:"cache",status:"connected",version:m,endpoint:o,latencyMs:y,details:{totalKeys:f,port:i,tls:s??null,database:0}}}catch(n){let a=Date.now()-e,l=n instanceof Error?n.message:String(n);return{serviceName:"Redis",category:"cache",status:"error",version:null,endpoint:o,latencyMs:a,details:{},errorMessage:l}}}async function oe(t){let e=Date.now(),o="",s=ne(t?.sqlServerTls,A("SQL_SERVER_TLS")),i=Number.NaN;try{let n=t?.sqlServerExecute;if(!n)throw new Error("SQL Server executor not configured");let a=H(t?.sqlServerHost??A("SQL_SERVER_HOST"),"SQL_SERVER_HOST");i=te(t?.sqlServerPort,A("SQL_SERVER_PORT"),"SQL_SERVER_PORT"),o=`${a}:${i}`;let l=await n(),p=l.version??"unknown",m=typeof l.db_name=="string"&&l.db_name!==""?l.db_name:null,f=p.split(`
2
- `)[0]??p,y=f.match(/Microsoft SQL Server \d+ \([^)]+\)/),b=y?y[0].replace("Microsoft SQL Server ",""):f.substring(0,30),d=Date.now()-e;return{serviceName:"SQL Server",category:"database",status:"connected",version:b,endpoint:o,latencyMs:d,details:{database:m,port:i,tls:s??null,fullVersion:f}}}catch(n){let a=Date.now()-e,l=n instanceof Error?n.message:String(n);return{serviceName:"SQL Server",category:"database",status:"error",version:null,endpoint:o,latencyMs:a,details:{},errorMessage:l}}}async function le(t){let e=t?.timeoutMs??3e3,o=Date.now(),s="";try{s=H(t?.backendApiHost??A("BACKEND_API_HOST"),"BACKEND_API_HOST");let i=await fetch(`${s}/openapi.json`,{signal:AbortSignal.timeout(e)});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);let n=await i.json(),a=Object.keys(n.paths??{}).length,l=Date.now()-o;return{serviceName:"AI Quant API",category:"api",status:"connected",version:typeof n.info?.version=="string"&&n.info.version!==""?n.info.version:null,endpoint:s,latencyMs:l,details:{title:n.info?.title??"AI Quant API",endpointsCount:a}}}catch(i){let n=Date.now()-o,a=i instanceof Error?i.message:String(i);return{serviceName:"AI Quant API",category:"api",status:"error",version:null,endpoint:s,latencyMs:n,details:{},errorMessage:a}}}async function J(t){let[e,o,s,i,n]=await Promise.all([se(t),ie(t),ae(t),oe(t),le(t)]),a=e.status==="connected"&&o.status==="connected"&&s.status==="connected"&&i.status==="connected"&&n.status==="connected";return{services:{qdrant:e,neo4j:o,redis:s,sqlServer:i,quantsApi:n},allHealthy:a,checkedAt:new Date().toISOString()}}function W(t){let{store:e,healthProbeOptions:o,resourceKey:s="storage_admin",requireUser:i,requirePermission:n,resolveTenantId:a,authorizeIngest:l}=t;async function p(y){return a?await a(y):"default"}async function m(y){let{request:b}=y;if(i&&!await i(b))throw new Response("\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002",{status:401});if(n)try{await n(b,{resourceKey:s,action:"read"})}catch(B){throw B instanceof Y.AuthzDeniedError?new Response("\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",{status:403}):B}let d=await p(b),[k,E,P]=await Promise.all([e.getFeatureFlags(d),e.getSystemParameters(d),e.getSyncCounts(d)]),g={featureFlags:k,systemParameters:E,syncCounts:P},[N,x,u,w,I,O,D,K,q,G,r,S,h,_,U,ue,de]=await Promise.all([e.getConfidentialityPolicies(d),e.getTranscriptionVocabulary(d),e.getTranscriptionReferences(d),e.getUnresolvedReferenceUris(d),e.getPoliciesMissingDestination(d),e.getPromptTemplates(d),e.getClassificationRules(d),e.getFailedSyncItems(d),e.getGraphSchema(d),e.getTriStoreAuditData(d,g),e.getUnresolvedEntities(d),e.getQdrantCollections(d),J({...o,tenantId:d}),e.getPipelineConfig(d,g),e.getRecentIngestItems(d),e.getOntologyStatus(d,g),e.getEnrichmentStrategies(d)]),pe=e.getCircuitBreakerStatus(),me=e.getStageMetrics();return{tenantId:d,featureFlags:g.featureFlags,confidentialityPolicies:N,transcriptionVocabulary:x,transcriptionReferences:u,unresolvedReferenceUris:w,policiesMissingDestination:I,systemParameters:g.systemParameters,promptTemplates:O,classificationRules:D,classificationRuleConsumer:e.classificationRuleConsumer??null,syncCounts:g.syncCounts.counts,totalFiles:g.syncCounts.total,failedSyncItems:K,circuitBreakerStatus:pe,pipelineConfig:_,stageMetrics:me,graphSchema:q,enrichmentStrategies:de,triStoreAuditData:G,unresolvedEntities:r,qdrantCollections:S,systemHealth:h,recentIngestItems:U,ontologyStatus:ue}}async function f(y){let{request:b}=y,d=null,k;if(i){let w=await i(b);if(!w)return Response.json({error:"\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002"},{status:401});let I=w;d=I.email||I.id||I.name||null,typeof I.accessToken=="string"&&I.accessToken!=="mock-access-token"&&(k=I.accessToken)}if(!d)return Response.json({error:"\u64CD\u4F5C\u8005\u3092\u7279\u5B9A\u3067\u304D\u306A\u3044\u305F\u3081\u8A2D\u5B9A\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002"},{status:403});if(n)try{await n(b,{resourceKey:s,action:"update"})}catch(w){if(w instanceof Y.AuthzDeniedError)return Response.json({error:"\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002"},{status:403});throw w}let E=await p(b),P=await b.formData(),g=String(P.get("intent")??"");if(g==="refresh_health")return Response.json({success:!0,refreshed:!0});let N=await Ae(e,E,g,P,d);if(N)return N;let x=await Ee(e,E,g,P,d,k);if(x)return x;if(g==="resolve_entity"){let w=String(P.get("entityId")??""),I=String(P.get("action")??"");return!w||I!=="merge"&&I!=="promote"?Response.json({error:"Valid entityId and action ('merge' | 'promote') are required"},{status:400}):(await e.resolveEntity(E,w,I),Response.json({success:!0,entityId:w,action:I}))}let u=await xe(e,E,g,P,d,b,l,k);return u||Response.json({error:`Unknown intent: ${g}`},{status:400})}return{loader:m,action:f}}function z(t){let e=String(t??"").trim();return e===""?null:e}function M(t){let e=String(t??"").trim();if(e==="")return null;let o=Number(e);if(!(!Number.isSafeInteger(o)||o<=0))return o}function _e(t){let e=String(t??"").trim();if(e==="")return null;let o=Number(e);if(!(!Number.isFinite(o)||o<=0))return o}async function Ae(t,e,o,s,i){if(o==="update_enrichment_strategy"){let n=String(s.get("stage")??"");if(!(0,ce.isEnrichmentStageKey)(n))return Response.json({error:"stage must be a canonical enrichment stage key"},{status:400});let a=M(s.get("strategyId")),l=M(s.get("domainId"));if(a==null||l===void 0||l===null)return Response.json({error:"strategyId and domainId must be positive integers naming existing rows"},{status:400});let p=String(s.get("enabled")??"")==="true";try{await t.updateEnrichmentStrategy(e,{strategyId:a,domainId:l,stage:n,enabled:p},i)}catch(m){return Response.json({error:m instanceof Error?m.message:"\u53D6\u308A\u8FBC\u307F\u6226\u7565\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,strategyId:a,domainId:l,stage:n,enabled:p})}if(o==="toggle_flag"){let n=String(s.get("flagKey")??""),a=String(s.get("enabled")??"")==="true";return n?(await t.toggleFeatureFlag(e,n,a,i),Response.json({success:!0,flagKey:n,enabled:a})):Response.json({error:"flagKey is required"},{status:400})}if(o==="update_confidentiality_policy"){let n=String(s.get("confidentialityLevel")??""),a=String(s.get("capability")??"");if(!(C.ConfidentialityLevelSchema.safeParse(n).success&&C.GovernedCapabilitySchema.safeParse(a).success))return Response.json({error:"confidentialityLevel and capability must be canonical values"},{status:400});let l=String(s.get("allowCloudProvider")??"")==="true";if(l&&!C.CLOUD_CAPABLE_CAPABILITIES.includes(a))return Response.json({error:`${a} sends nothing outside the deployment, so it has no cloud permission to grant`},{status:400});let p=String(s.get("promptKey")??"");return await t.updateConfidentialityPolicy(e,{confidentialityLevel:n,capability:a,isEnabled:String(s.get("isEnabled")??"")==="true",allowCloudProvider:l,promptKey:p===""?null:p},i),Response.json({success:!0,confidentialityLevel:n,capability:a})}if(o==="save_transcription_term"){let n=String(s.get("term")??"").trim();if(!n)return Response.json({error:"term is required"},{status:400});let a=_e(s.get("boost"));if(a===void 0)return Response.json({error:"boost must be a number greater than zero, or absent to let the service decide"},{status:400});let l=M(s.get("id"));return l===void 0?Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400}):(await t.saveTranscriptionTerm(e,{id:l,term:n,reading:z(s.get("reading")),boost:a,domainKey:z(s.get("domainKey")),isActive:String(s.get("isActive")??"true")==="true"},i),Response.json({success:!0,term:n}))}if(o==="save_transcription_reference"){let n=String(s.get("fileUri")??"").trim();if(!n)return Response.json({error:"fileUri is required"},{status:400});let a=M(s.get("id"));return a===void 0?Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400}):(await t.saveTranscriptionReference(e,{id:a,fileUri:n,domainKey:z(s.get("domainKey")),isActive:String(s.get("isActive")??"true")==="true"},i),Response.json({success:!0,fileUri:n}))}if(o==="update_parameter"){let n=String(s.get("paramKey")??""),a=String(s.get("paramValue")??"");return n?(await t.updateSystemParameter(e,n,a,i),Response.json({success:!0,paramKey:n,paramValue:a})):Response.json({error:"paramKey is required"},{status:400})}if(o==="update_prompt"){let n=String(s.get("templateKey")??""),a=String(s.get("payload")??"{}"),l={templateText:"",modelName:"",temperature:0,maxOutputTokens:0,endpointBaseUrl:null};try{l=JSON.parse(a)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}if(!n)return Response.json({error:"templateKey is required"},{status:400});try{return await t.updatePromptTemplate(e,n,l,i),Response.json({success:!0,templateKey:n})}catch(p){return Response.json({error:p instanceof Error?p.message:String(p)},{status:400})}}if(o==="reorder_rules"){let n=String(s.get("orderedRuleIds")??"[]"),a=[];try{a=JSON.parse(n)}catch{return Response.json({error:"Invalid orderedRuleIds JSON"},{status:400})}return await t.reorderClassificationRules(e,a,i),Response.json({success:!0,orderedRuleIds:a})}return null}async function Ee(t,e,o,s,i,n){if(o==="retry_job"){let a=String(s.get("fileId")??"");if(!a)return Response.json({error:"fileId is required"},{status:400});try{return await t.retrySyncItem(e,a,i,n),Response.json({success:!0,fileId:a})}catch(l){return Response.json({error:l instanceof Error?l.message:String(l)},{status:400})}}if(o==="retry_all_failed")try{return await t.retryAllFailedSyncItems(e,i,n),Response.json({success:!0,reconciled:!0})}catch(a){return Response.json({error:a instanceof Error?a.message:String(a)},{status:400})}if(o==="reconcile")try{let a=await t.reconcileTriStore(e,n);return Response.json({success:!0,reconciled:!0,result:a})}catch(a){return Response.json({error:a instanceof Error?a.message:String(a)},{status:400})}return null}function Ne(t){if(typeof t!="object"||t===null)return"payload must be an object";let e=t;if(typeof e.fileUri!="string"||e.fileUri.trim()==="")return"payload.fileUri is required";if(!C.ConfidentialityLevelSchema.safeParse(e.confidentialityLevel).success)return`payload.confidentialityLevel must be one of ${C.ConfidentialityLevelSchema.options.join(", ")}`;let s=e.departmentId;return s!=null&&(typeof s!="number"||!Number.isInteger(s))?"payload.departmentId must be an integer or null":null}async function xe(t,e,o,s,i,n,a,l){if(o==="ingest_document"){let p=String(s.get("payload")??"");if(!p)return Response.json({error:"payload is required"},{status:400});let m;try{m=JSON.parse(p)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}let f=Ne(m);if(f)return Response.json({error:f},{status:400});let y=m,b=await a(n,y);if(b!==null)return Response.json({error:b},{status:403});try{let d=l?await t.ingestDocument(e,y,i,l):await t.ingestDocument(e,y,i);return Response.json({success:!0,result:d})}catch(d){return Response.json({error:d instanceof Error?d.message:String(d)},{status:400})}}if(o==="inspect_uri"){let p=String(s.get("fileUri")??"").trim();if(!p)return Response.json({error:"fileUri is required"},{status:400});if(!t.inspectFileUri)return Response.json({error:"inspectFileUri is not implemented"},{status:501});try{let m=l?await t.inspectFileUri(e,p,l):await t.inspectFileUri(e,p);return Response.json({success:!0,inspection:m})}catch(m){return Response.json({error:m instanceof Error?m.message:String(m)},{status:400})}}return null}function Ce(t){let e=W(t);return{loader:e.loader,action:e.action,View:$,server:e}}0&&(module.exports={StorageAdminConsoleView,checkAllSystemHealth,checkBackendApiHealth,checkNeo4jHealth,checkQdrantHealth,checkRedisHealth,checkSqlServerHealth,createStorageAdminApp,createStorageAdminServer});
1
+ "use strict";var Ie=Object.defineProperty;var Rt=Object.getOwnPropertyDescriptor;var ht=Object.getOwnPropertyNames;var vt=Object.prototype.hasOwnProperty;var It=(e,t)=>{for(var n in t)Ie(e,n,{get:t[n],enumerable:!0})},wt=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ht(t))!vt.call(e,i)&&i!==n&&Ie(e,i,{get:()=>t[i],enumerable:!(r=Rt(t,i))||r.enumerable});return e};var At=e=>wt(Ie({},"__esModule",{value:!0}),e);var yn={};It(yn,{StorageAdminConsoleView:()=>Ee,checkAllSystemHealth:()=>xe,checkBackendApiHealth:()=>rt,checkNeo4jHealth:()=>et,checkQdrantHealth:()=>Xe,checkRedisHealth:()=>tt,checkSqlServerHealth:()=>nt,createStorageAdminApp:()=>gn,createStorageAdminServer:()=>Le});module.exports=At(yn);var q=require("@aiquants/console-ui"),U=require("@aiquants/enrichment-core"),S=require("@aiquants/enrichment-react"),h=require("@aiquants/governance-react"),g=require("react"),$=require("react-router");var oe="ja-JP";var Pt=/[^\s\x1c-\x1f\x85\ufeff]/;function le(e){return Pt.test(e)}function te(e,t){return new Promise(n=>n(e())).catch(n=>t(n instanceof Error?n.message:String(n)))}var ue=require("@aiquants/console-ui/core"),$e=require("@aiquants/enrichment-core"),T=require("react");var Nt=2e3,Tt=1e4;function we(e,t){return t.ok&&e.kind==="ready"&&(0,$e.isStrictlyEarlier)(t.value.readAt,e.value.readAt)?e:(0,ue.keepLastGood)(e,t)}var Et=new Set([401,403]);function _t(e){return e.kind==="failed"||e.refreshFailure!==null&&Et.has(e.refreshFailure.status)?null:e.value.active}function Ke(e,t){let[n,r]=(0,T.useState)(()=>({loaded:e,overview:we({kind:"loading"},e)}));n.loaded!==e&&r({loaded:e,overview:we(n.overview,e)});let i=(0,T.useRef)(t);i.current=t;let s=(0,T.useRef)(null);(0,T.useEffect)(()=>()=>s.current?.abort(),[]);let l=(0,T.useCallback)((c,m)=>te(m,y=>({ok:!1,status:null,reason:y})).then(y=>{c.aborted||r(v=>({loaded:v.loaded,overview:we(v.overview,y)}))}),[]),u=(0,T.useCallback)(()=>{let c=new AbortController;s.current=c,r(m=>({loaded:m.loaded,overview:(0,ue.beginReload)(m.overview,"reload")})),l(c.signal,()=>i.current(c.signal))},[l]),d=(0,T.useCallback)(c=>l(c,()=>i.current(c)),[l]);return{overview:n.overview,reload:u,poll:d}}function Ct(e){return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)}function xt(){return document.visibilityState==="visible"}function Ot(){return!0}function qe(e,t,n){let r=(0,T.useSyncExternalStore)(Ct,xt,Ot),i=t&&r,s=(0,T.useRef)(i),l=e.kind==="ready",u=_t(e),d=u===null?null:u.run.runUid,c=u===null?!1:u.isStale;(0,T.useEffect)(()=>{let m=i&&!s.current;if(s.current=i,!i||d===null&&!(m&&l))return;let y=new AbortController,v=c?Tt:Nt,b,I=async()=>{await n(y.signal),!y.signal.aborted&&d!==null&&(b=setTimeout(I,v))};return b=setTimeout(I,m?0:v),()=>{y.abort(),clearTimeout(b)}},[i,l,d,c,n])}var Ae={columns:2,className:"grid-cols-2",spanClassNames:{1:"col-span-1",2:"col-span-2"}},Pe={columns:4,className:"@min-[41.5rem]:grid-cols-4",spanClassNames:{1:"@min-[41.5rem]:col-span-1",2:"@min-[41.5rem]:col-span-2",3:"@min-[41.5rem]:col-span-3",4:"@min-[41.5rem]:col-span-4"}},Ne={className:"@min-[82rem]:grid-flow-col @min-[82rem]:auto-cols-fr @min-[82rem]:grid-cols-none",lastTabClassName:"@min-[82rem]:col-auto"};function Te(e,t){let n=t%e.columns,r=n===0?1:e.columns-n+1;return e.spanClassNames[r]}var a=require("react/jsx-runtime"),Ve="tab",de={key:"knowledge-authority",phrases:["\u6A29\u5A01\u53F0\u5E33 & \u898F\u7A0B\u885D\u7A81"]},K=[{key:"search",phrases:["\u30E1\u30BF\u30C7\u30FC\u30BF\u691C\u7D22","\u30EF\u30FC\u30AF\u30D9\u30F3\u30C1"]},{key:"ingest",phrases:["\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8","\u53D6\u308A\u8FBC\u307F & \u30E1\u30BF\u751F\u6210"]},{key:"pipeline",phrases:["\u30D1\u30A4\u30D7\u30E9\u30A4\u30F3 & \u63A5\u7D9A\u72B6\u614B"]},{key:"knowledge-graph",phrases:["\u30CA\u30EC\u30C3\u30B8\u30B0\u30E9\u30D5","\u63A2\u7D22"]},{key:"parameters",phrases:["\u30E2\u30C7\u30EB & \u30D1\u30E9\u30E1\u30FC\u30BF\u8A2D\u5B9A"]},{key:"prompts",phrases:["\u30D7\u30ED\u30F3\u30D7\u30C8 & \u30C9\u30E9\u30A4\u30E9\u30F3"]},de,{key:"data-retention",phrases:["\u30C7\u30FC\u30BF\u4FDD\u6301 & \u6574\u5408\u6027\u76E3\u67FB"]}];function Lt(e){return e.phrases.join("")}function Ft(e){return e!==null&&K.some(t=>t.key===e)}var jt="Tri-Store \u30C7\u30FC\u30BF\u6574\u5408\u6027\u76E3\u67FB";function Ut(e){return`\u76E3\u67FB\u306E\u6982\u6CC1\u3092\u8AAD\u3081\u307E\u305B\u3093\u3067\u3057\u305F (${e})\u3002`}function Dt(e){return`\u51E6\u7406\u5C65\u6B74\u3092\u8AAD\u3081\u307E\u305B\u3093\u3067\u3057\u305F (${e})\u3002`}var Be={state:"idle",formData:null,data:null,submit:()=>Promise.resolve()};function Je({data:e,fetcher:t,integrityFetcher:n,renderHeader:r,graphTraversal:i,onBrowseGraphNodes:s,onSimulateGovernance:l,onRefreshIngestQueue:u,onSearch:d,onLoadDocumentRuns:c,onCompareVariants:m,loadIntegrityOverview:y,loadIntegrityFindings:v,policyConflicts:b,documentAuthority:I}){let[f,B]=(0,g.useState)(null),[H,x]=(0,g.useState)(null),[O,k]=(0,g.useState)(!1),Q=(0,g.useMemo)(()=>{if(s!==void 0)return(o,R)=>{k(!0),te(()=>s(o,R),w=>({ok:!1,reason:w})).then(w=>{k(!1),x(w.ok?null:w.reason),w.ok&&B(w.page)})}},[s]),[G,z]=(0,$.useSearchParams)(),L=G.get(Ve),A=Ft(L)?L:K[0].key,F=o=>{z(R=>{let w=new URLSearchParams(R);return w.set(Ve,o),w},{replace:!1,preventScrollReset:!0})},re=Ht(e.recentIngestItems,u,A==="ingest"),j=Ke(e.integrityAudit,y);qe(j.overview,A==="data-retention",j.poll);let Z=(0,g.useRef)(null),me=(0,q.useFocusRescue)(()=>Z.current),[ge,ye]=(0,g.useState)(0),fe=(0,g.useCallback)(()=>ye(o=>o+1),[]),p=re===null?e:{...e,recentIngestItems:[...re]},J=(0,g.useRef)({}),be=(0,g.useCallback)(()=>J.current[A]??null,[A]),se=(0,g.useMemo)(()=>$t(e.enrichmentStrategies),[e.enrichmentStrategies]),Se=(0,g.useMemo)(()=>e.strategyVariants.map(Kt),[e.strategyVariants]),E=Bt(c),W=E.open,Re=W===void 0?void 0:o=>W(o,null),he=W===void 0?void 0:o=>W(o.metadataId,o.id),ie=(o,R)=>{let w=K.length-1,_;if(o.key==="ArrowRight"||o.key==="ArrowDown")_=R===w?0:R+1;else if(o.key==="ArrowLeft"||o.key==="ArrowUp")_=R===0?w:R-1;else if(o.key==="Home")_=0;else if(o.key==="End")_=w;else return;o.preventDefault();let ae=K[_].key;F(ae),J.current[ae]?.focus()},Fe={...p.featureFlags};if(t.formData&&t.formData.get("intent")==="toggle_flag"){let o=String(t.formData.get("flagKey")??""),R=String(t.formData.get("enabled")??"")==="true";o&&(Fe[o]=R)}let ot=t.data&&"inspection"in t.data?t.data.inspection:void 0,X=t.state==="idle"?null:t.formData?.get("intent"),lt=X==="inspect_uri",ut=X==="ingest_document",dt=X==="retry_job"||X==="retry_all_failed",ct=X==="resolve_entity",je=n.state==="idle"?null:n.formData?.get("intent"),pt=je==="start_integrity_run"?{kind:"starting",mode:U.IntegrityRunModeSchema.parse(n.formData?.get("mode"))}:je==="cancel_integrity_run"?{kind:"cancelling"}:{kind:"idle"},mt=(0,$.useRevalidator)(),[gt,ve]=(0,g.useState)(null),Ue=A!=="data-retention";(0,g.useEffect)(()=>{Ue&&ve(null)},[Ue]);let yt=o=>{let R=o?.failure;if(R===void 0){ve(null);return}ve(w=>({failure:R,occurrence:w===null?1:w.occurrence+1})),(0,h.integrityFailureNeedsOverviewReread)(R)&&mt.revalidate()},[ft,De]=(0,g.useState)("console"),{settledIntent:bt,submitAndAwait:Me}=Ge(t,()=>De("console"));Ge(n,o=>{De("integrity"),yt(o)});let He=(ft==="console"?t:n).data?.error,St=()=>{F(de.key),J.current[de.key]?.focus()},ee=bt==="retry_all_failed"&&t.data?.skipped!==void 0&&t.data.requeued!==void 0?{requeued:t.data.requeued,skipped:t.data.skipped}:null;return(0,a.jsx)(q.ConsoleUiRoot,{locale:"ja",formatLocale:oe,timeZone:p.displayTimeZone,testId:"storage-admin-console-ui",children:(0,a.jsxs)("div",{className:"container mx-auto space-y-6 p-6 font-sans text-slate-900","data-testid":"storage-admin-console",children:[He&&(0,a.jsx)("div",{className:"rounded-lg border border-red-200 border-solid bg-red-50 p-4 font-medium text-red-700 text-sm shadow-sm",role:"alert","data-testid":"storage-admin-error-alert",children:He}),r?r({title:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406",tenantId:p.tenantId}):(0,a.jsxs)("header",{className:"flex flex-col justify-between gap-2 border-slate-200 border-b border-solid pb-4 md:flex-row md:items-center",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("h1",{className:"font-bold text-2xl tracking-tight",children:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406"}),(0,a.jsxs)("p",{className:"mt-1 text-slate-500 text-sm",children:["\u30C6\u30CA\u30F3\u30C8: ",(0,a.jsx)("code",{className:"font-semibold text-slate-800",children:p.tenantId})," | \u5168\u30B7\u30B9\u30C6\u30E0\u72B6\u614B\u30FB\u30D1\u30E9\u30E1\u30FC\u30BF\u5236\u5FA1\u30FB\u6574\u5408\u6027\u76E3\u67FB"]})]}),(0,a.jsx)("div",{className:"flex items-center gap-2",children:(0,a.jsxs)("button",{type:"button","data-testid":"header-health-status-button",onClick:()=>F("pipeline"),className:"inline-flex items-center gap-2 rounded-full border border-slate-200 border-solid bg-slate-50 px-3 py-1.5 font-medium text-slate-700 text-xs transition-colors hover:bg-slate-100",children:[(0,a.jsx)("span",{className:`h-2 w-2 rounded-full ${p.systemHealth.allHealthy?"bg-emerald-500":"bg-amber-500"}`}),(0,a.jsxs)("span",{children:["\u5468\u8FBA\u6A5F\u80FD: ",p.systemHealth.allHealthy?"\u5168\u30B5\u30FC\u30D3\u30B9\u6B63\u5E38":"\u63A5\u7D9A\u8981\u78BA\u8A8D"]})]})})]}),(0,a.jsxs)("div",{className:"w-full space-y-6",children:[(0,a.jsx)("div",{className:"@container w-full","data-testid":"storage-admin-tablist-frame",children:(0,a.jsx)("div",{className:`grid w-full ${Ae.className} ${Pe.className} ${Ne.className} gap-1 rounded-xl bg-slate-100 p-1`,role:"tablist","aria-label":"\u904B\u7528\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u306E\u753B\u9762",children:K.map((o,R)=>{let w=A===o.key;return(0,a.jsx)("button",{id:`tab-${o.key}`,type:"button",role:"tab",ref:_=>{J.current[o.key]=_},"aria-selected":w,"aria-controls":`panel-${o.key}`,tabIndex:w?0:-1,"data-testid":`tab-trigger-${o.key}`,onKeyDown:_=>ie(_,R),onClick:()=>F(o.key),className:`wrap-anywhere break-keep rounded-lg px-3 py-2.5 text-center font-medium text-sm transition-all ${R===K.length-1?`${Te(Ae,K.length)} ${Te(Pe,K.length)} ${Ne.lastTabClassName}`:""} ${w?"bg-white text-slate-900 shadow-sm":"text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"}`,children:o.phrases.map((_,ae)=>(0,a.jsxs)(g.Fragment,{children:[ae>0&&(0,a.jsx)("wbr",{}),_]},_))},o.key)})})}),E.metadataId!==null&&(0,a.jsx)(S.PipelineRunInspector,{metadataId:E.metadataId,runs:E.runs,selectedRunId:E.selectedRunId,onSelectRun:E.selectRun,isLoading:E.isLoading,failure:E.failure,onClose:E.close,openRequest:E.openRequest,returnFocusFallback:be}),A==="search"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-search","aria-labelledby":"tab-search",className:"space-y-6","data-testid":"tab-content-search",children:[(0,a.jsx)(S.MetadataSearchWorkbench,{tenantId:p.tenantId,onSearch:d,circuitBreakerStatus:p.circuitBreakerStatus}),m!==void 0&&(0,a.jsx)(S.ModelComparisonWorkbench,{variants:Se,onCompare:m})]}),A==="ingest"&&(0,a.jsx)("div",{role:"tabpanel",id:"panel-ingest","aria-labelledby":"tab-ingest",className:"space-y-6","data-testid":"tab-content-ingest",children:(0,a.jsx)(S.DocumentIngestConsole,{tenantId:p.tenantId,policies:p.confidentialityPolicies,domainOptions:se,recentItems:p.recentIngestItems,inspectionResult:ot,isInspecting:lt,isSubmitting:ut,onInspectUri:o=>{t.submit({intent:"inspect_uri",fileUri:o},{method:"post"})},onIngestDocument:o=>{t.submit({intent:"ingest_document",payload:JSON.stringify(o)},{method:"post"})},onRetryItem:o=>{t.submit({intent:"retry_job",fileId:String(o)},{method:"post"})},onShowHistory:Re})}),A==="pipeline"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-pipeline","aria-labelledby":"tab-pipeline",className:"space-y-6","data-testid":"tab-content-pipeline",children:[(0,a.jsx)(S.PipelineFlowViewer,{featureFlags:p.featureFlags,metrics:p.pipelineStepMetrics,metricSampleWindow:p.pipelineStepMetricWindow}),(0,a.jsx)(qt,{runs:p.recentPipelineRuns,onOpenRun:he}),(0,a.jsx)(S.EnrichmentStrategyBoard,{strategies:p.enrichmentStrategies,featureFlags:p.featureFlags,isUpdating:t.state!=="idle",onToggleStage:(o,R,w)=>t.submit({intent:"update_enrichment_strategy",strategyId:String(o.id),domainId:String(o.domainId),stage:R,enabled:String(w)},{method:"post"})}),(0,a.jsx)(S.InfrastructureHealthMonitor,{health:p.systemHealth,isRefreshing:t.state!=="idle",onRefresh:()=>t.submit({intent:"refresh_health"},{method:"post"})})]}),A==="knowledge-graph"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-knowledge-graph","aria-labelledby":"tab-knowledge-graph",className:"space-y-6","data-testid":"tab-content-knowledge-graph",children:[(0,a.jsx)(S.OntologyStatusCard,{tenantId:p.tenantId,ontologyStatus:p.ontologyStatus}),(0,a.jsx)(h.KnowledgeGraphExplorer,{topologyMaxLabels:U.GRAPH_INDEX_LIMITS.topologyLabels.default,schema:p.graphSchema,tenantId:p.tenantId,unresolvedEntities:p.unresolvedEntities,traversal:i,onBrowseLabel:Q,nodeIndexPage:f,nodeIndexFailure:H,isNodeIndexLoading:O,isResolving:ct,onResolveEntity:(o,R)=>{t.submit({intent:"resolve_entity",entityId:o,action:R},{method:"post"})}})]}),A==="parameters"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-parameters","aria-labelledby":"tab-parameters",className:"space-y-6","data-testid":"tab-content-parameters",children:[(0,a.jsxs)("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[(0,a.jsx)(h.FeatureFlagBoard,{flags:Fe,isUpdating:t.state!=="idle",onToggleFlag:(o,R)=>{t.submit({intent:"toggle_flag",flagKey:o,enabled:String(R)},{method:"post"})}}),(0,a.jsx)(h.ClassificationRuleEditor,{rules:p.classificationRules,domainOptions:se,consultedBy:p.classificationRuleConsumer,onReorderRules:o=>{t.submit({intent:"reorder_rules",orderedRuleIds:JSON.stringify(o)},{method:"post"})}})]}),p.policiesMissingDestination.length>0&&(0,a.jsxs)("div",{"data-testid":"policies-missing-destination",role:"alert",style:{padding:"10px 12px",borderRadius:"6px",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"12px"},children:[(0,a.jsx)("strong",{children:"\u6B21\u306E\u533A\u5206\u30FB\u6A5F\u80FD\u306F\u5B9F\u884C\u6642\u306B\u5931\u6557\u3057\u307E\u3059\u3002"})," \u53C2\u7167\u3059\u308B\u30D7\u30ED\u30F3\u30D7\u30C8\u884C\u306B\u5B9B\u5148\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",(0,a.jsx)("ul",{style:{margin:"6px 0 0",paddingInlineStart:"18px"},children:p.policiesMissingDestination.map(o=>(0,a.jsxs)("li",{"data-testid":`missing-destination-${o.confidentialityLevel}-${o.capability}`,children:[o.confidentialityLevel," / ",o.capability," \u2192 ",o.promptKey," (",o.modelProvider,") \u306E ",(0,a.jsx)("code",{children:"extra_params.base_url"})]},`${o.confidentialityLevel}:${o.capability}`))}),(0,a.jsx)("span",{style:{display:"block",marginTop:"4px",fontSize:"11px"},children:"\u5B9B\u5148\u3092\u8A2D\u5B9A\u3057\u3066\u3082\u3001\u305D\u306E\u30DB\u30B9\u30C8\u304C\u914D\u5099\u5185\u3068\u3057\u3066\u767B\u9332\u3055\u308C\u3066\u3044\u306A\u3051\u308C\u3070\u62D2\u5426\u3055\u308C\u307E\u3059\u3002"})]}),(0,a.jsx)(h.ConfidentialityPolicyBoard,{policies:p.confidentialityPolicies,promptKeys:p.promptTemplates.map(o=>o.template_key),isUpdating:t.state!=="idle",onChangePolicy:o=>{t.submit({intent:"update_confidentiality_policy",confidentialityLevel:o.confidentialityLevel,capability:o.capability,isEnabled:String(o.isEnabled),allowCloudProvider:String(o.allowCloudProvider),promptKey:o.promptKey??""},{method:"post"})}}),(0,a.jsx)(h.TranscriptionAdaptationBoard,{vocabulary:p.transcriptionVocabulary,references:p.transcriptionReferences,unresolvedUris:p.unresolvedReferenceUris,isUpdating:t.state!=="idle",onSaveTerm:o=>Me({intent:"save_transcription_term",id:o.id===null?"":String(o.id),term:o.term,reading:o.reading??"",boost:o.boost===null?"":String(o.boost),domainKey:o.domainKey??"",isActive:String(o.isActive)},{method:"post"}),onSaveReference:o=>Me({intent:"save_transcription_reference",id:o.id===null?"":String(o.id),fileUri:o.fileUri,domainKey:o.domainKey??"",isActive:String(o.isActive)},{method:"post"})}),(0,a.jsx)(h.SystemParameterTable,{parameters:p.systemParameters,onSaveParameter:(o,R)=>{t.submit({intent:"update_parameter",paramKey:o,paramValue:String(R)},{method:"post"})}})]}),A==="prompts"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-prompts","aria-labelledby":"tab-prompts",className:"space-y-6","data-testid":"tab-content-prompts",children:[(0,a.jsx)(h.PromptTemplateConsole,{templates:p.promptTemplates,isSaving:t.state!=="idle",onSaveTemplate:o=>{t.submit({intent:"update_prompt",templateKey:o.template_key,payload:JSON.stringify({templateText:o.template_text,modelName:o.model_name,temperature:o.temperature,maxOutputTokens:o.max_output_tokens,responseSchema:o.response_schema,endpointBaseUrl:o.endpoint_base_url??null})},{method:"post"})}}),(0,a.jsx)(h.GovernanceDryRunConsole,{onSimulate:l})]}),A==="knowledge-authority"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-knowledge-authority","aria-labelledby":"tab-knowledge-authority",className:"space-y-6","data-testid":"tab-content-knowledge-authority",children:[(0,a.jsx)(h.DocumentAuthorityRegistry,{host:I,canUpdate:p.canUpdateKnowledge,onPolicyConflictsChanged:fe}),(0,a.jsx)(h.PolicyConflictQueue,{host:b,revision:ge})]}),A==="data-retention"&&(0,a.jsxs)("div",{role:"tabpanel",id:"panel-data-retention","aria-labelledby":"tab-data-retention",className:"space-y-6","data-testid":"tab-content-data-retention",children:[j.overview.kind==="ready"?(0,a.jsx)(h.TriStoreIntegrityAudit,{overview:j.overview.value,canReadFindings:p.canReadIntegrityFindings,command:pt,commandFailure:gt,onStartRun:(o,R)=>{n.submit(R===null?{intent:"start_integrity_run",mode:o}:{intent:"start_integrity_run",mode:o,basisRunUid:R},{method:"post"})},onCancelRun:o=>{n.submit({intent:"cancel_integrity_run",runUid:o},{method:"post"})},loadFindings:v,refreshFailure:j.overview.refreshFailure===null?null:j.overview.refreshFailure.reason,headingRef:Z}):(0,a.jsx)(q.Card,{title:jt,testId:"audit-overview-failed",headingRef:Z,children:(0,a.jsx)(q.ResourceFailed,{failure:j.overview,onReload:j.reload,forbiddenMessage:"\u76E3\u67FB\u306E\u6982\u6CC1\u3092\u95B2\u89A7\u3059\u308B\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",failureMessage:Ut,rescueRef:me,testId:"audit-overview-failed-resource"})}),(0,a.jsx)(h.PolicyConflictSummaryCard,{host:b,knowledgeTabLabel:Lt(de),onOpenKnowledgeTab:St}),ee!==null&&ee.skipped.length>0&&(0,a.jsxs)("div",{role:"status","data-testid":"retry-all-skipped",className:"rounded-lg border border-amber-200 border-solid bg-amber-50 p-4 text-amber-800 text-sm",children:[(0,a.jsxs)("strong",{children:["\u4E00\u62EC\u518D\u8A66\u884C: ",ee.requeued," \u4EF6\u3092\u518D\u6295\u5165\u3057\u3001",ee.skipped.length," \u4EF6\u3092\u636E\u3048\u7F6E\u304D\u307E\u3057\u305F\u3002"]})," ","\u636E\u3048\u7F6E\u3044\u305F\u884C\u306F\u5931\u6557\u306E\u307E\u307E\u6B8B\u3063\u3066\u3044\u307E\u3059\u3002",(0,a.jsx)("ul",{className:"mt-1.5 list-disc ps-5",children:ee.skipped.map(o=>(0,a.jsxs)("li",{"data-testid":`retry-all-skipped-${o.metadataId}`,children:["#",o.metadataId,": ",o.reason]},o.metadataId))})]}),(0,a.jsxs)("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[(0,a.jsx)(S.SyncStatusMonitor,{counts:p.syncCounts,totalFiles:p.totalFiles,failedItems:p.failedSyncItems,isRetrying:dt,onRetryItem:o=>{t.submit({intent:"retry_job",fileId:String(o)},{method:"post"})},onRetryAll:()=>{t.submit({intent:"retry_all_failed"},{method:"post"})}}),(0,a.jsx)(S.QdrantStorageCard,{overview:p.qdrantCollections,health:{healthy:p.systemHealth.services.qdrant.status==="connected",latency_ms:p.systemHealth.services.qdrant.latencyMs}})]})]})]})]})})}var Mt=new Set(U.EnrichmentSyncStatusSchema.options.filter(e=>e!=="SYNCED"&&!e.startsWith("FAILED"))),Qe=2e3;function Ht(e,t,n){let[r,i]=(0,g.useState)(null),s=(0,g.useRef)(t);s.current=t;let l=(0,g.useRef)(e);l.current!==e&&(l.current=e,r!==null&&i(null));let d=(r??e)?.some(c=>Mt.has(c.syncStatus))===!0;return(0,g.useEffect)(()=>{if(!(n&&d&&s.current))return;let c=!1,m,y=async()=>{let v=s.current;if(v!==void 0){try{let b=await v();if(c)return;i(b)}catch{if(c)return}m=setTimeout(y,Qe)}};return m=setTimeout(y,Qe),()=>{c=!0,clearTimeout(m)}},[d,n]),r}function Ge(e,t){let n=(0,g.useRef)(t);n.current=t;let r=(0,g.useRef)(null),i=(0,g.useRef)(!1),s=(0,g.useRef)(null);if(e.state!=="idle"){i.current=!0;let u=e.formData?.get("intent");typeof u=="string"&&(r.current=u)}(0,g.useEffect)(()=>{if(e.state!=="idle"||!i.current)return;i.current=!1,n.current(e.data);let u=s.current;if(u===null)return;s.current=null;let d=e.data?.error;typeof d=="string"?u.reject(new Error(d)):u.resolve()},[e.state,e.data]);let l=(0,g.useCallback)((...u)=>new Promise((d,c)=>{s.current?.reject(new Error("\u3053\u306E\u4FDD\u5B58\u306F\u5F8C\u7D9A\u306E\u9001\u4FE1\u306B\u7F6E\u304D\u63DB\u3048\u3089\u308C\u307E\u3057\u305F\u3002")),s.current={resolve:d,reject:c},e.submit(...u)}),[e]);return{settledIntent:e.state==="idle"?r.current:null,submitAndAwait:l}}function $t(e){let t=new Set,n=[];for(let r of e)t.has(r.domainKey)||(t.add(r.domainKey),n.push({key:r.domainKey,label:r.domainLabel}));return n}function Kt(e){return{strategyId:e.strategyId,label:`${e.domainKey} / ${e.variantKey}`,embeddingModel:e.embeddingModel}}function qt({runs:e,onOpenRun:t}){return(0,a.jsxs)("section",{className:"rounded-xl border border-slate-200 border-solid bg-white p-6 shadow-sm","aria-labelledby":"pipeline-recent-runs-heading","data-testid":"pipeline-recent-runs",children:[(0,a.jsx)("h2",{id:"pipeline-recent-runs-heading",className:"font-bold text-base text-slate-900",children:"\u76F4\u8FD1\u306E\u5B9F\u884C"}),e.length===0?(0,a.jsx)("p",{className:"mt-4 text-[13px] text-slate-500","data-testid":"pipeline-recent-runs-empty",children:"\u8A18\u9332\u3055\u308C\u305F\u5B9F\u884C\u304C\u3042\u308A\u307E\u305B\u3093\u3002"}):(0,a.jsx)("div",{className:"relative mt-4 overflow-x-auto","data-testid":"pipeline-recent-runs-scroll",children:(0,a.jsxs)("table",{className:"w-full text-left text-[13px]",children:[(0,a.jsx)("thead",{children:(0,a.jsxs)("tr",{className:"whitespace-nowrap border-slate-200 border-b border-solid text-[11px] text-slate-500 uppercase",children:[(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u5B9F\u884C"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u6587\u66F8"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u7A2E\u985E"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u304D\u3063\u304B\u3051"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u8A66\u884C"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u72B6\u614B"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u6B62\u307E\u3063\u305F\u6BB5"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u958B\u59CB"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u7D42\u4E86"}),(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:"\u8981\u6C42\u8005"}),t!==void 0&&(0,a.jsx)("th",{scope:"col",className:"px-3 py-2",children:(0,a.jsx)("span",{className:"sr-only","data-testid":"pipeline-recent-runs-action-header",children:"\u64CD\u4F5C"})})]})}),(0,a.jsx)("tbody",{children:e.map(n=>{let r=(0,S.pipelineRunPresentationKey)(n),i=S.PIPELINE_RUN_STATUS_PRESENTATION[r];return(0,a.jsxs)("tr",{className:"border-slate-100 border-b border-solid","data-testid":`pipeline-run-row-${n.id}`,"data-status":n.status,children:[(0,a.jsxs)("td",{className:"whitespace-nowrap px-3 py-2 font-mono","data-testid":`pipeline-run-id-${n.id}`,children:["#",n.id]}),(0,a.jsxs)("td",{className:"whitespace-nowrap px-3 py-2 font-mono","data-testid":`pipeline-run-metadata-${n.id}`,children:["#",n.metadataId]}),(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-kind-${n.id}`,children:U.DOCUMENT_KIND_LABELS[n.documentKind]}),(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-trigger-${n.id}`,"data-trigger":n.trigger,children:S.PIPELINE_TRIGGER_LABELS[n.trigger]}),(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-attempt-${n.id}`,children:n.attempt}),(0,a.jsx)("td",{className:"px-3 py-2",children:(0,a.jsx)("span",{className:`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 font-semibold text-[11px] ${i.className}`,"data-testid":`pipeline-run-status-${n.id}`,"data-status":n.status,"data-presentation":r,children:i.label})}),(0,a.jsx)("td",{className:"px-3 py-2","data-testid":`pipeline-run-failed-step-${n.id}`,children:n.failedStepKey===null?"\u2014":U.PIPELINE_STEPS[n.failedStepKey].label}),(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2 text-slate-500","data-testid":`pipeline-run-started-${n.id}`,children:(0,a.jsx)(S.RecordedInstant,{iso:n.startedAt,testId:`pipeline-run-started-value-${n.id}`})}),(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2 text-slate-500","data-testid":`pipeline-run-finished-${n.id}`,children:(0,a.jsx)(S.FinishedInstant,{iso:n.finishedAt,testId:`pipeline-run-finished-value-${n.id}`})}),(0,a.jsx)("td",{className:"wrap-anywhere px-3 py-2","data-testid":`pipeline-run-requested-by-${n.id}`,children:n.requestedBy}),t!==void 0&&(0,a.jsx)("td",{className:"whitespace-nowrap px-3 py-2 text-right",children:(0,a.jsx)("button",{type:"button",onClick:()=>t(n),"aria-label":`\u5B9F\u884C #${n.id} (\u6587\u66F8 #${n.metadataId}) \u306E\u8A73\u7D30`,className:"whitespace-nowrap rounded-sm border border-slate-300 border-solid bg-white px-2 py-0.5 font-semibold text-[11px] text-slate-700 hover:bg-slate-50","data-testid":`pipeline-run-open-${n.id}`,children:"\u8A73\u7D30"})})]},n.id)})})]})})]})}var ze={metadataId:null,runs:[],selectedRunId:null,isLoading:!1,failure:null};function Vt(e){for(let t of e)for(let n of t.steps){let r=n.provenance;if(r!==null){for(let[i,s]of Object.entries(r))if(typeof s=="string"&&!le(s))return`\u51E6\u7406\u5C65\u6B74\u306E\u8A18\u9332\u306B\u8AAD\u3081\u306A\u3044\u6765\u6B74\u306E\u5024\u304C\u3042\u308A\u307E\u3059 (\u5B9F\u884C ${t.id} \u306E\u6BB5 ${n.sequence} \u306E ${i})\u3002`}}return null}function Bt(e){let[t,n]=(0,g.useState)(ze),[r,i]=(0,g.useState)(0),s=(0,g.useRef)(0),l=(0,g.useRef)(null),u=(0,g.useMemo)(()=>{if(e!==void 0)return(m,y)=>{s.current+=1;let v=s.current;l.current?.abort();let b=new AbortController;l.current=b,i(I=>I+1),n({metadataId:m,runs:[],selectedRunId:y,isLoading:!0,failure:null}),te(()=>e(m,b.signal),I=>({ok:!1,status:null,reason:I})).then(I=>{if(s.current!==v)return;let f=I.ok?Vt(I.value):Dt(I.reason);if(!I.ok||f!==null){n({metadataId:m,runs:[],selectedRunId:y,isLoading:!1,failure:f});return}n({metadataId:m,runs:I.value,selectedRunId:y===null?Qt(I.value):y,isLoading:!1,failure:null})})}},[e]),d=(0,g.useCallback)(m=>{n(y=>({...y,selectedRunId:m}))},[]),c=(0,g.useCallback)(()=>{s.current+=1,l.current?.abort(),l.current=null,n(ze)},[]);return{...t,openRequest:r,open:u,selectRun:d,close:c}}function Qt(e){return e.length===0?null:e[0].id}function Gt(e){let t=(0,$.useLoaderData)(),n=(0,$.useFetcher)(),r=(0,$.useFetcher)(),i=e.data??t,s=e.fetcher??n,l=e.integrityFetcher??r;return i?(0,a.jsx)(Je,{...e,data:i,fetcher:s,integrityFetcher:l}):(0,a.jsx)("div",{className:"p-8 text-center text-slate-500","data-testid":"storage-admin-loading",children:"\u30C7\u30FC\u30BF\u8AAD\u307F\u8FBC\u307F\u4E2D..."})}function Ee(e){return e.data?(0,a.jsx)(Je,{...e,data:e.data,fetcher:e.fetcher??Be,integrityFetcher:e.integrityFetcher??Be}):(0,a.jsx)(Gt,{...e})}var ke=require("@aiquants/authz-core"),it=require("@aiquants/console-ui/core"),P=require("@aiquants/enrichment-core"),V=require("@aiquants/governance-core"),N=require("zod");var Ce=3e3;function M(e){return Math.round(performance.now()-e)}function C(e){return typeof e=="string"&&le(e)?e:null}function D(e){let t=globalThis.process;return t===void 0?void 0:t.env[e]}function ce(e,t){let n=e?.trim();if(!n)throw new Error(`${t} is not configured; this probe will not guess an endpoint to send credentials to.`);return n}function We(e,t,n){let r=e??(t?.trim()?Number(t):Number.NaN);if(!Number.isInteger(r)||r<=0||r>65535)throw new Error(`${n} is not configured with a valid port; this probe will not guess one.`);return r}function Ye(e,t){if(e!==void 0)return e;let n=t?.trim().toLowerCase();if(!(n===void 0||n===""))return n==="1"||n==="true"||n==="yes"||n==="on"}function Ze(e){let t=e.trim().split("://",1)[0]?.toLowerCase();if(t&&e.includes("://"))return t.endsWith("s")||t.includes("+s")}function zt(e){let n=e.split("://").slice(-1)[0].split("/",1)[0],r=n.split(":").pop();if(!r||r===n)return;let i=Number(r);return Number.isInteger(i)&&i>0&&i<=65535?i:void 0}async function _e(e,t){let n;try{return await Promise.race([e,new Promise((r,i)=>{n=setTimeout(()=>i(new Error(`Probe timed out after ${t}ms`)),t)})])}finally{clearTimeout(n)}}async function Xe(e){let t=e?.qdrantApiKey??D("QDRANT_API_KEY")??"",n=e?.timeoutMs??Ce,r=performance.now(),i="";try{i=ce(e?.qdrantUrl??D("QDRANT_URL"),"QDRANT_URL");let s={};t&&(s["api-key"]=t);let[l,u]=await Promise.all([fetch(`${i}/`,{headers:s,signal:AbortSignal.timeout(n)}),fetch(`${i}/collections`,{headers:s,signal:AbortSignal.timeout(n)})]);if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText}`);if(!u.ok)throw new Error(`HTTP ${u.status}: ${u.statusText} (/collections)`);let d=await l.json(),c=M(r),y=(await u.json()).result?.collections?.length??0;return{serviceName:"Qdrant",category:"vector",status:"connected",version:C(d.version),endpoint:i,latencyMs:c,details:{engine:C(d.title),collectionsCount:y,restPort:zt(i)??null,tls:Ze(i)??null}}}catch(s){let l=M(r),u=s instanceof Error?s.message:String(s);return{serviceName:"Qdrant",category:"vector",status:"error",version:null,endpoint:i,latencyMs:l,details:{},errorMessage:u}}}async function et(e){let t=e?.timeoutMs??Ce,n=performance.now(),r=C(e?.neo4jBoltUri??D("NEO4J_URI")),i=r===null?"":r;try{let s=e?.graphReader;if(!s)throw new Error("Graph reader not configured");let l=e?.tenantId,[u,d]=await Promise.all([_e(s("CALL dbms.components() YIELD versions, edition RETURN versions[0] AS version, edition",{}),t),_e(l?s("MATCH (n {tenantId: $tenantId}) RETURN count(n) AS node_count",{tenantId:l}):s("RETURN null AS node_count",{}),t)]);if(!u.ok)throw new Error(u.reason);if(!d.ok)throw new Error(d.reason);let[c,m]=u.rows[0]??[],y=d.rows[0]?.[0],v=M(n);return{serviceName:"Neo4j",category:"graph",status:"connected",version:C(c),endpoint:i,latencyMs:v,details:{edition:C(m),boltUri:r,nodeCount:typeof y=="number"?y:null,tls:r===null?null:Ze(r)??null}}}catch(s){let l=M(n),u=s instanceof Error?s.message:String(s);return{serviceName:"Neo4j",category:"graph",status:"error",version:null,endpoint:i,latencyMs:l,details:{},errorMessage:u}}}async function tt(e){let t=performance.now(),n="",r=Ye(e?.redisTls,D("REDIS_TLS")),i=Number.NaN;try{let s=e?.redisClient;if(!s)throw new Error("Redis client not configured");let l=ce(e?.redisHost??D("REDIS_HOST"),"REDIS_HOST");i=We(e?.redisPort,D("REDIS_PORT"),"REDIS_PORT"),n=`${r===!1?"redis":"rediss"}://${l}:${i}`,await s.ping();let u=await s.info("server"),d=C(u.match(/redis_version:([^\r\n]+)/)?.[1]),c=null;if(typeof s.dbSize=="function")try{c=await s.dbSize()}catch{c=null}let m=M(t);return{serviceName:"Redis",category:"cache",status:"connected",version:d,endpoint:n,latencyMs:m,details:{totalKeys:c,port:i,tls:r??null,database:0}}}catch(s){let l=M(t),u=s instanceof Error?s.message:String(s);return{serviceName:"Redis",category:"cache",status:"error",version:null,endpoint:n,latencyMs:l,details:{},errorMessage:u}}}function Jt(e){let t=e.match(/Microsoft SQL Server \d+ \([^)]+\)/);return C(t===null?e.substring(0,30):t[0].replace("Microsoft SQL Server ",""))}async function nt(e){let t=performance.now(),n="",r=Ye(e?.sqlServerTls,D("SQL_SERVER_TLS")),i=Number.NaN;try{let s=e?.sqlServerExecute;if(!s)throw new Error("SQL Server executor not configured");let l=ce(e?.sqlServerHost??D("SQL_SERVER_HOST"),"SQL_SERVER_HOST");i=We(e?.sqlServerPort,D("SQL_SERVER_PORT"),"SQL_SERVER_PORT"),n=`${l}:${i}`;let u=await s(),d=C(u.db_name),c=C(u.version),m=c===null?null:C(c.split(`
2
+ `)[0]),y=m===null?null:Jt(m),v=M(t);return{serviceName:"SQL Server",category:"database",status:"connected",version:y,endpoint:n,latencyMs:v,details:{database:d,port:i,tls:r??null,fullVersion:m}}}catch(s){let l=M(t),u=s instanceof Error?s.message:String(s);return{serviceName:"SQL Server",category:"database",status:"error",version:null,endpoint:n,latencyMs:l,details:{},errorMessage:u}}}async function rt(e){let t=e?.timeoutMs??Ce,n=performance.now(),r="";try{r=ce(e?.backendApiHost??D("BACKEND_API_HOST"),"BACKEND_API_HOST");let i=await fetch(`${r}/openapi.json`,{signal:AbortSignal.timeout(t)});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);let s=await i.json(),l=Object.keys(s.paths??{}).length,u=M(n);return{serviceName:"AI Quant API",category:"api",status:"connected",version:C(s.info?.version),endpoint:r,latencyMs:u,details:{title:C(s.info?.title),endpointsCount:l}}}catch(i){let s=M(n),l=i instanceof Error?i.message:String(i);return{serviceName:"AI Quant API",category:"api",status:"error",version:null,endpoint:r,latencyMs:s,details:{},errorMessage:l}}}async function xe(e){let[t,n,r,i,s]=await Promise.all([Xe(e),et(e),tt(e),nt(e),rt(e)]),l=t.status==="connected"&&n.status==="connected"&&r.status==="connected"&&i.status==="connected"&&s.status==="connected";return{services:{qdrant:t,neo4j:n,redis:r,sqlServer:i,quantsApi:s},allHealthy:l,checkedAt:new Date().toISOString()}}var Wt=N.z.object({templateText:N.z.string(),modelName:N.z.string(),temperature:N.z.number(),maxOutputTokens:N.z.number(),responseSchema:N.z.union([N.z.record(N.z.string(),N.z.unknown()),N.z.string(),N.z.null()]).optional(),endpointBaseUrl:N.z.string().nullable()}).strict(),Yt=N.z.discriminatedUnion("mode",[N.z.object({mode:P.IntegrityRunModeSchema.extract(["SCAN"]),basisRunUid:N.z.null()}).strict(),N.z.object({mode:P.IntegrityRunModeSchema.extract(["REPAIR"]),basisRunUid:N.z.string().uuid()}).strict()]),Zt=N.z.object({runUid:N.z.string().uuid()}).strict();function at(e){return e==="start_integrity_run"?"start":e==="cancel_integrity_run"?"cancel":null}function Y(e,t){return e.issues.map(n=>`${n.path.length===0?t:n.path.join(".")}: ${n.message}`).join("; ")}function Xt(e,t){if(e==="bool")return t==="true"||t==="false"?null:"paramValue must be 'true' or 'false' for a bool parameter";if(e==="int")return/^[+-]?\d+$/.test(t)&&Number.isSafeInteger(Number(t))?null:"paramValue must be a safe integer for an int parameter";if(e==="float")return t.trim()!==""&&Number.isFinite(Number(t))?null:"paramValue must be a finite number for a float parameter";if(e==="json")try{return JSON.parse(t),null}catch{return"paramValue must be valid JSON for a json parameter"}return null}function en(e){let t=P.PipelineRunSummarySchema.array().safeParse(e);if(!t.success)throw new Error(`getRecentPipelineRuns answered something that is not a run summary: ${Y(t.error,"getRecentPipelineRuns")}`);return t.data}function tn(e){let t=P.PipelineStepMetricSchema.array().safeParse(e);if(!t.success)throw new Error(`getPipelineStepMetrics answered something that is not a step metric: ${Y(t.error,"getPipelineStepMetrics")}`);let n=new Set;for(let r of t.data){let i=`${r.documentKind}/${r.stepKey}`;if(n.has(i))throw new Error(`getPipelineStepMetrics answered more than one metric for (documentKind, stepKey) = (${r.documentKind}, ${r.stepKey})`);n.add(i)}return t.data}function nn(e){if(!Number.isSafeInteger(e)||e<=0)throw new Error(`pipelineStepMetricWindow must be a positive safe integer, got ${String(e)}`);return e}async function rn(e,t){let n;try{n=await e.readIntegrityAuditOverview(t)}catch(i){return{ok:!1,status:null,reason:i instanceof Error?i.message:String(i)}}let r=P.IntegrityAuditOverviewSchema.safeParse(n);return r.success?{ok:!0,value:r.data}:{ok:!1,status:null,reason:`readIntegrityAuditOverview answered something that is not an audit overview: ${Y(r.error,"readIntegrityAuditOverview")}`}}function sn(e){return!Array.isArray(e)||e.length===0?"orderedRuleIds must be a non-empty array of rule ids":e.every(t=>typeof t=="number"&&Number.isSafeInteger(t)&&t>0)?new Set(e).size!==e.length?"orderedRuleIds must not name a rule twice":null:"orderedRuleIds must contain positive integers only"}function Le(e){let{store:t,healthProbeOptions:n,resourceKey:r="storage_admin",requireUser:i,requirePermission:s,resolveTenantId:l,authorizeIngest:u,canReadIntegrityFindings:d,canUpdateKnowledge:c}=e;async function m(v){let{request:b}=v;if(!await i(b))throw new Response("\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002",{status:401});try{await s(b,{resourceKey:r,action:"read"})}catch(ie){throw ie instanceof ke.AuthzDeniedError?new Response("\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",{status:403}):ie}let f=await l(b),B=nn(t.pipelineStepMetricWindow),[H,x,O]=await Promise.all([t.getFeatureFlags(f),t.getSystemParameters(f),t.getSyncCounts(f)]),k={featureFlags:H,systemParameters:x,syncCounts:O},[Q,G,z,L,A,F,re,j,Z,me,ge,ye,fe,p,J,be,se,Se,E,W,Re]=await Promise.all([t.getConfidentialityPolicies(f),t.getTranscriptionVocabulary(f),t.getTranscriptionReferences(f),t.getUnresolvedReferenceUris(f),t.getPoliciesMissingDestination(f),t.getPromptTemplates(f),t.getClassificationRules(f),t.getFailedSyncItems(f),t.getGraphSchema(f),rn(t,f),d(b),c(b),t.getUnresolvedEntities(f),t.getQdrantCollections(f),xe({...n,tenantId:f}),t.getRecentIngestItems(f),t.getOntologyStatus(f,k),t.getEnrichmentStrategies(f),t.getStrategyVariants(f),t.getPipelineStepMetrics(f),t.getRecentPipelineRuns(f)]),he=t.getCircuitBreakerStatus();return{tenantId:f,featureFlags:k.featureFlags,confidentialityPolicies:Q,transcriptionVocabulary:G,transcriptionReferences:z,unresolvedReferenceUris:L,policiesMissingDestination:A,systemParameters:k.systemParameters,promptTemplates:F,classificationRules:re,classificationRuleConsumer:t.classificationRuleConsumer??null,syncCounts:k.syncCounts.counts,totalFiles:k.syncCounts.total,failedSyncItems:j,circuitBreakerStatus:he,pipelineStepMetrics:tn(W),pipelineStepMetricWindow:B,recentPipelineRuns:en(Re),displayTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,graphSchema:Z,enrichmentStrategies:Se,strategyVariants:E,integrityAudit:me,canReadIntegrityFindings:ge,canUpdateKnowledge:ye,unresolvedEntities:fe,qdrantCollections:p,systemHealth:J,recentIngestItems:be,ontologyStatus:se}}async function y(v){let{request:b}=v,I=await i(b);if(!I)return Response.json({error:"\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002"},{status:401});if(I.email.trim()==="")return Response.json({error:"\u64CD\u4F5C\u8005\u3092\u7279\u5B9A\u3067\u304D\u306A\u3044\u305F\u3081\u8A2D\u5B9A\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002"},{status:403});if(I.accessToken==="")throw new Error("requireUser resolved an operator whose accessToken is an empty string; answer null when the session holds no token the upstream services accept");let f=I.email,B=I.accessToken===null?void 0:I.accessToken;try{await s(b,{resourceKey:r,action:"update"})}catch(L){if(L instanceof ke.AuthzDeniedError)return await un(b);throw L}let H=await l(b),x=await b.formData(),O=String(x.get("intent")??"");if(O==="refresh_health")return Response.json({success:!0,refreshed:!0});let k=await on(t,H,O,x,f);if(k)return k;let Q=await ln(t,H,O,x,f,B);if(Q)return Q;let G=await dn(t,H,O,x,B,()=>d(b));if(G)return G;if(O==="resolve_entity"){let L=String(x.get("entityId")??""),A=String(x.get("action")??"");if(!L||A!=="merge"&&A!=="promote")return Response.json({error:"Valid entityId and action ('merge' | 'promote') are required"},{status:400});try{return await t.resolveEntity(H,L,A),Response.json({success:!0,entityId:L,action:A})}catch(F){return Response.json({error:F instanceof Error?F.message:String(F)},{status:400})}}let z=await mn(t,H,O,x,f,b,u,B);return z||Response.json({error:`Unknown intent: ${O}`},{status:400})}return{loader:m,action:y}}function Oe(e){let t=String(e??"").trim();return t===""?null:t}function pe(e){let t=String(e??"").trim();if(t==="")return null;let n=Number(t);if(!(!Number.isSafeInteger(n)||n<=0))return n}function an(e){let t=String(e??"").trim();if(t==="")return null;let n=Number(t);if(!(!Number.isFinite(n)||n<=0))return n}async function on(e,t,n,r,i){if(n==="update_enrichment_strategy"){let s=String(r.get("stage")??"");if(!(0,P.isEnrichmentStageKey)(s))return Response.json({error:"stage must be a canonical enrichment stage key"},{status:400});let l=pe(r.get("strategyId")),u=pe(r.get("domainId"));if(l==null||u===void 0||u===null)return Response.json({error:"strategyId and domainId must be positive integers naming existing rows"},{status:400});let d=String(r.get("enabled")??"")==="true";try{await e.updateEnrichmentStrategy(t,{strategyId:l,domainId:u,stage:s,enabled:d},i)}catch(c){return Response.json({error:c instanceof Error?c.message:"\u53D6\u308A\u8FBC\u307F\u6226\u7565\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,strategyId:l,domainId:u,stage:s,enabled:d})}if(n==="toggle_flag"){let s=String(r.get("flagKey")??""),l=String(r.get("enabled")??"")==="true";if(!s)return Response.json({error:"flagKey is required"},{status:400});let u=await e.getFeatureFlags(t);return Object.hasOwn(u,s)?(await e.toggleFeatureFlag(t,s,l,i),Response.json({success:!0,flagKey:s,enabled:l})):Response.json({error:`flagKey names no feature flag of this tenant: ${s}`},{status:400})}if(n==="update_confidentiality_policy"){let s=String(r.get("confidentialityLevel")??""),l=String(r.get("capability")??"");if(!(V.ConfidentialityLevelSchema.safeParse(s).success&&V.GovernedCapabilitySchema.safeParse(l).success))return Response.json({error:"confidentialityLevel and capability must be canonical values"},{status:400});let u=String(r.get("allowCloudProvider")??"")==="true";if(u&&!V.CLOUD_CAPABLE_CAPABILITIES.includes(l))return Response.json({error:`${l} sends nothing outside the deployment, so it has no cloud permission to grant`},{status:400});let d=String(r.get("promptKey")??"");return await e.updateConfidentialityPolicy(t,{confidentialityLevel:s,capability:l,isEnabled:String(r.get("isEnabled")??"")==="true",allowCloudProvider:u,promptKey:d===""?null:d},i),Response.json({success:!0,confidentialityLevel:s,capability:l})}if(n==="save_transcription_term"){let s=String(r.get("term")??"").trim();if(!s)return Response.json({error:"term is required"},{status:400});let l=an(r.get("boost"));if(l===void 0)return Response.json({error:"boost must be a number greater than zero, or absent to let the service decide"},{status:400});let u=pe(r.get("id"));if(u===void 0)return Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400});try{await e.saveTranscriptionTerm(t,{id:u,term:s,reading:Oe(r.get("reading")),boost:l,domainKey:Oe(r.get("domainKey")),isActive:String(r.get("isActive")??"true")==="true"},i)}catch(d){return Response.json({error:d instanceof Error?d.message:"\u8A9E\u5F59\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,term:s})}if(n==="save_transcription_reference"){let s=String(r.get("fileUri")??"").trim();if(!s)return Response.json({error:"fileUri is required"},{status:400});let l=pe(r.get("id"));if(l===void 0)return Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400});try{await e.saveTranscriptionReference(t,{id:l,fileUri:s,domainKey:Oe(r.get("domainKey")),isActive:String(r.get("isActive")??"true")==="true"},i)}catch(u){return Response.json({error:u instanceof Error?u.message:"\u53C2\u7167\u8CC7\u6599\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,fileUri:s})}if(n==="update_parameter"){let s=String(r.get("paramKey")??""),l=String(r.get("paramValue")??"");if(!s)return Response.json({error:"paramKey is required"},{status:400});let u=(await e.getSystemParameters(t)).find(c=>c.key===s);if(u===void 0)return Response.json({error:`paramKey names no parameter of this tenant: ${s}`},{status:400});let d=Xt(u.data_type,l);if(d!==null)return Response.json({error:d},{status:400});try{(0,P.assertSystemParameterInRange)(s,Number(l))}catch(c){return Response.json({error:c.message},{status:400})}return await e.updateSystemParameter(t,s,l,i),Response.json({success:!0,paramKey:s,paramValue:l})}if(n==="update_prompt"){let s=String(r.get("templateKey")??""),l=String(r.get("payload")??"{}"),u;try{u=JSON.parse(l)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}if(!s)return Response.json({error:"templateKey is required"},{status:400});let d=Wt.safeParse(u);if(!d.success)return Response.json({error:`payload does not carry a prompt template update: ${Y(d.error,"payload")}`},{status:400});let c=d.data;try{return await e.updatePromptTemplate(t,s,c,i),Response.json({success:!0,templateKey:s})}catch(m){return Response.json({error:m instanceof Error?m.message:String(m)},{status:400})}}if(n==="reorder_rules"){let s=String(r.get("orderedRuleIds")??"[]"),l;try{l=JSON.parse(s)}catch{return Response.json({error:"Invalid orderedRuleIds JSON"},{status:400})}let u=sn(l);if(u!==null)return Response.json({error:u},{status:400});let d=l;return await e.reorderClassificationRules(t,d,i),Response.json({success:!0,orderedRuleIds:d})}return null}async function ln(e,t,n,r,i,s){if(n==="retry_job"){let l=String(r.get("fileId")??"");if(!l)return Response.json({error:"fileId is required"},{status:400});try{return await e.retrySyncItem(t,l,i,s),Response.json({success:!0,fileId:l})}catch(u){return Response.json({error:u instanceof Error?u.message:String(u)},{status:400})}}if(n==="retry_all_failed")try{let{requeued:l,skipped:u}=await e.retryAllFailedSyncItems(t,i,s);return Response.json({success:!0,requeued:l,skipped:u})}catch(l){return Response.json({error:l instanceof Error?l.message:String(l)},{status:400})}return null}function ne(e,t,n){let r=P.IntegrityCommandFailureSchema.parse({command:e,code:t,status:n}),i=P.INTEGRITY_COMMAND_CODES.find(s=>s.code===r.code);return Response.json({failure:r},{status:i===void 0?502:i.status})}async function un(e){let t=await e.formData().catch(()=>null),n=t===null?null:at(t.get("intent"));return n===null?Response.json({error:"\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002"},{status:403}):ne(n,"FORBIDDEN",null)}async function st(e,t){let n;try{n=P.IntegrityCommandReplySchema.parse(await t())}catch{return ne(e,"UPSTREAM_FAILED",null)}return n.ok?Response.json({success:!0,runUid:n.runUid}):ne(e,(0,P.integrityCommandFailureCodeOf)(e,n.status,n.errorCode),n.status)}async function dn(e,t,n,r,i,s){let l=at(n);if(l==="start"){let u=Yt.safeParse({mode:r.get("mode"),basisRunUid:r.get("basisRunUid")});if(!u.success)return Response.json({error:`start_integrity_run takes mode SCAN without basisRunUid, or mode REPAIR with basisRunUid (a UUID): ${Y(u.error,"form")}`},{status:400});let{mode:d,basisRunUid:c}=u.data;return i===void 0||d==="REPAIR"&&!await s()?ne(l,"FORBIDDEN",null):await st(l,()=>e.startIntegrityRun(t,d,c,i))}if(l==="cancel"){let u=Zt.safeParse({runUid:r.get("runUid")});return u.success?i===void 0?ne(l,"FORBIDDEN",null):await st(l,()=>e.cancelIntegrityRun(t,u.data.runUid,i)):Response.json({error:`cancel_integrity_run takes runUid (a UUID): ${Y(u.error,"form")}`},{status:400})}return null}function cn(e){if(typeof e!="object"||e===null)return"payload must be an object";let t=e;if(typeof t.fileUri!="string"||t.fileUri.trim()==="")return"payload.fileUri is required";if(!V.ConfidentialityLevelSchema.safeParse(t.confidentialityLevel).success)return`payload.confidentialityLevel must be one of ${V.ConfidentialityLevelSchema.options.join(", ")}`;let r=t.departmentId;return r!=null&&(typeof r!="number"||!Number.isInteger(r))?"payload.departmentId must be an integer or null":null}function pn(e){try{return(0,it.formatCount)(e,oe),null}catch{return`inspectFileUri answered a fileSize that is not a byte count (a non-negative safe integer): ${String(e)}`}}async function mn(e,t,n,r,i,s,l,u){if(n==="ingest_document"){let d=String(r.get("payload")??"");if(!d)return Response.json({error:"payload is required"},{status:400});let c;try{c=JSON.parse(d)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}let m=cn(c);if(m)return Response.json({error:m},{status:400});let y=c,v=await l(s,y);if(v!==null)return Response.json({error:v},{status:403});try{let b=u===void 0?await e.ingestDocument(t,y,i):await e.ingestDocument(t,y,i,u);return Response.json({success:!0,result:b})}catch(b){return Response.json({error:b instanceof Error?b.message:String(b)},{status:400})}}if(n==="inspect_uri"){let d=String(r.get("fileUri")??"").trim();if(!d)return Response.json({error:"fileUri is required"},{status:400});if(!e.inspectFileUri)return Response.json({error:"inspectFileUri is not implemented"},{status:501});let c;try{c=u===void 0?await e.inspectFileUri(t,d):await e.inspectFileUri(t,d,u)}catch(y){return Response.json({error:y instanceof Error?y.message:String(y)},{status:400})}let m=pn(c.fileSize);return m!==null?Response.json({error:m},{status:400}):Response.json({success:!0,inspection:c})}return null}function gn(e){let t=Le(e);return{loader:t.loader,action:t.action,View:Ee,server:t}}0&&(module.exports={StorageAdminConsoleView,checkAllSystemHealth,checkBackendApiHealth,checkNeo4jHealth,checkQdrantHealth,checkRedisHealth,checkSqlServerHealth,createStorageAdminApp,createStorageAdminServer});
package/dist/index.d.cts CHANGED
@@ -1,12 +1,34 @@
1
- import { EnrichmentStageKey } from "@aiquants/enrichment-core";
2
- export { SearchMode } from "@aiquants/enrichment-core";
3
- import { EnrichmentStrategyRow, FailedSyncItem, QdrantStorageOverview, CircuitBreakerState, PipelineConfig, DocumentIngestPayload, FileInspectionResult, RecentIngestItem, OntologyStatusData } from "@aiquants/enrichment-react";
4
- export { DocumentIngestLabel, DocumentIngestPayload, EnrichmentStrategyRow, FailedSyncItem, FileInspectionResult, FusionStrategy, MetadataSearchHit, MetadataSearchParams, MetadataSearchResult, OntologyStatusData, PipelineConfig, QdrantCollectionInfo, QdrantStorageOverview, RecentIngestItem, SearchHitGraphRelation, SearchHitScoreBreakdown, StrategyProvenance } from "@aiquants/enrichment-react";
5
- import { ConfidentialityPolicyRow, TranscriptionTermRow, TranscriptionReferenceRow, PromptTemplateItem, ClassificationRuleItem, GraphSchemaStats, TriStoreAuditData, TriStoreReconcileResult, GraphTraversalRunner, GraphNodeIndexOutcome, SimulationRunner } from "@aiquants/governance-react";
6
- export { ClassificationRuleItem as ClassificationRule, GraphNodeIndexOutcome, GraphNodeIndexPage, GraphNodeSummary, GraphSchemaStats, GraphTraversalInput, GraphTraversalOutcome, GraphTraversalRunner, PromptTemplateItem, SimulationOutcome, SimulationRunInput, SimulationRunResult, SimulationRunner, SimulationScoreSet, SimulationVerdictFlip, TriStoreAuditData, TriStoreReconcileResult } from "@aiquants/governance-react";
1
+ import { ResourceOutcome } from "@aiquants/console-ui/core";
2
+ export { CommandOutcome, ResourceOutcome } from "@aiquants/console-ui/core";
3
+ import { EnrichmentStageKey, PipelineStepMetric, PipelineRunSummary, IntegrityAuditOverview, IntegrityRunMode, IntegrityCommandReply, PipelineRunRecord, IntegrityCommandFailure } from "@aiquants/enrichment-core";
4
+ export { IntegrityAuditOverview, IntegrityCommandFailure, IntegrityCommandReply, IntegrityFindingPage, IntegrityFindingsQuery, IntegrityRunMode, PipelineRunRecord, PipelineRunSummary, PipelineStepMetric, PipelineStepRecord, SearchMode, StageProvenance } from "@aiquants/enrichment-core";
5
+ import { EnrichmentStrategyRow, FailedSyncItem, QdrantStorageOverview, CircuitBreakerState, DocumentIngestPayload, FileInspectionResult, RecentIngestItem, OntologyStatusData, MetadataSearchWorkbenchProps, ModelComparisonWorkbenchProps } from "@aiquants/enrichment-react";
6
+ export { ComparisonHit, ComparisonInput, ComparisonOutcome, ComparisonVariantResult, DocumentIngestLabel, DocumentIngestPayload, EnrichmentStrategyRow, FailedSyncItem, FileInspectionResult, FusionStrategy, MetadataSearchHit, MetadataSearchParams, MetadataSearchResult, OntologyStatusData, QdrantCollectionInfo, QdrantStorageOverview, RecentIngestItem, SearchHitGraphRelation, SearchHitScoreBreakdown, StrategyProvenance } from "@aiquants/enrichment-react";
7
+ import { ConfidentialityPolicyRow, TranscriptionTermRow, TranscriptionReferenceRow, PromptTemplateItem, ClassificationRuleItem, GraphSchemaStats, IntegrityFindingsLoader, PolicyConflictHost, DocumentAuthorityHost, GraphTraversalHost, GraphNodeIndexOutcome, SimulationRunner } from "@aiquants/governance-react";
8
+ export { ClassificationRuleItem as ClassificationRule, DocumentAuthorityHost, GraphNodeIndexOutcome, GraphNodeIndexPage, GraphNodeSummary, GraphRelationshipTypesOutcome, GraphRelationshipTypesReader, GraphSchemaStats, GraphTraversalHost, GraphTraversalInput, GraphTraversalOutcome, GraphTraversalRunner, IntegrityFindingsLoader, PolicyConflictHost, PromptTemplateItem, SimulationOutcome, SimulationRunInput, SimulationRunResult, SimulationRunner, SimulationScoreSet, SimulationVerdictFlip } from "@aiquants/governance-react";
7
9
  import * as react from "react";
8
10
  import { ReactNode } from "react";
9
11
  import { useFetcher } from "react-router";
12
+ export { AuthorityCandidatePage, AuthorityCandidateQuery, DocumentAuthorityCommand, DocumentAuthorityCommandRejection, DocumentAuthorityCommandResult, DocumentAuthorityPageQuery, DocumentAuthorityPageWithCategories, PolicyConflictDecision, PolicyConflictDecisionRejection, PolicyConflictDetail, PolicyConflictDetectionOutcome, PolicyConflictDetectionRequestRejection, PolicyConflictPage, PolicyConflictPageQuery, PolicyConflictSummary, ReplaceableAuthorityPage, ReplaceableAuthorityQuery } from "@aiquants/governance-core";
13
+ type IntegrityOverviewLoader = (signal: AbortSignal) => Promise<ResourceOutcome<IntegrityAuditOverview>>;
14
+ type MetadataSearchRunner = NonNullable<MetadataSearchWorkbenchProps["onSearch"]>;
15
+ type ModelComparisonRunner = ModelComparisonWorkbenchProps["onCompare"];
16
+ interface StrategyVariant {
17
+ readonly strategyId: number;
18
+ readonly variantKey: string;
19
+ readonly label: string;
20
+ readonly embeddingModel: string;
21
+ readonly domainKey: string;
22
+ }
23
+ type DocumentRunsLoader = (metadataId: number, signal: AbortSignal) => Promise<ResourceOutcome<readonly PipelineRunRecord[]>>;
24
+ interface RetryAllSkippedItem {
25
+ metadataId: number;
26
+ reason: string;
27
+ }
28
+ interface RetryAllFailedResult {
29
+ requeued: number;
30
+ skipped: readonly RetryAllSkippedItem[];
31
+ }
10
32
  interface DocumentIngestResult {
11
33
  metadataId: number;
12
34
  revision: number;
@@ -34,14 +56,23 @@ interface SystemInfrastructureHealth {
34
56
  allHealthy: boolean;
35
57
  checkedAt: string;
36
58
  }
37
- interface SystemParameter {
59
+ interface SystemParameterBase {
38
60
  key: string;
39
- value: string;
40
61
  category: string;
41
62
  description: string;
42
- data_type: "string" | "int" | "float" | "bool" | "json";
43
63
  is_secret: boolean;
44
64
  }
65
+ type SystemParameter = SystemParameterBase & ({
66
+ data_type: "bool";
67
+ value: boolean;
68
+ } | {
69
+ data_type: "int" | "float";
70
+ value: number;
71
+ } | {
72
+ data_type: "string" | "json";
73
+ value: string;
74
+ });
75
+ type SystemParameterDataType = SystemParameter["data_type"];
45
76
  interface PromptTemplateUpdate {
46
77
  templateText: string;
47
78
  modelName: string;
@@ -64,12 +95,6 @@ interface UnresolvedEntity {
64
95
  co_occurrences: number;
65
96
  suggested_action: "merge" | "promote";
66
97
  }
67
- type StageMetrics = Record<string, {
68
- latency_p50_ms: number;
69
- latency_p95_ms: number;
70
- throughput_rps: number;
71
- success_rate: number;
72
- }>;
73
98
  interface StorageAdminLoaderData {
74
99
  tenantId: string;
75
100
  featureFlags: Record<string, boolean>;
@@ -81,11 +106,16 @@ interface StorageAdminLoaderData {
81
106
  totalFiles: number;
82
107
  failedSyncItems: FailedSyncItem[];
83
108
  circuitBreakerStatus: Record<string, CircuitBreakerState>;
84
- pipelineConfig: PipelineConfig;
85
- stageMetrics: StageMetrics;
109
+ pipelineStepMetrics: readonly PipelineStepMetric[];
110
+ pipelineStepMetricWindow: number;
111
+ recentPipelineRuns: readonly PipelineRunSummary[];
112
+ displayTimeZone: string;
86
113
  graphSchema: GraphSchemaStats;
87
114
  enrichmentStrategies: EnrichmentStrategyRow[];
88
- triStoreAuditData: TriStoreAuditData;
115
+ strategyVariants: readonly StrategyVariant[];
116
+ integrityAudit: ResourceOutcome<IntegrityAuditOverview>;
117
+ canReadIntegrityFindings: boolean;
118
+ canUpdateKnowledge: boolean;
89
119
  unresolvedEntities: UnresolvedEntity[];
90
120
  qdrantCollections: QdrantStorageOverview;
91
121
  systemHealth: SystemInfrastructureHealth;
@@ -141,16 +171,19 @@ interface StorageAdminStore {
141
171
  }>;
142
172
  getFailedSyncItems(tenantId: string): Promise<FailedSyncItem[]>;
143
173
  retrySyncItem(tenantId: string, fileId: string, actor?: string, accessToken?: string): Promise<void>;
144
- retryAllFailedSyncItems(tenantId: string, actor?: string, accessToken?: string): Promise<void>;
174
+ retryAllFailedSyncItems(tenantId: string, actor?: string, accessToken?: string): Promise<RetryAllFailedResult>;
175
+ getPipelineStepMetrics(tenantId: string): Promise<readonly PipelineStepMetric[]>;
176
+ readonly pipelineStepMetricWindow: number;
177
+ getRecentPipelineRuns(tenantId: string): Promise<readonly PipelineRunSummary[]>;
178
+ getStrategyVariants(tenantId: string): Promise<readonly StrategyVariant[]>;
145
179
  getGraphSchema(tenantId: string): Promise<GraphSchemaStats>;
146
- getTriStoreAuditData(tenantId: string, snapshot: ConsoleConfigSnapshot): Promise<TriStoreAuditData>;
147
- reconcileTriStore(tenantId: string, accessToken?: string): Promise<TriStoreReconcileResult>;
180
+ readIntegrityAuditOverview(tenantId: string): Promise<IntegrityAuditOverview>;
181
+ startIntegrityRun(tenantId: string, mode: IntegrityRunMode, basisRunUid: string | null, accessToken: string): Promise<IntegrityCommandReply>;
182
+ cancelIntegrityRun(tenantId: string, runUid: string, accessToken: string): Promise<IntegrityCommandReply>;
148
183
  getUnresolvedEntities(tenantId: string): Promise<UnresolvedEntity[]>;
149
184
  resolveEntity(tenantId: string, entityId: string, action: "merge" | "promote"): Promise<void>;
150
185
  getQdrantCollections(tenantId: string): Promise<QdrantStorageOverview>;
151
186
  getCircuitBreakerStatus(): Record<string, CircuitBreakerState>;
152
- getPipelineConfig(tenantId: string, snapshot: ConsoleConfigSnapshot): Promise<PipelineConfig>;
153
- getStageMetrics(): StageMetrics;
154
187
  ingestDocument(tenantId: string, payload: DocumentIngestPayload, actor: string, accessToken?: string): Promise<DocumentIngestResult>;
155
188
  inspectFileUri?(tenantId: string, fileUri: string, accessToken?: string): Promise<FileInspectionResult>;
156
189
  getRecentIngestItems(tenantId: string): Promise<RecentIngestItem[]>;
@@ -178,8 +211,8 @@ interface HealthProbeOptions {
178
211
  redisPort?: number;
179
212
  redisTls?: boolean;
180
213
  sqlServerExecute?: () => Promise<{
181
- version: string;
182
- db_name: string;
214
+ version: string | null;
215
+ db_name: string | null;
183
216
  }>;
184
217
  sqlServerHost?: string;
185
218
  sqlServerPort?: number;
@@ -188,43 +221,63 @@ interface HealthProbeOptions {
188
221
  timeoutMs?: number;
189
222
  tenantId?: string;
190
223
  }
224
+ interface StorageAdminOperator {
225
+ readonly email: string;
226
+ readonly accessToken: string | null;
227
+ }
191
228
  interface CreateStorageAdminAppOptions {
192
229
  store: StorageAdminStore;
193
230
  healthProbeOptions?: HealthProbeOptions;
194
231
  resourceKey?: string;
195
- basePath?: string;
196
- requireUser?: (request: Request) => Promise<unknown>;
197
- requirePermission?: (request: Request, query: {
232
+ requireUser: (request: Request) => Promise<StorageAdminOperator | null>;
233
+ requirePermission: (request: Request, query: {
198
234
  resourceKey: string;
199
235
  action: "read" | "update";
200
236
  }) => Promise<unknown>;
201
- resolveTenantId?: (request: Request) => Promise<string> | string;
237
+ resolveTenantId: (request: Request) => Promise<string> | string;
238
+ canReadIntegrityFindings: (request: Request) => Promise<boolean>;
239
+ canUpdateKnowledge: (request: Request) => Promise<boolean>;
202
240
  authorizeIngest: (request: Request, payload: DocumentIngestPayload) => Promise<string | null>;
203
241
  }
242
+ interface StorageAdminActionData {
243
+ success?: boolean;
244
+ error?: string;
245
+ inspection?: FileInspectionResult;
246
+ result?: unknown;
247
+ requeued?: number;
248
+ skipped?: readonly RetryAllSkippedItem[];
249
+ failure?: IntegrityCommandFailure;
250
+ runUid?: string;
251
+ }
204
252
  interface StorageAdminFetcher {
205
253
  state: "idle" | "submitting" | "loading";
206
254
  formData?: FormData | null;
207
- data?: {
208
- error?: string;
209
- inspection?: FileInspectionResult;
210
- result?: unknown;
211
- } | null;
255
+ data?: StorageAdminActionData | null;
212
256
  submit: ReturnType<typeof useFetcher>["submit"];
213
257
  }
258
+ type AwaitableSubmit = (...args: Parameters<StorageAdminFetcher["submit"]>) => Promise<void>;
214
259
  interface StorageAdminConsoleViewProps {
215
260
  data?: StorageAdminLoaderData;
216
261
  fetcher?: StorageAdminFetcher;
262
+ integrityFetcher?: StorageAdminFetcher;
217
263
  renderHeader?: (props: {
218
264
  title: string;
219
265
  tenantId: string;
220
266
  }) => ReactNode;
221
- onTraverseGraph?: GraphTraversalRunner;
267
+ onSearch: MetadataSearchRunner;
268
+ loadIntegrityOverview: IntegrityOverviewLoader;
269
+ loadIntegrityFindings: IntegrityFindingsLoader;
270
+ policyConflicts: PolicyConflictHost;
271
+ documentAuthority: DocumentAuthorityHost;
272
+ onLoadDocumentRuns?: DocumentRunsLoader;
273
+ onCompareVariants?: ModelComparisonRunner;
274
+ graphTraversal?: GraphTraversalHost;
222
275
  onBrowseGraphNodes?: (label: string, pageIndex: number) => Promise<GraphNodeIndexOutcome>;
223
276
  onSimulateGovernance?: SimulationRunner;
224
277
  onRefreshIngestQueue?: IngestQueueRefresher;
225
278
  }
226
279
  type IngestQueueRefresher = () => Promise<readonly RecentIngestItem[]>;
227
- declare function StorageAdminConsoleView(props?: StorageAdminConsoleViewProps): react.JSX.Element;
280
+ declare function StorageAdminConsoleView(props: StorageAdminConsoleViewProps): react.JSX.Element;
228
281
  declare function createStorageAdminApp(options: CreateStorageAdminAppOptions): {
229
282
  loader: (args: {
230
283
  request: Request;
@@ -256,4 +309,4 @@ declare function createStorageAdminServer(options: CreateStorageAdminAppOptions)
256
309
  request: Request;
257
310
  }) => Promise<Response>;
258
311
  };
259
- export { type ConsoleConfigSnapshot, type CreateStorageAdminAppOptions, type DocumentIngestResult, type EnrichmentStrategyUpdate, type GraphReadOutcome, type GraphReader, type HealthProbeOptions, type IngestQueueRefresher, type PolicyWithoutDestination, type PromptTemplateUpdate, type ServiceHealthStatus, type StageMetrics, StorageAdminConsoleView, type StorageAdminConsoleViewProps, type StorageAdminFetcher, type StorageAdminLoaderData, type StorageAdminStore, type SystemInfrastructureHealth, type SystemParameter, type UnresolvedEntity, checkAllSystemHealth, checkBackendApiHealth, checkNeo4jHealth, checkQdrantHealth, checkRedisHealth, checkSqlServerHealth, createStorageAdminApp, createStorageAdminServer };
312
+ export { type AwaitableSubmit, type ConsoleConfigSnapshot, type CreateStorageAdminAppOptions, type DocumentIngestResult, type DocumentRunsLoader, type EnrichmentStrategyUpdate, type GraphReadOutcome, type GraphReader, type HealthProbeOptions, type IngestQueueRefresher, type IntegrityOverviewLoader, type MetadataSearchRunner, type ModelComparisonRunner, type PolicyWithoutDestination, type PromptTemplateUpdate, type RetryAllFailedResult, type RetryAllSkippedItem, type ServiceHealthStatus, type StorageAdminActionData, StorageAdminConsoleView, type StorageAdminConsoleViewProps, type StorageAdminFetcher, type StorageAdminLoaderData, type StorageAdminOperator, type StorageAdminStore, type StrategyVariant, type SystemInfrastructureHealth, type SystemParameter, type SystemParameterDataType, type UnresolvedEntity, checkAllSystemHealth, checkBackendApiHealth, checkNeo4jHealth, checkQdrantHealth, checkRedisHealth, checkSqlServerHealth, createStorageAdminApp, createStorageAdminServer };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,34 @@
1
- import { EnrichmentStageKey } from "@aiquants/enrichment-core";
2
- export { SearchMode } from "@aiquants/enrichment-core";
3
- import { EnrichmentStrategyRow, FailedSyncItem, QdrantStorageOverview, CircuitBreakerState, PipelineConfig, DocumentIngestPayload, FileInspectionResult, RecentIngestItem, OntologyStatusData } from "@aiquants/enrichment-react";
4
- export { DocumentIngestLabel, DocumentIngestPayload, EnrichmentStrategyRow, FailedSyncItem, FileInspectionResult, FusionStrategy, MetadataSearchHit, MetadataSearchParams, MetadataSearchResult, OntologyStatusData, PipelineConfig, QdrantCollectionInfo, QdrantStorageOverview, RecentIngestItem, SearchHitGraphRelation, SearchHitScoreBreakdown, StrategyProvenance } from "@aiquants/enrichment-react";
5
- import { ConfidentialityPolicyRow, TranscriptionTermRow, TranscriptionReferenceRow, PromptTemplateItem, ClassificationRuleItem, GraphSchemaStats, TriStoreAuditData, TriStoreReconcileResult, GraphTraversalRunner, GraphNodeIndexOutcome, SimulationRunner } from "@aiquants/governance-react";
6
- export { ClassificationRuleItem as ClassificationRule, GraphNodeIndexOutcome, GraphNodeIndexPage, GraphNodeSummary, GraphSchemaStats, GraphTraversalInput, GraphTraversalOutcome, GraphTraversalRunner, PromptTemplateItem, SimulationOutcome, SimulationRunInput, SimulationRunResult, SimulationRunner, SimulationScoreSet, SimulationVerdictFlip, TriStoreAuditData, TriStoreReconcileResult } from "@aiquants/governance-react";
1
+ import { ResourceOutcome } from "@aiquants/console-ui/core";
2
+ export { CommandOutcome, ResourceOutcome } from "@aiquants/console-ui/core";
3
+ import { EnrichmentStageKey, PipelineStepMetric, PipelineRunSummary, IntegrityAuditOverview, IntegrityRunMode, IntegrityCommandReply, PipelineRunRecord, IntegrityCommandFailure } from "@aiquants/enrichment-core";
4
+ export { IntegrityAuditOverview, IntegrityCommandFailure, IntegrityCommandReply, IntegrityFindingPage, IntegrityFindingsQuery, IntegrityRunMode, PipelineRunRecord, PipelineRunSummary, PipelineStepMetric, PipelineStepRecord, SearchMode, StageProvenance } from "@aiquants/enrichment-core";
5
+ import { EnrichmentStrategyRow, FailedSyncItem, QdrantStorageOverview, CircuitBreakerState, DocumentIngestPayload, FileInspectionResult, RecentIngestItem, OntologyStatusData, MetadataSearchWorkbenchProps, ModelComparisonWorkbenchProps } from "@aiquants/enrichment-react";
6
+ export { ComparisonHit, ComparisonInput, ComparisonOutcome, ComparisonVariantResult, DocumentIngestLabel, DocumentIngestPayload, EnrichmentStrategyRow, FailedSyncItem, FileInspectionResult, FusionStrategy, MetadataSearchHit, MetadataSearchParams, MetadataSearchResult, OntologyStatusData, QdrantCollectionInfo, QdrantStorageOverview, RecentIngestItem, SearchHitGraphRelation, SearchHitScoreBreakdown, StrategyProvenance } from "@aiquants/enrichment-react";
7
+ import { ConfidentialityPolicyRow, TranscriptionTermRow, TranscriptionReferenceRow, PromptTemplateItem, ClassificationRuleItem, GraphSchemaStats, IntegrityFindingsLoader, PolicyConflictHost, DocumentAuthorityHost, GraphTraversalHost, GraphNodeIndexOutcome, SimulationRunner } from "@aiquants/governance-react";
8
+ export { ClassificationRuleItem as ClassificationRule, DocumentAuthorityHost, GraphNodeIndexOutcome, GraphNodeIndexPage, GraphNodeSummary, GraphRelationshipTypesOutcome, GraphRelationshipTypesReader, GraphSchemaStats, GraphTraversalHost, GraphTraversalInput, GraphTraversalOutcome, GraphTraversalRunner, IntegrityFindingsLoader, PolicyConflictHost, PromptTemplateItem, SimulationOutcome, SimulationRunInput, SimulationRunResult, SimulationRunner, SimulationScoreSet, SimulationVerdictFlip } from "@aiquants/governance-react";
7
9
  import * as react from "react";
8
10
  import { ReactNode } from "react";
9
11
  import { useFetcher } from "react-router";
12
+ export { AuthorityCandidatePage, AuthorityCandidateQuery, DocumentAuthorityCommand, DocumentAuthorityCommandRejection, DocumentAuthorityCommandResult, DocumentAuthorityPageQuery, DocumentAuthorityPageWithCategories, PolicyConflictDecision, PolicyConflictDecisionRejection, PolicyConflictDetail, PolicyConflictDetectionOutcome, PolicyConflictDetectionRequestRejection, PolicyConflictPage, PolicyConflictPageQuery, PolicyConflictSummary, ReplaceableAuthorityPage, ReplaceableAuthorityQuery } from "@aiquants/governance-core";
13
+ type IntegrityOverviewLoader = (signal: AbortSignal) => Promise<ResourceOutcome<IntegrityAuditOverview>>;
14
+ type MetadataSearchRunner = NonNullable<MetadataSearchWorkbenchProps["onSearch"]>;
15
+ type ModelComparisonRunner = ModelComparisonWorkbenchProps["onCompare"];
16
+ interface StrategyVariant {
17
+ readonly strategyId: number;
18
+ readonly variantKey: string;
19
+ readonly label: string;
20
+ readonly embeddingModel: string;
21
+ readonly domainKey: string;
22
+ }
23
+ type DocumentRunsLoader = (metadataId: number, signal: AbortSignal) => Promise<ResourceOutcome<readonly PipelineRunRecord[]>>;
24
+ interface RetryAllSkippedItem {
25
+ metadataId: number;
26
+ reason: string;
27
+ }
28
+ interface RetryAllFailedResult {
29
+ requeued: number;
30
+ skipped: readonly RetryAllSkippedItem[];
31
+ }
10
32
  interface DocumentIngestResult {
11
33
  metadataId: number;
12
34
  revision: number;
@@ -34,14 +56,23 @@ interface SystemInfrastructureHealth {
34
56
  allHealthy: boolean;
35
57
  checkedAt: string;
36
58
  }
37
- interface SystemParameter {
59
+ interface SystemParameterBase {
38
60
  key: string;
39
- value: string;
40
61
  category: string;
41
62
  description: string;
42
- data_type: "string" | "int" | "float" | "bool" | "json";
43
63
  is_secret: boolean;
44
64
  }
65
+ type SystemParameter = SystemParameterBase & ({
66
+ data_type: "bool";
67
+ value: boolean;
68
+ } | {
69
+ data_type: "int" | "float";
70
+ value: number;
71
+ } | {
72
+ data_type: "string" | "json";
73
+ value: string;
74
+ });
75
+ type SystemParameterDataType = SystemParameter["data_type"];
45
76
  interface PromptTemplateUpdate {
46
77
  templateText: string;
47
78
  modelName: string;
@@ -64,12 +95,6 @@ interface UnresolvedEntity {
64
95
  co_occurrences: number;
65
96
  suggested_action: "merge" | "promote";
66
97
  }
67
- type StageMetrics = Record<string, {
68
- latency_p50_ms: number;
69
- latency_p95_ms: number;
70
- throughput_rps: number;
71
- success_rate: number;
72
- }>;
73
98
  interface StorageAdminLoaderData {
74
99
  tenantId: string;
75
100
  featureFlags: Record<string, boolean>;
@@ -81,11 +106,16 @@ interface StorageAdminLoaderData {
81
106
  totalFiles: number;
82
107
  failedSyncItems: FailedSyncItem[];
83
108
  circuitBreakerStatus: Record<string, CircuitBreakerState>;
84
- pipelineConfig: PipelineConfig;
85
- stageMetrics: StageMetrics;
109
+ pipelineStepMetrics: readonly PipelineStepMetric[];
110
+ pipelineStepMetricWindow: number;
111
+ recentPipelineRuns: readonly PipelineRunSummary[];
112
+ displayTimeZone: string;
86
113
  graphSchema: GraphSchemaStats;
87
114
  enrichmentStrategies: EnrichmentStrategyRow[];
88
- triStoreAuditData: TriStoreAuditData;
115
+ strategyVariants: readonly StrategyVariant[];
116
+ integrityAudit: ResourceOutcome<IntegrityAuditOverview>;
117
+ canReadIntegrityFindings: boolean;
118
+ canUpdateKnowledge: boolean;
89
119
  unresolvedEntities: UnresolvedEntity[];
90
120
  qdrantCollections: QdrantStorageOverview;
91
121
  systemHealth: SystemInfrastructureHealth;
@@ -141,16 +171,19 @@ interface StorageAdminStore {
141
171
  }>;
142
172
  getFailedSyncItems(tenantId: string): Promise<FailedSyncItem[]>;
143
173
  retrySyncItem(tenantId: string, fileId: string, actor?: string, accessToken?: string): Promise<void>;
144
- retryAllFailedSyncItems(tenantId: string, actor?: string, accessToken?: string): Promise<void>;
174
+ retryAllFailedSyncItems(tenantId: string, actor?: string, accessToken?: string): Promise<RetryAllFailedResult>;
175
+ getPipelineStepMetrics(tenantId: string): Promise<readonly PipelineStepMetric[]>;
176
+ readonly pipelineStepMetricWindow: number;
177
+ getRecentPipelineRuns(tenantId: string): Promise<readonly PipelineRunSummary[]>;
178
+ getStrategyVariants(tenantId: string): Promise<readonly StrategyVariant[]>;
145
179
  getGraphSchema(tenantId: string): Promise<GraphSchemaStats>;
146
- getTriStoreAuditData(tenantId: string, snapshot: ConsoleConfigSnapshot): Promise<TriStoreAuditData>;
147
- reconcileTriStore(tenantId: string, accessToken?: string): Promise<TriStoreReconcileResult>;
180
+ readIntegrityAuditOverview(tenantId: string): Promise<IntegrityAuditOverview>;
181
+ startIntegrityRun(tenantId: string, mode: IntegrityRunMode, basisRunUid: string | null, accessToken: string): Promise<IntegrityCommandReply>;
182
+ cancelIntegrityRun(tenantId: string, runUid: string, accessToken: string): Promise<IntegrityCommandReply>;
148
183
  getUnresolvedEntities(tenantId: string): Promise<UnresolvedEntity[]>;
149
184
  resolveEntity(tenantId: string, entityId: string, action: "merge" | "promote"): Promise<void>;
150
185
  getQdrantCollections(tenantId: string): Promise<QdrantStorageOverview>;
151
186
  getCircuitBreakerStatus(): Record<string, CircuitBreakerState>;
152
- getPipelineConfig(tenantId: string, snapshot: ConsoleConfigSnapshot): Promise<PipelineConfig>;
153
- getStageMetrics(): StageMetrics;
154
187
  ingestDocument(tenantId: string, payload: DocumentIngestPayload, actor: string, accessToken?: string): Promise<DocumentIngestResult>;
155
188
  inspectFileUri?(tenantId: string, fileUri: string, accessToken?: string): Promise<FileInspectionResult>;
156
189
  getRecentIngestItems(tenantId: string): Promise<RecentIngestItem[]>;
@@ -178,8 +211,8 @@ interface HealthProbeOptions {
178
211
  redisPort?: number;
179
212
  redisTls?: boolean;
180
213
  sqlServerExecute?: () => Promise<{
181
- version: string;
182
- db_name: string;
214
+ version: string | null;
215
+ db_name: string | null;
183
216
  }>;
184
217
  sqlServerHost?: string;
185
218
  sqlServerPort?: number;
@@ -188,43 +221,63 @@ interface HealthProbeOptions {
188
221
  timeoutMs?: number;
189
222
  tenantId?: string;
190
223
  }
224
+ interface StorageAdminOperator {
225
+ readonly email: string;
226
+ readonly accessToken: string | null;
227
+ }
191
228
  interface CreateStorageAdminAppOptions {
192
229
  store: StorageAdminStore;
193
230
  healthProbeOptions?: HealthProbeOptions;
194
231
  resourceKey?: string;
195
- basePath?: string;
196
- requireUser?: (request: Request) => Promise<unknown>;
197
- requirePermission?: (request: Request, query: {
232
+ requireUser: (request: Request) => Promise<StorageAdminOperator | null>;
233
+ requirePermission: (request: Request, query: {
198
234
  resourceKey: string;
199
235
  action: "read" | "update";
200
236
  }) => Promise<unknown>;
201
- resolveTenantId?: (request: Request) => Promise<string> | string;
237
+ resolveTenantId: (request: Request) => Promise<string> | string;
238
+ canReadIntegrityFindings: (request: Request) => Promise<boolean>;
239
+ canUpdateKnowledge: (request: Request) => Promise<boolean>;
202
240
  authorizeIngest: (request: Request, payload: DocumentIngestPayload) => Promise<string | null>;
203
241
  }
242
+ interface StorageAdminActionData {
243
+ success?: boolean;
244
+ error?: string;
245
+ inspection?: FileInspectionResult;
246
+ result?: unknown;
247
+ requeued?: number;
248
+ skipped?: readonly RetryAllSkippedItem[];
249
+ failure?: IntegrityCommandFailure;
250
+ runUid?: string;
251
+ }
204
252
  interface StorageAdminFetcher {
205
253
  state: "idle" | "submitting" | "loading";
206
254
  formData?: FormData | null;
207
- data?: {
208
- error?: string;
209
- inspection?: FileInspectionResult;
210
- result?: unknown;
211
- } | null;
255
+ data?: StorageAdminActionData | null;
212
256
  submit: ReturnType<typeof useFetcher>["submit"];
213
257
  }
258
+ type AwaitableSubmit = (...args: Parameters<StorageAdminFetcher["submit"]>) => Promise<void>;
214
259
  interface StorageAdminConsoleViewProps {
215
260
  data?: StorageAdminLoaderData;
216
261
  fetcher?: StorageAdminFetcher;
262
+ integrityFetcher?: StorageAdminFetcher;
217
263
  renderHeader?: (props: {
218
264
  title: string;
219
265
  tenantId: string;
220
266
  }) => ReactNode;
221
- onTraverseGraph?: GraphTraversalRunner;
267
+ onSearch: MetadataSearchRunner;
268
+ loadIntegrityOverview: IntegrityOverviewLoader;
269
+ loadIntegrityFindings: IntegrityFindingsLoader;
270
+ policyConflicts: PolicyConflictHost;
271
+ documentAuthority: DocumentAuthorityHost;
272
+ onLoadDocumentRuns?: DocumentRunsLoader;
273
+ onCompareVariants?: ModelComparisonRunner;
274
+ graphTraversal?: GraphTraversalHost;
222
275
  onBrowseGraphNodes?: (label: string, pageIndex: number) => Promise<GraphNodeIndexOutcome>;
223
276
  onSimulateGovernance?: SimulationRunner;
224
277
  onRefreshIngestQueue?: IngestQueueRefresher;
225
278
  }
226
279
  type IngestQueueRefresher = () => Promise<readonly RecentIngestItem[]>;
227
- declare function StorageAdminConsoleView(props?: StorageAdminConsoleViewProps): react.JSX.Element;
280
+ declare function StorageAdminConsoleView(props: StorageAdminConsoleViewProps): react.JSX.Element;
228
281
  declare function createStorageAdminApp(options: CreateStorageAdminAppOptions): {
229
282
  loader: (args: {
230
283
  request: Request;
@@ -256,4 +309,4 @@ declare function createStorageAdminServer(options: CreateStorageAdminAppOptions)
256
309
  request: Request;
257
310
  }) => Promise<Response>;
258
311
  };
259
- export { type ConsoleConfigSnapshot, type CreateStorageAdminAppOptions, type DocumentIngestResult, type EnrichmentStrategyUpdate, type GraphReadOutcome, type GraphReader, type HealthProbeOptions, type IngestQueueRefresher, type PolicyWithoutDestination, type PromptTemplateUpdate, type ServiceHealthStatus, type StageMetrics, StorageAdminConsoleView, type StorageAdminConsoleViewProps, type StorageAdminFetcher, type StorageAdminLoaderData, type StorageAdminStore, type SystemInfrastructureHealth, type SystemParameter, type UnresolvedEntity, checkAllSystemHealth, checkBackendApiHealth, checkNeo4jHealth, checkQdrantHealth, checkRedisHealth, checkSqlServerHealth, createStorageAdminApp, createStorageAdminServer };
312
+ export { type AwaitableSubmit, type ConsoleConfigSnapshot, type CreateStorageAdminAppOptions, type DocumentIngestResult, type DocumentRunsLoader, type EnrichmentStrategyUpdate, type GraphReadOutcome, type GraphReader, type HealthProbeOptions, type IngestQueueRefresher, type IntegrityOverviewLoader, type MetadataSearchRunner, type ModelComparisonRunner, type PolicyWithoutDestination, type PromptTemplateUpdate, type RetryAllFailedResult, type RetryAllSkippedItem, type ServiceHealthStatus, type StorageAdminActionData, StorageAdminConsoleView, type StorageAdminConsoleViewProps, type StorageAdminFetcher, type StorageAdminLoaderData, type StorageAdminOperator, type StorageAdminStore, type StrategyVariant, type SystemInfrastructureHealth, type SystemParameter, type SystemParameterDataType, type UnresolvedEntity, checkAllSystemHealth, checkBackendApiHealth, checkNeo4jHealth, checkQdrantHealth, checkRedisHealth, checkSqlServerHealth, createStorageAdminApp, createStorageAdminServer };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{EnrichmentSyncStatusSchema as ie,GRAPH_INDEX_LIMITS as ae}from"@aiquants/enrichment-core";import{DocumentIngestConsole as oe,EnrichmentStrategyBoard as le,InfrastructureHealthMonitor as ce,MetadataSearchWorkbench as ue,OntologyStatusCard as de,QdrantStorageCard as pe,RAGPipelineGraphViewer as me,SyncStatusMonitor as ge}from"@aiquants/enrichment-react";import{ClassificationRuleEditor as fe,ConfidentialityPolicyBoard as ye,FeatureFlagBoard as Se,GovernanceDryRunConsole as be,KnowledgeGraphExplorer as he,PromptTemplateConsole as ve,SystemParameterTable as Re,TranscriptionAdaptationBoard as Ie,TriStoreIntegrityAudit as we}from"@aiquants/governance-react";import{useCallback as Te,useEffect as Pe,useRef as K,useState as L}from"react";import{useFetcher as _e,useLoaderData as Ae,useSearchParams as Ee}from"react-router";import{jsx as p,jsxs as v}from"react/jsx-runtime";var Q="tab",x=[{key:"search",label:"\u30E1\u30BF\u30C7\u30FC\u30BF\u691C\u7D22\u30EF\u30FC\u30AF\u30D9\u30F3\u30C1"},{key:"ingest",label:"\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u53D6\u308A\u8FBC\u307F & \u30E1\u30BF\u751F\u6210"},{key:"rag-pipeline",label:"RAG \u5B9F\u884C\u57FA\u76E4 & \u63A5\u7D9A\u72B6\u614B"},{key:"knowledge-graph",label:"\u30CA\u30EC\u30C3\u30B8\u30B0\u30E9\u30D5\u63A2\u7D22"},{key:"parameters",label:"\u30E2\u30C7\u30EB & \u30D1\u30E9\u30E1\u30FC\u30BF\u8A2D\u5B9A"},{key:"prompts",label:"\u30D7\u30ED\u30F3\u30D7\u30C8 & \u30C9\u30E9\u30A4\u30E9\u30F3"},{key:"data-retention",label:"\u30C7\u30FC\u30BF\u4FDD\u6301 & \u6574\u5408\u6027\u76E3\u67FB"}];function Ne(t){return t!==null&&x.some(e=>e.key===t)}var xe={state:"idle",formData:null,data:null,submit:()=>Promise.resolve()};function V({data:t,fetcher:e,renderHeader:a,onTraverseGraph:i,onBrowseGraphNodes:o,onSimulateGovernance:n,onRefreshIngestQueue:s}){let[l,d]=L(null),[m,f]=L(null),[y,b]=L(!1),u=Te((r,S)=>{o!==void 0&&(b(!0),o(r,S).then(h=>{b(!1),f(h.ok?null:h.reason),h.ok&&d(h.page)}))},[o]),[N,_]=Ee(),w=N.get(Q),g=Ne(w)?w:x[0].key,A=r=>{_(S=>{let h=new URLSearchParams(S);return h.set(Q,r),h},{replace:!1,preventScrollReset:!0})},E=ke(t.recentIngestItems,s,g==="ingest"),c=E===t.recentIngestItems?t:{...t,recentIngestItems:E===void 0?void 0:[...E]},I=K({}),R=(r,S)=>{let h=x.length-1,T;if(r.key==="ArrowRight"||r.key==="ArrowDown")T=S===h?0:S+1;else if(r.key==="ArrowLeft"||r.key==="ArrowUp")T=S===0?h:S-1;else if(r.key==="Home")T=0;else if(r.key==="End")T=h;else return;r.preventDefault();let j=x[T].key;A(j),I.current[j]?.focus()},C={...c.featureFlags};if(e.formData&&e.formData.get("intent")==="toggle_flag"){let r=String(e.formData.get("flagKey")??""),S=String(e.formData.get("enabled")??"")==="true";r&&(C[r]=S)}let k=e.data?.error,U=e.data&&"inspection"in e.data?e.data.inspection:void 0,F=e.state!=="idle"&&e.formData?.get("intent")==="inspect_uri",H=e.state!=="idle"&&e.formData?.get("intent")==="ingest_document";return v("div",{className:"container mx-auto space-y-6 p-6 font-sans text-slate-900","data-testid":"storage-admin-console",children:[k&&p("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4 font-medium text-red-700 text-sm shadow-sm",role:"alert","data-testid":"storage-admin-error-alert",children:k}),a?a({title:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406",tenantId:c.tenantId}):v("header",{className:"flex flex-col justify-between gap-2 border-slate-200 border-b pb-4 md:flex-row md:items-center",children:[v("div",{children:[p("h1",{className:"font-bold text-2xl tracking-tight",children:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406"}),v("p",{className:"mt-1 text-slate-500 text-sm",children:["\u30C6\u30CA\u30F3\u30C8: ",p("code",{className:"font-semibold text-slate-800",children:c.tenantId})," | \u5168\u30B7\u30B9\u30C6\u30E0\u72B6\u614B\u30FB\u30D1\u30E9\u30E1\u30FC\u30BF\u5236\u5FA1\u30FB\u6574\u5408\u6027\u76E3\u67FB"]})]}),p("div",{className:"flex items-center gap-2",children:v("button",{type:"button","data-testid":"header-health-status-button",onClick:()=>A("rag-pipeline"),className:"inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 font-medium text-slate-700 text-xs transition-colors hover:bg-slate-100",children:[p("span",{className:`h-2 w-2 rounded-full ${c.systemHealth.allHealthy?"bg-emerald-500":"bg-amber-500"}`}),v("span",{children:["\u5468\u8FBA\u6A5F\u80FD: ",c.systemHealth.allHealthy?"\u5168\u30B5\u30FC\u30D3\u30B9\u6B63\u5E38":"\u63A5\u7D9A\u8981\u78BA\u8A8D"]})]})})]}),v("div",{className:"w-full space-y-6",children:[p("div",{className:"grid w-full grid-cols-2 gap-1 rounded-xl bg-slate-100 p-1 md:grid-cols-8",role:"tablist","aria-label":"Storage Administration Console Tabs",children:x.map((r,S)=>{let h=g===r.key;return p("button",{id:`tab-${r.key}`,type:"button",role:"tab",ref:T=>{I.current[r.key]=T},"aria-selected":h,"aria-controls":`panel-${r.key}`,tabIndex:h?0:-1,"data-testid":`tab-trigger-${r.key}`,onKeyDown:T=>R(T,S),onClick:()=>A(r.key),className:`rounded-lg px-3 py-2.5 text-center font-medium text-sm transition-all ${h?"bg-white text-slate-900 shadow-sm":"text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"}`,children:r.label},r.key)})}),g==="search"&&p("div",{role:"tabpanel",id:"panel-search","aria-labelledby":"tab-search",className:"space-y-6","data-testid":"tab-content-search",children:p(ue,{tenantId:c.tenantId,circuitBreakerStatus:c.circuitBreakerStatus})}),g==="ingest"&&p("div",{role:"tabpanel",id:"panel-ingest","aria-labelledby":"tab-ingest",className:"space-y-6","data-testid":"tab-content-ingest",children:p(oe,{tenantId:c.tenantId,policies:c.confidentialityPolicies,recentItems:c.recentIngestItems,inspectionResult:U,isInspecting:F,isSubmitting:H,onInspectUri:r=>{e.submit({intent:"inspect_uri",fileUri:r},{method:"post"})},onIngestDocument:r=>{e.submit({intent:"ingest_document",payload:JSON.stringify(r)},{method:"post"})},onRetryItem:r=>{e.submit({intent:"retry_job",fileId:String(r)},{method:"post"})}})}),g==="rag-pipeline"&&v("div",{role:"tabpanel",id:"panel-rag-pipeline","aria-labelledby":"tab-rag-pipeline",className:"space-y-6","data-testid":"tab-content-rag-pipeline",children:[p(me,{pipelineConfig:c.pipelineConfig,circuitBreakerStatus:c.circuitBreakerStatus,stageMetrics:c.stageMetrics}),p(le,{strategies:c.enrichmentStrategies,featureFlags:c.featureFlags,isUpdating:e.state!=="idle",onToggleStage:(r,S,h)=>e.submit({intent:"update_enrichment_strategy",strategyId:String(r.id),domainId:String(r.domainId),stage:S,enabled:String(h)},{method:"post"})}),p(ce,{health:c.systemHealth,isRefreshing:e.state!=="idle",onRefresh:()=>e.submit({intent:"refresh_health"},{method:"post"})})]}),g==="knowledge-graph"&&v("div",{role:"tabpanel",id:"panel-knowledge-graph","aria-labelledby":"tab-knowledge-graph",className:"space-y-6","data-testid":"tab-content-knowledge-graph",children:[p(de,{tenantId:c.tenantId,ontologyStatus:c.ontologyStatus}),p(he,{topologyMaxLabels:ae.topologyLabels.default,schema:c.graphSchema,tenantId:c.tenantId,unresolvedEntities:c.unresolvedEntities,onTraverse:i,onBrowseLabel:o===void 0?void 0:u,nodeIndexPage:l,nodeIndexFailure:m,isNodeIndexLoading:y,onResolveEntity:(r,S)=>{e.submit({intent:"resolve_entity",entityId:r,action:S},{method:"post"})}})]}),g==="parameters"&&v("div",{role:"tabpanel",id:"panel-parameters","aria-labelledby":"tab-parameters",className:"space-y-6","data-testid":"tab-content-parameters",children:[v("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[p(Se,{flags:C,isUpdating:e.state!=="idle",onToggleFlag:(r,S)=>{e.submit({intent:"toggle_flag",flagKey:r,enabled:String(S)},{method:"post"})}}),p(fe,{rules:c.classificationRules,consultedBy:c.classificationRuleConsumer,onReorderRules:r=>{e.submit({intent:"reorder_rules",orderedRuleIds:JSON.stringify(r)},{method:"post"})}})]}),c.policiesMissingDestination.length>0&&v("div",{"data-testid":"policies-missing-destination",role:"alert",style:{padding:"10px 12px",borderRadius:"6px",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"12px"},children:[p("strong",{children:"\u6B21\u306E\u533A\u5206\u30FB\u6A5F\u80FD\u306F\u5B9F\u884C\u6642\u306B\u5931\u6557\u3057\u307E\u3059\u3002"})," \u53C2\u7167\u3059\u308B\u30D7\u30ED\u30F3\u30D7\u30C8\u884C\u306B\u5B9B\u5148\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",p("ul",{style:{margin:"6px 0 0",paddingInlineStart:"18px"},children:c.policiesMissingDestination.map(r=>v("li",{"data-testid":`missing-destination-${r.confidentialityLevel}-${r.capability}`,children:[r.confidentialityLevel," / ",r.capability," \u2192 ",r.promptKey," (",r.modelProvider,") \u306E ",p("code",{children:"extra_params.base_url"})]},`${r.confidentialityLevel}:${r.capability}`))}),p("span",{style:{display:"block",marginTop:"4px",fontSize:"11px"},children:"\u5B9B\u5148\u3092\u8A2D\u5B9A\u3057\u3066\u3082\u3001\u305D\u306E\u30DB\u30B9\u30C8\u304C\u914D\u5099\u5185\u3068\u3057\u3066\u767B\u9332\u3055\u308C\u3066\u3044\u306A\u3051\u308C\u3070\u62D2\u5426\u3055\u308C\u307E\u3059\u3002"})]}),p(ye,{policies:c.confidentialityPolicies,promptKeys:c.promptTemplates.map(r=>r.template_key),isUpdating:e.state!=="idle",onChangePolicy:r=>{e.submit({intent:"update_confidentiality_policy",confidentialityLevel:r.confidentialityLevel,capability:r.capability,isEnabled:String(r.isEnabled),allowCloudProvider:String(r.allowCloudProvider),promptKey:r.promptKey??""},{method:"post"})}}),p(Ie,{vocabulary:c.transcriptionVocabulary,references:c.transcriptionReferences,unresolvedUris:c.unresolvedReferenceUris,isUpdating:e.state!=="idle",onSaveTerm:r=>{e.submit({intent:"save_transcription_term",id:r.id===null?"":String(r.id),term:r.term,reading:r.reading??"",boost:r.boost===null?"":String(r.boost),domainKey:r.domainKey??"",isActive:String(r.isActive)},{method:"post"})},onSaveReference:r=>{e.submit({intent:"save_transcription_reference",id:r.id===null?"":String(r.id),fileUri:r.fileUri,domainKey:r.domainKey??"",isActive:String(r.isActive)},{method:"post"})}}),p(Re,{parameters:c.systemParameters,onSaveParameter:(r,S)=>{e.submit({intent:"update_parameter",paramKey:r,paramValue:String(S)},{method:"post"})}})]}),g==="prompts"&&v("div",{role:"tabpanel",id:"panel-prompts","aria-labelledby":"tab-prompts",className:"space-y-6","data-testid":"tab-content-prompts",children:[p(ve,{templates:c.promptTemplates,isSaving:e.state!=="idle",onSaveTemplate:r=>{e.submit({intent:"update_prompt",templateKey:r.template_key,payload:JSON.stringify({templateText:r.template_text,modelName:r.model_name,temperature:r.temperature,maxOutputTokens:r.max_output_tokens,responseSchema:r.response_schema,endpointBaseUrl:r.endpoint_base_url??null})},{method:"post"})}}),p(be,{onSimulate:n})]}),g==="data-retention"&&v("div",{role:"tabpanel",id:"panel-data-retention","aria-labelledby":"tab-data-retention",className:"space-y-6","data-testid":"tab-content-data-retention",children:[p(we,{auditData:c.triStoreAuditData,onTriggerReconcile:()=>{e.submit({intent:"reconcile"},{method:"post"})}}),v("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[p(ge,{counts:c.syncCounts,totalFiles:c.totalFiles,failedItems:c.failedSyncItems,onRetryItem:r=>{e.submit({intent:"retry_job",fileId:String(r)},{method:"post"})},onRetryAll:()=>{e.submit({intent:"retry_all_failed"},{method:"post"})}}),p(pe,{collections:c.qdrantCollections.collections,probeFailure:c.qdrantCollections.probe_failure,health:{healthy:c.systemHealth.services.qdrant.status==="connected",latency_ms:c.systemHealth.services.qdrant.latencyMs}})]})]})]})]})}var Ce=new Set(ie.options.filter(t=>t!=="SYNCED"&&!t.startsWith("FAILED"))),$=2e3;function ke(t,e,a){let[i,o]=L(null),n=K(e);n.current=e;let s=K(t);s.current!==t&&(s.current=t,i!==null&&o(null));let l=i??t,d=l?.some(m=>Ce.has(m.syncStatus))===!0;return Pe(()=>{if(!(a&&d&&n.current))return;let m=!1,f,y=async()=>{let b=n.current;if(!(m||!b)){try{let u=await b();if(m)return;o(u)}catch{if(m)return}f=setTimeout(y,$)}};return f=setTimeout(y,$),()=>{m=!0,f!==void 0&&clearTimeout(f)}},[d,a]),l}function je(t){let e=Ae(),a=_e(),i=t.data??e,o=t.fetcher??a;return i?p(V,{data:i,fetcher:o,onRefreshIngestQueue:t.onRefreshIngestQueue,renderHeader:t.renderHeader,onTraverseGraph:t.onTraverseGraph,onBrowseGraphNodes:t.onBrowseGraphNodes,onSimulateGovernance:t.onSimulateGovernance}):p("div",{className:"p-8 text-center text-slate-500","data-testid":"storage-admin-loading",children:"\u30C7\u30FC\u30BF\u8AAD\u307F\u8FBC\u307F\u4E2D..."})}function J(t={}){return t.data?p(V,{data:t.data,fetcher:t.fetcher??xe,renderHeader:t.renderHeader,onTraverseGraph:t.onTraverseGraph,onBrowseGraphNodes:t.onBrowseGraphNodes,onSimulateGovernance:t.onSimulateGovernance}):p(je,{...t})}import{AuthzDeniedError as Z}from"@aiquants/authz-core";import{isEnrichmentStageKey as Me}from"@aiquants/enrichment-core";import{CLOUD_CAPABLE_CAPABILITIES as Ke,ConfidentialityLevelSchema as B,GovernedCapabilitySchema as qe}from"@aiquants/governance-core";function P(t){if(typeof globalThis<"u"&&"process"in globalThis)return globalThis.process?.env?.[t]}function O(t,e){let a=t?.trim();if(!a)throw new Error(`${e} is not configured; this probe will not guess an endpoint to send credentials to.`);return a}function z(t,e,a){let i=t??(e?.trim()?Number(e):Number.NaN);if(!Number.isInteger(i)||i<=0||i>65535)throw new Error(`${a} is not configured with a valid port; this probe will not guess one.`);return i}function Y(t,e){if(t!==void 0)return t;let a=e?.trim().toLowerCase();if(!(a===void 0||a===""))return a==="1"||a==="true"||a==="yes"||a==="on"}function W(t){let e=t.trim().split("://",1)[0]?.toLowerCase();if(e&&t.includes("://"))return e.endsWith("s")||e.includes("+s")}function Le(t){let a=(t.split("://").pop()??"").split("/",1)[0]??"",i=a.split(":").pop();if(!i||i===a)return;let o=Number(i);return Number.isInteger(o)&&o>0&&o<=65535?o:void 0}async function q(t,e){let a;try{return await Promise.race([t,new Promise((i,o)=>{a=setTimeout(()=>o(new Error(`Probe timed out after ${e}ms`)),e)})])}finally{a!==void 0&&clearTimeout(a)}}async function Oe(t){let e=t?.qdrantApiKey??P("QDRANT_API_KEY")??"",a=t?.timeoutMs??3e3,i=Date.now(),o="";try{o=O(t?.qdrantUrl??P("QDRANT_URL"),"QDRANT_URL");let n={};e&&(n["api-key"]=e);let[s,l]=await Promise.all([fetch(`${o}/`,{headers:n,signal:AbortSignal.timeout(a)}),fetch(`${o}/collections`,{headers:n,signal:AbortSignal.timeout(a)})]);if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText} (/collections)`);let d=await s.json(),m=Date.now()-i,y=(await l.json()).result?.collections?.length??0;return{serviceName:"Qdrant",category:"vector",status:"connected",version:d.version??"unknown",endpoint:o,latencyMs:m,details:{engine:d.title??"qdrant",collectionsCount:y,restPort:Le(o)??null,tls:W(o)??null}}}catch(n){let s=Date.now()-i,l=n instanceof Error?n.message:String(n);return{serviceName:"Qdrant",category:"vector",status:"error",version:null,endpoint:o,latencyMs:s,details:{},errorMessage:l}}}async function De(t){let e=t?.timeoutMs??3e3,a=Date.now(),i=t?.neo4jBoltUri??P("NEO4J_URI")??"";try{let o=t?.graphReader;if(!o)throw new Error("Graph reader not configured");let n=t?.tenantId,[s,l]=await Promise.all([q(o("CALL dbms.components() YIELD versions, edition RETURN versions[0] AS version, edition",{}),e),q(n?o("MATCH (n {tenantId: $tenantId}) RETURN count(n) AS node_count",{tenantId:n}):o("RETURN null AS node_count",{}),e)]);if(!s.ok)throw new Error(s.reason);if(!l.ok)throw new Error(l.reason);let[d,m]=s.rows[0]??[],f=l.rows[0]?.[0],y=Date.now()-a;return{serviceName:"Neo4j",category:"graph",status:"connected",version:typeof d=="string"?d:"unknown",endpoint:i,latencyMs:y,details:{edition:typeof m=="string"?m:"unknown",boltUri:i,nodeCount:typeof f=="number"?f:null,tls:W(i)??null}}}catch(o){let n=Date.now()-a,s=o instanceof Error?o.message:String(o);return{serviceName:"Neo4j",category:"graph",status:"error",version:null,endpoint:i,latencyMs:n,details:{},errorMessage:s}}}async function Ue(t){let e=Date.now(),a="",i=Y(t?.redisTls,P("REDIS_TLS")),o=Number.NaN;try{let n=t?.redisClient;if(!n)throw new Error("Redis client not configured");let s=O(t?.redisHost??P("REDIS_HOST"),"REDIS_HOST");o=z(t?.redisPort,P("REDIS_PORT"),"REDIS_PORT"),a=`${i===!1?"redis":"rediss"}://${s}:${o}`,await n.ping();let d=(await n.info("server")).match(/redis_version:([^\r\n]+)/),m=d?d[1]:"unknown",f=null;if(typeof n.dbSize=="function")try{f=await n.dbSize()}catch{f=null}let y=Date.now()-e;return{serviceName:"Redis",category:"cache",status:"connected",version:m,endpoint:a,latencyMs:y,details:{totalKeys:f,port:o,tls:i??null,database:0}}}catch(n){let s=Date.now()-e,l=n instanceof Error?n.message:String(n);return{serviceName:"Redis",category:"cache",status:"error",version:null,endpoint:a,latencyMs:s,details:{},errorMessage:l}}}async function Fe(t){let e=Date.now(),a="",i=Y(t?.sqlServerTls,P("SQL_SERVER_TLS")),o=Number.NaN;try{let n=t?.sqlServerExecute;if(!n)throw new Error("SQL Server executor not configured");let s=O(t?.sqlServerHost??P("SQL_SERVER_HOST"),"SQL_SERVER_HOST");o=z(t?.sqlServerPort,P("SQL_SERVER_PORT"),"SQL_SERVER_PORT"),a=`${s}:${o}`;let l=await n(),d=l.version??"unknown",m=typeof l.db_name=="string"&&l.db_name!==""?l.db_name:null,f=d.split(`
2
- `)[0]??d,y=f.match(/Microsoft SQL Server \d+ \([^)]+\)/),b=y?y[0].replace("Microsoft SQL Server ",""):f.substring(0,30),u=Date.now()-e;return{serviceName:"SQL Server",category:"database",status:"connected",version:b,endpoint:a,latencyMs:u,details:{database:m,port:o,tls:i??null,fullVersion:f}}}catch(n){let s=Date.now()-e,l=n instanceof Error?n.message:String(n);return{serviceName:"SQL Server",category:"database",status:"error",version:null,endpoint:a,latencyMs:s,details:{},errorMessage:l}}}async function He(t){let e=t?.timeoutMs??3e3,a=Date.now(),i="";try{i=O(t?.backendApiHost??P("BACKEND_API_HOST"),"BACKEND_API_HOST");let o=await fetch(`${i}/openapi.json`,{signal:AbortSignal.timeout(e)});if(!o.ok)throw new Error(`HTTP ${o.status}: ${o.statusText}`);let n=await o.json(),s=Object.keys(n.paths??{}).length,l=Date.now()-a;return{serviceName:"AI Quant API",category:"api",status:"connected",version:typeof n.info?.version=="string"&&n.info.version!==""?n.info.version:null,endpoint:i,latencyMs:l,details:{title:n.info?.title??"AI Quant API",endpointsCount:s}}}catch(o){let n=Date.now()-a,s=o instanceof Error?o.message:String(o);return{serviceName:"AI Quant API",category:"api",status:"error",version:null,endpoint:i,latencyMs:n,details:{},errorMessage:s}}}async function X(t){let[e,a,i,o,n]=await Promise.all([Oe(t),De(t),Ue(t),Fe(t),He(t)]),s=e.status==="connected"&&a.status==="connected"&&i.status==="connected"&&o.status==="connected"&&n.status==="connected";return{services:{qdrant:e,neo4j:a,redis:i,sqlServer:o,quantsApi:n},allHealthy:s,checkedAt:new Date().toISOString()}}function ee(t){let{store:e,healthProbeOptions:a,resourceKey:i="storage_admin",requireUser:o,requirePermission:n,resolveTenantId:s,authorizeIngest:l}=t;async function d(y){return s?await s(y):"default"}async function m(y){let{request:b}=y;if(o&&!await o(b))throw new Response("\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002",{status:401});if(n)try{await n(b,{resourceKey:i,action:"read"})}catch(M){throw M instanceof Z?new Response("\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",{status:403}):M}let u=await d(b),[N,_,w]=await Promise.all([e.getFeatureFlags(u),e.getSystemParameters(u),e.getSyncCounts(u)]),g={featureFlags:N,systemParameters:_,syncCounts:w},[A,E,c,I,R,C,k,U,F,H,r,S,h,T,j,te,ne]=await Promise.all([e.getConfidentialityPolicies(u),e.getTranscriptionVocabulary(u),e.getTranscriptionReferences(u),e.getUnresolvedReferenceUris(u),e.getPoliciesMissingDestination(u),e.getPromptTemplates(u),e.getClassificationRules(u),e.getFailedSyncItems(u),e.getGraphSchema(u),e.getTriStoreAuditData(u,g),e.getUnresolvedEntities(u),e.getQdrantCollections(u),X({...a,tenantId:u}),e.getPipelineConfig(u,g),e.getRecentIngestItems(u),e.getOntologyStatus(u,g),e.getEnrichmentStrategies(u)]),re=e.getCircuitBreakerStatus(),se=e.getStageMetrics();return{tenantId:u,featureFlags:g.featureFlags,confidentialityPolicies:A,transcriptionVocabulary:E,transcriptionReferences:c,unresolvedReferenceUris:I,policiesMissingDestination:R,systemParameters:g.systemParameters,promptTemplates:C,classificationRules:k,classificationRuleConsumer:e.classificationRuleConsumer??null,syncCounts:g.syncCounts.counts,totalFiles:g.syncCounts.total,failedSyncItems:U,circuitBreakerStatus:re,pipelineConfig:T,stageMetrics:se,graphSchema:F,enrichmentStrategies:ne,triStoreAuditData:H,unresolvedEntities:r,qdrantCollections:S,systemHealth:h,recentIngestItems:j,ontologyStatus:te}}async function f(y){let{request:b}=y,u=null,N;if(o){let I=await o(b);if(!I)return Response.json({error:"\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002"},{status:401});let R=I;u=R.email||R.id||R.name||null,typeof R.accessToken=="string"&&R.accessToken!=="mock-access-token"&&(N=R.accessToken)}if(!u)return Response.json({error:"\u64CD\u4F5C\u8005\u3092\u7279\u5B9A\u3067\u304D\u306A\u3044\u305F\u3081\u8A2D\u5B9A\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002"},{status:403});if(n)try{await n(b,{resourceKey:i,action:"update"})}catch(I){if(I instanceof Z)return Response.json({error:"\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002"},{status:403});throw I}let _=await d(b),w=await b.formData(),g=String(w.get("intent")??"");if(g==="refresh_health")return Response.json({success:!0,refreshed:!0});let A=await Be(e,_,g,w,u);if(A)return A;let E=await Qe(e,_,g,w,u,N);if(E)return E;if(g==="resolve_entity"){let I=String(w.get("entityId")??""),R=String(w.get("action")??"");return!I||R!=="merge"&&R!=="promote"?Response.json({error:"Valid entityId and action ('merge' | 'promote') are required"},{status:400}):(await e.resolveEntity(_,I,R),Response.json({success:!0,entityId:I,action:R}))}let c=await Ve(e,_,g,w,u,b,l,N);return c||Response.json({error:`Unknown intent: ${g}`},{status:400})}return{loader:m,action:f}}function G(t){let e=String(t??"").trim();return e===""?null:e}function D(t){let e=String(t??"").trim();if(e==="")return null;let a=Number(e);if(!(!Number.isSafeInteger(a)||a<=0))return a}function Ge(t){let e=String(t??"").trim();if(e==="")return null;let a=Number(e);if(!(!Number.isFinite(a)||a<=0))return a}async function Be(t,e,a,i,o){if(a==="update_enrichment_strategy"){let n=String(i.get("stage")??"");if(!Me(n))return Response.json({error:"stage must be a canonical enrichment stage key"},{status:400});let s=D(i.get("strategyId")),l=D(i.get("domainId"));if(s==null||l===void 0||l===null)return Response.json({error:"strategyId and domainId must be positive integers naming existing rows"},{status:400});let d=String(i.get("enabled")??"")==="true";try{await t.updateEnrichmentStrategy(e,{strategyId:s,domainId:l,stage:n,enabled:d},o)}catch(m){return Response.json({error:m instanceof Error?m.message:"\u53D6\u308A\u8FBC\u307F\u6226\u7565\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,strategyId:s,domainId:l,stage:n,enabled:d})}if(a==="toggle_flag"){let n=String(i.get("flagKey")??""),s=String(i.get("enabled")??"")==="true";return n?(await t.toggleFeatureFlag(e,n,s,o),Response.json({success:!0,flagKey:n,enabled:s})):Response.json({error:"flagKey is required"},{status:400})}if(a==="update_confidentiality_policy"){let n=String(i.get("confidentialityLevel")??""),s=String(i.get("capability")??"");if(!(B.safeParse(n).success&&qe.safeParse(s).success))return Response.json({error:"confidentialityLevel and capability must be canonical values"},{status:400});let l=String(i.get("allowCloudProvider")??"")==="true";if(l&&!Ke.includes(s))return Response.json({error:`${s} sends nothing outside the deployment, so it has no cloud permission to grant`},{status:400});let d=String(i.get("promptKey")??"");return await t.updateConfidentialityPolicy(e,{confidentialityLevel:n,capability:s,isEnabled:String(i.get("isEnabled")??"")==="true",allowCloudProvider:l,promptKey:d===""?null:d},o),Response.json({success:!0,confidentialityLevel:n,capability:s})}if(a==="save_transcription_term"){let n=String(i.get("term")??"").trim();if(!n)return Response.json({error:"term is required"},{status:400});let s=Ge(i.get("boost"));if(s===void 0)return Response.json({error:"boost must be a number greater than zero, or absent to let the service decide"},{status:400});let l=D(i.get("id"));return l===void 0?Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400}):(await t.saveTranscriptionTerm(e,{id:l,term:n,reading:G(i.get("reading")),boost:s,domainKey:G(i.get("domainKey")),isActive:String(i.get("isActive")??"true")==="true"},o),Response.json({success:!0,term:n}))}if(a==="save_transcription_reference"){let n=String(i.get("fileUri")??"").trim();if(!n)return Response.json({error:"fileUri is required"},{status:400});let s=D(i.get("id"));return s===void 0?Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400}):(await t.saveTranscriptionReference(e,{id:s,fileUri:n,domainKey:G(i.get("domainKey")),isActive:String(i.get("isActive")??"true")==="true"},o),Response.json({success:!0,fileUri:n}))}if(a==="update_parameter"){let n=String(i.get("paramKey")??""),s=String(i.get("paramValue")??"");return n?(await t.updateSystemParameter(e,n,s,o),Response.json({success:!0,paramKey:n,paramValue:s})):Response.json({error:"paramKey is required"},{status:400})}if(a==="update_prompt"){let n=String(i.get("templateKey")??""),s=String(i.get("payload")??"{}"),l={templateText:"",modelName:"",temperature:0,maxOutputTokens:0,endpointBaseUrl:null};try{l=JSON.parse(s)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}if(!n)return Response.json({error:"templateKey is required"},{status:400});try{return await t.updatePromptTemplate(e,n,l,o),Response.json({success:!0,templateKey:n})}catch(d){return Response.json({error:d instanceof Error?d.message:String(d)},{status:400})}}if(a==="reorder_rules"){let n=String(i.get("orderedRuleIds")??"[]"),s=[];try{s=JSON.parse(n)}catch{return Response.json({error:"Invalid orderedRuleIds JSON"},{status:400})}return await t.reorderClassificationRules(e,s,o),Response.json({success:!0,orderedRuleIds:s})}return null}async function Qe(t,e,a,i,o,n){if(a==="retry_job"){let s=String(i.get("fileId")??"");if(!s)return Response.json({error:"fileId is required"},{status:400});try{return await t.retrySyncItem(e,s,o,n),Response.json({success:!0,fileId:s})}catch(l){return Response.json({error:l instanceof Error?l.message:String(l)},{status:400})}}if(a==="retry_all_failed")try{return await t.retryAllFailedSyncItems(e,o,n),Response.json({success:!0,reconciled:!0})}catch(s){return Response.json({error:s instanceof Error?s.message:String(s)},{status:400})}if(a==="reconcile")try{let s=await t.reconcileTriStore(e,n);return Response.json({success:!0,reconciled:!0,result:s})}catch(s){return Response.json({error:s instanceof Error?s.message:String(s)},{status:400})}return null}function $e(t){if(typeof t!="object"||t===null)return"payload must be an object";let e=t;if(typeof e.fileUri!="string"||e.fileUri.trim()==="")return"payload.fileUri is required";if(!B.safeParse(e.confidentialityLevel).success)return`payload.confidentialityLevel must be one of ${B.options.join(", ")}`;let i=e.departmentId;return i!=null&&(typeof i!="number"||!Number.isInteger(i))?"payload.departmentId must be an integer or null":null}async function Ve(t,e,a,i,o,n,s,l){if(a==="ingest_document"){let d=String(i.get("payload")??"");if(!d)return Response.json({error:"payload is required"},{status:400});let m;try{m=JSON.parse(d)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}let f=$e(m);if(f)return Response.json({error:f},{status:400});let y=m,b=await s(n,y);if(b!==null)return Response.json({error:b},{status:403});try{let u=l?await t.ingestDocument(e,y,o,l):await t.ingestDocument(e,y,o);return Response.json({success:!0,result:u})}catch(u){return Response.json({error:u instanceof Error?u.message:String(u)},{status:400})}}if(a==="inspect_uri"){let d=String(i.get("fileUri")??"").trim();if(!d)return Response.json({error:"fileUri is required"},{status:400});if(!t.inspectFileUri)return Response.json({error:"inspectFileUri is not implemented"},{status:501});try{let m=l?await t.inspectFileUri(e,d,l):await t.inspectFileUri(e,d);return Response.json({success:!0,inspection:m})}catch(m){return Response.json({error:m instanceof Error?m.message:String(m)},{status:400})}}return null}function ct(t){let e=ee(t);return{loader:e.loader,action:e.action,View:J,server:e}}export{J as StorageAdminConsoleView,X as checkAllSystemHealth,He as checkBackendApiHealth,De as checkNeo4jHealth,Oe as checkQdrantHealth,Ue as checkRedisHealth,Fe as checkSqlServerHealth,ct as createStorageAdminApp,ee as createStorageAdminServer};
1
+ import{Card as Tt,ConsoleUiRoot as Et,ResourceFailed as _t,useFocusRescue as Ct}from"@aiquants/console-ui";import{DOCUMENT_KIND_LABELS as xt,EnrichmentSyncStatusSchema as Ot,GRAPH_INDEX_LIMITS as kt,IntegrityRunModeSchema as Lt,PIPELINE_STEPS as Ft}from"@aiquants/enrichment-core";import{DocumentIngestConsole as jt,EnrichmentStrategyBoard as Ut,FinishedInstant as Dt,InfrastructureHealthMonitor as Mt,MetadataSearchWorkbench as Ht,ModelComparisonWorkbench as $t,OntologyStatusCard as Kt,PIPELINE_RUN_STATUS_PRESENTATION as qt,PIPELINE_TRIGGER_LABELS as Vt,PipelineFlowViewer as Bt,PipelineRunInspector as Qt,pipelineRunPresentationKey as Gt,QdrantStorageCard as zt,RecordedInstant as Jt,SyncStatusMonitor as Wt}from"@aiquants/enrichment-react";import{ClassificationRuleEditor as Yt,ConfidentialityPolicyBoard as Zt,DocumentAuthorityRegistry as Xt,FeatureFlagBoard as en,GovernanceDryRunConsole as tn,integrityFailureNeedsOverviewReread as nn,KnowledgeGraphExplorer as rn,PolicyConflictQueue as sn,PolicyConflictSummaryCard as an,PromptTemplateConsole as on,SystemParameterTable as ln,TranscriptionAdaptationBoard as un,TriStoreIntegrityAudit as dn}from"@aiquants/governance-react";import{Fragment as cn,useCallback as W,useEffect as Ae,useMemo as se,useRef as k,useState as U}from"react";import{useFetcher as De,useLoaderData as pn,useRevalidator as mn,useSearchParams as gn}from"react-router";var ne="ja-JP";var mt=/[^\s\x1c-\x1f\x85\ufeff]/;function re(e){return mt.test(e)}function J(e,t){return new Promise(n=>n(e())).catch(n=>t(n instanceof Error?n.message:String(n)))}import{beginReload as gt,keepLastGood as yt}from"@aiquants/console-ui/core";import{isStrictlyEarlier as ft}from"@aiquants/enrichment-core";import{useCallback as be,useEffect as Fe,useRef as Re,useState as bt,useSyncExternalStore as St}from"react";var Rt=2e3,ht=1e4;function Se(e,t){return t.ok&&e.kind==="ready"&&ft(t.value.readAt,e.value.readAt)?e:yt(e,t)}var vt=new Set([401,403]);function It(e){return e.kind==="failed"||e.refreshFailure!==null&&vt.has(e.refreshFailure.status)?null:e.value.active}function je(e,t){let[n,r]=bt(()=>({loaded:e,overview:Se({kind:"loading"},e)}));n.loaded!==e&&r({loaded:e,overview:Se(n.overview,e)});let o=Re(t);o.current=t;let s=Re(null);Fe(()=>()=>s.current?.abort(),[]);let a=be((c,m)=>J(m,g=>({ok:!1,status:null,reason:g})).then(g=>{c.aborted||r(R=>({loaded:R.loaded,overview:Se(R.overview,g)}))}),[]),l=be(()=>{let c=new AbortController;s.current=c,r(m=>({loaded:m.loaded,overview:gt(m.overview,"reload")})),a(c.signal,()=>o.current(c.signal))},[a]),d=be(c=>a(c,()=>o.current(c)),[a]);return{overview:n.overview,reload:l,poll:d}}function wt(e){return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)}function At(){return document.visibilityState==="visible"}function Pt(){return!0}function Ue(e,t,n){let r=St(wt,At,Pt),o=t&&r,s=Re(o),a=e.kind==="ready",l=It(e),d=l===null?null:l.run.runUid,c=l===null?!1:l.isStale;Fe(()=>{let m=o&&!s.current;if(s.current=o,!o||d===null&&!(m&&a))return;let g=new AbortController,R=c?ht:Rt,f,h=async()=>{await n(g.signal),!g.signal.aborted&&d!==null&&(f=setTimeout(h,R))};return f=setTimeout(h,m?0:R),()=>{g.abort(),clearTimeout(f)}},[o,a,d,c,n])}var he={columns:2,className:"grid-cols-2",spanClassNames:{1:"col-span-1",2:"col-span-2"}},ve={columns:4,className:"@min-[41.5rem]:grid-cols-4",spanClassNames:{1:"@min-[41.5rem]:col-span-1",2:"@min-[41.5rem]:col-span-2",3:"@min-[41.5rem]:col-span-3",4:"@min-[41.5rem]:col-span-4"}},Ie={className:"@min-[82rem]:grid-flow-col @min-[82rem]:auto-cols-fr @min-[82rem]:grid-cols-none",lastTabClassName:"@min-[82rem]:col-auto"};function we(e,t){let n=t%e.columns,r=n===0?1:e.columns-n+1;return e.spanClassNames[r]}import{jsx as u,jsxs as S}from"react/jsx-runtime";var Me="tab",ie={key:"knowledge-authority",phrases:["\u6A29\u5A01\u53F0\u5E33 & \u898F\u7A0B\u885D\u7A81"]},D=[{key:"search",phrases:["\u30E1\u30BF\u30C7\u30FC\u30BF\u691C\u7D22","\u30EF\u30FC\u30AF\u30D9\u30F3\u30C1"]},{key:"ingest",phrases:["\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8","\u53D6\u308A\u8FBC\u307F & \u30E1\u30BF\u751F\u6210"]},{key:"pipeline",phrases:["\u30D1\u30A4\u30D7\u30E9\u30A4\u30F3 & \u63A5\u7D9A\u72B6\u614B"]},{key:"knowledge-graph",phrases:["\u30CA\u30EC\u30C3\u30B8\u30B0\u30E9\u30D5","\u63A2\u7D22"]},{key:"parameters",phrases:["\u30E2\u30C7\u30EB & \u30D1\u30E9\u30E1\u30FC\u30BF\u8A2D\u5B9A"]},{key:"prompts",phrases:["\u30D7\u30ED\u30F3\u30D7\u30C8 & \u30C9\u30E9\u30A4\u30E9\u30F3"]},ie,{key:"data-retention",phrases:["\u30C7\u30FC\u30BF\u4FDD\u6301 & \u6574\u5408\u6027\u76E3\u67FB"]}];function yn(e){return e.phrases.join("")}function fn(e){return e!==null&&D.some(t=>t.key===e)}var bn="Tri-Store \u30C7\u30FC\u30BF\u6574\u5408\u6027\u76E3\u67FB";function Sn(e){return`\u76E3\u67FB\u306E\u6982\u6CC1\u3092\u8AAD\u3081\u307E\u305B\u3093\u3067\u3057\u305F (${e})\u3002`}function Rn(e){return`\u51E6\u7406\u5C65\u6B74\u3092\u8AAD\u3081\u307E\u305B\u3093\u3067\u3057\u305F (${e})\u3002`}var He={state:"idle",formData:null,data:null,submit:()=>Promise.resolve()};function Ve({data:e,fetcher:t,integrityFetcher:n,renderHeader:r,graphTraversal:o,onBrowseGraphNodes:s,onSimulateGovernance:a,onRefreshIngestQueue:l,onSearch:d,onLoadDocumentRuns:c,onCompareVariants:m,loadIntegrityOverview:g,loadIntegrityFindings:R,policyConflicts:f,documentAuthority:h}){let[y,M]=U(null),[j,T]=U(null),[E,_]=U(!1),H=se(()=>{if(s!==void 0)return(i,b)=>{_(!0),J(()=>s(i,b),v=>({ok:!1,reason:v})).then(v=>{_(!1),T(v.ok?null:v.reason),v.ok&&M(v.page)})}},[s]),[$,K]=gn(),C=$.get(Me),I=fn(C)?C:D[0].key,x=i=>{K(b=>{let v=new URLSearchParams(b);return v.set(Me,i),v},{replace:!1,preventScrollReset:!0})},Z=vn(e.recentIngestItems,l,I==="ingest"),O=je(e.integrityAudit,g);Ue(O.overview,I==="data-retention",O.poll);let Q=k(null),le=Ct(()=>Q.current),[ue,de]=U(0),ce=W(()=>de(i=>i+1),[]),p=Z===null?e:{...e,recentIngestItems:[...Z]},q=k({}),pe=W(()=>q.current[I]??null,[I]),X=se(()=>In(e.enrichmentStrategies),[e.enrichmentStrategies]),me=se(()=>e.strategyVariants.map(wn),[e.strategyVariants]),A=Nn(c),V=A.open,ge=V===void 0?void 0:i=>V(i,null),ye=V===void 0?void 0:i=>V(i.metadataId,i.id),ee=(i,b)=>{let v=D.length-1,P;if(i.key==="ArrowRight"||i.key==="ArrowDown")P=b===v?0:b+1;else if(i.key==="ArrowLeft"||i.key==="ArrowUp")P=b===0?v:b-1;else if(i.key==="Home")P=0;else if(i.key==="End")P=v;else return;i.preventDefault();let te=D[P].key;x(te),q.current[te]?.focus()},_e={...p.featureFlags};if(t.formData&&t.formData.get("intent")==="toggle_flag"){let i=String(t.formData.get("flagKey")??""),b=String(t.formData.get("enabled")??"")==="true";i&&(_e[i]=b)}let tt=t.data&&"inspection"in t.data?t.data.inspection:void 0,G=t.state==="idle"?null:t.formData?.get("intent"),nt=G==="inspect_uri",rt=G==="ingest_document",st=G==="retry_job"||G==="retry_all_failed",it=G==="resolve_entity",Ce=n.state==="idle"?null:n.formData?.get("intent"),at=Ce==="start_integrity_run"?{kind:"starting",mode:Lt.parse(n.formData?.get("mode"))}:Ce==="cancel_integrity_run"?{kind:"cancelling"}:{kind:"idle"},ot=mn(),[lt,fe]=U(null),xe=I!=="data-retention";Ae(()=>{xe&&fe(null)},[xe]);let ut=i=>{let b=i?.failure;if(b===void 0){fe(null);return}fe(v=>({failure:b,occurrence:v===null?1:v.occurrence+1})),nn(b)&&ot.revalidate()},[dt,Oe]=U("console"),{settledIntent:ct,submitAndAwait:ke}=Ke(t,()=>Oe("console"));Ke(n,i=>{Oe("integrity"),ut(i)});let Le=(dt==="console"?t:n).data?.error,pt=()=>{x(ie.key),q.current[ie.key]?.focus()},z=ct==="retry_all_failed"&&t.data?.skipped!==void 0&&t.data.requeued!==void 0?{requeued:t.data.requeued,skipped:t.data.skipped}:null;return u(Et,{locale:"ja",formatLocale:ne,timeZone:p.displayTimeZone,testId:"storage-admin-console-ui",children:S("div",{className:"container mx-auto space-y-6 p-6 font-sans text-slate-900","data-testid":"storage-admin-console",children:[Le&&u("div",{className:"rounded-lg border border-red-200 border-solid bg-red-50 p-4 font-medium text-red-700 text-sm shadow-sm",role:"alert","data-testid":"storage-admin-error-alert",children:Le}),r?r({title:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406",tenantId:p.tenantId}):S("header",{className:"flex flex-col justify-between gap-2 border-slate-200 border-b border-solid pb-4 md:flex-row md:items-center",children:[S("div",{children:[u("h1",{className:"font-bold text-2xl tracking-tight",children:"\u30B9\u30C8\u30EC\u30FC\u30B8 AI \u30A8\u30F3\u30EA\u30C3\u30C1\u30E1\u30F3\u30C8 & \u30AC\u30D0\u30CA\u30F3\u30B9\u904B\u7528\u7BA1\u7406"}),S("p",{className:"mt-1 text-slate-500 text-sm",children:["\u30C6\u30CA\u30F3\u30C8: ",u("code",{className:"font-semibold text-slate-800",children:p.tenantId})," | \u5168\u30B7\u30B9\u30C6\u30E0\u72B6\u614B\u30FB\u30D1\u30E9\u30E1\u30FC\u30BF\u5236\u5FA1\u30FB\u6574\u5408\u6027\u76E3\u67FB"]})]}),u("div",{className:"flex items-center gap-2",children:S("button",{type:"button","data-testid":"header-health-status-button",onClick:()=>x("pipeline"),className:"inline-flex items-center gap-2 rounded-full border border-slate-200 border-solid bg-slate-50 px-3 py-1.5 font-medium text-slate-700 text-xs transition-colors hover:bg-slate-100",children:[u("span",{className:`h-2 w-2 rounded-full ${p.systemHealth.allHealthy?"bg-emerald-500":"bg-amber-500"}`}),S("span",{children:["\u5468\u8FBA\u6A5F\u80FD: ",p.systemHealth.allHealthy?"\u5168\u30B5\u30FC\u30D3\u30B9\u6B63\u5E38":"\u63A5\u7D9A\u8981\u78BA\u8A8D"]})]})})]}),S("div",{className:"w-full space-y-6",children:[u("div",{className:"@container w-full","data-testid":"storage-admin-tablist-frame",children:u("div",{className:`grid w-full ${he.className} ${ve.className} ${Ie.className} gap-1 rounded-xl bg-slate-100 p-1`,role:"tablist","aria-label":"\u904B\u7528\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u306E\u753B\u9762",children:D.map((i,b)=>{let v=I===i.key;return u("button",{id:`tab-${i.key}`,type:"button",role:"tab",ref:P=>{q.current[i.key]=P},"aria-selected":v,"aria-controls":`panel-${i.key}`,tabIndex:v?0:-1,"data-testid":`tab-trigger-${i.key}`,onKeyDown:P=>ee(P,b),onClick:()=>x(i.key),className:`wrap-anywhere break-keep rounded-lg px-3 py-2.5 text-center font-medium text-sm transition-all ${b===D.length-1?`${we(he,D.length)} ${we(ve,D.length)} ${Ie.lastTabClassName}`:""} ${v?"bg-white text-slate-900 shadow-sm":"text-slate-600 hover:bg-slate-200/50 hover:text-slate-900"}`,children:i.phrases.map((P,te)=>S(cn,{children:[te>0&&u("wbr",{}),P]},P))},i.key)})})}),A.metadataId!==null&&u(Qt,{metadataId:A.metadataId,runs:A.runs,selectedRunId:A.selectedRunId,onSelectRun:A.selectRun,isLoading:A.isLoading,failure:A.failure,onClose:A.close,openRequest:A.openRequest,returnFocusFallback:pe}),I==="search"&&S("div",{role:"tabpanel",id:"panel-search","aria-labelledby":"tab-search",className:"space-y-6","data-testid":"tab-content-search",children:[u(Ht,{tenantId:p.tenantId,onSearch:d,circuitBreakerStatus:p.circuitBreakerStatus}),m!==void 0&&u($t,{variants:me,onCompare:m})]}),I==="ingest"&&u("div",{role:"tabpanel",id:"panel-ingest","aria-labelledby":"tab-ingest",className:"space-y-6","data-testid":"tab-content-ingest",children:u(jt,{tenantId:p.tenantId,policies:p.confidentialityPolicies,domainOptions:X,recentItems:p.recentIngestItems,inspectionResult:tt,isInspecting:nt,isSubmitting:rt,onInspectUri:i=>{t.submit({intent:"inspect_uri",fileUri:i},{method:"post"})},onIngestDocument:i=>{t.submit({intent:"ingest_document",payload:JSON.stringify(i)},{method:"post"})},onRetryItem:i=>{t.submit({intent:"retry_job",fileId:String(i)},{method:"post"})},onShowHistory:ge})}),I==="pipeline"&&S("div",{role:"tabpanel",id:"panel-pipeline","aria-labelledby":"tab-pipeline",className:"space-y-6","data-testid":"tab-content-pipeline",children:[u(Bt,{featureFlags:p.featureFlags,metrics:p.pipelineStepMetrics,metricSampleWindow:p.pipelineStepMetricWindow}),u(An,{runs:p.recentPipelineRuns,onOpenRun:ye}),u(Ut,{strategies:p.enrichmentStrategies,featureFlags:p.featureFlags,isUpdating:t.state!=="idle",onToggleStage:(i,b,v)=>t.submit({intent:"update_enrichment_strategy",strategyId:String(i.id),domainId:String(i.domainId),stage:b,enabled:String(v)},{method:"post"})}),u(Mt,{health:p.systemHealth,isRefreshing:t.state!=="idle",onRefresh:()=>t.submit({intent:"refresh_health"},{method:"post"})})]}),I==="knowledge-graph"&&S("div",{role:"tabpanel",id:"panel-knowledge-graph","aria-labelledby":"tab-knowledge-graph",className:"space-y-6","data-testid":"tab-content-knowledge-graph",children:[u(Kt,{tenantId:p.tenantId,ontologyStatus:p.ontologyStatus}),u(rn,{topologyMaxLabels:kt.topologyLabels.default,schema:p.graphSchema,tenantId:p.tenantId,unresolvedEntities:p.unresolvedEntities,traversal:o,onBrowseLabel:H,nodeIndexPage:y,nodeIndexFailure:j,isNodeIndexLoading:E,isResolving:it,onResolveEntity:(i,b)=>{t.submit({intent:"resolve_entity",entityId:i,action:b},{method:"post"})}})]}),I==="parameters"&&S("div",{role:"tabpanel",id:"panel-parameters","aria-labelledby":"tab-parameters",className:"space-y-6","data-testid":"tab-content-parameters",children:[S("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[u(en,{flags:_e,isUpdating:t.state!=="idle",onToggleFlag:(i,b)=>{t.submit({intent:"toggle_flag",flagKey:i,enabled:String(b)},{method:"post"})}}),u(Yt,{rules:p.classificationRules,domainOptions:X,consultedBy:p.classificationRuleConsumer,onReorderRules:i=>{t.submit({intent:"reorder_rules",orderedRuleIds:JSON.stringify(i)},{method:"post"})}})]}),p.policiesMissingDestination.length>0&&S("div",{"data-testid":"policies-missing-destination",role:"alert",style:{padding:"10px 12px",borderRadius:"6px",backgroundColor:"#fef2f2",color:"#b91c1c",fontSize:"12px"},children:[u("strong",{children:"\u6B21\u306E\u533A\u5206\u30FB\u6A5F\u80FD\u306F\u5B9F\u884C\u6642\u306B\u5931\u6557\u3057\u307E\u3059\u3002"})," \u53C2\u7167\u3059\u308B\u30D7\u30ED\u30F3\u30D7\u30C8\u884C\u306B\u5B9B\u5148\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",u("ul",{style:{margin:"6px 0 0",paddingInlineStart:"18px"},children:p.policiesMissingDestination.map(i=>S("li",{"data-testid":`missing-destination-${i.confidentialityLevel}-${i.capability}`,children:[i.confidentialityLevel," / ",i.capability," \u2192 ",i.promptKey," (",i.modelProvider,") \u306E ",u("code",{children:"extra_params.base_url"})]},`${i.confidentialityLevel}:${i.capability}`))}),u("span",{style:{display:"block",marginTop:"4px",fontSize:"11px"},children:"\u5B9B\u5148\u3092\u8A2D\u5B9A\u3057\u3066\u3082\u3001\u305D\u306E\u30DB\u30B9\u30C8\u304C\u914D\u5099\u5185\u3068\u3057\u3066\u767B\u9332\u3055\u308C\u3066\u3044\u306A\u3051\u308C\u3070\u62D2\u5426\u3055\u308C\u307E\u3059\u3002"})]}),u(Zt,{policies:p.confidentialityPolicies,promptKeys:p.promptTemplates.map(i=>i.template_key),isUpdating:t.state!=="idle",onChangePolicy:i=>{t.submit({intent:"update_confidentiality_policy",confidentialityLevel:i.confidentialityLevel,capability:i.capability,isEnabled:String(i.isEnabled),allowCloudProvider:String(i.allowCloudProvider),promptKey:i.promptKey??""},{method:"post"})}}),u(un,{vocabulary:p.transcriptionVocabulary,references:p.transcriptionReferences,unresolvedUris:p.unresolvedReferenceUris,isUpdating:t.state!=="idle",onSaveTerm:i=>ke({intent:"save_transcription_term",id:i.id===null?"":String(i.id),term:i.term,reading:i.reading??"",boost:i.boost===null?"":String(i.boost),domainKey:i.domainKey??"",isActive:String(i.isActive)},{method:"post"}),onSaveReference:i=>ke({intent:"save_transcription_reference",id:i.id===null?"":String(i.id),fileUri:i.fileUri,domainKey:i.domainKey??"",isActive:String(i.isActive)},{method:"post"})}),u(ln,{parameters:p.systemParameters,onSaveParameter:(i,b)=>{t.submit({intent:"update_parameter",paramKey:i,paramValue:String(b)},{method:"post"})}})]}),I==="prompts"&&S("div",{role:"tabpanel",id:"panel-prompts","aria-labelledby":"tab-prompts",className:"space-y-6","data-testid":"tab-content-prompts",children:[u(on,{templates:p.promptTemplates,isSaving:t.state!=="idle",onSaveTemplate:i=>{t.submit({intent:"update_prompt",templateKey:i.template_key,payload:JSON.stringify({templateText:i.template_text,modelName:i.model_name,temperature:i.temperature,maxOutputTokens:i.max_output_tokens,responseSchema:i.response_schema,endpointBaseUrl:i.endpoint_base_url??null})},{method:"post"})}}),u(tn,{onSimulate:a})]}),I==="knowledge-authority"&&S("div",{role:"tabpanel",id:"panel-knowledge-authority","aria-labelledby":"tab-knowledge-authority",className:"space-y-6","data-testid":"tab-content-knowledge-authority",children:[u(Xt,{host:h,canUpdate:p.canUpdateKnowledge,onPolicyConflictsChanged:ce}),u(sn,{host:f,revision:ue})]}),I==="data-retention"&&S("div",{role:"tabpanel",id:"panel-data-retention","aria-labelledby":"tab-data-retention",className:"space-y-6","data-testid":"tab-content-data-retention",children:[O.overview.kind==="ready"?u(dn,{overview:O.overview.value,canReadFindings:p.canReadIntegrityFindings,command:at,commandFailure:lt,onStartRun:(i,b)=>{n.submit(b===null?{intent:"start_integrity_run",mode:i}:{intent:"start_integrity_run",mode:i,basisRunUid:b},{method:"post"})},onCancelRun:i=>{n.submit({intent:"cancel_integrity_run",runUid:i},{method:"post"})},loadFindings:R,refreshFailure:O.overview.refreshFailure===null?null:O.overview.refreshFailure.reason,headingRef:Q}):u(Tt,{title:bn,testId:"audit-overview-failed",headingRef:Q,children:u(_t,{failure:O.overview,onReload:O.reload,forbiddenMessage:"\u76E3\u67FB\u306E\u6982\u6CC1\u3092\u95B2\u89A7\u3059\u308B\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",failureMessage:Sn,rescueRef:le,testId:"audit-overview-failed-resource"})}),u(an,{host:f,knowledgeTabLabel:yn(ie),onOpenKnowledgeTab:pt}),z!==null&&z.skipped.length>0&&S("div",{role:"status","data-testid":"retry-all-skipped",className:"rounded-lg border border-amber-200 border-solid bg-amber-50 p-4 text-amber-800 text-sm",children:[S("strong",{children:["\u4E00\u62EC\u518D\u8A66\u884C: ",z.requeued," \u4EF6\u3092\u518D\u6295\u5165\u3057\u3001",z.skipped.length," \u4EF6\u3092\u636E\u3048\u7F6E\u304D\u307E\u3057\u305F\u3002"]})," ","\u636E\u3048\u7F6E\u3044\u305F\u884C\u306F\u5931\u6557\u306E\u307E\u307E\u6B8B\u3063\u3066\u3044\u307E\u3059\u3002",u("ul",{className:"mt-1.5 list-disc ps-5",children:z.skipped.map(i=>S("li",{"data-testid":`retry-all-skipped-${i.metadataId}`,children:["#",i.metadataId,": ",i.reason]},i.metadataId))})]}),S("div",{className:"grid grid-cols-1 gap-6 md:grid-cols-2",children:[u(Wt,{counts:p.syncCounts,totalFiles:p.totalFiles,failedItems:p.failedSyncItems,isRetrying:st,onRetryItem:i=>{t.submit({intent:"retry_job",fileId:String(i)},{method:"post"})},onRetryAll:()=>{t.submit({intent:"retry_all_failed"},{method:"post"})}}),u(zt,{overview:p.qdrantCollections,health:{healthy:p.systemHealth.services.qdrant.status==="connected",latency_ms:p.systemHealth.services.qdrant.latencyMs}})]})]})]})]})})}var hn=new Set(Ot.options.filter(e=>e!=="SYNCED"&&!e.startsWith("FAILED"))),$e=2e3;function vn(e,t,n){let[r,o]=U(null),s=k(t);s.current=t;let a=k(e);a.current!==e&&(a.current=e,r!==null&&o(null));let d=(r??e)?.some(c=>hn.has(c.syncStatus))===!0;return Ae(()=>{if(!(n&&d&&s.current))return;let c=!1,m,g=async()=>{let R=s.current;if(R!==void 0){try{let f=await R();if(c)return;o(f)}catch{if(c)return}m=setTimeout(g,$e)}};return m=setTimeout(g,$e),()=>{c=!0,clearTimeout(m)}},[d,n]),r}function Ke(e,t){let n=k(t);n.current=t;let r=k(null),o=k(!1),s=k(null);if(e.state!=="idle"){o.current=!0;let l=e.formData?.get("intent");typeof l=="string"&&(r.current=l)}Ae(()=>{if(e.state!=="idle"||!o.current)return;o.current=!1,n.current(e.data);let l=s.current;if(l===null)return;s.current=null;let d=e.data?.error;typeof d=="string"?l.reject(new Error(d)):l.resolve()},[e.state,e.data]);let a=W((...l)=>new Promise((d,c)=>{s.current?.reject(new Error("\u3053\u306E\u4FDD\u5B58\u306F\u5F8C\u7D9A\u306E\u9001\u4FE1\u306B\u7F6E\u304D\u63DB\u3048\u3089\u308C\u307E\u3057\u305F\u3002")),s.current={resolve:d,reject:c},e.submit(...l)}),[e]);return{settledIntent:e.state==="idle"?r.current:null,submitAndAwait:a}}function In(e){let t=new Set,n=[];for(let r of e)t.has(r.domainKey)||(t.add(r.domainKey),n.push({key:r.domainKey,label:r.domainLabel}));return n}function wn(e){return{strategyId:e.strategyId,label:`${e.domainKey} / ${e.variantKey}`,embeddingModel:e.embeddingModel}}function An({runs:e,onOpenRun:t}){return S("section",{className:"rounded-xl border border-slate-200 border-solid bg-white p-6 shadow-sm","aria-labelledby":"pipeline-recent-runs-heading","data-testid":"pipeline-recent-runs",children:[u("h2",{id:"pipeline-recent-runs-heading",className:"font-bold text-base text-slate-900",children:"\u76F4\u8FD1\u306E\u5B9F\u884C"}),e.length===0?u("p",{className:"mt-4 text-[13px] text-slate-500","data-testid":"pipeline-recent-runs-empty",children:"\u8A18\u9332\u3055\u308C\u305F\u5B9F\u884C\u304C\u3042\u308A\u307E\u305B\u3093\u3002"}):u("div",{className:"relative mt-4 overflow-x-auto","data-testid":"pipeline-recent-runs-scroll",children:S("table",{className:"w-full text-left text-[13px]",children:[u("thead",{children:S("tr",{className:"whitespace-nowrap border-slate-200 border-b border-solid text-[11px] text-slate-500 uppercase",children:[u("th",{scope:"col",className:"px-3 py-2",children:"\u5B9F\u884C"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u6587\u66F8"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u7A2E\u985E"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u304D\u3063\u304B\u3051"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u8A66\u884C"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u72B6\u614B"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u6B62\u307E\u3063\u305F\u6BB5"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u958B\u59CB"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u7D42\u4E86"}),u("th",{scope:"col",className:"px-3 py-2",children:"\u8981\u6C42\u8005"}),t!==void 0&&u("th",{scope:"col",className:"px-3 py-2",children:u("span",{className:"sr-only","data-testid":"pipeline-recent-runs-action-header",children:"\u64CD\u4F5C"})})]})}),u("tbody",{children:e.map(n=>{let r=Gt(n),o=qt[r];return S("tr",{className:"border-slate-100 border-b border-solid","data-testid":`pipeline-run-row-${n.id}`,"data-status":n.status,children:[S("td",{className:"whitespace-nowrap px-3 py-2 font-mono","data-testid":`pipeline-run-id-${n.id}`,children:["#",n.id]}),S("td",{className:"whitespace-nowrap px-3 py-2 font-mono","data-testid":`pipeline-run-metadata-${n.id}`,children:["#",n.metadataId]}),u("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-kind-${n.id}`,children:xt[n.documentKind]}),u("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-trigger-${n.id}`,"data-trigger":n.trigger,children:Vt[n.trigger]}),u("td",{className:"whitespace-nowrap px-3 py-2","data-testid":`pipeline-run-attempt-${n.id}`,children:n.attempt}),u("td",{className:"px-3 py-2",children:u("span",{className:`inline-flex whitespace-nowrap rounded-full px-2 py-0.5 font-semibold text-[11px] ${o.className}`,"data-testid":`pipeline-run-status-${n.id}`,"data-status":n.status,"data-presentation":r,children:o.label})}),u("td",{className:"px-3 py-2","data-testid":`pipeline-run-failed-step-${n.id}`,children:n.failedStepKey===null?"\u2014":Ft[n.failedStepKey].label}),u("td",{className:"whitespace-nowrap px-3 py-2 text-slate-500","data-testid":`pipeline-run-started-${n.id}`,children:u(Jt,{iso:n.startedAt,testId:`pipeline-run-started-value-${n.id}`})}),u("td",{className:"whitespace-nowrap px-3 py-2 text-slate-500","data-testid":`pipeline-run-finished-${n.id}`,children:u(Dt,{iso:n.finishedAt,testId:`pipeline-run-finished-value-${n.id}`})}),u("td",{className:"wrap-anywhere px-3 py-2","data-testid":`pipeline-run-requested-by-${n.id}`,children:n.requestedBy}),t!==void 0&&u("td",{className:"whitespace-nowrap px-3 py-2 text-right",children:u("button",{type:"button",onClick:()=>t(n),"aria-label":`\u5B9F\u884C #${n.id} (\u6587\u66F8 #${n.metadataId}) \u306E\u8A73\u7D30`,className:"whitespace-nowrap rounded-sm border border-slate-300 border-solid bg-white px-2 py-0.5 font-semibold text-[11px] text-slate-700 hover:bg-slate-50","data-testid":`pipeline-run-open-${n.id}`,children:"\u8A73\u7D30"})})]},n.id)})})]})})]})}var qe={metadataId:null,runs:[],selectedRunId:null,isLoading:!1,failure:null};function Pn(e){for(let t of e)for(let n of t.steps){let r=n.provenance;if(r!==null){for(let[o,s]of Object.entries(r))if(typeof s=="string"&&!re(s))return`\u51E6\u7406\u5C65\u6B74\u306E\u8A18\u9332\u306B\u8AAD\u3081\u306A\u3044\u6765\u6B74\u306E\u5024\u304C\u3042\u308A\u307E\u3059 (\u5B9F\u884C ${t.id} \u306E\u6BB5 ${n.sequence} \u306E ${o})\u3002`}}return null}function Nn(e){let[t,n]=U(qe),[r,o]=U(0),s=k(0),a=k(null),l=se(()=>{if(e!==void 0)return(m,g)=>{s.current+=1;let R=s.current;a.current?.abort();let f=new AbortController;a.current=f,o(h=>h+1),n({metadataId:m,runs:[],selectedRunId:g,isLoading:!0,failure:null}),J(()=>e(m,f.signal),h=>({ok:!1,status:null,reason:h})).then(h=>{if(s.current!==R)return;let y=h.ok?Pn(h.value):Rn(h.reason);if(!h.ok||y!==null){n({metadataId:m,runs:[],selectedRunId:g,isLoading:!1,failure:y});return}n({metadataId:m,runs:h.value,selectedRunId:g===null?Tn(h.value):g,isLoading:!1,failure:null})})}},[e]),d=W(m=>{n(g=>({...g,selectedRunId:m}))},[]),c=W(()=>{s.current+=1,a.current?.abort(),a.current=null,n(qe)},[]);return{...t,openRequest:r,open:l,selectRun:d,close:c}}function Tn(e){return e.length===0?null:e[0].id}function En(e){let t=pn(),n=De(),r=De(),o=e.data??t,s=e.fetcher??n,a=e.integrityFetcher??r;return o?u(Ve,{...e,data:o,fetcher:s,integrityFetcher:a}):u("div",{className:"p-8 text-center text-slate-500","data-testid":"storage-admin-loading",children:"\u30C7\u30FC\u30BF\u8AAD\u307F\u8FBC\u307F\u4E2D..."})}function Be(e){return e.data?u(Ve,{...e,data:e.data,fetcher:e.fetcher??He,integrityFetcher:e.integrityFetcher??He}):u(En,{...e})}import{AuthzDeniedError as We}from"@aiquants/authz-core";import{formatCount as jn}from"@aiquants/console-ui/core";import{assertSystemParameterInRange as Un,INTEGRITY_COMMAND_CODES as Dn,IntegrityAuditOverviewSchema as Mn,IntegrityCommandFailureSchema as Hn,IntegrityCommandReplySchema as $n,IntegrityRunModeSchema as Ye,integrityCommandFailureCodeOf as Kn,isEnrichmentStageKey as qn,PipelineRunSummarySchema as Vn,PipelineStepMetricSchema as Bn}from"@aiquants/enrichment-core";import{CLOUD_CAPABLE_CAPABILITIES as Qn,ConfidentialityLevelSchema as Ee,GovernedCapabilitySchema as Gn}from"@aiquants/governance-core";import{z as w}from"zod";var Ne=3e3;function F(e){return Math.round(performance.now()-e)}function N(e){return typeof e=="string"&&re(e)?e:null}function L(e){let t=globalThis.process;return t===void 0?void 0:t.env[e]}function ae(e,t){let n=e?.trim();if(!n)throw new Error(`${t} is not configured; this probe will not guess an endpoint to send credentials to.`);return n}function Qe(e,t,n){let r=e??(t?.trim()?Number(t):Number.NaN);if(!Number.isInteger(r)||r<=0||r>65535)throw new Error(`${n} is not configured with a valid port; this probe will not guess one.`);return r}function Ge(e,t){if(e!==void 0)return e;let n=t?.trim().toLowerCase();if(!(n===void 0||n===""))return n==="1"||n==="true"||n==="yes"||n==="on"}function ze(e){let t=e.trim().split("://",1)[0]?.toLowerCase();if(t&&e.includes("://"))return t.endsWith("s")||t.includes("+s")}function _n(e){let n=e.split("://").slice(-1)[0].split("/",1)[0],r=n.split(":").pop();if(!r||r===n)return;let o=Number(r);return Number.isInteger(o)&&o>0&&o<=65535?o:void 0}async function Pe(e,t){let n;try{return await Promise.race([e,new Promise((r,o)=>{n=setTimeout(()=>o(new Error(`Probe timed out after ${t}ms`)),t)})])}finally{clearTimeout(n)}}async function Cn(e){let t=e?.qdrantApiKey??L("QDRANT_API_KEY")??"",n=e?.timeoutMs??Ne,r=performance.now(),o="";try{o=ae(e?.qdrantUrl??L("QDRANT_URL"),"QDRANT_URL");let s={};t&&(s["api-key"]=t);let[a,l]=await Promise.all([fetch(`${o}/`,{headers:s,signal:AbortSignal.timeout(n)}),fetch(`${o}/collections`,{headers:s,signal:AbortSignal.timeout(n)})]);if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText} (/collections)`);let d=await a.json(),c=F(r),g=(await l.json()).result?.collections?.length??0;return{serviceName:"Qdrant",category:"vector",status:"connected",version:N(d.version),endpoint:o,latencyMs:c,details:{engine:N(d.title),collectionsCount:g,restPort:_n(o)??null,tls:ze(o)??null}}}catch(s){let a=F(r),l=s instanceof Error?s.message:String(s);return{serviceName:"Qdrant",category:"vector",status:"error",version:null,endpoint:o,latencyMs:a,details:{},errorMessage:l}}}async function xn(e){let t=e?.timeoutMs??Ne,n=performance.now(),r=N(e?.neo4jBoltUri??L("NEO4J_URI")),o=r===null?"":r;try{let s=e?.graphReader;if(!s)throw new Error("Graph reader not configured");let a=e?.tenantId,[l,d]=await Promise.all([Pe(s("CALL dbms.components() YIELD versions, edition RETURN versions[0] AS version, edition",{}),t),Pe(a?s("MATCH (n {tenantId: $tenantId}) RETURN count(n) AS node_count",{tenantId:a}):s("RETURN null AS node_count",{}),t)]);if(!l.ok)throw new Error(l.reason);if(!d.ok)throw new Error(d.reason);let[c,m]=l.rows[0]??[],g=d.rows[0]?.[0],R=F(n);return{serviceName:"Neo4j",category:"graph",status:"connected",version:N(c),endpoint:o,latencyMs:R,details:{edition:N(m),boltUri:r,nodeCount:typeof g=="number"?g:null,tls:r===null?null:ze(r)??null}}}catch(s){let a=F(n),l=s instanceof Error?s.message:String(s);return{serviceName:"Neo4j",category:"graph",status:"error",version:null,endpoint:o,latencyMs:a,details:{},errorMessage:l}}}async function On(e){let t=performance.now(),n="",r=Ge(e?.redisTls,L("REDIS_TLS")),o=Number.NaN;try{let s=e?.redisClient;if(!s)throw new Error("Redis client not configured");let a=ae(e?.redisHost??L("REDIS_HOST"),"REDIS_HOST");o=Qe(e?.redisPort,L("REDIS_PORT"),"REDIS_PORT"),n=`${r===!1?"redis":"rediss"}://${a}:${o}`,await s.ping();let l=await s.info("server"),d=N(l.match(/redis_version:([^\r\n]+)/)?.[1]),c=null;if(typeof s.dbSize=="function")try{c=await s.dbSize()}catch{c=null}let m=F(t);return{serviceName:"Redis",category:"cache",status:"connected",version:d,endpoint:n,latencyMs:m,details:{totalKeys:c,port:o,tls:r??null,database:0}}}catch(s){let a=F(t),l=s instanceof Error?s.message:String(s);return{serviceName:"Redis",category:"cache",status:"error",version:null,endpoint:n,latencyMs:a,details:{},errorMessage:l}}}function kn(e){let t=e.match(/Microsoft SQL Server \d+ \([^)]+\)/);return N(t===null?e.substring(0,30):t[0].replace("Microsoft SQL Server ",""))}async function Ln(e){let t=performance.now(),n="",r=Ge(e?.sqlServerTls,L("SQL_SERVER_TLS")),o=Number.NaN;try{let s=e?.sqlServerExecute;if(!s)throw new Error("SQL Server executor not configured");let a=ae(e?.sqlServerHost??L("SQL_SERVER_HOST"),"SQL_SERVER_HOST");o=Qe(e?.sqlServerPort,L("SQL_SERVER_PORT"),"SQL_SERVER_PORT"),n=`${a}:${o}`;let l=await s(),d=N(l.db_name),c=N(l.version),m=c===null?null:N(c.split(`
2
+ `)[0]),g=m===null?null:kn(m),R=F(t);return{serviceName:"SQL Server",category:"database",status:"connected",version:g,endpoint:n,latencyMs:R,details:{database:d,port:o,tls:r??null,fullVersion:m}}}catch(s){let a=F(t),l=s instanceof Error?s.message:String(s);return{serviceName:"SQL Server",category:"database",status:"error",version:null,endpoint:n,latencyMs:a,details:{},errorMessage:l}}}async function Fn(e){let t=e?.timeoutMs??Ne,n=performance.now(),r="";try{r=ae(e?.backendApiHost??L("BACKEND_API_HOST"),"BACKEND_API_HOST");let o=await fetch(`${r}/openapi.json`,{signal:AbortSignal.timeout(t)});if(!o.ok)throw new Error(`HTTP ${o.status}: ${o.statusText}`);let s=await o.json(),a=Object.keys(s.paths??{}).length,l=F(n);return{serviceName:"AI Quant API",category:"api",status:"connected",version:N(s.info?.version),endpoint:r,latencyMs:l,details:{title:N(s.info?.title),endpointsCount:a}}}catch(o){let s=F(n),a=o instanceof Error?o.message:String(o);return{serviceName:"AI Quant API",category:"api",status:"error",version:null,endpoint:r,latencyMs:s,details:{},errorMessage:a}}}async function Je(e){let[t,n,r,o,s]=await Promise.all([Cn(e),xn(e),On(e),Ln(e),Fn(e)]),a=t.status==="connected"&&n.status==="connected"&&r.status==="connected"&&o.status==="connected"&&s.status==="connected";return{services:{qdrant:t,neo4j:n,redis:r,sqlServer:o,quantsApi:s},allHealthy:a,checkedAt:new Date().toISOString()}}var zn=w.object({templateText:w.string(),modelName:w.string(),temperature:w.number(),maxOutputTokens:w.number(),responseSchema:w.union([w.record(w.string(),w.unknown()),w.string(),w.null()]).optional(),endpointBaseUrl:w.string().nullable()}).strict(),Jn=w.discriminatedUnion("mode",[w.object({mode:Ye.extract(["SCAN"]),basisRunUid:w.null()}).strict(),w.object({mode:Ye.extract(["REPAIR"]),basisRunUid:w.string().uuid()}).strict()]),Wn=w.object({runUid:w.string().uuid()}).strict();function Xe(e){return e==="start_integrity_run"?"start":e==="cancel_integrity_run"?"cancel":null}function B(e,t){return e.issues.map(n=>`${n.path.length===0?t:n.path.join(".")}: ${n.message}`).join("; ")}function Yn(e,t){if(e==="bool")return t==="true"||t==="false"?null:"paramValue must be 'true' or 'false' for a bool parameter";if(e==="int")return/^[+-]?\d+$/.test(t)&&Number.isSafeInteger(Number(t))?null:"paramValue must be a safe integer for an int parameter";if(e==="float")return t.trim()!==""&&Number.isFinite(Number(t))?null:"paramValue must be a finite number for a float parameter";if(e==="json")try{return JSON.parse(t),null}catch{return"paramValue must be valid JSON for a json parameter"}return null}function Zn(e){let t=Vn.array().safeParse(e);if(!t.success)throw new Error(`getRecentPipelineRuns answered something that is not a run summary: ${B(t.error,"getRecentPipelineRuns")}`);return t.data}function Xn(e){let t=Bn.array().safeParse(e);if(!t.success)throw new Error(`getPipelineStepMetrics answered something that is not a step metric: ${B(t.error,"getPipelineStepMetrics")}`);let n=new Set;for(let r of t.data){let o=`${r.documentKind}/${r.stepKey}`;if(n.has(o))throw new Error(`getPipelineStepMetrics answered more than one metric for (documentKind, stepKey) = (${r.documentKind}, ${r.stepKey})`);n.add(o)}return t.data}function er(e){if(!Number.isSafeInteger(e)||e<=0)throw new Error(`pipelineStepMetricWindow must be a positive safe integer, got ${String(e)}`);return e}async function tr(e,t){let n;try{n=await e.readIntegrityAuditOverview(t)}catch(o){return{ok:!1,status:null,reason:o instanceof Error?o.message:String(o)}}let r=Mn.safeParse(n);return r.success?{ok:!0,value:r.data}:{ok:!1,status:null,reason:`readIntegrityAuditOverview answered something that is not an audit overview: ${B(r.error,"readIntegrityAuditOverview")}`}}function nr(e){return!Array.isArray(e)||e.length===0?"orderedRuleIds must be a non-empty array of rule ids":e.every(t=>typeof t=="number"&&Number.isSafeInteger(t)&&t>0)?new Set(e).size!==e.length?"orderedRuleIds must not name a rule twice":null:"orderedRuleIds must contain positive integers only"}function et(e){let{store:t,healthProbeOptions:n,resourceKey:r="storage_admin",requireUser:o,requirePermission:s,resolveTenantId:a,authorizeIngest:l,canReadIntegrityFindings:d,canUpdateKnowledge:c}=e;async function m(R){let{request:f}=R;if(!await o(f))throw new Response("\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002",{status:401});try{await s(f,{resourceKey:r,action:"read"})}catch(ee){throw ee instanceof We?new Response("\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002",{status:403}):ee}let y=await a(f),M=er(t.pipelineStepMetricWindow),[j,T,E]=await Promise.all([t.getFeatureFlags(y),t.getSystemParameters(y),t.getSyncCounts(y)]),_={featureFlags:j,systemParameters:T,syncCounts:E},[H,$,K,C,I,x,Z,O,Q,le,ue,de,ce,p,q,pe,X,me,A,V,ge]=await Promise.all([t.getConfidentialityPolicies(y),t.getTranscriptionVocabulary(y),t.getTranscriptionReferences(y),t.getUnresolvedReferenceUris(y),t.getPoliciesMissingDestination(y),t.getPromptTemplates(y),t.getClassificationRules(y),t.getFailedSyncItems(y),t.getGraphSchema(y),tr(t,y),d(f),c(f),t.getUnresolvedEntities(y),t.getQdrantCollections(y),Je({...n,tenantId:y}),t.getRecentIngestItems(y),t.getOntologyStatus(y,_),t.getEnrichmentStrategies(y),t.getStrategyVariants(y),t.getPipelineStepMetrics(y),t.getRecentPipelineRuns(y)]),ye=t.getCircuitBreakerStatus();return{tenantId:y,featureFlags:_.featureFlags,confidentialityPolicies:H,transcriptionVocabulary:$,transcriptionReferences:K,unresolvedReferenceUris:C,policiesMissingDestination:I,systemParameters:_.systemParameters,promptTemplates:x,classificationRules:Z,classificationRuleConsumer:t.classificationRuleConsumer??null,syncCounts:_.syncCounts.counts,totalFiles:_.syncCounts.total,failedSyncItems:O,circuitBreakerStatus:ye,pipelineStepMetrics:Xn(V),pipelineStepMetricWindow:M,recentPipelineRuns:Zn(ge),displayTimeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,graphSchema:Q,enrichmentStrategies:me,strategyVariants:A,integrityAudit:le,canReadIntegrityFindings:ue,canUpdateKnowledge:de,unresolvedEntities:ce,qdrantCollections:p,systemHealth:q,recentIngestItems:pe,ontologyStatus:X}}async function g(R){let{request:f}=R,h=await o(f);if(!h)return Response.json({error:"\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002"},{status:401});if(h.email.trim()==="")return Response.json({error:"\u64CD\u4F5C\u8005\u3092\u7279\u5B9A\u3067\u304D\u306A\u3044\u305F\u3081\u8A2D\u5B9A\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002"},{status:403});if(h.accessToken==="")throw new Error("requireUser resolved an operator whose accessToken is an empty string; answer null when the session holds no token the upstream services accept");let y=h.email,M=h.accessToken===null?void 0:h.accessToken;try{await s(f,{resourceKey:r,action:"update"})}catch(C){if(C instanceof We)return await ar(f);throw C}let j=await a(f),T=await f.formData(),E=String(T.get("intent")??"");if(E==="refresh_health")return Response.json({success:!0,refreshed:!0});let _=await sr(t,j,E,T,y);if(_)return _;let H=await ir(t,j,E,T,y,M);if(H)return H;let $=await or(t,j,E,T,M,()=>d(f));if($)return $;if(E==="resolve_entity"){let C=String(T.get("entityId")??""),I=String(T.get("action")??"");if(!C||I!=="merge"&&I!=="promote")return Response.json({error:"Valid entityId and action ('merge' | 'promote') are required"},{status:400});try{return await t.resolveEntity(j,C,I),Response.json({success:!0,entityId:C,action:I})}catch(x){return Response.json({error:x instanceof Error?x.message:String(x)},{status:400})}}let K=await dr(t,j,E,T,y,f,l,M);return K||Response.json({error:`Unknown intent: ${E}`},{status:400})}return{loader:m,action:g}}function Te(e){let t=String(e??"").trim();return t===""?null:t}function oe(e){let t=String(e??"").trim();if(t==="")return null;let n=Number(t);if(!(!Number.isSafeInteger(n)||n<=0))return n}function rr(e){let t=String(e??"").trim();if(t==="")return null;let n=Number(t);if(!(!Number.isFinite(n)||n<=0))return n}async function sr(e,t,n,r,o){if(n==="update_enrichment_strategy"){let s=String(r.get("stage")??"");if(!qn(s))return Response.json({error:"stage must be a canonical enrichment stage key"},{status:400});let a=oe(r.get("strategyId")),l=oe(r.get("domainId"));if(a==null||l===void 0||l===null)return Response.json({error:"strategyId and domainId must be positive integers naming existing rows"},{status:400});let d=String(r.get("enabled")??"")==="true";try{await e.updateEnrichmentStrategy(t,{strategyId:a,domainId:l,stage:s,enabled:d},o)}catch(c){return Response.json({error:c instanceof Error?c.message:"\u53D6\u308A\u8FBC\u307F\u6226\u7565\u3092\u66F4\u65B0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,strategyId:a,domainId:l,stage:s,enabled:d})}if(n==="toggle_flag"){let s=String(r.get("flagKey")??""),a=String(r.get("enabled")??"")==="true";if(!s)return Response.json({error:"flagKey is required"},{status:400});let l=await e.getFeatureFlags(t);return Object.hasOwn(l,s)?(await e.toggleFeatureFlag(t,s,a,o),Response.json({success:!0,flagKey:s,enabled:a})):Response.json({error:`flagKey names no feature flag of this tenant: ${s}`},{status:400})}if(n==="update_confidentiality_policy"){let s=String(r.get("confidentialityLevel")??""),a=String(r.get("capability")??"");if(!(Ee.safeParse(s).success&&Gn.safeParse(a).success))return Response.json({error:"confidentialityLevel and capability must be canonical values"},{status:400});let l=String(r.get("allowCloudProvider")??"")==="true";if(l&&!Qn.includes(a))return Response.json({error:`${a} sends nothing outside the deployment, so it has no cloud permission to grant`},{status:400});let d=String(r.get("promptKey")??"");return await e.updateConfidentialityPolicy(t,{confidentialityLevel:s,capability:a,isEnabled:String(r.get("isEnabled")??"")==="true",allowCloudProvider:l,promptKey:d===""?null:d},o),Response.json({success:!0,confidentialityLevel:s,capability:a})}if(n==="save_transcription_term"){let s=String(r.get("term")??"").trim();if(!s)return Response.json({error:"term is required"},{status:400});let a=rr(r.get("boost"));if(a===void 0)return Response.json({error:"boost must be a number greater than zero, or absent to let the service decide"},{status:400});let l=oe(r.get("id"));if(l===void 0)return Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400});try{await e.saveTranscriptionTerm(t,{id:l,term:s,reading:Te(r.get("reading")),boost:a,domainKey:Te(r.get("domainKey")),isActive:String(r.get("isActive")??"true")==="true"},o)}catch(d){return Response.json({error:d instanceof Error?d.message:"\u8A9E\u5F59\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,term:s})}if(n==="save_transcription_reference"){let s=String(r.get("fileUri")??"").trim();if(!s)return Response.json({error:"fileUri is required"},{status:400});let a=oe(r.get("id"));if(a===void 0)return Response.json({error:"id must be a positive integer naming an existing row, or absent for a new one"},{status:400});try{await e.saveTranscriptionReference(t,{id:a,fileUri:s,domainKey:Te(r.get("domainKey")),isActive:String(r.get("isActive")??"true")==="true"},o)}catch(l){return Response.json({error:l instanceof Error?l.message:"\u53C2\u7167\u8CC7\u6599\u3092\u4FDD\u5B58\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002"},{status:400})}return Response.json({success:!0,fileUri:s})}if(n==="update_parameter"){let s=String(r.get("paramKey")??""),a=String(r.get("paramValue")??"");if(!s)return Response.json({error:"paramKey is required"},{status:400});let l=(await e.getSystemParameters(t)).find(c=>c.key===s);if(l===void 0)return Response.json({error:`paramKey names no parameter of this tenant: ${s}`},{status:400});let d=Yn(l.data_type,a);if(d!==null)return Response.json({error:d},{status:400});try{Un(s,Number(a))}catch(c){return Response.json({error:c.message},{status:400})}return await e.updateSystemParameter(t,s,a,o),Response.json({success:!0,paramKey:s,paramValue:a})}if(n==="update_prompt"){let s=String(r.get("templateKey")??""),a=String(r.get("payload")??"{}"),l;try{l=JSON.parse(a)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}if(!s)return Response.json({error:"templateKey is required"},{status:400});let d=zn.safeParse(l);if(!d.success)return Response.json({error:`payload does not carry a prompt template update: ${B(d.error,"payload")}`},{status:400});let c=d.data;try{return await e.updatePromptTemplate(t,s,c,o),Response.json({success:!0,templateKey:s})}catch(m){return Response.json({error:m instanceof Error?m.message:String(m)},{status:400})}}if(n==="reorder_rules"){let s=String(r.get("orderedRuleIds")??"[]"),a;try{a=JSON.parse(s)}catch{return Response.json({error:"Invalid orderedRuleIds JSON"},{status:400})}let l=nr(a);if(l!==null)return Response.json({error:l},{status:400});let d=a;return await e.reorderClassificationRules(t,d,o),Response.json({success:!0,orderedRuleIds:d})}return null}async function ir(e,t,n,r,o,s){if(n==="retry_job"){let a=String(r.get("fileId")??"");if(!a)return Response.json({error:"fileId is required"},{status:400});try{return await e.retrySyncItem(t,a,o,s),Response.json({success:!0,fileId:a})}catch(l){return Response.json({error:l instanceof Error?l.message:String(l)},{status:400})}}if(n==="retry_all_failed")try{let{requeued:a,skipped:l}=await e.retryAllFailedSyncItems(t,o,s);return Response.json({success:!0,requeued:a,skipped:l})}catch(a){return Response.json({error:a instanceof Error?a.message:String(a)},{status:400})}return null}function Y(e,t,n){let r=Hn.parse({command:e,code:t,status:n}),o=Dn.find(s=>s.code===r.code);return Response.json({failure:r},{status:o===void 0?502:o.status})}async function ar(e){let t=await e.formData().catch(()=>null),n=t===null?null:Xe(t.get("intent"));return n===null?Response.json({error:"\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093\u3002"},{status:403}):Y(n,"FORBIDDEN",null)}async function Ze(e,t){let n;try{n=$n.parse(await t())}catch{return Y(e,"UPSTREAM_FAILED",null)}return n.ok?Response.json({success:!0,runUid:n.runUid}):Y(e,Kn(e,n.status,n.errorCode),n.status)}async function or(e,t,n,r,o,s){let a=Xe(n);if(a==="start"){let l=Jn.safeParse({mode:r.get("mode"),basisRunUid:r.get("basisRunUid")});if(!l.success)return Response.json({error:`start_integrity_run takes mode SCAN without basisRunUid, or mode REPAIR with basisRunUid (a UUID): ${B(l.error,"form")}`},{status:400});let{mode:d,basisRunUid:c}=l.data;return o===void 0||d==="REPAIR"&&!await s()?Y(a,"FORBIDDEN",null):await Ze(a,()=>e.startIntegrityRun(t,d,c,o))}if(a==="cancel"){let l=Wn.safeParse({runUid:r.get("runUid")});return l.success?o===void 0?Y(a,"FORBIDDEN",null):await Ze(a,()=>e.cancelIntegrityRun(t,l.data.runUid,o)):Response.json({error:`cancel_integrity_run takes runUid (a UUID): ${B(l.error,"form")}`},{status:400})}return null}function lr(e){if(typeof e!="object"||e===null)return"payload must be an object";let t=e;if(typeof t.fileUri!="string"||t.fileUri.trim()==="")return"payload.fileUri is required";if(!Ee.safeParse(t.confidentialityLevel).success)return`payload.confidentialityLevel must be one of ${Ee.options.join(", ")}`;let r=t.departmentId;return r!=null&&(typeof r!="number"||!Number.isInteger(r))?"payload.departmentId must be an integer or null":null}function ur(e){try{return jn(e,ne),null}catch{return`inspectFileUri answered a fileSize that is not a byte count (a non-negative safe integer): ${String(e)}`}}async function dr(e,t,n,r,o,s,a,l){if(n==="ingest_document"){let d=String(r.get("payload")??"");if(!d)return Response.json({error:"payload is required"},{status:400});let c;try{c=JSON.parse(d)}catch{return Response.json({error:"Invalid JSON payload"},{status:400})}let m=lr(c);if(m)return Response.json({error:m},{status:400});let g=c,R=await a(s,g);if(R!==null)return Response.json({error:R},{status:403});try{let f=l===void 0?await e.ingestDocument(t,g,o):await e.ingestDocument(t,g,o,l);return Response.json({success:!0,result:f})}catch(f){return Response.json({error:f instanceof Error?f.message:String(f)},{status:400})}}if(n==="inspect_uri"){let d=String(r.get("fileUri")??"").trim();if(!d)return Response.json({error:"fileUri is required"},{status:400});if(!e.inspectFileUri)return Response.json({error:"inspectFileUri is not implemented"},{status:501});let c;try{c=l===void 0?await e.inspectFileUri(t,d):await e.inspectFileUri(t,d,l)}catch(g){return Response.json({error:g instanceof Error?g.message:String(g)},{status:400})}let m=ur(c.fileSize);return m!==null?Response.json({error:m},{status:400}):Response.json({success:!0,inspection:c})}return null}function Br(e){let t=et(e);return{loader:t.loader,action:t.action,View:Be,server:t}}export{Be as StorageAdminConsoleView,Je as checkAllSystemHealth,Fn as checkBackendApiHealth,xn as checkNeo4jHealth,Cn as checkQdrantHealth,On as checkRedisHealth,Ln as checkSqlServerHealth,Br as createStorageAdminApp,et as createStorageAdminServer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/enrichment-react-router",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "React Router (v7 / v8) adapter for storage AI enrichment & knowledge governance admin console.",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -36,25 +36,29 @@
36
36
  "license": "MIT",
37
37
  "peerDependencies": {
38
38
  "@aiquants/authz-core": "^0.6.1",
39
- "@aiquants/enrichment-core": "^0.1.1",
40
- "@aiquants/enrichment-react": "^0.1.0",
41
- "@aiquants/governance-core": "^0.1.0",
42
- "@aiquants/governance-react": "^0.1.0",
43
- "react": ">=18",
44
- "react-dom": ">=18",
45
- "react-router": "^7.0.0 || ^8.0.0"
39
+ "@aiquants/console-ui": "^0.1.0",
40
+ "@aiquants/enrichment-core": "^0.3.1",
41
+ "@aiquants/enrichment-react": "^0.2.0",
42
+ "@aiquants/governance-core": "^0.2.1",
43
+ "@aiquants/governance-react": "^0.2.0",
44
+ "react": ">=19",
45
+ "react-dom": ">=19",
46
+ "react-router": "^7.0.0 || ^8.0.0",
47
+ "zod": "^3.25.0"
46
48
  },
47
49
  "devDependencies": {
48
50
  "@aiquants/authz-core": "0.6.1",
49
- "@aiquants/enrichment-core": "0.1.1",
50
- "@aiquants/enrichment-react": "0.1.0",
51
- "@aiquants/governance-core": "0.1.0",
52
- "@aiquants/governance-react": "0.1.0",
51
+ "@aiquants/console-ui": "0.1.0",
52
+ "@aiquants/enrichment-core": "0.3.1",
53
+ "@aiquants/enrichment-react": "0.2.0",
54
+ "@aiquants/governance-core": "0.2.1",
55
+ "@aiquants/governance-react": "0.2.0",
53
56
  "@testing-library/jest-dom": "^6.9.1",
54
57
  "@testing-library/react": "^16.3.2",
55
58
  "@testing-library/user-event": "^14.6.1",
56
59
  "@types/react": "^19.2.7",
57
60
  "@types/react-dom": "^19.2.3",
61
+ "@vitest/coverage-v8": "^4.1.8",
58
62
  "jsdom": "^27.4.0",
59
63
  "react": "^19.2.7",
60
64
  "react-dom": "^19.2.7",
@@ -62,7 +66,8 @@
62
66
  "rimraf": "^6.1.2",
63
67
  "tsup": "^8.5.1",
64
68
  "typescript": "^5.9.3",
65
- "vitest": "^4.1.10"
69
+ "vitest": "^4.1.10",
70
+ "zod": "^3.25.76"
66
71
  },
67
72
  "engines": {
68
73
  "node": ">=18.0.0",
@@ -75,9 +80,9 @@
75
80
  "build": "tsup && node ../../.config/scripts/strip-dts-comments.mjs dist",
76
81
  "build:watch": "tsup --watch",
77
82
  "dev": "tsup --watch",
78
- "publish:patch": "pnpm run typecheck && pnpm run --if-present test && pnpm version patch --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
79
- "publish:minor": "pnpm run typecheck && pnpm run --if-present test && pnpm version minor --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
80
- "publish:major": "pnpm run typecheck && pnpm run --if-present test && pnpm version major --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
83
+ "publish:patch": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version patch --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
84
+ "publish:minor": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version minor --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
85
+ "publish:major": "pnpm run typecheck && pnpm run --if-present test && pnpm run build && node ../../.config/scripts/check-publish-leaks.mjs && pnpm version major --no-git-tag-version --no-git-checks && pnpm publish --no-git-checks",
81
86
  "typecheck": "tsc --noEmit",
82
87
  "clean": "rimraf dist",
83
88
  "lint": "biome lint src/",