@wip/react
@wip/react
What it is. @wip/react is the React-hooks layer over @wip/client, built on TanStack Query v5 (@tanstack/react-query). It exposes one read hook (useQuery-based) or mutation hook (useMutation-based) per WIP operation across terminologies/terms (def-store), templates (template-store), documents (document-store), files, registry/namespaces, and the reporting layer, plus a hierarchical query-key factory (wipKeys), per-domain default stale times (STALE_TIMES), a brand-attribution component (WipFooter), and two hooks built on top of the primitives (useFormSchema, useBulkImport). Callers are frontend devs building the UI of a WIP-backed app. (package.json: "description": "React hooks for WIP client (TanStack Query)"; src/index.ts export groups.)
Install & import. Package @wip/react, version 0.18.0, "private": true (package.json). No npm publishConfig is present in scope — the package is consumed as a workspace/file dependency, matching README.md's own install snippet:
{
"dependencies": {
"@wip/client": "file:../../libs/wip-client",
"@wip/react": "file:../../libs/wip-react",
"@tanstack/react-query": "^5.0.0",
"react": "^18.0.0 || ^19.0.0"
}
}
Entry point per package.json exports: ESM ./dist/index.js (types ./dist/index.d.ts), CJS ./dist/index.cjs (types ./dist/index.d.cts); built by tsup (tsup.config.ts: entry: ['src/index.ts'], format: ['esm','cjs'], dts: true). react, react-dom, @tanstack/react-query, and @wip/client are declared external in the build (tsup.config.ts:12) and are peerDependencies in package.json — they are not bundled and must be installed by the consumer. Primary import:
import { WipProvider, useWipClient, useDocuments, useCreateDocument } from '@wip/react'
node >=18.0.0 (package.json engines).
⚠ Scope note applying to every entry below: parameter/return types imported from
@wip/client(BulkResultItem,BulkResponse,WipBulkItemError, every*Request/*Responsetype,Namespace,Template,Document,Term,Terminology,FormField,BulkImportProgress, etc.) are named here exactly as imported, but their field-level shape is defined in@wip/client, which is outside this doc'ssource_scope(libs/wip-reactonly). Field-level detail for those types belongs in the@wip/clientlibrary doc — see "See also".
Core API
Grouped in the order src/index.ts groups them (Provider → Brand component → key/stale-time utilities → read hooks by domain → write hooks by domain → specialized hooks).
Provider & client access
WipProvider({ client, children })
- Purpose. React context provider that makes a
WipClientinstance available to every hook in the subtree. - Parameters.
client: WipClient(required);children: ReactNode(required). - Returns.
ReactElement, synchronous — wrapschildrenin<WipClientContext.Provider value={client}>. - Throws / errors. None.
- Example.
(<WipProvider client={wipClient}><App /></WipProvider>src/provider.tsx:6-17)
useWipClient()
- Purpose. Reads the
WipClientinstance from context. - Parameters. None.
- Returns.
WipClient, synchronous. - Throws / errors.
Error('useWipClient must be used within a <WipProvider>')when called outside a<WipProvider>(src/provider.tsx:19-25; behavior asserted bytests/provider.test.tsx:41-50). - Example.
const client = useWipClient() client.documents.listDocuments()
Brand-attribution component
WipFooter(props: WipFooterProps)
- Purpose. Renders a "Built on WIP" attribution
<footer>with an inline SVG logo mark. - Parameters. All optional:
appName?: string(prefixes"<appName> · ");className?: string(merged onto the wrapper);variant?: 'compact' | 'full', default'compact'—'full'is accepted by the type but not distinctly rendered in this version (see Gotchas);style?: CSSProperties;buildStamp?: string,buildSha?: string— rendered as a muted suffix, both ignored when equal to the literal'dev'sentinel. (src/WipFooter.tsx:3-24) - Returns.
ReactElement, synchronous. - Throws / errors. None.
- Example.
(rendering asserted by<WipFooter appName="ClinTrial" buildStamp={import.meta.env.VITE_BUILD_STAMP} buildSha={import.meta.env.VITE_BUILD_SHA} /> // → "ClinTrial · Built on WIP · 2026-06-20T09:00:00Z · a1b2c3d"tests/wip-footer.test.tsx)
Cache & stale-time utilities
wipKeys
- Purpose. Hierarchical TanStack Query key factory, one branch per domain (
terminologies,terms,templates,documents,files,registry,reporting), each with.allplus list/detail/etc. builders. - Parameters. N/A — a plain
constobject of key-builder functions. - Returns. Each builder returns a
readonly [...]tuple (as const), e.g.wipKeys.documents.detail(id) → ['wip','documents','detail', id]. Full key list:src/utils/keys.ts:1-68. - Throws / errors. None.
- Example.
queryClient.invalidateQueries({ queryKey: wipKeys.documents.all })
STALE_TIMES
- Purpose. Per-domain default
staleTime(ms), applied by every read hook unless the caller overrides it. - Parameters. N/A.
- Returns.
{ terminologies: 300000, terms: 300000, templates: 300000, documents: 30000, files: 600000, registry: 300000, reporting: 60000 }(src/utils/defaults.ts:2-17). - Throws / errors. None.
- Example.
useDocuments(params, { staleTime: STALE_TIMES.documents * 2 })
Terminologies & terms (read)
useTerminologies(params?, options?)
- Purpose. Lists terminologies.
- Parameters.
params?: { page?, page_size?, status?, value?, namespace? };options?: Omit<UseQueryOptions<TerminologyListResponse>, 'queryKey'|'queryFn'>. - Returns.
UseQueryResult<TerminologyListResponse>wrappingclient.defStore.listTerminologies(params); always enabled;staleTime: STALE_TIMES.terminologies. - Throws / errors. Not thrown — fetch failures surface via the result's
errorfield (TanStack Query convention). - Example.
const { data } = useTerminologies({ status: 'active' })(src/hooks/use-terminologies.ts:8-19)
useTerminology(id, options?)
- Purpose. Fetch one terminology by id.
- Parameters.
id: string. - Returns.
UseQueryResult<Terminology>wrappingclient.defStore.getTerminology(id); enabled!!id. - Example.
useTerminology('COUNTRY')(src/hooks/use-terminologies.ts:21-33)
useTerms(terminologyId, params?, options?)
- Purpose. Lists terms under a terminology.
- Parameters.
terminologyId: string;params?: { page?, page_size?, status?, search? }. - Returns.
UseQueryResult<TermListResponse>wrappingclient.defStore.listTerms(terminologyId, params); enabled!!terminologyId. - Example.
useTerms('COUNTRY', { search: 'united' })(src/hooks/use-terms.ts:8-21)
useTerm(id, options?)
- Purpose. Fetch one term by id.
- Parameters.
id: string. - Returns.
UseQueryResult<Term>wrappingclient.defStore.getTerm(id); enabled!!id. - Example.
useTerm('COUNTRY:United States')(src/hooks/use-terms.ts:23-35)
Templates (read)
useTemplates(params?, options?)
- Purpose. Lists templates.
- Parameters.
params?: { page?, page_size?, status?, extends?, value?, latest_only?, namespace? }. - Returns.
UseQueryResult<TemplateListResponse>wrappingclient.templates.listTemplates(params); always enabled. - Example.
useTemplates({ latest_only: true, status: 'active' })(src/hooks/use-templates.ts:8-22)
useTemplate(id, options?)
- Parameters.
id: string. - Returns.
UseQueryResult<Template>wrappingclient.templates.getTemplate(id); enabled!!id. (src/hooks/use-templates.ts:24-36)
useTemplateByValue(value, options?)
- Parameters.
value: string. - Returns.
UseQueryResult<Template>wrappingclient.templates.getTemplateByValue(value); enabled!!value. - Example.
useTemplateByValue('PATIENT_RECORD')(src/hooks/use-templates.ts:38-50)
Documents (read)
useDocuments(params?, options?)
- Parameters.
params?: DocumentQueryParams(type from@wip/client). - Returns.
UseQueryResult<DocumentListResponse>wrappingclient.documents.listDocuments(params); always enabled. (src/hooks/use-documents.ts:19-30)
useDocument(id, options?)
- Parameters.
id: string. - Returns.
UseQueryResult<Document>wrappingclient.documents.getDocument(id); enabled!!id. (src/hooks/use-documents.ts:32-44)
useQueryDocuments(query, options?)
- Parameters.
query: DocumentQueryRequest. - Returns.
UseQueryResult<DocumentListResponse>wrappingclient.documents.queryDocuments(query). - Enabled.
!!(query.template_id || (query.filters && query.filters.length > 0))— a query with neither atemplate_idnor filters never fires. - Example.
(useQueryDocuments({ template_id: 'PATIENT_RECORD', filters: [{ field: 'data.country', operator: 'eq', value: 'US' }], sort_by: 'created_at', sort_order: 'desc', })src/hooks/use-documents.ts:46-58; example filter shape fromREADME.md:263-271)
useTableView(templateId, params?, options?)
- Purpose. Spreadsheet-style projection of a template's documents — column definitions plus one row per document, the same projection the CSV export uses.
- Parameters.
templateId: string;params?: TableViewParams. - Returns.
UseQueryResult<TableViewResponse>wrappingclient.documents.getTableView(templateId, params); enabled!!templateId. (src/hooks/use-documents.ts:60-84)
useDocumentVersions(id, options?)
- Parameters.
id: string. - Returns.
UseQueryResult<DocumentVersionResponse>wrappingclient.documents.getVersions(id); enabled!!id. (src/hooks/use-documents.ts:86-98)
useDocumentRelationships(documentId, params?, options?)
- Purpose. Lists relationship documents (templates with
usage: 'relationship') incident to a document, incoming or outgoing. - Parameters.
documentId: string;params?: DocumentRelationshipsParams. - Returns.
UseQueryResult<DocumentListResponse>wrappingclient.documents.getDocumentRelationships(documentId, params); enabled!!documentId. (src/hooks/use-documents.ts:100-123)
useTraverseDocuments(documentId, params?, options?)
- Purpose. BFS traversal of the relationship graph from a document.
- Parameters.
documentId: string;params?: DocumentTraverseParams. - Returns.
UseQueryResult<DocumentTraverseResponse>wrappingclient.documents.traverseDocuments(documentId, params); enabled!!documentId. Server-side capped atdepth=10,max_nodes=1000— checkdata.truncatedwhen a cap fired. (src/hooks/use-documents.ts:125-147)
Files (read)
useFiles(params?, options?)
- Parameters.
params?: FileQueryParams. - Returns.
UseQueryResult<FileListResponse>wrappingclient.files.listFiles(params); always enabled. (src/hooks/use-files.ts:8-19)
useFile(id, options?)
- Parameters.
id: string. - Returns.
UseQueryResult<FileEntity>wrappingclient.files.getFile(id); enabled!!id. (src/hooks/use-files.ts:21-33)
useDownloadUrl(id, options?)
- Parameters.
id: string. - Returns.
UseQueryResult<FileDownloadResponse>wrappingclient.files.getDownloadUrl(id); enabled!!id.staleTimeis a local60 * 1000literal, notSTALE_TIMES.files— pre-signed URLs expire. (src/hooks/use-files.ts:35-47)
Registry & namespaces (read)
useNamespaces(options?)
- Parameters. None besides
options?. - Returns.
UseQueryResult<Namespace[]>wrappingclient.registry.listNamespaces(); always enabled. (src/hooks/use-registry.ts:8-18)
useRegistrySearch(params, options?)
- Parameters.
params: RegistrySearchParams— required, no default. - Returns.
UseQueryResult<RegistrySearchResponse>wrappingclient.registry.unifiedSearch(params); enabled!!params.q. (src/hooks/use-registry.ts:20-32)
Reporting & batch sync (read)
useReportQuery(sql, params?, options?)
- Purpose. Read-only SQL against the PostgreSQL reporting layer for cross-entity aggregation/analytics; eventually consistent, not for authoritative state.
- Parameters.
sql: string;params?: unknown[];options?extends query options withmaxRows?,timeoutSeconds?,namespace?. - Returns.
UseQueryResult<ReportQueryResult>wrappingclient.reporting.runQuery(sql, params, { max_rows, timeout_seconds, namespace });staleTimefixed at a local10_000ms constant (REPORT_QUERY_STALE_TIME), not fromSTALE_TIMES. - Gotcha (from source JSDoc). Unqualified table names resolve inside one namespace's PG schema (
"<ns>"."doc_<value>"); for cross-namespace SQL, omitnamespaceand schema-qualify each table yourself. The cache key includesnamespaceexplicitly (wipKeys.reporting.query(sql, params, namespace)). - Example.
useReportQuery('SELECT location, COUNT(*) FROM aa_event GROUP BY location')(src/hooks/use-reporting.ts:18-72)
useIntegrityCheck(params?, options?)
- Parameters.
params?: { template_status?, document_status?, template_limit?, document_limit?, check_term_refs?, recent_first? }. - Returns.
UseQueryResult<IntegrityCheckResult>wrappingclient.reporting.getIntegrityCheck(params); always enabled. (src/hooks/use-reporting.ts:74-92)
useActivity(params?, options?)
- Parameters.
params?: { types?: string; limit?: number }. - Returns.
UseQueryResult<ActivityResponse>wrappingclient.reporting.getRecentActivity(params); always enabled. (src/hooks/use-reporting.ts:94-105)
useSyncStatus(options?)
- Purpose. Sync-service status — running state, NATS/Postgres connections, events processed/failed, tables managed; usable as the "first-time setup" CTA signal (
tables_managed=0but documents exist). - Returns.
UseQueryResult<SyncStatus>wrappingclient.reporting.getSyncStatus(); always enabled. (src/hooks/use-reporting.ts:118-137)
useBatchJobs(options?)
- Purpose. Lists all batch sync jobs. In-memory server-side — a reporting-sync restart clears the list.
- Returns.
UseQueryResult<BatchSyncJob[]>wrappingclient.reporting.listBatchJobs();staleTime: 0— always refetches; passrefetchIntervalfor live polling. (src/hooks/use-reporting.ts:149-159)
useBatchJob(jobId, options?)
- Parameters.
jobId: string. - Returns.
UseQueryResult<BatchSyncJob>wrappingclient.reporting.getBatchJob(jobId);staleTime: 0; enabledBoolean(jobId). (src/hooks/use-reporting.ts:165-177)
Reporting & batch sync (write)
useTriggerBatchSyncAll(options?)
- Purpose. Triggers a batch sync for every template with
sync_enabled=true. - Parameters (mutate variable).
{ force?: boolean; page_size?: number } | void. - Returns.
UseMutationResult<BatchSyncResponse[], Error, BatchSyncAllVars>wrappingclient.reporting.triggerBatchSyncAll(vars). - Invalidates.
wipKeys.reporting.batchJobs(). (src/hooks/use-reporting.ts:182-196)
useTriggerBatchSync(options?)
- Parameters.
{ template_value: string; force?: boolean; page_size?: number }. - Returns.
UseMutationResult<BatchSyncResponse, Error, BatchSyncVars>wrappingclient.reporting.triggerBatchSync(template_value, { force, page_size }). - Invalidates.
wipKeys.reporting.batchJobs(). (src/hooks/use-reporting.ts:204-220)
useTriggerTerminologySync(options?) / useTriggerTermSync(options?) / useTriggerTermRelationSync(options?)
- Parameters.
{ namespace: string; pageSize?: number }(EntitySyncVars), for all three. - Returns.
UseMutationResult<BatchEntitySyncResult, Error, EntitySyncVars>, wrappingclient.reporting.triggerTerminologySync/triggerTermSync/triggerTermRelationSyncrespectively — synchronous server-side sync, not queued. - Invalidates. None — no cache invalidation call in any of the three (backend-only sync).
(
src/hooks/use-reporting.ts:225-258)
useCancelBatchJob(options?)
- Parameters.
jobId: string. - Returns.
UseMutationResult<BatchJobCancelResult, Error, string>wrappingclient.reporting.cancelBatchJob(jobId). - Invalidates.
wipKeys.reporting.batchJobs()andwipKeys.reporting.batchJob(jobId). (src/hooks/use-reporting.ts:261-277)
useClearCompletedJobs(options?)
- Parameters. None (
void). - Returns.
UseMutationResult<BatchJobsCleared, Error, void>wrappingclient.reporting.clearCompletedJobs(). - Invalidates.
wipKeys.reporting.batchJobs(). (src/hooks/use-reporting.ts:280-294)
Terminology mutations
useCreateTerminology(options?)
- Parameters.
CreateTerminologyRequest. - Returns.
UseMutationResult<BulkResultItem, Error, CreateTerminologyRequest>wrappingclient.defStore.createTerminology(data). - Throws / errors.
WipBulkItemErrorwhen the resolved item'sstatus === 'error'— WIP's bulk-first API always returns HTTP 200; see Gotchas. - Invalidates.
wipKeys.terminologies.all. (src/hooks/use-mutations.ts:36-50)
useUpdateTerminology(options?)
- Parameters.
{ id: string; data: UpdateTerminologyRequest }. - Returns.
UseMutationResult<BulkResultItem, ...>wrappingclient.defStore.updateTerminology(id, data). InvalidateswipKeys.terminologies.all. (src/hooks/use-mutations.ts:52-67)
useDeleteTerminology(options?)
- Parameters.
id: string. - Returns.
UseMutationResult<BulkResultItem, Error, string>wrappingclient.defStore.deleteTerminology(id). InvalidateswipKeys.terminologies.all. (src/hooks/use-mutations.ts:69-83)
Term mutations
useCreateTerm(terminologyId, namespace, options?)
- Parameters.
terminologyId: string,namespace: string— both hook arguments, not part of the mutate payload; mutate variable isCreateTermRequest. - Returns.
UseMutationResult<BulkResultItem, Error, CreateTermRequest>wrappingclient.defStore.createTerm(terminologyId, data, { namespace }). - Invalidates.
wipKeys.terms.allandwipKeys.terminologies.detail(terminologyId)(parent's term count changed). (src/hooks/use-mutations.ts:89-106)
useUpdateTerm(options?)
- Parameters.
{ termId: string; data: UpdateTermRequest }. Returns. wrapsclient.defStore.updateTerm(termId, data). Invalidates.wipKeys.terms.all. (src/hooks/use-mutations.ts:108-123)
useDeprecateTerm(options?)
- Parameters.
{ termId: string; data: DeprecateTermRequest }. Returns. wrapsclient.defStore.deprecateTerm(termId, data). Invalidates.wipKeys.terms.all. (src/hooks/use-mutations.ts:125-140)
useDeleteTerm(terminologyId, options?)
- Parameters.
terminologyId: string(hook argument); mutate variabletermId: string. - Returns. wraps
client.defStore.deleteTerm(termId). Invalidates.wipKeys.terms.allandwipKeys.terminologies.detail(terminologyId). (src/hooks/use-mutations.ts:142-158)
Template mutations
useCreateTemplate(options?)
- Parameters.
CreateTemplateRequest. Returns. wrapsclient.templates.createTemplate(data). Invalidates.wipKeys.templates.all. (src/hooks/use-mutations.ts:164-178)
useUpdateTemplate(options?)
- Parameters.
{ id: string; data: UpdateTemplateRequest }. Returns. wrapsclient.templates.updateTemplate(id, data). Invalidates.wipKeys.templates.all. (src/hooks/use-mutations.ts:180-195)
useDeleteTemplate(options?)
- Parameters.
{ id: string; updatedBy?: string; version?: number; force?: boolean; hardDelete?: boolean }. Returns. wrapsclient.templates.deleteTemplate(id, opts). Invalidates.wipKeys.templates.all. - Note.
hardDeleteis exposed as a flag on this hook; the elevated-permission check itself lives server-side (template-store), out of this doc's scope. (src/hooks/use-mutations.ts:197-212)
useActivateTemplate(options?)
- Parameters.
{ id: string; namespace: string; dry_run?: boolean }. Returns.UseMutationResult<ActivateTemplateResponse, ...>wrappingclient.templates.activateTemplate(id, opts). Invalidates.wipKeys.templates.all. (src/hooks/use-mutations.ts:214-229)
useReactivateTemplate(options?)
- Parameters.
{ id: string; version: number; namespace: string }. Returns.UseMutationResult<Template, ...>wrappingclient.templates.reactivateTemplate(id, version, opts). Invalidates.wipKeys.templates.all. (src/hooks/use-mutations.ts:231-246)
useAddEdgeTypeEndpoints(options?)
- Parameters.
{ id: string; namespace: string; addSourceTemplates?: string[]; addTargetTemplates?: string[] }. Returns.UseMutationResult<Template, ...>wrappingclient.templates.addEdgeTypeEndpoints(id, opts). Invalidates.wipKeys.templates.all. - Note. Option names are additive only (
add...) — consistent with edge-type endpoints being immutable-by-removal after creation. (src/hooks/use-mutations.ts:248-270)
Document mutations
useCreateDocument(options?)
- Parameters.
CreateDocumentRequest. Returns.UseMutationResult<BulkResultItem, ...>wrappingclient.documents.createDocument(data). Invalidates.wipKeys.documents.all. (src/hooks/use-mutations.ts:276-290)
useCreateDocuments(options?)
- Parameters.
CreateDocumentRequest[]. Returns.UseMutationResult<BulkResponse, ...>— the full bulk envelope, no per-item throw. Invalidates.wipKeys.documents.all. (src/hooks/use-mutations.ts:292-306)
useUpdateDocument(options?)
- Purpose. Applies an RFC 7396 JSON Merge Patch to a document.
- Parameters.
{ documentId: string; patch: Record<string, unknown>; ifMatch?: number }. - Returns.
UseMutationResult<BulkResultItem, ...>wrappingclient.documents.updateDocument(documentId, patch, { ifMatch }). - Throws / errors.
WipBulkItemError(witherrorCodepopulated) on per-item failure (source JSDoc,use-mutations.ts:308-314). - Invalidates.
wipKeys.documents.detail(documentId),wipKeys.documents.versions(documentId),wipKeys.documents.all. (src/hooks/use-mutations.ts:315-340)
useUpdateDocuments(options?)
- Purpose. Bulk variant of
useUpdateDocument— resolves with the rawBulkResponseso per-itemerror_codecan be inspected without a thrown exception interrupting the batch. - Parameters.
PatchDocumentRequest[]. Returns.UseMutationResult<BulkResponse, ...>wrappingclient.documents.updateDocuments(items). Invalidates.wipKeys.documents.all. (src/hooks/use-mutations.ts:342-361)
useDeleteDocument(options?)
- Parameters.
{ id: string; updatedBy?: string }. Returns. wrapsclient.documents.deleteDocument(id, { updatedBy }). Invalidates.wipKeys.documents.all. (src/hooks/use-mutations.ts:363-377)
useArchiveDocument(options?)
- Parameters.
{ id: string; archivedBy?: string }. Returns. wrapsclient.documents.archiveDocument(id, archivedBy). Invalidates.wipKeys.documents.all. (src/hooks/use-mutations.ts:379-393)
File mutations
useUploadFile(options?)
- Parameters.
{ file: File | Blob; filename?: string; metadata?: FileUploadMetadata; namespace?: string }. - Returns.
UseMutationResult<FileEntity, ...>— not aBulkResultItem(single-entity upload). Wrapsclient.files.uploadFile(file, filename, metadata, namespace). Invalidates.wipKeys.files.all. (src/hooks/use-mutations.ts:399-414)
useUpdateFileMetadata(options?)
- Parameters.
{ fileId: string; data: UpdateFileMetadataRequest }. Returns. wrapsclient.files.updateMetadata(fileId, data). Invalidates.wipKeys.files.all. (src/hooks/use-mutations.ts:416-431)
useDeleteFile(options?)
- Parameters.
fileId: string. Returns. wrapsclient.files.deleteFile(fileId). Invalidates.wipKeys.files.all. (src/hooks/use-mutations.ts:433-447)
useDeleteFiles(options?)
- Parameters.
string[]. Returns.UseMutationResult<BulkResponse, ...>wrappingclient.files.deleteFiles(fileIds). Invalidates.wipKeys.files.all. (src/hooks/use-mutations.ts:449-463)
useHardDeleteFile(options?)
- Purpose. Permanent, unrecoverable delete.
- Parameters.
fileId: string. Returns.UseMutationResult<void, Error, string>wrappingclient.files.hardDeleteFile(fileId). Invalidates.wipKeys.files.all. (src/hooks/use-mutations.ts:465-479)
Term-relation mutations
Term-relations are the term-ontology edges (
is_a,part_of, ...) — a distinct concept from the document-to-document relationship documents surfaced byuseDocumentRelationships/useTraverseDocumentsabove. Per source comment, the platform renamed this surface in WIP commit2eeb872;@wip/reactpicked up the rename with no backward-compat alias (src/hooks/use-mutations.ts:484-491).
useCreateTermRelations(options?)
- Parameters.
{ items: CreateTermRelationRequest[]; namespace: string }. Returns.UseMutationResult<BulkResponse, ...>wrappingclient.defStore.createTermRelations(items, namespace). Invalidates.wipKeys.terms.all. (src/hooks/use-mutations.ts:492-507)
useDeleteTermRelations(options?)
- Parameters.
{ items: DeleteTermRelationRequest[]; namespace: string }. Returns. wrapsclient.defStore.deleteTermRelations(items, namespace). Invalidates.wipKeys.terms.all. (src/hooks/use-mutations.ts:509-524)
Namespace mutations
useCreateNamespace(options?)
- Parameters.
CreateNamespaceRequest. Returns.UseMutationResult<Namespace, ...>— not aBulkResultItem. Wrapsclient.registry.createNamespace(data). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:530-544)
useUpdateNamespace(options?)
- Parameters.
{ prefix: string; data: UpdateNamespaceRequest }. Returns. wrapsclient.registry.updateNamespace(prefix, data). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:546-561)
useArchiveNamespace(options?)
- Parameters.
{ prefix: string; archivedBy?: string }. Returns. wrapsclient.registry.archiveNamespace(prefix, archivedBy). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:563-578)
useRestoreNamespace(options?)
- Parameters.
{ prefix: string; restoredBy?: string }. Returns. wrapsclient.registry.restoreNamespace(prefix, restoredBy). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:580-595)
useDeleteNamespace(options?)
- Parameters.
{ prefix: string; deletedBy?: string }. Returns.UseMutationResult<void, ...>. Wrapsclient.registry.deleteNamespace(prefix, deletedBy). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:597-612)
Registry-entry mutations
useAddSynonym(options?)
- Parameters.
AddSynonymRequest. - Returns.
UseMutationResult<{ status: string; registry_id?: string; error?: string }, ...>— the result carries its ownstatus/errorfields rather than throwing on a failed add. Wrapsclient.registry.addSynonym(data). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:618-632)
useRemoveSynonym(options?)
- Parameters.
RemoveSynonymRequest. Returns. same{ status, registry_id?, error? }shape. Wrapsclient.registry.removeSynonym(data). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:634-648)
useMergeEntries(options?)
- Parameters.
MergeRequest. Returns.{ status: string; preferred_id?: string; deprecated_id?: string; error?: string }. Wrapsclient.registry.mergeEntries(data). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:650-664)
useDeactivateEntry(options?)
- Parameters.
{ entryId: string; updatedBy?: string }. Returns.{ status: string }. Wrapsclient.registry.deactivateEntry(entryId, updatedBy). Invalidates.wipKeys.registry.all. (src/hooks/use-mutations.ts:666-681)
Specialized hooks
useFormSchema(templateValue, options?)
- Purpose. Fetches a template by value and converts it to a framework-agnostic form-field schema in one hook.
- Parameters.
templateValue: string. - Returns.
UseQueryResult<FormField[]>— combinesclient.templates.getTemplateByValue(templateValue)thentemplateToFormSchema(template)(both from@wip/client).staleTime: STALE_TIMES.templates. Enabled!!templateValue. Query key:[...wipKeys.templates.byValue(value), 'form-schema']. FormFieldproperties (perREADME.md:542, describing an@wip/client-defined type):name,label,inputType(text/number/integer/checkbox/date/datetime/select/search/file/group/list),required,defaultValue,isIdentity,terminologyCode,referenceType,targetTemplates,targetTerminologies,fileConfig,validation(pattern, minLength, maxLength, minimum, maximum, enum),semanticType,children,arrayItemType. (src/hooks/use-form-schema.ts:1-26)
useBulkImport(options)
- Purpose. Progress-tracked batch import, wrapping
bulkImport()from@wip/clientin a mutation hook. - Parameters.
{ writeFn: (batch: T[]) => Promise<BulkResponse>; batchSize?: number; continueOnError?: boolean; invalidateKeys?: readonly unknown[] }.⚠ GAP:
batchSize/continueOnErrorare forwarded tobulkImport()exactly as given (src/hooks/use-bulk-import.ts:19-23) — this hook does not itself apply a default.README.md:594-595documents defaults of100/false, but those, if enforced, live inside@wip/client'sbulkImport(), which is outside this doc'ssource_scope. Verify the literal default values against the@wip/clientlibrary doc before relying on them. - Returns.
UseMutationResult<BulkResponse, Error, T[]>extended withprogress: BulkImportProgress | null({ processed, total, succeeded, failed }) andreset()(clears progress and resets the mutation).invalidateKeysdefaults towipKeys.allwhen omitted (src/hooks/use-bulk-import.ts:25). Progress is cleared 2s after the mutation settles (setTimeout,use-bulk-import.ts:28-31). - Example.
(const { mutate, progress } = useBulkImport({ writeFn: (batch) => client.defStore.createTerms(terminologyId, batch), batchSize: 100, continueOnError: true, }) mutate(terms)src/hooks/use-bulk-import.ts:1-45)
Usage patterns
1. Provider setup, then a read + a write. Wrap the tree with both QueryClientProvider (TanStack) and WipProvider; useWipClient() throws outside WipProvider.
const queryClient = new QueryClient()
const wipClient = createWipClient({ baseUrl: '', auth: { type: 'api-key', key: 'dev_master_key_for_testing' } })
function App() {
return (
<QueryClientProvider client={queryClient}>
<WipProvider client={wipClient}>
<MyComponent />
</WipProvider>
</QueryClientProvider>
)
}
function MyComponent() {
const { data } = useTerminologies({ status: 'active' })
const createDoc = useCreateDocument()
return (
<button onClick={() => createDoc.mutate({ template_id: 'TPL-1', data: { name: 'Test' } })}>
Create Document
</button>
)
}
(README.md:60-105)
2. Template-driven document form. useFormSchema + useTemplateByValue + useCreateDocument — the canonical flow for rendering a form from a template and writing back a matching document.
function DocumentForm({ templateValue }: { templateValue: string }) {
const { data: fields } = useFormSchema(templateValue)
const { data: template } = useTemplateByValue(templateValue)
const createDoc = useCreateDocument()
const handleSubmit = (formData: Record<string, unknown>) => {
if (!template) return
createDoc.mutate({ template_id: template.template_id, data: formData })
}
if (!fields) return <div>Loading...</div>
return <DynamicForm fields={fields} onSubmit={handleSubmit} />
}
(README.md:761-782)
3. Bulk import with progress tracking. useBulkImport wraps any bulk writeFn (e.g. client.defStore.createTerms) with automatic batching and a live progress object.
const { mutate, isPending, progress } = useBulkImport({
writeFn: (batch) => client.defStore.createTerms(terminologyId, batch),
batchSize: 100,
continueOnError: true,
invalidateKeys: wipKeys.terms.all,
})
mutate(terms)
// progress.processed / progress.total / progress.succeeded / progress.failed
(README.md:552-589; hook mechanics from src/hooks/use-bulk-import.ts)
Gotchas
- Bulk-first, always HTTP 200. Single-item mutation hooks (
useCreateDocument,useCreateTerminology, etc.) resolve with aBulkResultItem; the underlying client throwsWipBulkItemErrorifstatus === "error", surfaced viamutation.error. Bulk mutation hooks (useCreateDocuments,useUpdateDocuments,useDeleteFiles,useCreateTermRelations,useDeleteTermRelations) resolve the fullBulkResponseand never throw per-item — you must checkresults[i].statusyourself. (README.md:21-38;use-mutations.ts:308-314JSDoc) - Peer dependencies are externalized, not bundled.
tsup.config.ts:12listsreact,react-dom,@tanstack/react-query,@wip/clientasexternal;package.jsonpeerDependenciespin@tanstack/react-query ^5.0.0,@wip/client *,react ^18.0.0 || ^19.0.0. Install them yourself. - Detail/dependent queries are disabled until their key argument is truthy (
enabled: !!idpattern acrossuseTerminology,useTerm,useTemplate,useDocument,useFile,useDownloadUrl,useTableView,useDocumentRelationships,useTraverseDocuments,useBatchJob) — safe for conditional rendering, butdatasilently staysundefinedrather than erroring if you forget the guard. - Not every hook uses
STALE_TIMES.useDownloadUrlhardcodes60_000ms locally (pre-signed URLs expire) anduseReportQueryhardcodes its own10_000ms constant — both intentionally override the domain default. useBatchJobs/useBatchJobsetstaleTime: 0(live in-memory job state on reporting-sync); passrefetchIntervalfor polling rather than relying on background refetch.wipKeys.reporting.query()bakesnamespaceinto the cache key — the same SQL against two namespaces is cached separately, because a reporting table is a per-namespace PG schema ("<ns>"."doc_<value>") (src/utils/keys.ts:59-63comment).WipFooter'svariantprop accepts'full'in its type, but the component renders identically for both values in this version — only thedata-wip-footer-variantattribute changes; distinct'full'rendering is "reserved for v1.5" (src/WipFooter.tsx:9comment).WipFooter's inline SVG carries explicitwidth/height(16/16) rather than relying only on theh-4Tailwind class, becausenode_modules/@wip/react/**is not in a consumer's Tailwindcontentconfig by default — without the intrinsic attributes, the SVG (viewBoxonly) fills its flex parent (src/WipFooter.tsx:42-49comment).useCreateTerm/useDeleteTermtaketerminologyId/namespaceas hook arguments, not part of themutate()payload — every other write hook takes all its variable data throughmutate().- Term-relations vs relationship documents are different concepts sharing the word "relation".
useCreateTermRelations/useDeleteTermRelationsoperate on the term-ontology graph (is_a,part_of);useDocumentRelationships/useTraverseDocumentswalk document-to-document relationship documents. No aliasing between the two surfaces (use-mutations.ts:484-491). - Registry-entry write hooks don't throw
WipBulkItemError.useAddSynonym,useRemoveSynonym,useMergeEntries,useDeactivateEntryresolve with a{ status, ... }object carrying its own optionalerrorfield — checkdata.status/data.error, not justmutation.error. useBulkImport's documentedbatchSize/continueOnErrordefaults live outside this package — see the ⚠ GAP underuseBulkImportin Core API.
See also
- @wip/client — the client library
@wip/reactwraps; every hook body callsclient.documents.*,client.templates.*,client.defStore.*,client.files.*,client.registry.*, orclient.reporting.*, and it is the source of every request/response type named above. - Document-Store API, Template-Store API, Def-Store API, Registry API, Reporting & Analytics — the REST surfaces reached through
[@wip/client](/docs/wip-client/)'s namespaces. - API Conventions — the bulk-first 200 /
BulkResponsecontract this library's mutation hooks surface directly. - PoNIFs — bulk-first's "200 isn't success" behavior is one of WIP's named non-intuitive features.
- Data Model Reference — the document/template/term shapes returned by the read hooks.
- Identity & the Registry — the natural-upsert semantics behind the create/update mutation hooks.
