feat: add Ripple Custody full api support - #38
Conversation
| for (const [key, value] of Object.entries(query)) { | ||
| if (value !== undefined) { | ||
| // Custody query params are scalars; skip null/undefined and non-scalars. | ||
| if (value !== undefined && value !== null && typeof value !== 'object') { |
There was a problem hiding this comment.
Are arrays meant to be included or not? In line 24, Query = Record<string, unknown> so an array is allowed but this line (if (value !== undefined && value !== null && typeof value !== 'object') {) would drop any array.
| targetDomainId: options.domainId, | ||
| id: intentId, | ||
|
|
||
| return buildProposeEnvelope(intentSigner, { |
There was a problem hiding this comment.
If someone passes their own id but no matching options.id would a random id be generated for the envelope id? In that case the 2 values would diverge which goes against the added comment here. Is this divergence ok?
| const entries = [] | ||
| let skipped = 0 | ||
| for (const [path, item] of Object.entries(spec.paths ?? {})) { | ||
| for (const method of METHODS) { | ||
| const op = item[method] | ||
| if (op === undefined) continue | ||
| // openapi-typescript keys the generated `operations` off operationId, so an | ||
| // operation without one is neither typed nor routable — skip it and report | ||
| // the count rather than emitting an unusable entry. | ||
| if (op.operationId === undefined) { | ||
| skipped += 1 | ||
| continue | ||
| } | ||
| entries.push([op.operationId, method.toUpperCase(), path]) | ||
| } | ||
| } |
There was a problem hiding this comment.
Is there a risk of a repeated operationIds? Looks like the generator tracks missing operationIds but has no check for duplicates. A duplicate operationId would produce duplicate CUSTODY_ROUTES object key
High Level Overview of Change
custody.api.call— a typed, unsigned HTTP passthrough to any Ripple Custody v1 endpoint the SDK doesn't model as a first-class vertical.custody.api.propose— the signed governed-intent counterpart; wraps any intent payload in aCore_Proposeenvelope, signs it, and submits it (e.g. releasing quarantined transfers) without a dedicated method.Context of Change
api.callmirrors the existing Palisade passthrough (generated route map +operationstypes).api.proposereuses the existingIntentSigner; the envelope build/sign logic is extracted into a sharedbuildProposeEnvelopethat the native transaction path now also uses (no duplication, behavior unchanged).Type of Change
Test Plan
custody-apisuite covering call routing/path-interpolation and propose envelope/signing/overrides; full unit tier green.api.callreads (getMe,getAccounts),api.proposesigned-envelope acceptance, and a non-mutatingv0_ReleaseQuarantinedTransfersdry-run that validates the payload shape.typecheck,lint,format, and the dual ESM+CJSbuildall pass.