@arki/failure
For @arki/[email protected] · source CHANGELOG.md
0.2.0
Minor Changes
- 6601242: Breaking:
assertNeveris renamedunreachable, with no alias. Its default message no longer contains the value (it could leak a secret). The error code staysARKI_FAILURE_E004. New:invariant(condition, message?)asserts a condition and throwsFailureErrorARKI_FAILURE_E008; the message may be a function, built only on failure. - 2000a7e: Fix:
is,assertandensurenow answer about a value that is itself a failure. Before,is(failureValue, recordSchema)returnedfalsefor an invalid-input failure and threw for any other failure, becauseparsereturns a failure-valued output and a rejection the same way.@arki/failure/schemanow exportsexecuteSchema, which runs a schema once without unwrapping ({ value }or a failure), and the throwing channel is built on it.
0.1.0
Minor Changes
-
57313a4: Cursor encoding and decoding return canonical failures. Database pagination preserves those outcomes before building SQL or returning a page. Check codec results and declare the original cursor failures at RPC boundaries.
Failure lint rules now catch discarded callback returns, nested aggregate and iterator results, and blind acceptance through aliases or generic failure guards. Handle each outcome or forward it to its owner. Browser contract linting admits canonical failure definitions while keeping exception bridges in implementations. The exported lock conformance suite now checks each queued task's acquisition outcome before accepting its completion counts.
Dot acquires telemetry instruments inside guarded execution, so importing before SDK setup works and broken reporters cannot replace application outcomes.
-
232d3e8: Make failure the acyclic validation foundation. Schema parsing now returns exact typed validation failures, and failure revival returns typed protocol/validator defects instead of throwing. Add validated versioned JSON envelopes; retain legacy envelope reads while rejecting non-JSON data and changing output transforms. oRPC error maps validate output-only wire data.
Migrate consumers to check failures, propagate them through Journal event/write/replay and queue/mail operations, and use explicit exception bridges at foreign callbacks. Journal rejects invalid event entries before inserting them. See
@arki/failure/docs/upgrade-typed-validation.mdfor breaking API and stored-data migration details. -
3f6d39f: New
stoppable(value, stoppedBy?)builds aStoppable<Value, Failures>, so a partial-success function's return type is inferred: returnstoppable(value)when the work finished andstoppable(value, failure)when a failure stopped it, with noPromise<Stoppable<...>>annotation. It returns a shallow copy ofvalueand adds thestoppedBykey only when a failure is given. -
7f9b4bb: Fixes from the first real app that used
@arki/failure.@arki/failure/orpcis safe in the browser. It importsORPCErrorfrom@orpc/clientinstead of@orpc/server. It is the same class, so typed errors still reach the client asdefined: true. The optional peer dependency is now@orpc/client.- The lint config
configs.recommendedcovers TypeScript files only (**/*.{ts,tsx,mts,cts}). Themust-userule needs type information, so it no longer crashes on plain.jsfiles such aseslint.config.js. matchtakes nookhandler when the value can only be a failure, as on the client afterreviveRpcError. Then the handlers are one per failure code. Passingokthere is a type error, like any stale handler. A value that can be a success still needsok.- The README shows three patterns: a function that returns nothing or a failure, a partial success that keeps its progress with the failure inside the result, and how to choose a status (422 when an upstream service refuses us, 401 only for "not signed in", 503 when an upstream is down).
-
86efafc: New
Stoppable<Value, Failures>type for a partial success:Value & { readonly stoppedBy?: Failures }. Callers readresult.stoppedBydirectly, with no'stoppedBy' in resultcheck.orThrowRpc(@arki/failure/orpc) takes an optional third argument:orThrowRpc(value, errors, success)throws the failure as before, or returnssuccess. It is for a usecase that returns nothing or a failure, such asreturn orThrowRpc(await disconnect(id), errors, { success: true }). The two-argument form is unchanged. The README gains an "Adopting in an app" section, and "Choosing a status" now says to name an upstream HTTP statusupstreamStatus. -
d541df1: New package: typed expected failures with no wrapper and no runtime.
defineFailure(code, { data, message, status, remediation })names a failure once; calling the definition makes a frozen, branded failure value that a function returns like any other value, so its return type is inferred asValue | Failure<…>and the compiler makes every caller check. Message templates ('no post {id}') are checked against the data schema. AddsisFailure(a promise is a type error), exhaustivematch,recover(partial handling that removes the handled codes from the type),orThrowwithUnexpectedFailure,attemptfor code that throws,revivefor failures that went through JSON,findCausefor cause chains,partition,collect,assertNever,FailureOf,SuccessOf. Entries:@arki/failure/orpc(errorMap, andorThrowRpc(value, errors), where a failure the contract does not list is a compile error) and@arki/failure/eslint(themust-userule for discarded failures). The data schema is any Standard Schema; the core has no dependencies. -
f6a15d0: Breaking: failure data is typed as the schema's output, and the package builds on
@arki/schema.StandardSchemaV1andSchemaInputare no longer exported. Import them from@arki/schema.DataOf<Schema>is the schema's output type, the live value a failure carries. It was the input type, which disagreed withrevive, which passes the validated output to the definition.StandardSchemaV1is now the real spec type, stricter than the old local copy (validatemust return a Standard Schema result).- New dependency:
@arki/schema. FailureErrortakes an optional fourth argument,ErrorOptions.revivevalidates with@arki/schema'sparse.ARKI_FAILURE_E006andARKI_FAILURE_E007now carry theSchemaError/SchemaRunErrorascause. A validator that throws is no longer reported as bad data: itsSchemaRunError(ARKI_SCHEMA_E002) passes through.
-
4913009: Security: outside data can no longer pass as a failure.
isFailure(and@arki/log's failure check) now require the~failurebrand on the value's prototype and refuse it as an own property. Before, JSON such as{"~failure": true, "code": "x", "status": 500}from an API response, queue message or tool result counted as a failure, so boundaries skipped output schemas and answered with an attacker-chosen status or code. Real failures, revived ones and failures from a second copy of the package are still recognised. -
232d3e8: RPC error maps retain their original failure definitions for exact revival by another contract adapter. Use
rpcFailureDefinitionsto read these references; wire JSON remains unchanged.Add reusable browser-safe action contracts, server execution ownership and scoped OpenTelemetry helpers. Native RPC/HTTP adapters parse and encode once while sharing canonical failures and explicit exposure, principal and approval policies.
Breaking: HTTP boundaries and auth policies return typed canonical failure values; update callers that inspect legacy strings or expect thrown refusals. Retry ownership is explicit. MCP adds browser-safe contract annotations and callable tools that reuse the gateway's typed native client, preserve canonical failures, and enforce access, approval and result budgets. Hosts provide approval authority; the full MCP server and durable confirmation store remain separate work.
-
73ef41b:
failure/must-useis stricter. It now reports a discardedPromise.allorPromise.allSettledwhose items can be failures (the result is an array, so the old check missed it), andvoidis no longer an opt-out:void (await remove(id))is reported too. The only deliberate discard left is// eslint-disable-next-line failure/must-use -- <reason>. This can break lint in code that usedvoidto drop a failure.New rule
failure/no-blind-accept, on inconfigs.recommended. It reportsaccept(r)(orctx.accept(r)) whenrwas not checked by kind:if (isFailure(r)) accept(r)and an uncheckedaccept(r)are reported;if (OutOfStock.is(r)) accept(r)andif (OutOfStock.is(r) || Busy.is(r)) accept(r)pass. The checked call names are set withnames(default['accept']). This can break lint in code that accepts any failure. -
f796e5a: New in
@arki/failure/orpc:reviveRpcError(error, definitions). On the client, it turns a caughtORPCErrorwhose code is one of the definitions back into the live failure, and checks its data with the definition's schema likerevive. Any other error givesundefined, so you rethrow it. The result is typed from the definitions, so frontend code canmatchon failures the same way backend code does.
Patch Changes
-
f43d509: Docs standard: AGENTS.md, an agent guide, llms.txt, CHANGELOG, a tested example, a rewritten README, and
@fix/@verifynotes on every error code. The README no longer names a private app.no demo impact: documentation and doc-example changes only, runtime behaviour unchanged
0.0.0
Not published yet. The first release is 0.1.0, so there is nothing to upgrade from.