Port Python SDK route generation from nextlove to Metalsmith#581
Merged
Conversation
Replace the @seamapi/nextlove-sdk-generator based route generation with the metalsmith + handlebars + @seamapi/blueprint architecture used by seamapi/javascript-http. The generated output under seam/routes/ is byte-identical. The blueprint drives the route, endpoint, and namespace structure. The raw OpenAPI spec is still consulted wherever the nextlove generator derived output from data the blueprint normalizes differently (integer vs number types, resource schema set and order, parameter flattening); each of those spots carries a TODO to migrate to the blueprint once output is allowed to change. - Add codegen/ with the Metalsmith pipeline, plugin, context builders, and Handlebars layouts and partials - Remove generate-routes.js - Pin @seamapi/types at 1.910.0 for output parity and use @seamapi/blueprint 0.55.0 - Bump del to ^8 to satisfy the @seamapi/smith peer range - Ignore *.hbs and CODEGEN.md in a new .prettierignore since the glimmer parser mangles Python-flavored templates - Re-include codegen/lib/ in .gitignore (the Python template ignores lib/) and ignore the generated CODEGEN.md seed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Every comment describing behavior to address later now leads with TODO so the deferred work is greppable: the parameter comparator precedence quirk and the unwired deeply nested namespaces. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
- Trim devDependencies to direct imports only: metalsmith, @metalsmith/layouts, jstransformer-handlebars, del, tsx, typescript, eslint, jiti, and mkdirp are @seamapi/smith peers that npm installs automatically, matching how seamapi/docs consumes smith - Add tsconfig.json extending @seamapi/smith/tsconfig.base.json with a typecheck script and codegen/index.ts stub, mirroring seamapi/docs and seamapi/javascript-http - Widen response type properties for exactOptionalPropertyTypes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
razor-x
commented
Jul 21, 2026
- Add lint, postlint, and preformat scripts using @seamapi/smith/eslint-config via a one-line eslint.config.ts, matching seamapi/docs - Replace relative parent imports with lib/* path imports (tsconfig baseUrl and paths), satisfying import/no-relative-parent-imports and matching the smith import sort convention - Mark every file and function that exists only for output parity with a TEMPORARY banner and a TODO to delete it once generated output is allowed to change, so temp code is skippable in review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Match how seamapi/docs consumes @seamapi/smith: extend the base tsconfig with no compiler option overrides and use plain relative imports in codegen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
CODEGEN.md moves to the top of the file. The codegen/lib/ negation moves next to the lib/ pattern it negates, since a gitignore negation only takes effect after the pattern it overrides. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
The CODEGEN.md gitignore rule matches any depth, so the Metalsmith source seed codegen/content/CODEGEN.md was never committed and CI failed to generate with ENOENT on the missing directory. Force-add the seed exactly as seamapi/javascript-http does; the ignore rule still covers the generated CODEGEN.md at the repository root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
razor-x
commented
Jul 21, 2026
| eggs/ | ||
| .eggs/ | ||
| lib/ | ||
| # Negations must follow the pattern they negate, so this cannot move to the top |
Member
Author
There was a problem hiding this comment.
Suggested change
| # Negations must follow the pattern they negate, so this cannot move to the top |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Add exception for codegen/lib in .gitignore
razor-x
marked this pull request as ready for review
July 21, 2026 16:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR replaces the direct dependency on
@seamapi/nextlove-sdk-generatorwith a Metalsmith-based code generation pipeline for Python SDK route files. The generation logic has been ported and restructured to align with the existingjavascript-httpcodegen plugin architecture.Key Changes
Replaced generation script: Removed
generate-routes.jswhich called@seamapi/nextlove-sdk-generatordirectly. Replaced withcodegen/smith.tsthat uses Metalsmith as the build orchestrator.Ported core generation logic: Migrated route generation from
@seamapi/nextlove-sdk-generatortocodegen/lib/routes.ts, which:Extracted OpenAPI utilities: Created modular OpenAPI processing functions:
get-filtered-routes.ts: Filters documented routesget-parameter-and-response-schema.ts: Extracts request/response schemasdeep-flatten-one-of-and-all-of-schema.ts: Flattens complex schema compositionsflatten-obj-schema.ts: Normalizes object schemasmap-parent-to-children-resource.ts: Maps resource hierarchiestypes.ts: Minimal OpenAPI type definitionsIntroduced data models: Created
class-model.tsto represent route classes, methods, and parameters independently of serialization.Built layout context builders: Created context builders for Handlebars templates:
layouts/route.ts: Builds context for individual route class fileslayouts/models.ts: Builds context for the models filelayouts/routes-index.ts: Builds context for the routes index fileAdded Handlebars templates: Created template files for code generation:
route.hbs: Route class templatemodels.hbs: Models file templateroutes-index.hbs: Routes index templatepartials/route-method.hbs: Route method templatepartials/abstract-route-class.hbs: Abstract class templatepartials/model-dataclass.hbs: Dataclass templatepartials/abstract-routes.hbs: Abstract routes templateAdded utility modules:
map-python-type.ts: Maps OpenAPI types to Python typescustom-resource-name-conversions.ts: Handles special resource name mappingsendpoint-rules.ts: Defines endpoint filtering ruleshandlebars-helpers.ts: Custom Handlebars helpersUpdated build configuration: Modified
package.jsonto usetsx codegen/smith.tsinstead ofnode generate-routes.js, and added dependencies on@metalsmith/layouts,@seamapi/blueprint, and@seamapi/smith.Added configuration files: Created
.prettierignoreto exclude Handlebars templates from formatting.Notable Implementation Details
@seamapi/blueprintdata once generated output changes are allowed.javascript-httpcodegen, making it maintainable and extensible.https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s