registrystack / registrystack/registry-stack
Node client ergonomics: transition by name, route selector, envelope helpers, action input translation
- 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
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