feat(user-manager-client): vendor Semrush User Manager spec + generated types (foundation slice)#1680
Conversation
…ion pipeline Foundation slice for @adobe/spacecat-shared-user-manager-client, mirroring the Project Engine foundation (LLMO-5461) applied to the larger User Manager API (LLMO-5558). Private, types-only package: vendors the Swagger 2.0 spec (/enterprise/users/api, 234 paths / 284 operations, 187 Auth-Data-Jwt routes) and wires the swagger2openapi --patch -> openapi-typescript / datamodel-codegen pipeline behind `npm run generate`. The openapi-fetch client wrapper with dual auth (IMS bearer + API-Key) and the counterfact mock store land in follow-up PRs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generated by `npm run generate` from the vendored spec. Committed in its own commit and marked linguist-generated (see .gitattributes) so it collapses in review and is excluded from diff counts. - src/generated/types.ts: openapi-typescript 7.13.0 paths/components (all ops) - python/serenity_user_manager/: datamodel-codegen pydantic_v2 package Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds @adobe/spacecat-shared-user-manager-client and its generation-pipeline devDeps (openapi-typescript, swagger2openapi, counterfact) to the root lockfile so `npm ci` stays in sync in CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
This PR will trigger a minor release when merged. |
There was a problem hiding this comment.
Hey @byteclimber,
Verdict: Request changes - one blocking finding on test assertion quality; the rest is clean.
Changes: Vendors the Semrush User Manager Swagger 2.0 spec and wires a generation pipeline producing TypeScript and Pydantic types as a new private foundation-slice package (21 files).
Must fix before merge
- [Important] Generated-types test assertions too generic to catch spec drift -
test/foundation.test.js:69-77(details inline)
Non-blocking (3): minor issues and suggestions
- suggestion: Use a different port for the mock script to avoid collision with project-engine-client (both use 4010) -
package.json:21 - nit:
publishConfig.access: "public"is a no-op whileprivate: trueis set; remove or document the intent -package.json:38 - suggestion: Add
spec/to.npmignoreas defense-in-depth against accidental spec publication if the package ever goes public -.npmignore
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 31s | Cost: $4.98 | Commit: 8733f50d3f3f8a678f39391b3b018194b78b017b
If this code review was useful, please react with 👍. Otherwise, react with 👎.
…ests Addresses mysticat-bot review: `/child` and `/status` were too generic and would pass against any large OpenAPI types file. Replace with the full, unambiguous path templates that only exist in this spec. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Hey @byteclimber,
Verdict: Approve - prior blocking finding addressed, clean foundation slice.
Changes: Vendors the Semrush User Manager Swagger 2.0 spec and wires a generation pipeline producing TypeScript and Pydantic types as a new private foundation-slice package (21 files).
Non-blocking (1): minor issues and suggestions
- nit: Root CLAUDE.md states "containing 23 packages" which becomes 24 after this PR merges - update the count or remove the hard number -
CLAUDE.md
Previously flagged, now resolved
- Generated-types test assertions now use spec-specific path fragments (
/v2/workspaces/{id}/child,/v1/workspaces/{id}/status) that discriminate against wrong-spec wiring.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 0m 33s | Cost: $3.53 | Commit: 1f346914ee06607a5294a27d4ba102d8c6363a76
If this code review was useful, please react with 👍. Otherwise, react with 👎.
Auth-Data-Jwt appears on ~187 operations in the vendored spec but is a vendor spec artifact — the live Adobe gateway authenticates on Authorization: Bearer only (same finding as rainer-friederich CR2 on Project Engine PR #1661, 2026-06-15). Sending Auth-Data-Jwt returns 401. Update README and test label to make clear this is a spec artifact, not the live auth contract. A generation-time overlay to strip it from generated types follows in a later PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Hey @byteclimber,
Verdict: Approve - clean documentation fix, no blocking concerns.
Changes: Clarifies that Auth-Data-Jwt is a vendor spec artifact (not sent to the live gateway) in README and test descriptions (21 files).
Non-blocking (2): minor issues and suggestions
- nit: Blockquote break in the "Spec auth correction" callout - the sentence starting "Refresh is manual..." falls outside the
>prefix, making it render as body text rather than part of the callout -packages/spacecat-shared-user-manager-client/README.md:38 - nit: Root CLAUDE.md states "containing 23 packages" which becomes 24 after this PR merges - update the count or remove the hard number -
CLAUDE.md
Previously flagged, now resolved
- Generated-types test assertions now use spec-specific path fragments (
/v2/workspaces/{id}/child,/v1/workspaces/{id}/status) that discriminate against wrong-spec wiring.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 0m 46s | Cost: $2.41 | Commit: ce524e41219635cfe984b78f820c821f31017d56
If this code review was useful, please react with 👍. Otherwise, react with 👎.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirror the project-engine-client overlay machinery so the vendored Semrush
User Manager swagger can be corrected at generation time without ever editing
the pristine vendored file (kept faithful for re-vendoring).
scripts/apply-overlay.mjs is a small generic OpenAPI-Overlay applier (update /
remove with a tiny JSONPath dialect) that reads spec/overlays/corrections.yaml
and rewrites the swagger2openapi output build/openapi3.json in place. The YAML
is the single source of truth for the corrections; the script just executes it.
Wired into `npm run generate` as the spec:overlay step (js-yaml devDep added).
Two corrections, both verified against the live API and its api-service
transport (src/support/serenity/rest-transport.js):
- CR1: the spec models Auth-Data-Jwt as a required header on ~187 operations,
but the live API authenticates on Authorization: Bearer <IMS> only (Semrush
accepts the IMS bearer directly). Remove Auth-Data-Jwt from every operation
and add an imsBearer security scheme + global security requirement.
- CR2: GET /v1/workspaces/{id}/status is typed as an array of
WorkspaceCheckResponse, but the live API returns a single object
({ status: "not ready" | "created" | "error" }) — the transport reads it as
status.status === 'created'. Drop the array wrapper.
Regenerated src/generated/types.ts (Auth-Data-Jwt header gone from all ops,
status 200 now a single object; path/operation/schema counts unchanged). The
Pydantic models are unaffected (the overlay touches auth headers and a response
envelope, neither of which is a component schema). Added overlay-guard tests
pinning CR1 and CR2 against the generated surface; reworded the vendored-spec
Auth-Data-Jwt test to drop the inaccurate "Adobe gateway" framing.
LLMO-5461
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the js-yaml entry to package-lock.json to match the devDependency added in the previous commit. Fixes the CI "Verify package-lock.json is in sync" gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
README was written for a pre-overlay foundation slice and described the
correction overlay as a follow-up; it also carried the inaccurate "Adobe
gateway" framing and an unverified admin/API-Key auth split. Rewrite it to
match what this PR actually ships:
- the overlay is present, not a follow-up; added a "Spec corrections" section
documenting CR1 (strip Auth-Data-Jwt, add imsBearer — Semrush accepts the IMS
bearer directly) and CR2 (GET /v1/workspaces/{id}/status returns a single
object, not an array);
- dropped the "Adobe gateway"/token-exchange fiction and the unverified
API-Key admin-route claim (no gateway exists; the live API takes Bearer IMS);
- wired the overlay step into the pipeline diagram + commands table; fixed a
run-on sentence in the spec-source note; the client wrapper + stateful mock
remain the genuine follow-ups.
Also sync the overlay applier with the project-engine-client copy (LLMO-5461),
which was refactored to be unit-testable: scripts/apply-overlay.mjs now exports
its pure functions and runs IO only via a guarded main(), and a 0-match remove
warns (stale-correction signal) while a 0-match update still throws. Ported the
matching test/overlay.test.js (added sinon devDep). The two copies now differ
only by their header comment; a shared extraction is a tracked follow-up.
Suite: 24 passing, lint clean, package-lock in sync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README: drop the "this PR vendors…" framing — a README is durable package
docs, not a PR description, and that line reads wrong the moment it merges.
Replaced with a roadmap note ("Not here yet: …").
- Sync the overlay applier with the project-engine-client copy (LLMO-5461),
which was refactored again in review: applyOverlay() now returns a structured
result per action ({ target, remove, hits, staleRemove }) and prints nothing —
the CLI main() does all user-facing logging. The two copies again differ only
by their header comment.
- overlay.test.js asserts the structured result (no console stubbing), so it no
longer needs sinon — dropped the now-unused sinon devDep.
Suite: 24 passing, lint clean, package-lock in sync; regenerated types.ts is
byte-identical (the refactor is output-equivalent).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@byteclimber — summary of what changed on this branch after your last commit ( The foundation slice (vendored spec + generated types + foundation test) is yours. Everything after 1. Spec-correction overlay + corrections (
Regenerated 2. README to mergeable + durable ( 3. Overlay applier kept in lockstep with the Project Engine copy. |
There was a problem hiding this comment.
Hey @byteclimber,
Verdict: Approve - clean foundation slice, prior blocking finding addressed, no new blocking concerns.
Changes: Vendors the Semrush User Manager Swagger 2.0 spec, adds a spec-correction overlay (CR1: auth scheme, CR2: response shape), wires a generation pipeline producing TypeScript and Pydantic types, and tests both the overlay logic and the generated surface (25 files).
Non-blocking (4): minor issues and suggestions
- suggestion: Guard
deepMergeagainst prototype-pollution keys (__proto__,constructor) - low risk today since the overlay is hand-authored, but trivial hardening if the function is reused -scripts/apply-overlay.mjs:121 - suggestion: Add a preflight check to the
generatescript (or split intogenerate:ts-only) so devs who lackdatamodel-codegenon PATH get a clear error instead of a partial pipeline failure -package.json:22 - nit: The CR2 overlay actions (remove then update) are order-dependent - a brief YAML comment noting "order matters" would prevent accidental reordering -
spec/overlays/corrections.yaml:42 - nit: Root CLAUDE.md states "containing 23 packages" which becomes 24 after this PR merges - update the count or remove the hard number -
CLAUDE.md
Previously flagged, now resolved
- Generated-types test assertions now use spec-specific path fragments (
/v2/workspaces/{id}/child,/v1/workspaces/{id}/status) that discriminate against wrong-spec wiring.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 2m 53s | Cost: $4.67 | Commit: dbd38ef641c43e90f8171eb20a442f68c939750d
If this code review was useful, please react with 👍. Otherwise, react with 👎.
From MysticatBot's approving review:
- apply-overlay deepMerge now skips prototype-pollution keys (__proto__,
constructor, prototype) — trivial hardening for the (hand-authored today,
reused tomorrow) overlay applier; covered by a new test.
- generate:pydantic preflights for datamodel-codegen on PATH and fails with a
clear "pip install datamodel-code-generator" message instead of a cryptic
partial-pipeline 127.
- corrections.yaml CR2: documented that the remove-then-update pair is
order-dependent (update deep-merges, so removing the array wrapper must run
first) to prevent accidental reordering.
- root CLAUDE.md: dropped the brittle hard-coded package count ("23 packages")
so it can't drift as packages are added.
24 passing + new guard test, lint clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the 4 non-blocking items from the approval (
24 passing + the new guard test, lint clean. Re-requesting review. |
The structure diagram still said "23 npm workspace packages" after the prose count was removed; drop the number there too so neither can drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Hey @byteclimber,
⚠ Degraded review - no spec document was found for this change (searched the PR links, the touched repos' docs, the architecture/guidelines docs, and linked Jira). This review covers code-level quality but could not validate the change against an agreed design, so confidence is reduced. Add a spec link (PR template section 4) and re-request review for a full-confidence pass.
Verdict: Approve - prior non-blocking suggestions all addressed cleanly, no new concerns.
Changes: Adds prototype-pollution guard to deepMerge, preflight check for datamodel-codegen, overlay ordering comment, and CLAUDE.md package-count fix (5 files).
Non-blocking (1): minor issues and suggestions
- nit: CLAUDE.md Monorepo Structure tree still says "23 npm workspace packages" but should be 24 after this PR merges (the Architecture Overview paragraph was fixed, but the tree diagram was not) -
CLAUDE.md
Previously flagged, now resolved
- deepMerge prototype-pollution guard implemented with Set-based key blocklist and test exercising JSON.parse bypass of V8 proto optimization.
- generate:pydantic script now fails fast with a clear error when datamodel-codegen is not on PATH.
- CR2 overlay actions now carry an ordering comment explaining why remove must precede update.
- Architecture Overview paragraph no longer hardcodes the package count.
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 1m 22s | Cost: $2.99 | Commit: a35445188d1c569795683ece56051fe20c97c151
If this code review was useful, please react with 👍. Otherwise, react with 👎.
There was a problem hiding this comment.
Hey @byteclimber,
⚠ Degraded review - no spec document was found for this change (searched the PR links, the touched repos' docs, the architecture/guidelines docs, and linked Jira). This review covers code-level quality but could not validate the change against an agreed design, so confidence is reduced. Add a spec link (PR template section 4) and re-request review for a full-confidence pass.
Verdict: Approve - prior nits cleanly addressed, no new concerns.
Changes: Addresses four non-blocking review suggestions (deepMerge prototype-pollution guard, pydantic preflight, overlay order comment, CLAUDE.md count fix) across 5 files.
Previously flagged, now resolved
- deepMerge now skips prototype-pollution keys (
__proto__,constructor,prototype) with a Set guard and accompanying test. generate:pydanticpreflights fordatamodel-codegenon PATH with a clear install message on failure.- CR2 overlay actions documented as order-dependent (remove before update to avoid invalid mixed schema).
- Root CLAUDE.md dropped the brittle hard-coded package count ("23 packages").
Skill: pr-review | Model: us.anthropic.claude-opus-4-6-v1[1m] | Duration: 7m 58s | Cost: $2.35 | Commit: 187e6f52699ce58fe874e73abfade00aeaefeed6
If this code review was useful, please react with 👍. Otherwise, react with 👎.
|
🎉 This PR is included in version @adobe/spacecat-shared-user-manager-client-v1.0.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
What
Adds
@adobe/spacecat-shared-user-manager-client— the foundation slice for typed integration with Semrush's User Manager API (/enterprise/users/api). Mirrors the Project Engine foundation (LLMO-5461), applied to the larger User Manager API (LLMO-5558).A private, types-only package (identical shape to
spacecat-shared-project-engine-client):spec/usermanager_swagger.yaml(Swagger 2.0, 234 paths / 284 operations, 187Auth-Data-Jwtuser-facing routes + admin API-Key routes).npm run generate:swagger2openapi --patch→openapi-typescript(src/generated/types.ts, all ops) +datamodel-codegen(python/serenity_user_manager/, Pydantic v2).Auth-Data-Jwt) and key generated paths.What's deferred (follow-up PRs, per the Project Engine sequencing)
UserManagerApiClient(openapi-fetchover the generatedpaths) with dual auth — caller's raw IMS token asAuthorization: Bearerfor user-facing routes, API-Key header for admin routes (andAuth-Data-Jwtnarrowed out of the public surface).spacecat-api-service(swap the hand-rolledserenity/rest-transport.jsUSERS_API_PREFIXcalls).Notes
SEMRUSH_PROJECTS_BASE_URL); only the basePath differs.linguist-generated(.gitattributes), so they collapse in review.datamodel-code-generatoris a Python tool (not an npm dep):pip install datamodel-code-generator.Validation
npm run generate→types.ts(25.5k lines) + Pydantic package.npm test→ 7 passing (foundation).npm run lint→ clean.🤖 Generated with Claude Code