refactor: introduce @orpc/interop package for compatibility layer#873
Conversation
A compatibility layer that builds & re-exports upstream packages that don't yet meet oRPC's requirements.
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughIntroduces a new internal package @orpc/interop that re-exports json-schema-typed (multiple drafts) and compression. Migrates consumers from @orpc/json-schema-typed to @orpc/interop, updates ESLint restrictions and exceptions, adjusts Dependabot exclusions, adds lightweight interop tests, removes the old json-schema-typed package manifest, and updates related build/tsconfig/dependency wiring. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Summary of Changes
Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a new @orpc/interop package, which serves as a compatibility layer for external dependencies that do not fully meet oRPC's requirements, such as ESM compatibility or specific upstream issues. This refactoring centralizes the handling of these dependencies, specifically re-exporting json-schema-typed and compression. The change streamlines dependency management, enforces consistent import paths across the monorepo, and prepares for future compatibility needs.
Highlights
- New
@orpc/interopPackage: A dedicated package,@orpc/interop, has been created to serve as a compatibility layer, building and re-exporting external packages that require special handling within the oRPC ecosystem. - Centralized Dependency Management: The
json-schema-typedpackage (due to an upstream issue) and thecompressionpackage (for ESM compatibility) are now re-exported through@orpc/interop, centralizing their management and ensuring consistent and controlled usage across the monorepo. - ESLint Rule Updates: ESLint import restrictions have been updated to enforce the use of
@orpc/interopforjson-schema-typedandcompression, and to manage@opentelemetry/apiimports more explicitly, ensuring adherence to the new module structure. - Monorepo Refactoring: The existing
packages/json-schema-typedhas been removed, and its contents and responsibilities have been migrated into the newpackages/interoppackage. All internal references across the monorepo have been updated to point to the new@orpc/interoppackage.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request refactors the project to introduce a new @orpc/interop package. This package serves as a compatibility layer, re-exporting upstream packages like json-schema-typed and compression to handle issues such as ESM compatibility. This is a good architectural improvement that isolates compatibility hacks. The changes are mostly correct, with updates to package configurations, imports, and ESLint rules to reflect this new structure. I have one suggestion regarding the ESLint configuration to ensure the import restrictions work as intended.
More templates
@orpc/arktype
@orpc/client
@orpc/contract
@orpc/experimental-durable-event-iterator
@orpc/hey-api
@orpc/interop
@orpc/json-schema
@orpc/nest
@orpc/openapi
@orpc/openapi-client
@orpc/otel
@orpc/react
@orpc/react-query
@orpc/server
@orpc/shared
@orpc/solid-query
@orpc/standard-server
@orpc/standard-server-aws-lambda
@orpc/standard-server-fetch
@orpc/standard-server-node
@orpc/standard-server-peer
@orpc/svelte-query
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/vue-colada
@orpc/vue-query
@orpc/zod
commit: |
There was a problem hiding this comment.
Actionable comments posted: 2
🔭 Outside diff range comments (2)
packages/json-schema/tsconfig.json (1)
3-9: Add “composite”: true to interop tsconfig and update json-schema dependenciesThe
packages/json-schema/tsconfig.jsonreference to../interoprequires that interop is a composite project and that json-schema consumers depend on the correct package.• In packages/interop/tsconfig.json, add or update:
{ "compilerOptions": { "composite": true, // …other settings } }• In packages/json-schema/package.json:
– Ensure you have a dependency on@orpc/interop.
– Remove any@orpc/json-schema-typedentry if still present.
• In packages/json-schema/src, remove or update any imports from@orpc/json-schema-typedto point at@orpc/interop.These changes will enable TypeScript project references to work correctly and eliminate stale typings.
packages/openapi/tsconfig.json (1)
3-11: Addcomposite: trueto the interop tsconfigThe interop package is missing
"composite": true, which is required for project references to work correctly. The OpenAPI package has no stale@orpc/json-schema-typedimports and already imports from@orpc/interop/json-schema-typedinschema.ts. Please update:• packages/interop/tsconfig.json
{ "compilerOptions": { + "composite": true, // … other options … }, // … rest of config … }
🧹 Nitpick comments (9)
packages/interop/src/json-schema-typed/index.test.ts (1)
1-3: Test assumes runtime exports from a types-only module; either add a sentinel runtime export or switch to type-level testsjson-schema-typed is typically type-only; without an intentional runtime export, Object.keys(module) may be 0 and this test will fail. If you intend to enforce a runtime presence, add and assert a documented sentinel. Otherwise, consider using type tests (e.g., tsd) rather than runtime assertions.
Option A: Assert a sentinel (requires adding a runtime export in ./index.ts):
-it('exports something', async () => { - expect(Object.keys(await import('./index')).length).toBeGreaterThanOrEqual(1) -}) +it('exposes interop sentinel', async () => { + const mod = await import('./index') + expect('__interopSentinel' in mod).toBe(true) +})Outside this range (in packages/interop/src/json-schema-typed/index.ts), add a pure, tree-shakeable export:
/* @__PURE__ */ export const __interopSentinel = true as constOption B: If you don’t want runtime exports, replace with a minimal sanity check and add type-level tests using tsd.
-it('exports something', async () => { - expect(Object.keys(await import('./index')).length).toBeGreaterThanOrEqual(1) -}) +it('is importable at runtime (types-only surface allowed)', async () => { + expect(await import('./index')).toEqual(expect.any(Object)) +})To add tsd tests, I can draft a tsd setup that validates the re-exported types—say the presence of JSONSchema types across drafts. Want me to open a follow-up PR?
packages/interop/src/json-schema-typed/draft-2020-12.test.ts (1)
1-3: Same concern: tighten assertion or introduce a documented runtime sentinelAs with index.test.ts, asserting that there’s “at least one export” is fragile for type-only modules. Either:
- add a tree-shakeable sentinel and assert it explicitly, or
- relax to a minimal importability check and cover the surface with tsd type tests.
If using a sentinel:
-it('exports something', async () => { - expect(Object.keys(await import('./draft-2020-12')).length).toBeGreaterThanOrEqual(1) -}) +it('exposes interop sentinel for draft-2020-12', async () => { + const mod = await import('./draft-2020-12') + expect('__interopSentinel' in mod).toBe(true) +})And in packages/interop/src/json-schema-typed/draft-2020-12.ts:
export { /* ...types... */ } from 'json-schema-typed/draft-2020-12' /* @__PURE__ */ export const __interopSentinel = true as constAlternatively, keep the module importable and defer correctness to type-level tests.
packages/interop/src/compression/index.ts (1)
1-4: Prefer direct re-export to avoid an intermediate bindingA one-liner passthrough keeps the module minimal and avoids an extra local symbol.
Apply this diff:
-// eslint-disable-next-line no-restricted-imports -import compression from 'compression' - -export default compression +// eslint-disable-next-line no-restricted-imports +export { default } from 'compression'packages/interop/src/json-schema-typed/draft-2019-09.test.ts (1)
1-3: Strengthen assertions beyond “exports something”This check can pass even if the wrong things are exported. Consider adding type-level assertions (e.g., expectTypeOf) or targeted presence checks for known symbols to lock the API surface for this draft.
If you’re using Vitest, I can propose a small type test (e.g., a *.test-d.ts or an expectTypeOf-based test) that ensures JSON Schema types are correctly re-exported.
packages/otel/src/instrumentation.ts (1)
2-3: Confirm the lint suppression is still necessaryGiven the updated no-restricted-imports configuration (with allowed names), this line-level disable may be redundant. If the rule is intended to allow { context, propagation, trace } from @opentelemetry/api here, prefer removing the suppression to keep the file clean. Otherwise, consider codifying the exception in ESLint config rather than per-file disables.
packages/interop/src/json-schema-typed/draft-07.test.ts (1)
1-3: Use more specific checks to guard against accidental API regressionsSimilar to the 2019-09 draft test, assert the presence of expected named exports and/or add type-level assertions. This will catch subtle breakage that a simple “has at least one export” won’t detect.
Happy to draft a couple of targeted assertions (runtime and types) for draft-07 that mirror upstream’s intended surface.
packages/interop/README.md (1)
66-75: Add quick usage examples and minor capitalization nitConsider adding short “how to import” snippets and capitalize ESM for consistency.
## `@orpc/interop` A compatibility layer that builds & re-exports upstream packages that don't yet meet oRPC's requirements. **Included packages:** - [json-schema-typed](https://www.npmjs.com/package/json-schema-typed) to address issue [RemyRylan/json-schema-typed#116](https://github.com/RemyRylan/json-schema-typed/issues/116) -- [compression](https://www.npmjs.com/package/compression) for esm compatibility +- [compression](https://www.npmjs.com/package/compression) for ESM compatibility + +Examples: + +```ts +// Re-exported compression +import compression from '@orpc/interop/compression' + +// Re-exported json-schema-typed (all drafts) +import * as JST from '@orpc/interop/json-schema-typed' +import * as JST07 from '@orpc/interop/json-schema-typed/draft-07' +import * as JST2019 from '@orpc/interop/json-schema-typed/draft-2019-09' +import * as JST2020 from '@orpc/interop/json-schema-typed/draft-2020-12' +```packages/interop/src/compression/index.test.ts (1)
1-3: Consider adding more comprehensive tests beyond basic export validation.While the current test verifies that the module exports something, it would be beneficial to add tests that verify the actual functionality of the re-exported compression module to ensure the interop layer works correctly.
it('exports something', async () => { expect(Object.keys(await import('./index')).length).toBeGreaterThanOrEqual(1) }) + +it('exports compression function', async () => { + const compression = await import('./index') + expect(typeof compression.default).toBe('function') +}) + +it('compression function can be called', async () => { + const compression = await import('./index') + const middleware = compression.default() + expect(typeof middleware).toBe('function') +})packages/openapi/src/schema.ts (1)
1-5: Prefer direct re-exports to reduce indirection and keep only the type-only import for keywordsThis avoids creating intermediate local bindings and makes treeshaking intent explicit, while preserving the type-only import for typeof keywords at Line 66.
Apply:
-import type { JSONSchema, keywords } from '@orpc/interop/json-schema-typed/draft-2020-12' -import { ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from '@orpc/interop/json-schema-typed/draft-2020-12' +import type { keywords } from '@orpc/interop/json-schema-typed/draft-2020-12' @@ -export { JSONSchemaContentEncoding, JSONSchemaFormat, JSONSchemaTypeName } -export type { JSONSchema } +export { ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from '@orpc/interop/json-schema-typed/draft-2020-12' +export type { JSONSchema } from '@orpc/interop/json-schema-typed/draft-2020-12'
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.github/dependabot.yml(1 hunks)eslint.config.js(2 hunks)packages/interop/README.md(3 hunks)packages/interop/build.config.ts(1 hunks)packages/interop/package.json(1 hunks)packages/interop/src/compression/index.test.ts(1 hunks)packages/interop/src/compression/index.ts(1 hunks)packages/interop/src/json-schema-typed/draft-07.test.ts(1 hunks)packages/interop/src/json-schema-typed/draft-2019-09.test.ts(1 hunks)packages/interop/src/json-schema-typed/draft-2020-12.test.ts(1 hunks)packages/interop/src/json-schema-typed/index.test.ts(1 hunks)packages/json-schema-typed/build.config.ts(0 hunks)packages/json-schema-typed/package.json(0 hunks)packages/json-schema/package.json(1 hunks)packages/json-schema/src/types.ts(1 hunks)packages/json-schema/tsconfig.json(1 hunks)packages/openapi/package.json(1 hunks)packages/openapi/src/schema.ts(1 hunks)packages/openapi/tsconfig.json(1 hunks)packages/otel/src/instrumentation.ts(1 hunks)packages/server/build.config.ts(0 hunks)packages/server/package.json(1 hunks)packages/server/src/adapters/node/compression-plugin.ts(1 hunks)packages/server/tsconfig.json(1 hunks)
💤 Files with no reviewable changes (3)
- packages/json-schema-typed/package.json
- packages/server/build.config.ts
- packages/json-schema-typed/build.config.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: publish-commit
- GitHub Check: test
- GitHub Check: lint
🔇 Additional comments (17)
packages/openapi/package.json (1)
66-75: Interop replacement verified and ready to mergeNo lingering imports of
@orpc/json-schema-typedwere found, and the@orpc/interoppackage.json export map includes all required subpaths:•
./json-schema-typed
•./json-schema-typed/draft-07
•./json-schema-typed/draft-2019-09
•./json-schema-typed/draft-2020-12
•./compressionAll imports in
packages/json-schema/src/types.tsandpackages/openapi/src/schema.tscorrectly reference the interop subpaths.packages/server/tsconfig.json (2)
11-12: LGTM: adding interop to TS project references is correctThis ensures build/type-check ordering includes the new compatibility layer. No concerns here.
11-12: Verify composite build readiness and dependency wiringTo avoid tsc -b graph issues:
- Ensure packages/interop/tsconfig.json has "composite": true.
- Ensure packages/server/package.json lists @orpc/interop as a dependency (not just a TS reference).
I can provide a quick script to check both if helpful.
packages/interop/src/compression/index.ts (1)
1-4: Double-check type availability and interop settingsAt publish time, the emitted d.ts for this module will depend on types for compression. Please verify:
- @types/compression is present (if compression doesn’t ship its own types).
- The TS config used by interop enables the interop you expect (esModuleInterop/allowSyntheticDefaultImports), or that your build toolchain handles CJS default interop cleanly for both ESM (mjs) and CJS (cjs) outputs.
If either is missing, consumers may see any/unknown types or runtime import quirks.
.github/dependabot.yml (1)
25-26: Confirm intent: exclude from grouping vs. ignore entirelyThese entries exclude json-schema-typed and compression from the dev-dependencies-minor-patch group, but Dependabot will still open PRs for them in other groups. If your intent is to fully ignore updates for these inline’d packages, add an explicit ignore block outside of groups as well; otherwise, this change is fine for grouping behavior only.
Would you like me to add an ignore entry for these packages repo-wide to prevent any PRs for them?
packages/server/package.json (1)
129-129: Compression interop imports verified
- No remaining
import 'compression'orrequire('compression')usages inpackages/server- Confirmed
import compression from '@orpc/interop/compression'inpackages/server/src/adapters/node/compression-plugin.ts:4Approved.
packages/interop/README.md (2)
1-2: Clear “internal package” warning – niceThis sets the right expectation for consumers of the interop layer.
14-16: Badge update to @orpc/interop – good catchThe npm badge and link now point to the correct package.
eslint.config.js (2)
76-76: Reasonable override for content/playground areasDisabling no-restricted-imports in content and playgrounds keeps examples flexible without weakening core packages.
37-54: UseimportNames(notallowImportNames) and enableallowTypeImportsReplace the
no-restricted-importsconfig ineslint.config.js(around lines 37–54):paths: [ { name: '@opentelemetry/api', - allowImportNames: [ + importNames: [ 'AttributeValue', 'Context', 'ContextAPI', 'Exception', 'PropagationAPI', 'Span', 'SpanOptions', 'SpanStatusCode', 'TraceAPI', 'Tracer', ], + allowTypeImports: true, message: 'Require explicit runtime import from @orpc/opentelemetry', }, ],packages/interop/package.json (2)
16-44: Well-structured dual export configuration for development and production.The dual export configuration properly separates development-time TypeScript source paths (lines 45-51) from production distribution artifacts (lines 16-44). This allows for efficient development workflows while ensuring proper build artifacts are published.
60-64: All devDependencies in packages/interop/package.json are up-to-date and secureThe current versions (
compression@^1.8.1,@types/compression@^1.8.1,json-schema-typed@^8.0.1) match the latest published releases, and no vulnerabilities were reported bynpm audit. No further action is needed.packages/json-schema/package.json (1)
38-38: LGTM! Clean dependency migration to interop.The dependency update from
@orpc/json-schema-typedto@orpc/interopcorrectly aligns with the new interop compatibility layer approach.packages/server/src/adapters/node/compression-plugin.ts (1)
4-4: LGTM! Clean migration to interop layer.The import change from direct
compressionto@orpc/interop/compressionmaintains the same API surface while leveraging the new compatibility layer. The rest of the code remains unchanged, ensuring no breaking changes.packages/json-schema/src/types.ts (2)
1-3: LGTM! Clean import migration to interop layer.The import paths have been correctly updated to use the new
@orpc/interopcompatibility layer while maintaining the same type exports. The removal of the ESLint disable directive suggests proper configuration alignment.
1-8: All JSON Schema draft exports resolve correctly
packages/interop/package.jsondefines exports for./json-schema-typedand each draft (draft-07,draft-2019-09,draft-2020-12).- Source files under
packages/interop/src/json-schema-typed/(draft-07.ts,draft-2019-09.ts,draft-2020-12.ts) re-export from the correspondingjson-schema-typedmodules.- Tests in
packages/interop/src/json-schema-typed/*.test.tsconfirm each export surface.- In
packages/json-schema/src/types.ts, the union typeJsonSchemacorrectly importsJSONSchemafrom all three drafts, preserving backward compatibility.No further changes required.
packages/openapi/src/schema.ts (1)
1-2: Interop import path migration verified: subpath and symbol re-exports existThe
@orpc/interoppackage’s export map includes
"./json‐schema‐typed/draft‐2020‐12": "./src/json‐schema‐typed/draft‐2020‐12.ts",
and that file doesexport * from 'json-schema-typed/draft-2020-12', pulling inkeywords,ContentEncoding,Format, andTypeNameas expected. No further changes needed.
A compatibility layer that builds & re-exports upstream packages that don't yet meet oRPC's requirements.
Summary by CodeRabbit
New Features
Chores
Documentation
Tests