Skip to content

Conversation

@stalniy
Copy link
Contributor

@stalniy stalniy commented Jan 21, 2026

📝 Description

moves type patching on message type level by post-processing ts-proto output. This makes the transport layer and the SDK unaware of patching issues. Depends on #211

🔧 Purpose of the Change

  • New feature implementation
  • Bug fix
  • Documentation update
  • Code refactoring
  • Dependency upgrade
  • Other: [specify]

📌 Related Issues

  • Closes #ISSUE_NUMBER
  • References #ISSUE_NUMBER

✅ Checklist

  • I've updated relevant documentation
  • Code follows Akash Network's style guide
  • I've added/updated relevant unit tests
  • Dependencies have been properly updated
  • I agree and adhered to the Contribution Guidelines

📎 Notes for Reviewers

[Include any additional context, architectural decisions, or specific areas to focus on]

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

Walkthrough

Refactors type patching from runtime application into compile-time wrapping of generated proto exports; removes runtime patch infrastructure (applyPatches, ServiceClientOptions, requiresTypePatching) and updates generators, SDK/client factories, transports, and tests accordingly.

Changes

Cohort / File(s) Summary
Proto generation scripts
ts/script/fix-ts-proto-generated-types.ts, ts/script/protoc-gen-customtype-patches.ts, ts/script/protoc-gen-type-index-files.ts
Adds applyPatching() to wrap exported proto constants with patched(...) when matching patches; introduces PluginOptions.patchWholeTree, generates a PatchMessage helper/patched export, and removes prior custom field-patching flow from index generation.
SDK/client creation
ts/script/protoc-gen-sdk-object.ts, ts/src/sdk/client/createClientFactory.ts, ts/src/sdk/client/createServiceClient.ts, ts/src/sdk/client/createServiceClient.spec.ts
Removes options/ServiceClientOptions from client factories and SDK generator; strips per-method patching/encode-decode hooks and related tests; simplifies createSDK and service client signatures.
SDK initialization entrypoints
ts/src/sdk/chain/createChainNodeSDK.ts, ts/src/sdk/chain/createChainNodeWebSDK.ts
Removes passing of custom type patches into SDK creation; instantiates node and cosmos SDKs directly without patch configuration.
Type patching infra & types
ts/src/sdk/client/applyPatches.ts, ts/src/sdk/client/types.ts, ts/src/sdk/types.ts
Deletes runtime applyPatches implementation; moves/introduces TypePatches type into client/types.ts; removes SDKOptions export.
Transport API & implementations
ts/src/sdk/transport/types.ts, ts/src/sdk/transport/grpc/createGrpcTransport.ts, ts/src/sdk/transport/grpc/createGrpcTransport.spec.ts, ts/src/sdk/transport/tx/createTxTransport.ts
Removes requiresTypePatching from the Transport interface and from gRPC/Tx transport implementations and their tests.
Stream handling
ts/src/sdk/client/stream.ts
Makes transform optional in handleStreamResponse, returning the iterator directly when no transform provided.
Tests (generator)
ts/test/functional/protoc-gen-customtype-patches.spec.ts
Adds lifecycle cleanup, introduces PluginOptions usage, splits tests into patchWholeTree: true/false scenarios, and restructures config helper and snapshots.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • ygrishajev
  • baktun14

Poem

