registrystack / registrystack/registry-stack

Node client ergonomics: transition by name, route selector, envelope helpers, action input translation

Open
#1,021 0 comments 0 reactions 0 assignees View on GitHub
agent-ready area:breg area:casework criticality:p3 enhancement javascript rust
Dominant language
Rust
Stars
2
Forks
0
Avg merge
2h 57m
Merged PRs (30d)
128

Description

## What Happened

Three independent consumers of `@registrystack/client` (the OpenFn adaptor in `registrystack/openfn-language-registry-stack`, a downstream acceptance harness, and its app server) each rebuilt the same convenience layer over the typed facade. The structured calls exist and are fine; what is missing is composition. Verified against 0.30.0:

1. **No action by name.** Executing one lifecycle action from (route, id, operation) means `getRecord`, `selectLifecycle`, `lifecycleActions`, filter by `operation` and `stage`, `executeLifecycleAction`. The action already carries its precondition internally, so a composite is pure composition of public calls. The adaptor's `executeLifecycleAction` wrapper is exactly this code.
2. **No route selector.** `BRegMetadata` has `selectCreate`, `selectPatch`, `selectLifecycle`, `selectAttachments`, `selectImmediateAction`, `selectTombstone`, `selectBatch`, but nothing returns the record route for an entity and profile. Consumers filter `operations` and regex `path`.
3. **Envelope shapes differ by call path.** Single reads nest the record under `data`; list items are bare records; lifecycle and immediate-action receipts are minimal shapes without `domainData`. Consumers hedge with `a?.data?.x ?? a.x`. This is the wire contract and should not change; the client should own the unwrapping.
4. **`invokeAction` takes only wire `apiName`s.** Translating declared input ids, wiring `referenceInputs`, and gating on `targetConditionsPath` derive from the same descriptor the client already validates against.
5. **Casework envelopes.** List and single read return a bare `WorkItem`; claim, release and decide return `MutationResponse { item, attempt }`; the hosted decision returns `HostedTerminalResult` without `actions`. Same remedy: a helper, not a wire change.

## Expected Behavior

Additive, client-only methods, no server change, no new authority:

- `transition(authority, route, id, operation, idempotencyKey, { stage?, format? })` in the BReg namespace, returning the lifecycle receipt and the refetched record.
- `selectRoute(entityIdentifier, expectedProfile)` on `BRegMetadata`.
- `recordOf(value)` for BReg and `itemOf(outcome)` for Casework, returning the record or item from any of the documented shapes.
- `invokeAction` accepting declared input ids as well as `apiName`s, with the reference-input subset and target-condition fetch handled inside.
- Tests: multi-stage disambiguation (same operation, two stages on one record), and a regression test that pins the three BReg envelope shapes and the three Casework shapes as the intended contract.

## Environment

`@registrystack/client` 0.30.0.

Triage: later. Reference consumer for the shape of these helpers is the OpenFn adaptor, which is the one consumer that does not duplicate wrappers. Related: #854 (field-addressed errors on the typed client).

Contributor guide

Open the contributing guide

Research direction

Start by locating the @registrystack/client BReg and Casework namespaces, BRegMetadata, and the existing OpenFn adaptor wrappers referenced in the issue. Compare the documented envelope shapes and action descriptors, then add the listed client-only helpers and tests for multi-stage disambiguation and all six envelope forms; done means the helpers compose existing public calls without server changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, typescript
Domain
api, developer-experience, testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.