-
-
Notifications
You must be signed in to change notification settings - Fork 35
v27 is for Nikki Kuhnhausen
#3148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughVersion 27 refactors TypeScript handling by injecting the TypeScript runtime into Integration/TypescriptAPI, adds an async Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client Code
participant Integration as Integration
participant Base as IntegrationBase
participant TSAPI as TypescriptAPI
participant TS as TypeScript Runtime
rect rgb(240,248,255)
Note over Client,Integration: New v27 async create flow
Client->>Integration: await Integration.create({ config, routing, serverUrl? })
activate Integration
Integration->>TS: load peer TypeScript (auto-load)
TS-->>Integration: ts module
Integration->>Base: super(ts, serverUrl)
activate Base
Base->>TSAPI: new TypescriptAPI(ts)
activate TSAPI
TSAPI->>TS: createIdentifier / build nodes
TSAPI-->>Base: id helpers ready
deactivate TSAPI
Base-->>Integration: initialized
deactivate Base
Integration-->>Client: Integration instance
deactivate Integration
end
rect rgb(255,240,245)
Note over Client,Integration: Old v26 direct constructor (sync)
Client->>Integration: new Integration({ config, routing })
Note over Integration: Synchronous path, no create() factory
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (8)📓 Common learnings📚 Learning: 2025-05-27T19:27:13.492ZApplied to files:
📚 Learning: 2025-06-02T21:11:20.768ZApplied to files:
📚 Learning: 2025-08-05T14:43:24.702ZApplied to files:
📚 Learning: 2025-08-01T09:48:13.742ZApplied to files:
📚 Learning: 2025-10-02T17:42:48.840ZApplied to files:
📚 Learning: 2025-09-29T06:00:16.488ZApplied to files:
📚 Learning: 2025-09-29T03:35:55.561ZApplied to files:
⏰ 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). (2)
🔇 Additional comments (1)
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. Comment |
The better implementation of #3139 using the dynamic `import()` instead of `createRequire()`. The new implementation requires either: - to import and provide the `typescript` to `Integration::constructor()` - or to use the new async method `Integration::create()` This is a breaking change. `typescript` becomes an optional peer dependency. Documentation adjusted accordingly. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated README installation section to clarify TypeScript handling. * Enhanced frontend client generation examples with explicit TypeScript configuration instructions and usage patterns. * **New Features** * Added async factory method for integration setup, offering alternative to direct instantiation. * Made TypeScript an optional peer dependency instead of required, reducing installation footprint. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Thanks to #3156 storing the runtime distinguishable brand in the `bag` is no longer required, since metadata became inheritable between zod schemas in `globalRegistry` starting from Zod v4.3.0. See https://github.com/colinhacks/zod/pull/5578/changes for implementation. Breaking changes to the Zod Plugin: - min Zod version 4.3.4 - `pack()` and `unpack()` removed (no longer needed) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Metadata now inherits across chained schema operations and constraints. * **Breaking Changes** * Removed pack/unpack utilities; use schema.meta() for metadata. * Brand metadata moved to a namespaced meta key ("x-brand"); retrieve via schema.meta() or the getBrand() helper. * **Chores** * Bumped Zod requirement to ^4.3.4 and plugin version to 4.0.0-beta.1. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
@pullfrog please review the PR and also make me a summary of the changes describing the next major release in a paragraph no longer than 4 sentences. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
express-zod-api/package.json (1)
60-84: Consider updating the minimum TypeScript version constraint.Since TypeScript became optional in
peerDependenciesMeta, the minimum peer dependency constraint^5.1.3is less critical for consumers. However, it may be worth reviewing whether the minimum should be bumped to^5.9.2to match the development baseline—TypeScript has released 8 major versions since 5.1.3 (now at 5.9.2 as of January 2026). If the Integration API doesn't impose version constraints, the current minimum is acceptable; otherwise, the constraint should align with what has been tested.migration/index.ts (1)
13-20: Migration rule is on the right track; consider refining async detection, generics, and import handlingThe overall approach—finding
new Integration({ ... })calls, preferringIntegration.create()in async contexts, and otherwise injecting atypescriptproperty—is sound. A few details are worth tightening:
Async context detection is incomplete
hasAsyncCtxonly considersAwaitExpression,ArrowFunctionExpression, andFunctionExpression. Anew Integration({ ... })inside anasync function foo() { ... }(aFunctionDeclaration) will be treated as non‑async and migrated to the constructor+typescriptbranch, even thoughawait Integration.create()would be valid there.A small adjustment keeps behavior consistent for async declarations:
Possible tweak to include async function declarations
const hasAsyncCtx = ctx.sourceCode .getAncestors(node) .some( (one) => one.type === NT.AwaitExpression ||
((one.type === NT.ArrowFunctionExpression ||one.type === NT.FunctionExpression) &&
((one.type === NT.ArrowFunctionExpression ||one.type === NT.FunctionExpression ||one.type === NT.FunctionDeclaration) && one.async), );</details>
Explicit generics on
new Integration<...>()are droppedThe async fix replaces the entire
NewExpressionwith(await Integration.create(<object>)). If callers wrotenew Integration<MyRouting>({ ... }), those type arguments are lost. If they relied on explicit generics, this silently changes the type story.It would be safer to preserve
typeArgumentswhen present (e.g., by reconstructing the call usingctx.sourceCode.getTexton them, or by leveraging the AST rather than raw text).Unconditional
typescriptimport can conflict with existing importsThe non‑async branch always inserts
import typescript from "typescript";at the very top of the file. If the file already imports from"typescript"(default, namespace, or named), this can introduce duplicate bindings or conflicting imports.Before inserting, consider scanning
ctx.sourceCode.ast.bodyfor existingImportDeclarations whosesource.value === "typescript", and either:
- Reuse the existing local identifier (e.g.,
ts) in the added property, or- Skip adding a new import when a suitable one already exists.
Formatting of inserted
typescriptpropertyPrepending
typescript,directly beforenode.properties[0]works but may clash with local formatting (indentation / trailing commas) in multi‑line objects. Not a blocker, but you might later switch to using the printer or at least respecting the existing whitespace around the first property.These aren’t blockers for the migration but would make the rule more robust against real‑world usage.
Also applies to: 62-109
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
migration/__snapshots__/index.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (37)
.github/workflows/codeql-analysis.yml.github/workflows/node.js.ymlCHANGELOG.mdREADME.mdSECURITY.mdcompat-test/eslint.config.jscompat-test/migration.spec.tscompat-test/package.jsoneslint.config.jsexample/generate-client.tsexpress-zod-api/package.jsonexpress-zod-api/src/integration-base.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/startup-logo.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/src/zts.tsexpress-zod-api/tests/env.spec.tsexpress-zod-api/tests/integration.spec.tsexpress-zod-api/tests/zts.spec.tsexpress-zod-api/vitest.setup.tsmigration/README.mdmigration/index.spec.tsmigration/index.tsmigration/package.jsonpnpm-workspace.yamlzod-plugin/CHANGELOG.mdzod-plugin/README.mdzod-plugin/package.jsonzod-plugin/src/brand.tszod-plugin/src/index.tszod-plugin/src/meta.tszod-plugin/src/packer.tszod-plugin/src/runtime.tszod-plugin/tests/brand.spec.tszod-plugin/tests/index.spec.tszod-plugin/tests/packer.spec.tszod-plugin/tests/runtime.spec.ts
💤 Files with no reviewable changes (4)
- zod-plugin/src/index.ts
- zod-plugin/src/packer.ts
- zod-plugin/tests/packer.spec.ts
- zod-plugin/tests/index.spec.ts
🧰 Additional context used
🧠 Learnings (30)
📓 Common learnings
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2697
File: CHANGELOG.md:5-5
Timestamp: 2025-06-02T21:11:20.768Z
Learning: In the express-zod-api repository, RobinTail follows a release workflow where package.json version is only updated on the master branch after merging all planned release changes. Changelog entries may show future version numbers while package.json remains at the previous version during feature development, and this is intentional workflow, not a version inconsistency that needs to be flagged.
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2974
File: express-zod-api/src/documentation-helpers.ts:48-48
Timestamp: 2025-09-29T06:00:16.488Z
Learning: In the express-zod-api repository, the project uses pnpm workspaces with autoInstallPeers: false, meaning peerDependencies are not installed. The actual TypeScript version used for development comes from devDependencies which references "catalog:dev" in pnpm-workspace.yaml where it's set to a recent version (^5.9.2), not the peerDependency version which is just the minimum consumer requirement.
📚 Learning: 2025-05-27T19:30:51.885Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: compat-test/sample.ts:1-1
Timestamp: 2025-05-27T19:30:51.885Z
Learning: Files in compat-test/ directories, especially those named sample.ts or similar, are often test fixtures for migration scripts and may intentionally contain deprecated or "incorrect" code that the migration tooling is designed to fix. These should not be flagged as issues.
Applied to files:
compat-test/eslint.config.jseslint.config.jsmigration/README.mdcompat-test/package.jsoncompat-test/migration.spec.tsmigration/index.spec.ts
📚 Learning: 2025-09-29T06:06:58.605Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2974
File: migration/tsconfig.json:2-2
Timestamp: 2025-09-29T06:06:58.605Z
Learning: tsconfig/node20 includes "moduleResolution": "node16" in its base configuration, along with other settings like "module": "nodenext", "target": "es2022", and "strict": true. When extending from tsconfig/node20, explicit moduleResolution configuration is not needed.
Applied to files:
compat-test/eslint.config.jsmigration/README.md
📚 Learning: 2025-06-14T16:42:52.972Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2736
File: express-zod-api/tsup.config.ts:12-26
Timestamp: 2025-06-14T16:42:52.972Z
Learning: In express-zod-api tsup configurations, the direct mutation of `options.supported` in the `esbuildOptions` callback is intentional behavior and should not be flagged as a side effect issue.
Applied to files:
compat-test/eslint.config.jsexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexpress-zod-api/tests/env.spec.tsexpress-zod-api/src/zts.tsmigration/index.tsexpress-zod-api/src/integration-base.tsexpress-zod-api/package.jsonzod-plugin/src/runtime.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-08-05T14:43:24.702Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2869
File: zod-plugin/package.json:42-44
Timestamp: 2025-08-05T14:43:24.702Z
Learning: Zod version 4 has been officially released and is stable. As of August 2025, the latest published version is 4.0.14 (published July 30, 2025). Zod v4 is available on npm and can be used in peer dependencies with version constraints like "^4.0.0".
Applied to files:
zod-plugin/package.jsonpnpm-workspace.yamlCHANGELOG.mdzod-plugin/README.mdzod-plugin/CHANGELOG.mdexpress-zod-api/package.json
📚 Learning: 2025-05-27T19:27:13.492Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/tests/form-schema.spec.ts:31-31
Timestamp: 2025-05-27T19:27:13.492Z
Learning: Zod version 3.25.0 and later expose the Zod v4 API through the special import paths "zod/v4" and "zod/v4/core", allowing v4 features like .loose() to be used even when the package.json dependency shows a 3.x version.
Applied to files:
zod-plugin/package.jsonpnpm-workspace.yamlCHANGELOG.mdzod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdzod-plugin/CHANGELOG.mdexpress-zod-api/package.jsonexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-06-02T21:11:20.768Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2697
File: CHANGELOG.md:5-5
Timestamp: 2025-06-02T21:11:20.768Z
Learning: In the express-zod-api repository, RobinTail follows a release workflow where package.json version is only updated on the master branch after merging all planned release changes. Changelog entries may show future version numbers while package.json remains at the previous version during feature development, and this is intentional workflow, not a version inconsistency that needs to be flagged.
Applied to files:
zod-plugin/package.jsonmigration/package.jsonpnpm-workspace.yamlCHANGELOG.mdexpress-zod-api/package.json
📚 Learning: 2025-08-01T09:48:13.742Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-08-01T09:48:13.742Z
Learning: In express-zod-api, when migrating from Zod v3 to v4, the correct approach for internal type imports is to change from `import type { $ZodType } from "zod/v4/core"` to `import { z } from "zod"` and then use `z.core.$ZodType`. The zod/v4/core module is reexported as z.core by the main zod package, making this a valid and working approach.
Applied to files:
zod-plugin/package.jsonzod-plugin/src/meta.tsmigration/package.jsonREADME.mdpnpm-workspace.yamlexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexpress-zod-api/tests/env.spec.tsCHANGELOG.mdzod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdexpress-zod-api/src/zts.tszod-plugin/CHANGELOG.mdexpress-zod-api/src/integration-base.tszod-plugin/src/runtime.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-27T20:08:50.699Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/metadata.ts:5-13
Timestamp: 2025-05-27T20:08:50.699Z
Learning: The `_zod` property in Zod v4 schemas is officially documented and recommended for library authors to differentiate between Zod 3 and Zod 4 schemas at runtime, despite the underscore prefix. This is explicitly mentioned in Zod's library authors documentation and is not a private internal property.
Applied to files:
zod-plugin/package.jsonzod-plugin/src/meta.tszod-plugin/src/brand.tszod-plugin/README.mdzod-plugin/CHANGELOG.md
📚 Learning: 2025-05-27T20:03:34.213Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: example/factories.ts:35-42
Timestamp: 2025-05-27T20:03:34.213Z
Learning: The `./example` directory in the express-zod-api repository contains demonstration code for educational purposes only, not intended for production use. Example code can make simplified assumptions for brevity and clarity, and should not be flagged for missing production-level error handling, security measures, or edge case handling.
Applied to files:
zod-plugin/package.jsonmigration/package.jsonREADME.mdexample/generate-client.tsexpress-zod-api/package.json
📚 Learning: 2025-09-29T06:00:16.488Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2974
File: express-zod-api/src/documentation-helpers.ts:48-48
Timestamp: 2025-09-29T06:00:16.488Z
Learning: In the express-zod-api repository, the project uses pnpm workspaces with autoInstallPeers: false, meaning peerDependencies are not installed. The actual TypeScript version used for development comes from devDependencies which references "catalog:dev" in pnpm-workspace.yaml where it's set to a recent version (^5.9.2), not the peerDependency version which is just the minimum consumer requirement.
Applied to files:
zod-plugin/package.jsonmigration/package.jsonREADME.mdpnpm-workspace.yamlexpress-zod-api/tests/zts.spec.tsexample/generate-client.tsCHANGELOG.mdexpress-zod-api/package.jsonzod-plugin/src/runtime.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-08-08T11:59:04.814Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2878
File: zod-plugin/runtime.ts:39-42
Timestamp: 2025-08-08T11:59:04.814Z
Learning: express-zod-api/zod-plugin/runtime.ts (TypeScript): Do not memoize the ZodType.prototype.brand getter. The current design returning setBrand.bind(this) on each access is intentional/preferred; avoid redefining "brand" as a data property per instance.
Applied to files:
zod-plugin/src/meta.tsexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexpress-zod-api/tests/env.spec.tszod-plugin/tests/brand.spec.tszod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdexpress-zod-api/src/zts.tszod-plugin/src/runtime.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-08-08T16:45:20.527Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-08-08T16:45:20.527Z
Learning: express-zod-api/zod-plugin: The brand setter must be immutable and always invoke pack→.check() via the getter-bound setBrand. Including brandProperty with an explicit undefined enables unbranding and should not be optimized away.
Applied to files:
zod-plugin/src/meta.tsexpress-zod-api/vitest.setup.tszod-plugin/tests/brand.spec.tszod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdzod-plugin/src/runtime.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-08-08T16:45:20.527Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-08-08T16:45:20.527Z
Learning: express-zod-api zod-plugin: The brand setter must stay immutable and always invoke pack→.check() (onattach). Including brandProperty with an explicit undefined enables “unbranding” (overwriting a previous brand) and should not be optimized away.
Applied to files:
zod-plugin/src/meta.tsexpress-zod-api/vitest.setup.tszod-plugin/tests/brand.spec.tszod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdzod-plugin/src/runtime.ts
📚 Learning: 2025-08-08T16:45:20.527Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-08-08T16:45:20.527Z
Learning: express-zod-api/zod-plugin: The ZodType.prototype.brand getter returns setBrand.bind(this) each time (no memoization). setBrand must always call pack() and include { brand: undefined } when unbranding so that pack → .check() runs and prior brand is overwritten; do not suggest removing the explicit undefined entry.
Applied to files:
zod-plugin/src/meta.tsexpress-zod-api/vitest.setup.tszod-plugin/tests/brand.spec.tszod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdexpress-zod-api/src/zts.tszod-plugin/src/runtime.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-08-08T16:45:20.527Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-08-08T16:45:20.527Z
Learning: In express-zod-api zod-plugin, the brand setter must be immutable and always call `.check()` (packer’s onattach). Therefore, writing an explicit undefined entry in the bag for brand is intentional and should not be suggested for removal.
Applied to files:
zod-plugin/src/meta.tsexpress-zod-api/vitest.setup.tszod-plugin/tests/brand.spec.tszod-plugin/tests/runtime.spec.tszod-plugin/src/brand.tszod-plugin/README.mdzod-plugin/src/runtime.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-10-02T17:42:48.840Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-10-02T17:42:48.840Z
Learning: In express-zod-api v25 (ESM-only), the `.example()` method error occurs when user code runs as CommonJS. Express Zod API patches Zod's ESM bundle with `.example()`, but CommonJS code requires a separate CJS bundle instance that lacks this patch. Users must run their code as ESM by: (1) setting `"type": "module"` in package.json, (2) using `.mts` or `.mjs` file extensions, or (3) using tools like `tsx` or `vite-node` that provide their own ESM-compatible compilation.
Applied to files:
zod-plugin/src/meta.tsREADME.mdexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexample/generate-client.tsCHANGELOG.mdzod-plugin/tests/runtime.spec.tscompat-test/package.jsonexpress-zod-api/src/zts.tsexpress-zod-api/package.jsonzod-plugin/src/runtime.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-06-02T21:08:56.475Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2697
File: CHANGELOG.md:5-5
Timestamp: 2025-06-02T21:08:56.475Z
Learning: The `cjs-test` directory in the express-zod-api repository is a test workspace and should be excluded when checking for main project version consistency with changelog entries.
Applied to files:
migration/package.jsonexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/env.spec.tscompat-test/package.jsonexpress-zod-api/src/typescript-api.ts
📚 Learning: 2025-09-29T03:35:55.561Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-09-29T03:35:55.561Z
Learning: In the express-zod-api repository, packages are built using tsdown before publishing. Source code with .ts extensions is not published - only the built JavaScript bundles and declaration files in the dist/ directory are published to npm. This means .ts extensions in source imports don't affect consumers.
Applied to files:
README.mdpnpm-workspace.yamlexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexample/generate-client.tsCHANGELOG.mdzod-plugin/tests/runtime.spec.tscompat-test/package.jsonexpress-zod-api/src/zts.tsexpress-zod-api/src/integration-base.tsexpress-zod-api/package.jsonzod-plugin/src/runtime.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-12-18T13:42:39.225Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 3054
File: pnpm-workspace.yaml:68-68
Timestamp: 2025-12-18T13:42:39.225Z
Learning: In the express-zod-api repository, Vite is overridden to v8 beta in pnpm-workspace.yaml specifically to ensure vitest (which depends on Vite) uses the same rolldown bundler as tsdown and unrun. This override is intentional for toolchain consistency, as Vite is only used for testing purposes (not production).
Applied to files:
README.mdpnpm-workspace.yamlexpress-zod-api/tests/zts.spec.tscompat-test/package.jsonexpress-zod-api/package.json
📚 Learning: 2025-05-27T20:27:17.015Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/json-schema-helpers.ts:1-3
Timestamp: 2025-05-27T20:27:17.015Z
Learning: Ramda is correctly listed as a dependency in express-zod-api/package.json, so imports of ramda utilities are properly supported.
Applied to files:
README.mdpnpm-workspace.yamlexpress-zod-api/src/zts.tsexpress-zod-api/src/typescript-api.ts
📚 Learning: 2025-05-28T18:58:10.064Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2428
File: express-zod-api/src/index.ts:44-44
Timestamp: 2025-05-28T18:58:10.064Z
Learning: The type-only import `import type {} from "qs";` in express-zod-api/src/index.ts is necessary to avoid TS2742 errors for exported functions like attachRouting, makeRequestMock, testEndpoint, and testMiddleware that have types depending on types/qs. This import provides the reference TypeScript needs to infer portable type names.
Applied to files:
README.mdexpress-zod-api/vitest.setup.tsexpress-zod-api/tests/zts.spec.tsexample/generate-client.tszod-plugin/tests/runtime.spec.tscompat-test/package.jsoncompat-test/migration.spec.tsexpress-zod-api/src/zts.tsmigration/index.tsexpress-zod-api/src/integration-base.tsexpress-zod-api/package.jsonzod-plugin/src/runtime.tsexpress-zod-api/src/integration.tsexpress-zod-api/src/typescript-api.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-28T19:19:27.727Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 0
File: :0-0
Timestamp: 2025-05-28T19:19:27.727Z
Learning: In pnpm workspaces, most configuration can now be done directly in pnpm-workspace.yaml using the `settings` section instead of requiring .npmrc files. This includes workspace linking, dependency resolution, and performance settings.
Applied to files:
pnpm-workspace.yaml
📚 Learning: 2025-05-27T20:27:17.015Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/json-schema-helpers.ts:1-3
Timestamp: 2025-05-27T20:27:17.015Z
Learning: The JSONSchema type is not exported from the main "zod" module and must be imported from "zod/v4/core" when using Zod v4. This is acceptable for type-only imports as they don't create runtime dependencies.
Applied to files:
pnpm-workspace.yamlexpress-zod-api/vitest.setup.tszod-plugin/src/brand.tszod-plugin/CHANGELOG.mdexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-28T07:58:09.853Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/documentation-helpers.ts:508-512
Timestamp: 2025-05-28T07:58:09.853Z
Learning: In express-zod-api, when working with Zod's JSON schema override callbacks, using `delete` to mutate `ctx.jsonSchema` is the recommended approach per Zod's official documentation, even if it triggers performance linting warnings. This is preferable to creating copies with `undefined` values, especially for snapshot testing.
Applied to files:
express-zod-api/vitest.setup.tszod-plugin/README.mdexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-28T05:04:40.327Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/io-schema.ts:5-8
Timestamp: 2025-05-28T05:04:40.327Z
Learning: The Base type `object & { [Symbol.iterator]?: never }` in express-zod-api correctly excludes arrays and other iterables from IOSchema. Arrays are properly rejected because they have a defined Symbol.iterator method which conflicts with the never constraint, as demonstrated by TypeScript compiler errors when attempting to assign z.array() to IOSchema.
Applied to files:
express-zod-api/vitest.setup.tsexpress-zod-api/src/zts.ts
📚 Learning: 2025-05-27T20:22:30.428Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/tests/zts.spec.ts:160-162
Timestamp: 2025-05-27T20:22:30.428Z
Learning: In express-zod-api/tests/zts.spec.ts, the `Fruits` enum intentionally contains both string and numeric members (Apple = "apple", Banana = "banana", Cantaloupe = "cantaloupe", A = 5) and is used with `z.enum(Fruits)` to test how the system handles mixed enum types. This is by design for testing purposes.
Applied to files:
express-zod-api/tests/zts.spec.tsexpress-zod-api/src/zts.tsexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-27T19:35:57.357Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/tests/buffer-schema.spec.ts:32-37
Timestamp: 2025-05-27T19:35:57.357Z
Learning: In the express-zod-api project, tests are run from the `express-zod-api` workspace directory, and the project uses an ESM-first environment without `__dirname`. Relative paths like `../logo.svg` in test files correctly resolve to the repository root due to this test execution context.
Applied to files:
express-zod-api/tests/zts.spec.tsexpress-zod-api/tests/env.spec.tszod-plugin/tests/brand.spec.tscompat-test/package.jsonexpress-zod-api/tests/integration.spec.ts
📚 Learning: 2025-05-27T20:40:19.548Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2546
File: express-zod-api/src/json-schema-helpers.ts:75-87
Timestamp: 2025-05-27T20:40:19.548Z
Learning: In express-zod-api's `flattenIO` function in json-schema-helpers.ts, the `additionalProperties` field is used as a template to generate property schemas for literal property names extracted from `propertyNames.const` and `propertyNames.enum`. Converting boolean `additionalProperties` values to empty objects `{}` via `Object(entry.additionalProperties)` is intentional behavior, as the function only needs property schema templates, not the boolean semantics of `additionalProperties`.
Applied to files:
express-zod-api/src/zts.ts
📚 Learning: 2025-09-08T09:24:05.821Z
Learnt from: RobinTail
Repo: RobinTail/express-zod-api PR: 2922
File: example/endpoints/list-users.ts:4-4
Timestamp: 2025-09-08T09:24:05.821Z
Learning: In Zod v4, z.literal() accepts arrays and supports multiple values in a single schema (e.g., z.literal(["manager", "operator", "admin"]) is valid), unlike previous versions where it only accepted single literal values. The .value property was replaced with .values which is a Set.
Applied to files:
zod-plugin/CHANGELOG.md
🧬 Code graph analysis (8)
zod-plugin/src/meta.ts (1)
zod-plugin/src/brand.ts (1)
brandProperty(4-4)
express-zod-api/tests/zts.spec.ts (1)
express-zod-api/src/typescript-api.ts (1)
TypescriptAPI(14-474)
example/generate-client.ts (2)
express-zod-api/src/integration.ts (1)
Integration(66-246)express-zod-api/src/index.ts (1)
Integration(28-28)
express-zod-api/tests/env.spec.ts (1)
express-zod-api/src/documentation.ts (1)
subject(137-149)
zod-plugin/tests/brand.spec.ts (1)
zod-plugin/src/brand.ts (2)
brandProperty(4-4)getBrand(10-19)
zod-plugin/src/brand.ts (1)
zod-plugin/src/index.ts (1)
getBrand(2-2)
zod-plugin/src/runtime.ts (1)
zod-plugin/src/meta.ts (1)
brandSetter(21-23)
express-zod-api/src/integration.ts (1)
express-zod-api/src/peer-helpers.ts (1)
loadPeer(3-11)
🔇 Additional comments (72)
express-zod-api/src/startup-logo.ts (1)
15-15: Dedication message updated appropriately.The string replacement from "for Lia" to "for Nikki" is clean and maintains proper padding alignment with
.padEnd(20). This is a meaningful and fitting dedication to honor Nikki Kuhnhausen.zod-plugin/package.json (1)
3-3: LGTM! Version bump aligns with breaking changes.The major version bump to 4.0.0-beta.1 is appropriate given the breaking changes described in the PR (removal of pack/unpack utilities, brand handling moved to inheritable metadata). The beta designation correctly signals pre-release status.
compat-test/eslint.config.js (1)
6-6: LGTM! Migration rule updated for v27.The ESLint configuration correctly enforces the new v27 migration rule, aligning with the broader release preparation.
migration/README.md (1)
21-21: LGTM! Documentation updated for v27 migration.The README example correctly reflects the new migration rule version, ensuring users apply the v27 migration script.
SECURITY.md (1)
7-7: LGTM! Version 27 added to supported versions table.The addition of version 27.x.x with code name "Nikki" and planned release date of February 2026 aligns with the PR objectives and honors the dedication to Nikki Kuhnhausen.
pnpm-workspace.yaml (1)
53-53: Verify the Zod version constraint — 4.3.4 did not introduce the metadata registry feature.The metadata registry system (including globalRegistry) was introduced in Zod v4.0.0, not in 4.3.4. The 4.3.4 changelog includes updates for patternProperties, looseRecord, and other improvements, but no metadata-related changes. If the brand handling feature only requires Zod's metadata registry, the constraint can be lowered to
"^4.0.0". If 4.3.4 is needed for a different reason, clarify the requirement in the commit message.Likely an incorrect or invalid review comment.
.github/workflows/node.js.yml (1)
8-10: LGTM! Branch triggers updated for v27 release cycle.The removal of v22 and addition of v26 and make-v27 branches correctly aligns with the version progression documented in the PR.
.github/workflows/codeql-analysis.yml (1)
16-19: LGTM! CodeQL workflow aligned with main CI.The branch filter updates are consistent with
.github/workflows/node.js.yml, ensuring security scanning coverage matches the main build workflow.migration/package.json (1)
3-3: LGTM! Version bump appropriate for v27 beta release.The migration package version correctly advances to
27.0.0-beta.0, aligning with the overall v27 release cycle documented in the PR.zod-plugin/CHANGELOG.md (1)
5-10: Update CHANGELOG version header to match package.jsonThe CHANGELOG documents
v4.0.0as a stable release, but package.json declares the actual current version as4.0.0-beta.1. The changelog entry header should bev4.0.0-beta.1to maintain consistency with the package version during the beta development phase.⛔ Skipped due to learnings
Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2697 File: CHANGELOG.md:5-5 Timestamp: 2025-06-02T21:11:20.768Z Learning: In the express-zod-api repository, RobinTail follows a release workflow where package.json version is only updated on the master branch after merging all planned release changes. Changelog entries may show future version numbers while package.json remains at the previous version during feature development, and this is intentional workflow, not a version inconsistency that needs to be flagged.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2546 File: express-zod-api/tests/form-schema.spec.ts:31-31 Timestamp: 2025-05-27T19:27:13.492Z Learning: Zod version 3.25.0 and later expose the Zod v4 API through the special import paths "zod/v4" and "zod/v4/core", allowing v4 features like .loose() to be used even when the package.json dependency shows a 3.x version.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2869 File: zod-plugin/package.json:42-44 Timestamp: 2025-08-05T14:43:24.702Z Learning: Zod version 4 has been officially released and is stable. As of August 2025, the latest published version is 4.0.14 (published July 30, 2025). Zod v4 is available on npm and can be used in peer dependencies with version constraints like "^4.0.0".Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2546 File: express-zod-api/src/metadata.ts:5-13 Timestamp: 2025-05-27T20:08:50.699Z Learning: The `_zod` property in Zod v4 schemas is officially documented and recommended for library authors to differentiate between Zod 3 and Zod 4 schemas at runtime, despite the underscore prefix. This is explicitly mentioned in Zod's library authors documentation and is not a private internal property.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2546 File: express-zod-api/src/json-schema-helpers.ts:1-3 Timestamp: 2025-05-27T20:27:17.015Z Learning: The JSONSchema type is not exported from the main "zod" module and must be imported from "zod/v4/core" when using Zod v4. This is acceptable for type-only imports as they don't create runtime dependencies.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2546 File: express-zod-api/src/json-schema-helpers.ts:1-3 Timestamp: 2025-05-27T20:27:17.015Z Learning: The JSONSchema type is not exported from the main "zod" module and must be imported from "zod/v4/core" when using Zod v4. This is acceptable for type-only imports as they don't create runtime dependencies.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 0 File: :0-0 Timestamp: 2025-08-01T09:48:13.742Z Learning: In express-zod-api, when migrating from Zod v3 to v4, the correct approach for internal type imports is to change from `import type { $ZodType } from "zod/v4/core"` to `import { z } from "zod"` and then use `z.core.$ZodType`. The zod/v4/core module is reexported as z.core by the main zod package, making this a valid and working approach.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 0 File: :0-0 Timestamp: 2025-08-08T16:45:20.527Z Learning: express-zod-api/zod-plugin: The ZodType.prototype.brand getter returns setBrand.bind(this) each time (no memoization). setBrand must always call pack() and include { brand: undefined } when unbranding so that pack → .check() runs and prior brand is overwritten; do not suggest removing the explicit undefined entry.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 2922 File: example/endpoints/list-users.ts:4-4 Timestamp: 2025-09-08T09:24:05.821Z Learning: In Zod v4, z.literal() accepts arrays and supports multiple values in a single schema (e.g., z.literal(["manager", "operator", "admin"]) is valid), unlike previous versions where it only accepted single literal values. The .value property was replaced with .values which is a Set.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 0 File: :0-0 Timestamp: 2025-08-08T16:45:20.527Z Learning: express-zod-api zod-plugin: The brand setter must stay immutable and always invoke pack→.check() (onattach). Including brandProperty with an explicit undefined enables “unbranding” (overwriting a previous brand) and should not be optimized away.Learnt from: RobinTail Repo: RobinTail/express-zod-api PR: 0 File: :0-0 Timestamp: 2025-08-08T16:45:20.527Z Learning: express-zod-api/zod-plugin: The brand setter must be immutable and always invoke pack→.check() via the getter-bound setBrand. Including brandProperty with an explicit undefined enables unbranding and should not be optimized away.zod-plugin/src/meta.ts (1)
2-2: LGTM! brandSetter correctly implements Zod v4 inheritable metadata pattern.The implementation properly uses
.meta()to store brand metadata with thebrandPropertykey, replacing the previouspack()/unpack()approach. The optionalbrandparameter enables both branding and unbranding scenarios, and the return value supports method chaining. Zod ^4.3.4 fully supports inheritable metadata via.meta()as documented.compat-test/package.json (1)
6-6: LGTM - Intentional migration test fixture.The updated pretest script generates a sample that uses the new
Integrationconstructor pattern. Based on learnings, files incompat-test/directories are often test fixtures for migration scripts and may intentionally contain deprecated or incomplete code that migration tooling is designed to detect and fix.Based on learnings, compat-test files are intentionally used as migration test fixtures.
express-zod-api/src/zts.ts (1)
103-104: LGTM - Consistent use of Ramda utilities.The refactor from
Object.values(def.entries).map(api.makeLiteralType.bind(api))toR.map(api.makeLiteralType, Object.values(def.entries))maintains the same functionality while aligning with the codebase's Ramda-first style.express-zod-api/vitest.setup.ts (1)
22-28: LGTM - Simplified schema serialization aligned with metadata-based branding.The removal of the custom override handler for injecting
x-brandinto JSON schemas aligns with v27's shift to inheritable metadata for brand handling. The simplifiedtoJSONSchemacall with onlyunrepresentable: "any"is cleaner and consistent with the new approach.express-zod-api/package.json (1)
3-3: LGTM - Version bump for v27 major release.The version bump to
27.0.0-beta.1is appropriate for the breaking changes in this PR, including the Integration API changes and optional TypeScript peer dependency.Based on learnings, the version workflow in this repository intentionally allows package.json to be updated during feature development.
eslint.config.js (2)
179-182: LGTM - Enforcing consistent use of makeId() helper.The new lint rule discourages direct use of
createIdentifierin favor of themakeId()helper, aligning with the PR's shift toward id-based helpers and maintaining consistency with other TypeScript factory helper rules.
241-246: LGTM - Appropriate relaxation of performance constraints for migration tooling.Removing
performanceConcernsfrom the migration config makes sense, as migration scripts don't require the same runtime performance optimizations as production code. Import concerns are appropriately retained for consistency.CHANGELOG.md (1)
3-34: v27 changelog entry accurately describes the Integration breaking changeThe bullets and diff snippets correctly capture the new requirement to either pass a
typescriptvalue into theIntegrationconstructor or switch toawait Integration.create({ ... }), and the Zod^4.3.4note aligns with the plugin’s new minimum version. No changes needed here.zod-plugin/README.md (1)
16-18: Branding README updates are consistent with the new plugin behaviorDocumenting
.brand()as shorthand for setting"x-brand"inmeta, showing it inschema.meta(), and describinggetBrand()as the runtime accessor all line up with the new inheritable-metadata-based branding, and the Zod^4.3.4requirement matches the implementation constraints.Also applies to: 21-21, 32-32, 37-37
express-zod-api/tests/zts.spec.ts (1)
9-16: TypescriptAPI instantiation is correctly updatedCreating
apiwithnew TypescriptAPI(ts)matches the new constructor signature and keeps the test harness in sync with the implementation ofTypescriptAPIand itsprintNodehelper.compat-test/migration.spec.ts (1)
7-9: Compat test expectation correctly reflects the new migration outputThe expected content now includes the
typescriptimport and thetypescriptproperty in theIntegrationconstructor argument, which matches the behavior of the updated migration rule for non‑async call sites.README.md (2)
184-184: Documentation correctly reflects TypeScript as optional peer dependency.The removal of
typescriptfrom the installation example aligns with the breaking change where TypeScript is now an optional peer dependency that must be explicitly provided toIntegration.
1078-1093: Clear documentation of the new TypeScript integration pattern.The updated example correctly demonstrates:
- Installing TypeScript as a prerequisite
- Importing and passing the TypeScript module to
Integration- Mentioning the alternative
Integration.create()factory method for async loadingThis provides users with clear guidance on the breaking API change.
express-zod-api/tests/env.spec.ts (1)
132-136: Appropriate test coverage for Zod 4.3.0 metadata inheritance.This test correctly verifies that metadata defined on a parent schema is preserved when creating a child schema through chaining. The assertion
expect(subject.meta()).toHaveProperty("one", "test")confirms the inheritance behavior that is central to the v27 branding refactor.zod-plugin/src/runtime.ts (1)
3-8: Branding refactored to use inheritable metadata via brandSetter.The change from
setBrandtobrandSetteraligns with the PR's objective to leverage Zod 4.3+ inheritable metadata. ThebrandSetterfunction (frommeta.ts) usesthis.meta({ [brandProperty]: brand })to attach brands via metadata, which is now preserved across schema transformations.Based on learnings, the getter returning a new bound function on each access is intentional design.
Also applies to: 30-30
zod-plugin/tests/brand.spec.ts (1)
1-19: Tests correctly updated for metadata-based branding.The test updates reflect the architectural shift:
brandPropertychanged to"x-brand"(line 7)getBrandnow reads fromglobalRegistrymetadata instead of internal bag- Test directly manipulates
globalRegistryto verify the new metadata-based approachThese changes align with the Zod 4.3+ inheritable metadata feature and the removal of the
pack/unpackutilities.example/generate-client.ts (1)
5-10: Example correctly demonstrates the new TypeScript integration pattern.The addition of
import typescript from "typescript"and passing it to theIntegrationconstructor illustrates the breaking API change where TypeScript is now an optional peer dependency that must be explicitly provided.Based on learnings, the
./exampledirectory contains demonstration code for educational purposes.zod-plugin/tests/runtime.spec.ts (3)
71-74: LGTM! Brand verification via metadata.The test correctly validates that branding is now stored in and accessed through
.meta()with the "x-brand" key, aligning with Zod v4's metadata-driven approach.
76-83: Good test coverage for brand persistence through refinements.The test correctly verifies that brand metadata is preserved when applying refinements like
.regex(), which is essential for the metadata-based branding approach.
85-91: Good validation of metadata property coexistence.This test appropriately verifies that brand metadata coexists with other metadata properties like description, confirming the metadata approach handles multiple properties correctly.
express-zod-api/tests/integration.spec.ts (4)
2-2: LGTM! Correct import for Zod v4 metadata access.The
globalRegistryimport is the appropriate public API for accessing and manipulating schema metadata in Zod v4.
29-30: LGTM! Demonstrates explicit TypeScript injection.The test correctly shows the synchronous constructor pattern where TypeScript is explicitly provided, one of the two supported initialization patterns in v27.
53-53: LGTM! Correct usage of async factory method.The tests appropriately demonstrate the
Integration.create()pattern, which asynchronously loads the TypeScript peer dependency. This is the recommended approach when TypeScript is not explicitly provided.Also applies to: 76-76, 113-113, 139-139
136-136: No action needed.globalRegistry.remove(schema)is the correct Zod v4 API for removing schema metadata in custom brand handling scenarios. The implementation aligns with the established patterns used throughout the codebase.migration/index.spec.ts (3)
25-25: LGTM! Valid migration target established.The valid test case correctly demonstrates the expected form after migration, with
typescriptprovided in the Integration constructor arguments.
28-40: Good migration test for adding typescript parameter.The test correctly validates that the migration automatically adds the TypeScript import and injects it into the Integration constructor when missing. This covers the most common upgrade scenario.
56-69: LGTM! Correct handling of async context migration.The test correctly validates conversion to
Integration.create()in async contexts. The doubleawaitpattern is necessary: one for the factory method, one forprintFormatted(). The parentheses ensure proper precedence.express-zod-api/src/integration.ts (5)
17-18: LGTM! TypeScript dependency injection properly typed.The addition of the
typescriptparameter toIntegrationParamscorrectly establishes TypeScript as an injectable dependency with proper typing.
82-94: LGTM! TypeScript dependency injection implemented correctly.The constructor properly extracts the
typescriptparameter and passes it to the base class viasuper(), enabling dependency injection of the TypeScript API throughout the inheritance chain.
181-186: LGTM! Async factory pattern correctly implemented.The static
create()method properly implements the async factory pattern for loading the optional TypeScript peer dependency via dynamic import. This enables TypeScript to be optional while providing a convenient initialization path.
159-161: Factory method pattern applied consistently.The use of
this.makeMethodType()andthis.makeRequestType()is consistent with the factory method refactoring seen elsewhere in the file (line 67). This architectural pattern appears to be applied uniformly.
67-67: Factory methods are properly implemented.The factory methods
makeSomeOfType(),makeMethodType(), andmakeRequestType()are all correctly defined in theIntegrationBaseclass (lines 79–102). The change from property reference to method call is intentional and follows a consistent factory pattern for creating TypeScript AST type nodes.zod-plugin/src/brand.ts (3)
1-1: LGTM! Correct import for Zod v4 metadata API.The addition of
globalRegistryto the imports is appropriate for accessing schema metadata in Zod v4, replacing the previous internal bag-based approach.
3-4: Good use of JSON Schema extension convention.The rename from
"brand"to"x-brand"follows the JSON Schema convention for custom extension properties (x- prefix). This is a breaking change but aligns with Zod v4's metadata approach and standard conventions.
10-11: LGTM! Correct migration to globalRegistry API.The implementation correctly uses
globalRegistry.get(subject)to retrieve metadata, properly handling undefined results with nullish coalescing and maintaining the expected type checking for valid brand values.express-zod-api/src/typescript-api.ts (12)
23-24: LGTM! Clean dependency injection pattern.The constructor now accepts the TypeScript compiler API as a parameter, enabling better testability and supporting async loading. This is a well-structured breaking change that aligns with the PR's goal of making
typescriptan optional peer dependency.
74-74: Good addition of centralized identifier factory.The
makeIdhelper provides a single point for identifier creation, reducing boilerplate across the codebase.
78-78: LGTM! Consistent use of makeId for string-to-identifier conversion.The updated
makePropertyIdentifierandmakeTemplatemethods properly leveragemakeIdfor string-based identifier creation.Also applies to: 83-89
97-120: LGTM! Parameter signature updated to string-based initialization.The change from
init?: ts.ExpressiontoinitId?: stringsimplifies the API for common use cases where initialization is a simple identifier reference.
224-229: LGTM! Simplified signature fromts.Identifier[]tostring[].The
makeDeconstructionmethod now accepts plain strings, delegating identifier creation to internal logic. This aligns with the broader refactor pattern.
251-257: LGTM! Updated to use method reference directly.The
makePublicLiteralTypenow passesthis.makeLiteralTypedirectly toR.map, which works correctly sincemakeLiteralTypeis defined as an arrow function.
289-290: LGTM! Method name parameter simplified to string.This change is consistent with the overall refactor direction and simplifies the caller's interface.
385-402: LGTM! Clean variadic signature with string-to-identifier coercion.The
makeTernarymethod now accepts eitherts.Expressionorstringfor all three arguments, with automatic conversion viamakeId. The implementation is clean and type-safe.
404-420: LGTM! Consistent string-to-identifier conversion inmakeCall.The method now handles string arguments throughout, converting them to identifiers via
makeIdwhere needed.
422-423: LGTM!makeNewandmakeAssignmentupdated for string inputs.Both methods now accept string parameters and convert them appropriately, maintaining consistency with the refactored API.
Also applies to: 428-438
157-157: Arrow function binding inensureTypeNodeis correct and safe.The
ensureTypeNodemethod is defined as an arrow function (public ensureTypeNode = (...) => ...), which automatically bindsthisto the instance. Passingthis.ensureTypeNodetoR.mapat line 157 is therefore safe and maintains proper context without requiring additional binding workarounds. This pattern is used consistently throughout the codebase.
377-379: No action needed—makeParamis already correctly defined as an arrow function.The code is correct as-is.
makeParamis defined as an arrow function at line 97 (public makeParam = (...) =>), which automatically bindsthisto the lexical scope. When passed toR.mapat line 378, it maintains proper binding. This follows the same pattern asensureTypeNodementioned in the original concern.Likely an incorrect or invalid review comment.
express-zod-api/src/integration-base.ts (15)
14-31: LGTM! Clean base class constructor with dependency injection.The protected constructor properly initializes the
TypescriptAPIwith the injected TypeScript compiler. Thereadonlymodifier onapiensures immutability after construction.
33-64: LGTM! Simplified identifier storage as plain strings.Converting
#idsfromts.Identifierobjects to plain strings simplifies the internal API. Identifiers are now created on-demand viamakeIdwhere needed, reducing upfront object allocation.
67-73: LGTM! Interface names simplified to strings.The
interfacesrecord now stores plain string names instead ofts.Identifierobjects, consistent with the#idsrefactor.
79-102: LGTM! Helper methods renamed withmakeprefix for consistency.The renamed methods (
makeMethodType,makeSomeOfType,makeRequestType) follow a consistent naming convention and properly use string-based identifiers.
108-109: LGTM!someOfupdated to use string-based type reference.The method now correctly passes the string identifier to
ensureTypeNode.
145-145: LGTM! Tag mapping uses method reference directly.
R.map(this.api.literally, tags)works correctly sinceliterallyis an arrow function onTypescriptAPI.
157-173: LGTM! Implementation type construction uses string-based parameter names.The method properly constructs the function type using string keys for parameters.
179-198: LGTM!makeParseRequestFnupdated with string-based identifiers.The method correctly uses string identifiers and
makeIdfor type references.
204-269: LGTM!makeSubstituteFnproperly usesmakeIdfor runtime expressions.The method correctly distinguishes between:
- String identifiers used as property keys (passed directly)
- Runtime identifier references (wrapped with
makeId)This is a comprehensive and correct update.
272-317: LGTM! Provider method updated with string-based parameters.The
#makeProvidermethod correctly uses string identifiers throughout, including for type parameters.
323-338: LGTM! Client class construction and search params helper updated.Both
makeClientClassand#makeSearchParamscorrectly use the new string-based identifier pattern.Also applies to: 341-344
362-501: LGTM!makeDefaultImplementationcomprehensively updated.All identifier references within the default implementation have been correctly updated to use
makeIdwhere needed for runtime expressions.
503-537: LGTM! Subscription class methods updated consistently.Both
#makeSubscriptionConstructorand#makeOnMethodproperly use string identifiers andmakeIdfor runtime expressions.Also applies to: 544-601
607-637: LGTM! Subscription class type parameters use string-based identifiers.The
makeSubscriptionClassmethod correctly uses string identifiers for type constraints.
640-667: LGTM! Usage statements generation updated.The
makeUsageStatementsmethod correctly uses the updated APIs throughout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall. This is a well-structured major version release with thoughtful breaking changes. The TypeScript injection pattern is sensible—making typescript an optional peer dependency and offering both synchronous (constructor with injection) and asynchronous (Integration.create()) initialization paths gives users flexibility.
One minor observation: the migration ESLint rule handles the async context detection well, but it might produce awkward output in rare edge cases (e.g., deeply nested async contexts). The auto-fix wrapping (await Integration.create(...)) should work correctly for the common case though.
v27 Release Summary
Version 27 makes TypeScript an optional peer dependency with explicit injection into the Integration class—use new Integration({ typescript, ... }) with an import, or call the new async Integration.create() factory method for automatic loading. The Zod Plugin now leverages Zod 4.3.4's inheritable metadata feature, removing the need for pack/unpack utilities while simplifying brand handling by storing brands in standard metadata under x-brand.
|
✅ Review complete for PR #3148 Summary: No blocking issues found. The changes are well-structured with thoughtful breaking changes for TypeScript injection and Zod metadata improvements. v27 Release SummaryVersion 27 makes TypeScript an optional peer dependency with explicit injection into the |

Nikki Kuhnhausen was 17 years young transgender woman. She was murdered by David Bogdanov in 2019. Her body was identified from decayed remains on December 7th, in the Larch Mountain area near Vancouver, Washington. Authorities were able to identify the body from personal effects; subsequent examination showed she died from strangulation. Nikki had previously been missing since June 5th when she left with David Bogdanov, a 25-year-old male she met in Snapchat, who has since been charged with second degree murder. Authorities believe that Bogdanov, looking for a sexual encounter, became enraged upon learning of Nikki's transgender origins.
https://katu.com/news/local/missing-vancouver-teen-nikki-kuhnhausen-found-dead-in-remote-clark-county-location-suspect-arrested
Transgender women suffer too frequently from transphobic violence and cruelty, being the less protected social group. I'd like to raise an awareness of this problem. Humans should be creators — not killers. But most importantly, I want every transgender girl to have an opportunity to create applications quickly and, in general, learn to write code easily in order to receive job offers and leave dangerously transphobic territories for more favorable and civilized ones, and live happily there. Protect transgender women.
Version 27 makes
typescriptan optional peer dependency with explicit injection of the manually imported module into theIntegrationclass constructor (new Integration({ typescript, ... })), or by calling the new asyncIntegration.create()factory method for automatic loading. The Zod Plugin now leverages Zod 4.3's inheritable metadata feature, removing the need forpack()andunpack()helpers while simplifying brand handling by storing brands in standard metadata underx-brandproperty.Integration#3149Summary by CodeRabbit
New Features
Breaking Changes
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.