vitess.io/vitess@v0.16.2/web/vtadmin/src/hooks/api.ts (about) 1 /** 2 * Copyright 2021 The Vitess Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 import { 17 useMutation, 18 UseMutationOptions, 19 useQueries, 20 useQuery, 21 useQueryClient, 22 UseQueryOptions, 23 UseQueryResult, 24 } from 'react-query'; 25 import { 26 fetchBackups, 27 fetchClusters, 28 fetchExperimentalTabletDebugVars, 29 fetchGates, 30 fetchKeyspace, 31 fetchKeyspaces, 32 fetchSchema, 33 FetchSchemaParams, 34 fetchSchemas, 35 fetchTablet, 36 FetchTabletParams, 37 pingTablet, 38 fetchTablets, 39 fetchVSchema, 40 FetchVSchemaParams, 41 fetchVtctlds, 42 fetchVTExplain, 43 fetchWorkflow, 44 fetchWorkflows, 45 TabletDebugVarsResponse, 46 refreshState, 47 runHealthCheck, 48 deleteTablet, 49 refreshTabletReplicationSource, 50 startReplication, 51 stopReplication, 52 setReadOnly, 53 setReadWrite, 54 ValidateKeyspaceParams, 55 validateKeyspace, 56 validateSchemaKeyspace, 57 ValidateSchemaKeyspaceParams, 58 ValidateVersionKeyspaceParams, 59 validateVersionKeyspace, 60 fetchShardReplicationPositions, 61 createKeyspace, 62 reloadSchema, 63 deleteShard, 64 reloadSchemaShard, 65 tabletExternallyPromoted, 66 plannedFailoverShard, 67 emergencyFailoverShard, 68 rebuildKeyspaceGraph, 69 removeKeyspaceCell, 70 createShard, 71 GetTopologyPathParams, 72 getTopologyPath, 73 validate, 74 ValidateParams, 75 validateShard, 76 ValidateShardParams, 77 getFullStatus, 78 GetFullStatusParams, 79 validateVersionShard, 80 ValidateVersionShardParams, 81 } from '../api/http'; 82 import { vtadmin as pb, vtctldata } from '../proto/vtadmin'; 83 import { formatAlias } from '../util/tablets'; 84 85 /** 86 * useBackups is a query hook that fetches all backups across every cluster. 87 */ 88 export const useBackups = (options?: UseQueryOptions<pb.ClusterBackup[], Error> | undefined) => 89 useQuery(['backups'], fetchBackups, options); 90 91 /** 92 * useClusters is a query hook that fetches all clusters VTAdmin is configured to discover. 93 */ 94 export const useClusters = (options?: UseQueryOptions<pb.Cluster[], Error> | undefined) => 95 useQuery(['clusters'], fetchClusters, options); 96 97 /** 98 * useGates is a query hook that fetches all VTGates across every cluster. 99 */ 100 export const useGates = (options?: UseQueryOptions<pb.VTGate[], Error> | undefined) => 101 useQuery(['gates'], fetchGates, options); 102 103 /** 104 * useKeyspace is a query hook that fetches a single keyspace by name. 105 */ 106 export const useKeyspace = ( 107 params: Parameters<typeof fetchKeyspace>[0], 108 options?: UseQueryOptions<pb.Keyspace, Error> 109 ) => { 110 const queryClient = useQueryClient(); 111 return useQuery(['keyspace', params], () => fetchKeyspace(params), { 112 initialData: () => { 113 const keyspaces = queryClient.getQueryData<pb.Keyspace[]>('keyspaces'); 114 return (keyspaces || []).find( 115 (k) => k.cluster?.id === params.clusterID && k.keyspace?.name === params.name 116 ); 117 }, 118 ...options, 119 }); 120 }; 121 122 /** 123 * useCreateKeyspace is a mutation query hook that creates a keyspace. 124 */ 125 export const useCreateKeyspace = ( 126 params: Parameters<typeof createKeyspace>[0], 127 options: UseMutationOptions<Awaited<ReturnType<typeof createKeyspace>>, Error> 128 ) => { 129 return useMutation<Awaited<ReturnType<typeof createKeyspace>>, Error>(() => { 130 return createKeyspace(params); 131 }, options); 132 }; 133 134 /** 135 * useKeyspaces is a query hook that fetches all keyspaces across every cluster. 136 */ 137 export const useKeyspaces = (options?: UseQueryOptions<pb.Keyspace[], Error> | undefined) => 138 useQuery(['keyspaces'], fetchKeyspaces, options); 139 140 /** 141 * useSchemas is a query hook that fetches all schemas across every cluster. 142 */ 143 export const useSchemas = (options?: UseQueryOptions<pb.Schema[], Error> | undefined) => 144 useQuery(['schemas'], fetchSchemas, options); 145 146 /** 147 * useTablets is a query hook that fetches all tablets across every cluster. 148 */ 149 export const useTablets = (options?: UseQueryOptions<pb.Tablet[], Error> | undefined) => 150 useQuery(['tablets'], fetchTablets, options); 151 152 /** 153 * useVtctlds is a query hook that fetches all vtctlds across every cluster. 154 */ 155 export const useVtctlds = (options?: UseQueryOptions<pb.Vtctld[], Error> | undefined) => 156 useQuery(['vtctlds'], fetchVtctlds, options); 157 158 /** 159 * useTablet is a query hook that fetches a single tablet by alias. 160 */ 161 export const useTablet = (params: Parameters<typeof fetchTablet>[0], options?: UseQueryOptions<pb.Tablet, Error>) => { 162 const queryClient = useQueryClient(); 163 return useQuery(['tablet', params], () => fetchTablet(params), { 164 initialData: () => { 165 const tablets = queryClient.getQueryData<pb.Tablet[]>('tablets'); 166 return (tablets || []).find( 167 (t) => t.cluster?.id === params.clusterID && formatAlias(t.tablet?.alias) === params.alias 168 ); 169 }, 170 ...options, 171 }); 172 }; 173 174 /** 175 * 176 * useDeleteTablet is a mutate hook that deletes a tablet by alias and optionally, cluster id. 177 */ 178 export const useDeleteTablet = ( 179 params: Parameters<typeof deleteTablet>[0], 180 options: UseMutationOptions<Awaited<ReturnType<typeof deleteTablet>>, Error> 181 ) => { 182 return useMutation<Awaited<ReturnType<typeof deleteTablet>>, Error>(() => { 183 return deleteTablet(params); 184 }, options); 185 }; 186 187 /** 188 * useRefreshTabletReplicationSource performs a `CHANGE REPLICATION SOURCE TO` 189 * on a tablet to replicate from the current primary in the shard. 190 */ 191 export const useRefreshTabletReplicationSource = ( 192 params: Parameters<typeof refreshTabletReplicationSource>[0], 193 options: UseMutationOptions<Awaited<ReturnType<typeof refreshTabletReplicationSource>>, Error> 194 ) => { 195 return useMutation<Awaited<ReturnType<typeof refreshTabletReplicationSource>>, Error>(() => { 196 return refreshTabletReplicationSource(params); 197 }, options); 198 }; 199 200 /** 201 * useSetReadOnly sets the tablet to read only 202 */ 203 export const useSetReadOnly = ( 204 params: Parameters<typeof setReadOnly>[0], 205 options: UseMutationOptions<Awaited<ReturnType<typeof setReadOnly>>, Error> 206 ) => { 207 return useMutation<Awaited<ReturnType<typeof setReadOnly>>, Error>(() => { 208 return setReadOnly(params); 209 }, options); 210 }; 211 212 /** 213 * useSetReadWrite sets the tablet to read only 214 */ 215 export const useSetReadWrite = ( 216 params: Parameters<typeof setReadWrite>[0], 217 options: UseMutationOptions<Awaited<ReturnType<typeof setReadWrite>>, Error> 218 ) => { 219 return useMutation<Awaited<ReturnType<typeof setReadWrite>>, Error>(() => { 220 return setReadWrite(params); 221 }, options); 222 }; 223 224 /** 225 * useShardReplicationPositions is a query hook that shows the replication status 226 * of each replica machine in the shard graph. 227 */ 228 export const useShardReplicationPositions = ( 229 params: Parameters<typeof fetchShardReplicationPositions>[0], 230 options?: UseQueryOptions<pb.GetShardReplicationPositionsResponse, Error> | undefined 231 ) => useQuery(['shard_replication_positions', params], () => fetchShardReplicationPositions(params), options); 232 233 /** 234 * useStartReplication starts replication on the specified tablet. 235 */ 236 export const useStartReplication = ( 237 params: Parameters<typeof startReplication>[0], 238 options: UseMutationOptions<Awaited<ReturnType<typeof startReplication>>, Error> 239 ) => { 240 return useMutation<Awaited<ReturnType<typeof startReplication>>, Error>(() => { 241 return startReplication(params); 242 }, options); 243 }; 244 245 /** 246 * useStopReplication stops replication on the specified tablet. 247 */ 248 export const useStopReplication = ( 249 params: Parameters<typeof stopReplication>[0], 250 options: UseMutationOptions<Awaited<ReturnType<typeof stopReplication>>, Error> 251 ) => { 252 return useMutation<Awaited<ReturnType<typeof stopReplication>>, Error>(() => { 253 return stopReplication(params); 254 }, options); 255 }; 256 257 /** 258 * usePingTablet is a query hook that pings a single tablet by tablet alias and (optionally) cluster id. 259 */ 260 export const usePingTablet = ( 261 params: Parameters<typeof pingTablet>[0], 262 options?: UseQueryOptions<pb.PingTabletResponse, Error> 263 ) => { 264 return useQuery(['ping-tablet', params], () => pingTablet(params), options); 265 }; 266 267 /** 268 * useRefreshState is a query hook that reloads the tablet record on the specified tablet. 269 */ 270 export const useRefreshState = ( 271 params: Parameters<typeof refreshState>[0], 272 options?: UseQueryOptions<pb.RefreshStateResponse, Error> 273 ) => { 274 return useQuery(['refresh-state', params], () => refreshState(params), options); 275 }; 276 277 /** 278 * useRefreshState is a query hook that reloads the tablet record on the specified tablet. 279 */ 280 export const useHealthCheck = ( 281 params: Parameters<typeof runHealthCheck>[0], 282 options?: UseQueryOptions<pb.RunHealthCheckResponse, Error> 283 ) => { 284 return useQuery(['run-health-check', params], () => runHealthCheck(params), options); 285 }; 286 287 export const useExperimentalTabletDebugVars = ( 288 params: FetchTabletParams, 289 options?: UseQueryOptions<TabletDebugVarsResponse, Error> 290 ) => { 291 return useQuery( 292 ['experimental/tablet/debug/vars', params], 293 () => fetchExperimentalTabletDebugVars(params), 294 options 295 ); 296 }; 297 298 // Future enhancement: add vtadmin-api endpoint to fetch /debug/vars 299 // for multiple tablets in a single request. https://github.com/vitessio/vitess/projects/12#card-63086674 300 export const useManyExperimentalTabletDebugVars = ( 301 params: FetchTabletParams[], 302 defaultOptions: UseQueryOptions<TabletDebugVarsResponse, Error> = {} 303 ) => { 304 // Robust typing for useQueries is still in progress, so we do 305 // some sneaky type-casting. See https://github.com/tannerlinsley/react-query/issues/1675 306 const queries = params.map((p) => ({ 307 queryKey: ['experimental/tablet/debug/vars', p], 308 queryFn: () => fetchExperimentalTabletDebugVars(p), 309 ...(defaultOptions as any), 310 })); 311 return useQueries(queries) as UseQueryResult<TabletDebugVarsResponse, Error>[]; 312 }; 313 314 /** 315 * useWorkflowsResponse is a query hook that fetches all workflows (by cluster) across every cluster. 316 */ 317 export const useWorkflowsResponse = (options?: UseQueryOptions<pb.GetWorkflowsResponse, Error> | undefined) => 318 useQuery(['workflows'], fetchWorkflows, options); 319 320 /** 321 * useWorkflows is a helper hook for when a flattened list of workflows 322 * (across all clusters) is required. Under the hood, this call uses the 323 * useWorkflowsResponse hook and therefore uses the same query cache. 324 */ 325 export const useWorkflows = (...args: Parameters<typeof useWorkflowsResponse>) => { 326 const { data, ...query } = useWorkflowsResponse(...args); 327 328 if (!data?.workflows_by_cluster) { 329 return { data: undefined, ...query }; 330 } 331 332 const workflows = Object.entries(data.workflows_by_cluster).reduce( 333 (acc: pb.Workflow[], [clusterID, { workflows }]) => { 334 (workflows || []).forEach((w) => acc.push(pb.Workflow.create(w))); 335 return acc; 336 }, 337 [] 338 ); 339 340 return { data: workflows, ...query }; 341 }; 342 343 /** 344 * useSchema is a query hook that fetches a single schema for the given parameters. 345 */ 346 export const useSchema = (params: FetchSchemaParams, options?: UseQueryOptions<pb.Schema, Error> | undefined) => { 347 const queryClient = useQueryClient(); 348 return useQuery(['schema', params], () => fetchSchema(params), { 349 initialData: () => { 350 const schemas = queryClient.getQueryData<pb.Schema[]>('schemas'); 351 return (schemas || []).find( 352 (s: pb.Schema) => 353 s.cluster?.id === params.clusterID && 354 s.keyspace === params.keyspace && 355 s.table_definitions.find((td) => td.name === params.table) 356 ); 357 }, 358 ...options, 359 }); 360 }; 361 362 /** 363 * useValidateKeyspace is a query hook that validates that all nodes reachable from the specified keyspace are consistent. 364 */ 365 export const useValidateKeyspace = ( 366 params: ValidateKeyspaceParams, 367 options?: UseMutationOptions<Awaited<ReturnType<typeof validateKeyspace>>, Error> 368 ) => { 369 return useMutation<Awaited<ReturnType<typeof validateKeyspace>>, Error>(() => { 370 return validateKeyspace(params); 371 }, options); 372 }; 373 374 /** 375 * useValidateKeyspace is a query hook that validates that all nodes reachable from the specified keyspace are consistent. 376 */ 377 export const useValidateSchemaKeyspace = ( 378 params: ValidateSchemaKeyspaceParams, 379 options?: UseMutationOptions<Awaited<ReturnType<typeof validateSchemaKeyspace>>, Error> 380 ) => { 381 return useMutation<Awaited<ReturnType<typeof validateSchemaKeyspace>>, Error>(() => { 382 return validateSchemaKeyspace(params); 383 }, options); 384 }; 385 386 /** 387 * useValidateVersion is a query hook that validates that all nodes reachable from the specified keyspace are consistent. 388 */ 389 export const useValidateVersionKeyspace = ( 390 params: ValidateVersionKeyspaceParams, 391 options?: UseMutationOptions<Awaited<ReturnType<typeof validateVersionKeyspace>>, Error> 392 ) => { 393 return useMutation<Awaited<ReturnType<typeof validateVersionKeyspace>>, Error>(() => { 394 return validateVersionKeyspace(params); 395 }, options); 396 }; 397 398 /** 399 * useVSchema is a query hook that fetches a single vschema definition for the given parameters. 400 */ 401 export const useVSchema = (params: FetchVSchemaParams, options?: UseQueryOptions<pb.VSchema, Error> | undefined) => { 402 return useQuery(['vschema', params], () => fetchVSchema(params)); 403 }; 404 405 export const useVTExplain = ( 406 params: Parameters<typeof fetchVTExplain>[0], 407 options?: UseQueryOptions<pb.VTExplainResponse, Error> | undefined 408 ) => { 409 return useQuery(['vtexplain', params], () => fetchVTExplain(params), { ...options }); 410 }; 411 412 /** 413 * useWorkflow is a query hook that fetches a single workflow for the given parameters. 414 */ 415 export const useWorkflow = ( 416 params: Parameters<typeof fetchWorkflow>[0], 417 options?: UseQueryOptions<pb.Workflow, Error> | undefined 418 ) => { 419 const queryClient = useQueryClient(); 420 return useQuery(['workflow', params], () => fetchWorkflow(params), { 421 // If the workflow already exists in the cache from a previous fetchWorkflows call, 422 // then use that for the initial data. 423 // 424 // Important note: `initialData` is persisted to the query cache. If the shapes of the GetWorkflowsResponse 425 // and Workflow protobuf types ever change such that Workflow is not a subset of GetWorkflowsResponse 426 // (e.g., the /api/workflow/... route provides different information than the /api/workflows route) 427 // then instead we will want to use `placeholderData`. (Unfortunately, the HTTP request boundary 428 // is one area where we have to assume typesafety... until we can, perhaps, one day switch to using 429 // gRPC on the client. Or, we could investigate code generating a TypeScript HTTP client. Possibilities!) 430 // 431 // See https://react-query.tanstack.com/guides/initial-query-data for more context on how initialData works. 432 initialData: () => { 433 const workflows = queryClient.getQueryData<pb.GetWorkflowsResponse>('workflows'); 434 const cw = workflows?.workflows_by_cluster[params.clusterID]; 435 if (!cw) return undefined; 436 437 const workflow = (cw.workflows || []).find( 438 (w) => 439 w.cluster?.id === params.clusterID && 440 w.keyspace === params.keyspace && 441 w.workflow?.name === params.name 442 ); 443 444 if (!workflow) return undefined; 445 446 return pb.Workflow.create(workflow); 447 }, 448 ...options, 449 }); 450 }; 451 452 /** 453 * useReloadSchema is a mutate hook that reloads schemas in one or more 454 * keyspaces, shards, or tablets in the cluster, depending on the request parameters. 455 */ 456 export const useReloadSchema = ( 457 params: Parameters<typeof reloadSchema>[0], 458 options?: UseMutationOptions<Awaited<ReturnType<typeof reloadSchema>>, Error> 459 ) => { 460 return useMutation<Awaited<ReturnType<typeof reloadSchema>>, Error>(() => { 461 return reloadSchema(params); 462 }, options); 463 }; 464 465 /** 466 * useDeleteShard is a mutate hook that deletes a shard in a keyspace. 467 */ 468 export const useDeleteShard = ( 469 params: Parameters<typeof deleteShard>[0], 470 options?: UseMutationOptions<Awaited<ReturnType<typeof deleteShard>>, Error> 471 ) => { 472 return useMutation<Awaited<ReturnType<typeof deleteShard>>, Error>(() => { 473 return deleteShard(params); 474 }, options); 475 }; 476 477 /* 478 * useRebuildKeyspaceGraph is a mutate hook that rebuilds keyspace graphs for one or 479 * more cells in a keyspace. 480 */ 481 export const useRebuildKeyspaceGraph = ( 482 params: Parameters<typeof rebuildKeyspaceGraph>[0], 483 options?: UseMutationOptions<Awaited<ReturnType<typeof rebuildKeyspaceGraph>>, Error> 484 ) => { 485 return useMutation<Awaited<ReturnType<typeof rebuildKeyspaceGraph>>, Error>(() => { 486 return rebuildKeyspaceGraph(params); 487 }, options); 488 }; 489 490 /** 491 * useReloadSchemaShard is a mutate hook that reloads the schema on all tablets in a shard. This is done on a best-effort basis. 492 */ 493 export const useReloadSchemaShard = ( 494 params: Parameters<typeof reloadSchemaShard>[0], 495 options?: UseMutationOptions<Awaited<ReturnType<typeof reloadSchemaShard>>, Error> 496 ) => { 497 return useMutation<Awaited<ReturnType<typeof reloadSchemaShard>>, Error>(() => { 498 return reloadSchemaShard(params); 499 }, options); 500 }; 501 502 /** 503 * useTabletExternallyPromoted is a mutate hook that changes metadata in the topology server to 504 * acknowledge a shard primary change performed by an external tool (e.g. 505 * orchestrator). 506 */ 507 export const useTabletExternallyPromoted = ( 508 params: Parameters<typeof tabletExternallyPromoted>[0], 509 options?: UseMutationOptions<Awaited<ReturnType<typeof tabletExternallyPromoted>>, Error> 510 ) => { 511 return useMutation<Awaited<ReturnType<typeof tabletExternallyPromoted>>, Error>(() => { 512 return tabletExternallyPromoted(params); 513 }, options); 514 }; 515 516 /** 517 * usePlannedFailoverShard reparents the shard to a new primary that can either be explicitly specified, or chosen by Vitess. 518 * This calls PlannedReparentShard in vtctlservice 519 * See https://vitess.io/docs/reference/programs/vtctl/shards/#plannedreparentshard 520 */ 521 export const usePlannedFailoverShard = ( 522 params: Parameters<typeof plannedFailoverShard>[0], 523 options?: UseMutationOptions<Awaited<ReturnType<typeof plannedFailoverShard>>, Error> 524 ) => { 525 return useMutation<Awaited<ReturnType<typeof plannedFailoverShard>>, Error>(() => { 526 return plannedFailoverShard(params); 527 }, options); 528 }; 529 530 /** 531 * useEmergencyFailoverShard reparents the shard to the new primary. Assumes the old primary is dead and not responding. 532 * This calls EmergencyReparentShard in vtctlservice 533 * See https://vitess.io/docs/reference/programs/vtctl/shards/#emergencyreparentshard 534 */ 535 export const useEmergencyFailoverShard = ( 536 params: Parameters<typeof emergencyFailoverShard>[0], 537 options?: UseMutationOptions<Awaited<ReturnType<typeof emergencyFailoverShard>>, Error> 538 ) => { 539 return useMutation<Awaited<ReturnType<typeof emergencyFailoverShard>>, Error>(() => { 540 return emergencyFailoverShard(params); 541 }, options); 542 }; 543 544 /** 545 * useRemoveKeyspaceCell is a mutate hook that removes a keyspace cell from the Cells list for all shards in the keyspace, and the SrvKeyspace for that keyspace in that cell. 546 */ 547 export const useRemoveKeyspaceCell = ( 548 params: Parameters<typeof removeKeyspaceCell>[0], 549 options?: UseMutationOptions<Awaited<ReturnType<typeof removeKeyspaceCell>>, Error> 550 ) => { 551 return useMutation<Awaited<ReturnType<typeof removeKeyspaceCell>>, Error>(() => { 552 return removeKeyspaceCell(params); 553 }, options); 554 }; 555 556 /** 557 * useCreateShard is a mutate hook that creates a shard in a keyspace 558 */ 559 export const useCreateShard = ( 560 params: Parameters<typeof createShard>[0], 561 options?: UseMutationOptions<Awaited<ReturnType<typeof createShard>>, Error> 562 ) => { 563 return useMutation<Awaited<ReturnType<typeof createShard>>, Error>(() => { 564 return createShard(params); 565 }, options); 566 }; 567 568 /** 569 * useTopologyPath is a query hook that fetches a cell at the specified path in the topology server. 570 */ 571 export const useTopologyPath = ( 572 params: GetTopologyPathParams, 573 options?: UseQueryOptions<vtctldata.GetTopologyPathResponse, Error> | undefined 574 ) => { 575 return useQuery(['topology-path', params], () => getTopologyPath(params)); 576 }; 577 /** 578 * useValidate is a mutate hook that validates that all nodes reachable from the global replication graph, 579 * as well as all tablets in discoverable cells, are consistent. 580 */ 581 export const useValidate = ( 582 params: Parameters<typeof validate>[0], 583 options?: UseMutationOptions<Awaited<ReturnType<typeof validate>>, Error, ValidateParams> 584 ) => { 585 return useMutation<Awaited<ReturnType<typeof validate>>, Error, ValidateParams>(() => { 586 return validate(params); 587 }, options); 588 }; 589 590 /** 591 * useValidateShard is a mutate hook that validates that that all nodes 592 * reachable from the specified shard are consistent. 593 */ 594 export const useValidateShard = ( 595 params: Parameters<typeof validateShard>[0], 596 options?: UseMutationOptions<Awaited<ReturnType<typeof validateShard>>, Error, ValidateShardParams> 597 ) => { 598 return useMutation<Awaited<ReturnType<typeof validateShard>>, Error, ValidateShardParams>(() => { 599 return validateShard(params); 600 }, options); 601 }; 602 603 /** 604 * useGetFullStatus is a query hook that fetches the full status of a tablet 605 */ 606 export const useGetFullStatus = ( 607 params: GetFullStatusParams, 608 options?: UseQueryOptions<vtctldata.GetFullStatusResponse, Error> | undefined 609 ) => useQuery(['full-status', params], () => getFullStatus(params), options); 610 611 /** 612 * useValidateVersionShard is a mutate hook that validates that the version on the primary matches all of the replicas. 613 */ 614 export const useValidateVersionShard = ( 615 params: Parameters<typeof validateVersionShard>[0], 616 options?: UseMutationOptions<Awaited<ReturnType<typeof validateVersionShard>>, Error, ValidateVersionShardParams> 617 ) => { 618 return useMutation<Awaited<ReturnType<typeof validateVersionShard>>, Error, ValidateVersionShardParams>(() => { 619 return validateVersionShard(params); 620 }, options); 621 };