🐰
I wove the patches in the build-time light,
Wrapped exported types with gentle might,
No runtime hops, just tidy lines,
Generated helpers, neat designs,
A little rabbit's coding delight 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(ts): moves type patching on message type level' directly summarizes the main change—relocating type patching logic to the message type level via ts-proto post-processing.
Description check ✅ Passed The description includes context about moving type patching to the message level and notes a dependency on PR #211, though the 'Notes for Reviewers' section lacks specific details for focus areas.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/type-patching

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the C:ts label Jan 21, 2026
@stalniy stalniy force-pushed the refactor/type-patching branch from bf5a45b to 40974ac Compare January 21, 2026 11:12
@stalniy stalniy force-pushed the refactor/type-patching branch from 40974ac to 03525bc Compare January 21, 2026 11:13
@stalniy stalniy force-pushed the refactor/type-patching branch from 03525bc to e5d5284 Compare January 23, 2026 08:57
@stalniy stalniy marked this pull request as ready for review January 23, 2026 08:57
@stalniy stalniy requested a review from a team as a code owner January 23, 2026 08:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@ts/script/fix-ts-proto-generated-types.ts`:
- Around line 72-76: The computed importPath uses relativePath(filePath, ...)
which uses the file path instead of its directory, producing off-by-one imports;
change the call in fix-ts-proto-generated-types.ts to compute the relative path
from the file's directory (e.g. use path.dirname(filePath) or an equivalent to
get the directory) when building importPath for
`${ROOT_DIR}/generated/protos/patches/${prefix}PatchMessage.ts`, and ensure any
required path module is imported; keep references to namespace, prefix,
importPath, relativePath, filePath, symbolName, imports and exports when making
the change.

In `@ts/test/functional/protoc-gen-customtype-patches.spec.ts`:
- Around line 15-19: The cleanup check in the afterEach uses access(outputDir,
fsConst.W_OK).catch(() => false) but access resolves to undefined on success
(falsy), so the condition never runs; update the afterEach to correctly detect
successful access by either awaiting access in a try/catch (call
rmdir(outputDir, { recursive: true }) in the try when access succeeds) or change
the promise handling to await access(...).then(() => true).catch(() => false)
before the if; reference the afterEach, access, outputDir, rmdir, and
fsConst.W_OK identifiers when making the change.
🧹 Nitpick comments (2)
ts/src/sdk/client/createServiceClient.spec.ts (1)

329-334: Remove stale requiresTypePatching from mock transport.

The requiresTypePatching property does not exist in the Transport interface (which only defines unary and stream methods). This line should be removed to keep the mock aligned with the actual type definition.

♻️ Suggested fix
     return {
-      requiresTypePatching: true,
       unary: notImplemented,
       stream: notImplemented,
       [responseType]: method,
     } as unknown as Omit<Transport, T> & Record<T, jest.MockedFunction<Transport[T]>>;
ts/script/fix-ts-proto-generated-types.ts (1)

72-73: Hardcoded namespace mapping may need extension.

The mapping namespace === "akash" ? "node" : namespace works for current namespaces but requires manual updates for new namespaces that don't follow this convention. Consider extracting this to a configuration constant for easier maintenance.

baktun14
baktun14 previously approved these changes Jan 23, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@ts/script/protoc-gen-customtype-patches.ts`:
- Around line 129-135: The current generator builds patchesTypeFileName with
fileName.replace("CustomTypePatches","PatchMessage") and imports
`./${fileName}.ts`, which fails for custom output filenames and non-.ts
extensions; update the logic in the block that sets patchesTypeFileName,
patchTypeFile and the patchTypeFile.print calls (symbols: patchesTypeFileName,
fileName, patchTypeFile.print, and schema.options.importExtension) to 1)
validate fileName doesn't already collide with the intended PatchMessage name
and derive a safe PatchMessage basename using path.basename(fileName) and a
deterministic suffix (fail-fast if a collision would occur), 2) compute the
import path using the basename plus schema.options.importExtension (or default)
rather than hardcoding ".ts" and preserve relative directory semantics, and 3)
ensure the printed import uses the safe basename/importExtension so generated
imports are correct for custom filenames and extensions.
♻️ Duplicate comments (1)
ts/script/fix-ts-proto-generated-types.ts (1)

72-76: Bug: relativePath computed from file path instead of its directory.

Line 74 uses relativePath(filePath, ...) which computes the relative path from the source file itself rather than its containing directory. This produces incorrect import paths (off by one directory level).

Additionally, for cross-platform compatibility, consider using path.posix.relative to ensure forward slashes in import paths on Windows.

🐛 Proposed fix
-import { dirname, relative as relativePath, resolve as resolvePath } from "node:path";
+import { dirname, posix, resolve as resolvePath } from "node:path";

And in injectOwnHelpers (lines 54, 57) and applyPatching (line 74):

-      const importPath = relativePath(filePath, `${ROOT_DIR}/generated/protos/patches/${prefix}PatchMessage.ts`);
+      const importPath = posix.relative(dirname(filePath), `${ROOT_DIR}/generated/protos/patches/${prefix}PatchMessage.ts`);

Similarly update lines 54 and 57 to use posix.relative(dirname(path), ...).

🧹 Nitpick comments (1)
ts/script/fix-ts-proto-generated-types.ts (1)

19-23: Consider adding error handling for missing patch files.

If the glob matches no files or a patch file fails to import, this would silently result in an empty typesToPatch set. Given the fail-fast preference for build scripts, consider adding validation that at least one patch file was processed, or logging when patches are loaded.

💡 Optional enhancement
 const typesToPatch = new Set<string>();
 for await (const patchFile of fs.glob(`${ROOT_DIR}/generated/patches/*CustomTypePatches.ts`)) {
   const { patches } = await import(patchFile);
   Object.keys(patches).forEach((key) => typesToPatch.add(key));
 }
+
+if (typesToPatch.size === 0) {
+  console.warn("Warning: No type patches found. Verify patch files exist.");
+}

Based on learnings, fail-fast behavior is preferred for build-time scripts.

Comment on lines +129 to +135
const patchesTypeFileName = fileName.replace("CustomTypePatches", "PatchMessage");
const patchTypeFile = schema.generateFile(patchesTypeFileName);
patchTypeFile.print(`import { patches } from "./${fileName}";`);
patchTypeFile.print(`import type { MessageDesc } from "../../sdk/client/types.ts";`);
patchTypeFile.print(`export const patched = <T extends MessageDesc>(messageDesc: T): T => {`);
patchTypeFile.print(` const patchMessage = patches[messageDesc.$type as keyof typeof patches] as any;`);
patchTypeFile.print(` if (!patchMessage) return messageDesc;`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard PatchMessage filename + honor importExtension/relative path.
Line 129 uses replace("CustomTypePatches", "PatchMessage"), which no-ops for custom output filenames (env var) and can collide with the patches file. Line 131 also imports ./${fileName} (including any subdirs) and hardcodes .ts, ignoring schema.options.importExtension. Both can break generated output when non-default filenames or extensions are used. Suggest validating the filename, deriving a safe PatchMessage filename, and importing by basename + importExtension.

🛠️ Suggested fix
-  const patchesTypeFileName = fileName.replace("CustomTypePatches", "PatchMessage");
+  const patchesTypeFileName = fileName.replace(/CustomTypePatches\.ts$/, "PatchMessage.ts");
+  if (patchesTypeFileName === fileName) {
+    throw new Error(`Unexpected patches output filename: ${fileName}`);
+  }
   const patchTypeFile = schema.generateFile(patchesTypeFileName);
-  patchTypeFile.print(`import { patches } from "./${fileName}";`);
+  const patchesImport = basename(fileName).replace(/\.ts$/, "");
+  patchTypeFile.print(`import { patches } from "./${patchesImport}${importExtension}";`);

Based on learnings, fail-fast behavior is preferred for build-time scripts.

🤖 Prompt for AI Agents
In `@ts/script/protoc-gen-customtype-patches.ts` around lines 129 - 135, The
current generator builds patchesTypeFileName with
fileName.replace("CustomTypePatches","PatchMessage") and imports
`./${fileName}.ts`, which fails for custom output filenames and non-.ts
extensions; update the logic in the block that sets patchesTypeFileName,
patchTypeFile and the patchTypeFile.print calls (symbols: patchesTypeFileName,
fileName, patchTypeFile.print, and schema.options.importExtension) to 1)
validate fileName doesn't already collide with the intended PatchMessage name
and derive a safe PatchMessage basename using path.basename(fileName) and a
deterministic suffix (fail-fast if a collision would occur), 2) compute the
import path using the basename plus schema.options.importExtension (or default)
rather than hardcoding ".ts" and preserve relative directory semantics, and 3)
ensure the printed import uses the safe basename/importExtension so generated
imports are correct for custom filenames and extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants