Skip to content

VERIFY (temporary): #1038 + #1039 combined — do not merge - #1040

Closed
arkhindi12 wants to merge 3 commits into
conduit-protocol:mainfrom
arkhindi12:verify/combined
Closed

arkhindi12 wants to merge 3 commits into
conduit-protocol:mainfrom
arkhindi12:verify/combined

Conversation

@arkhindi12

Copy link
Copy Markdown
Contributor

Temporary draft PR used only to run the full CI matrix on the combined state of #1038 and #1039. The @streamfi/react job requires needs: [build], which is skipped while #1038's fixes are absent, so this is the only way to prove that job is green. Will be closed once verification completes.

zaguza added 3 commits November 4, 2026 17:53
`main` has not typechecked since 2026-10-31; CI has been red for 36
consecutive runs. `Lint & typecheck` and `Test` both fail, which skips
`Build`, `@streamfi/react`, and the bundle-size check.

Most of these are not type-only problems: several reference identifiers
that do not exist in scope, so the affected paths could not have executed
since they were merged. Two features that were merged were then silently
dropped by a later merge and are restored here from their original commits.

Typecheck: 23 errors -> 0
Tests:     28 failed / 1615 passed -> 0 failed / 1643 passed
Lint:      14 errors -> 13 (none introduced)

Runtime bugs fixed
------------------

* custom-fetch: `sendOnce` referenced `controller`, `timer`, `onCallerAbort`
  and `registration`, none of which existed in the file. The function could
  not compile, so every custom-fetch RPC request was dead code. Rebuilt the
  abort plumbing around a single AbortController so the caller's signal and
  the request timeout both cancel the in-flight fetch, and wired up
  `registration.timeoutMs`, which was stored but never read.

* soroban: `getLatestLedgerInfo` read `ledger.closedAt`, which does not exist.
  `getLatestLedger` returns `closeTime` (Unix seconds, as a string) — verified
  against a live testnet node and the JSON-RPC schema. `new Date(undefined)`
  yielded NaN, so the returned ledger timestamp was always NaN. Read the
  correct field and fall back to now when it is absent.

* client: `streams`, `governor` and `tokens` were declared `readonly` and then
  reassigned in `tryFailoverRpc()`. That did not compile, which means RPC
  failover could never run. Dropped `readonly` (the fields are genuinely
  mutable across failover) and guarded the index lookup against
  `noUncheckedIndexedAccess` widening it to `undefined`.

* with-retry: a server-supplied `Retry-After` was parsed and then destroyed by
  jitter — `Math.random() * delay` meant a 2s directive could retry after 0ms,
  immediately re-triggering the 429. Jitter now applies only to client-guessed
  backoff, since `Retry-After` is a directive rather than an estimate.

Features restored (merged, then dropped by a later merge)
---------------------------------------------------------

* `simulateBatch` / `BatchPayload` / `BatchSimulationSummary` (conduit-protocol#959): added by
  conduit-protocol#1034, removed when conduit-protocol#1026 rewrote `batch-tx.ts` from an older base.

* `StreamStatus` / `deriveStreamStatus`: added by 1662982, absent from
  `types/index.ts` on main. Restored verbatim.

Both were re-added from their original commits rather than reimplemented.

Overload fixes
--------------

`onStreamEvent` in both `events.ts` and `streams.ts` declared overloads whose
narrower single-parameter callbacks were incompatible with the implementation
signature under `strictFunctionTypes`. The implementation now takes the union
of the two callback shapes.

Test fixes
----------

* streams.test.ts: three call sites used a 55-character contract address, so
  token validation failed before reaching the duration/rate assertions. Swapped
  for the valid 56-character address already used elsewhere in the file.

* soroban-retry-after.test.ts: the no-header fallback test asserted an exact
  500ms boundary while the default `full` jitter picks a random delay in
  [0, 500]. Stubbed Math.random instead of changing the production default.

* relayer-stress.test.ts: the heartbeat tests awaited `connect()` while fake
  timers were installed, but the mock fires `onopen` via `setTimeout(0)` —
  which never ran, so `connect()` hung until the 5s test timeout. Now advance
  timers around the await. File runtime drops from 26s to 1s.

* freighter-wallet-adapter.test.ts / batch-tx-simulate-batch.test.ts: mock and
  fixture shapes adjusted for `exactOptionalPropertyTypes`.
`Lint & typecheck` runs lint before typecheck, so the 13 pre-existing lint
errors on main kept the job red even after the typecheck step passed.

Lint: 13 errors -> 0 (warnings unchanged at 54)

* unused imports dropped: `StrKey` (constants), `SorobanRpc` (errors — it only
  appeared in prose and the `SorobanRpcError` class name, never as a value),
  `TopUpEvent` / `ClawbackEvent` (events), `BatchWithdrawItem` (streams).

* client: `require("./soroban.js")` inside `tryFailoverRpc` replaced with a
  static import of `getConsecutiveTimeouts`. `soroban.ts` does not import
  `client.ts`, so there is no cycle to protect against with a lazy require.

* walletconnect: `(...args: any[])` -> `unknown[]` on the emitter shims. The
  listener bodies never touch the arguments.

* builder: `(builder as any)._startTime` -> a narrow
  `{ _startTime: number }` cast, keeping the accessed shape explicit.

* signer: the lazily imported `@ledgerhq` modules now carry a local
  `LedgerStrApp` interface matching `LedgerDevice`, plus an explicit guard on
  `TransportWebUSB.create`. The previous `any` was hiding the fact that a
  missing `create` would throw a TypeError rather than the intended
  `LedgerHardwareError`.

* indexer: `while (true)` -> `for (;;)` in `fetchAll`. Same semantics, but the
  loop no longer trips `no-constant-condition`.

* streams: the operation bag stays `Record<string, any>` with a justification
  comment and a scoped disable. A concrete type here would have to be a union
  of every operation variant, and each switch branch already narrows the keys
  it reads — tightening it to `unknown` produced 16 errors.

Verified: tsc --noEmit clean, eslint 0 errors, vitest 1643/1643, build ok.
…tests

`@streamfi/react` has never passed CI: the job is gated on `needs: [build]`,
and `build` has been skipped on every run since main stopped typechecking, so
these errors were never surfaced. Now that conduit-protocol#1038 unblocks the chain, the
package fails 20 type errors across 10 files and 40 of its 102 tests.

Typecheck: 20 errors -> 0
Tests:     40 failed / 62 passed -> 0 failed / 111 passed

`StreamFiProvider` — `rpcHeaders` was never implemented
-------------------------------------------------------

conduit-protocol#1009 (`a9d49a2`) added a call site without the feature:

```tsx
const customFetch = rpcHeaders && Object.keys(rpcHeaders).length > 0
  ? makeHeaderFetch(rpcHeaders)
  : undefined;
```

Neither name existed. `rpcHeaders` is not a member of `StreamFiProviderProps`
(only `config`, `defaultNetwork`, `children`, `queryClient`), and
`makeHeaderFetch` appears nowhere in the repository — `git log -S` finds only
that one commit. The feature was merged as a use of things that were never
added, so the package could not compile and `rpcHeaders` did nothing.

Implemented the intended behaviour rather than deleting the call site, since
`ConduitConfig.customFetch` is already the documented hook for exactly this
("request-tracing headers"):

* `makeHeaderFetch(headers, baseFetch?)` wraps `fetch` and merges `headers`
  into each request. A header set per request wins; `Headers` handles the
  case-insensitive merge. `undefined` values are skipped — `Headers` would
  otherwise stringify them into the literal `"undefined"`.
* `RpcHeaders = Record<string, string | undefined>` exported from the package.
* `rpcHeaders` added to `StreamFiProviderProps` and destructured, memoised on
  the prop so a new wrapper is not registered on every render
  (`registerCustomFetch` is keyed by `rpcUrl` and would be overwritten).

Covered by 9 new tests: header injection, caller-wins precedence, `Headers`
and tuple init forms, `undefined` values, omitted `init`, and three provider
cases (headers forwarded, no headers, empty object).

`rootDir` violations
--------------------

`useCircuitState` and `useTransactionHistory` imported across the package
boundary into the SDK's source tree (`../../../../src/...`), which `tsc`
refuses to emit outside `rootDir`. They now import the package's public
surface: `@conduit-protocol/sdk` and `@conduit-protocol/sdk/dashboard`.

The circuit test had the same import, which mattered beyond `rootDir`: the
hook resolved the package (→ `dist/`) while the test resolved `src/`, creating
two separate circuit registries, so `recordFailure` never affected the state
the hook read. Aligned the test with the hook.

Stale SDK signatures
--------------------

* `useStreamsByRecipient` / `useStreamsBySender` treated
  `factory.streamsBySender()` as `bigint[]`; it returns
  `{ ids, hasMore }`. They also re-derived `hasMore` from `ids.length === limit`
  while the SDK already computes it against the *clamped* limit — now uses the
  SDK's value.
* `useCancelStream`: `CancelStreamFn` claimed `Promise<string>`, but the
  documented behaviour is "opens the in-app confirmation flow; does not
  contact the wallet", and both paths return `undefined`. Corrected to
  `Promise<void>`; `confirmCancel` remains the call that yields a hash.

Smaller fixes
-------------

* `useTransferStreamRecipient`: `useState` used but not imported.
* `useGovernorConfig` / `useGovernorProposals`: optional result and option
  fields did not admit `undefined` under `exactOptionalPropertyTypes`.
* `useTransactionHistory`: `walletAddress: undefined` spread conditionally
  instead of passed explicitly.
* `useStreamNotes`: `noUncheckedIndexedAccess` — guard the key/value pair
  before indexing.

Test fixes
----------

* Seven files mocked `@conduit-protocol/sdk` with only `ConduitClient`, so
  every render threw "No SUPPORTED_NETWORKS export". The mocks now stub what
  `StreamFiProvider` reads at module scope.
* `useStreamCountdown`: the hook polls on `requestAnimationFrame`, and jsdom
  quantises frames to ~16.67ms, so `advanceTimersByTime(1000)` lands at
  ~983ms — one frame short of the boundary. Advancing by a frame extra makes
  the tests exercise the hook rather than the frame scheduler; the two
  `progressFraction` equality checks became `toBeCloseTo`.
* `issue-989`: the test awaited `resume()` against a never-resolving `get`,
  but `resume()` settles only after the post-submit refresh. It asserts
  submission, so it now waits for the mutation call instead of the promise.

Verified: `tsc --noEmit` clean, 111/111 tests, `tsup` build succeeds. SDK
suite still 1643/1643 and typechecks clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant