Management mutations and queries
UsePersistedOperations registers six fields on the schema for browsing and editing persisted operations, all under the operations.persistedOperations namespace. This matches the layout for every other Trax management feature (operations.manifestGroups, operations.deadLetters, etc.). Every field calls IPersistedOperationsService, the same service the Trax dashboard's persisted-operations pages call, so both accept and refuse the same things.
These fields always bypass persisted-operation enforcement (PersistedOperationEnforcementMiddleware, in the HotChocolate execution pipeline), because persisting them by id would be a chicken-and-egg. They are protected by the operations namespace's authorization posture: GateOperations(...), the builder's RequireAuthorization(), or an explicit AllowAnonymousOperations(). A host that exposes the namespace with none of the three refuses to start.
Mutations
uploadPersistedOperation
Insert or update an operation. Runs schema validation, requires exactly one operation in the document, then runs the shape-diff guardrail.
| Input field | Type | Required | Notes |
|---|---|---|---|
id | String! | yes | Build-time-stable identifier. Opaque string - no parse rule. The <name>_v<N> convention is recommended for readability. |
document | String! | yes | The GraphQL document the id resolves to. |
description | String | no | Operator-facing note recorded on the row. |
bypassShapeDiff | Boolean | no | When true, allows an edit that changes the response shape. Default false. |
version | Int | no | Operator-controlled metadata stored on the row. Not used for routing. Default 0. |
tenantKey | String | no | Tenant scope. Null targets the single-tenant row set. |
Payload: { success, operation, errors[] }.
deactivatePersistedOperation
Soft-delete; subsequent requests for the id resolve to null. The reason is required and recorded in the audit log.
| Input field | Type | Required |
|---|---|---|
id | String! | yes |
reason | String! | yes |
tenantKey | String | no |
restorePersistedOperation
Reactivate a deactivated row.
| Input field | Type | Required |
|---|---|---|
id | String! | yes |
tenantKey | String | no |
Queries
persistedOperations(filter, take, skip)
Paginated list, newest-updated first.
| Filter field | Type | Notes |
|---|---|---|
isActive | Boolean | When set, restricts to active or deactivated rows. |
tenantKey | String | Tenant scope. |
idStartsWith | String | Prefix filter on the id. |
Defaults: take is 50 when not given, zero or negative, or over 200 (a take of 500 returns 50 rows, not 200); skip is floored at 0.
persistedOperation(id, tenantKey)
Look up a single row. Returns null when missing.
persistedOperationHistory(id, tenantKey, take, skip)
Audit history for an operation, most-recent first. Same take / skip defaults as persistedOperations.
Error payload
All mutations return errors via the payload errors[] array; mutations never throw to the client. Each entry has:
| Field | Type | Notes |
|---|---|---|
code | String! | Stable code: PARSE_FAILED, SCHEMA_VALIDATION_FAILED, SHAPE_DIFF_VIOLATION, NOT_FOUND, INVALID_INPUT (an empty required field, or a document with other than one operation). |
message | String! | Human-readable message. |
locations | [Location!] | 1-based line / column. Present on parse errors and most schema-validation errors. |
path | [String!] | Response path. Present on some schema-validation errors. |
oldFingerprint | String | Present only on SHAPE_DIFF_VIOLATION. |
newFingerprint | String | Present only on SHAPE_DIFF_VIOLATION. |
See PersistedOperationException for the underlying exception types and how the codes map.
Example: upload
mutation Upload($input: UploadPersistedOperationInput!) {
operations {
persistedOperations {
uploadPersistedOperation(input: $input) {
success
operation { id shapeFingerprint isActive }
errors {
code
message
locations { line column }
oldFingerprint
newFingerprint
}
}
}
}
}{
"input": {
"id": "userProfile_v1",
"document": "query UserProfile($id: Int!) { user(id: $id) { id name email } }"
}
}