Skip to content

Add project routes API - #219

Merged
ricardo-agz merged 4 commits into
mainfrom
ricardo/project-routes-api
Aug 5, 2026
Merged

Add project routes API#219
ricardo-agz merged 4 commits into
mainfrom
ricardo/project-routes-api

Conversation

@ricardo-agz

@ricardo-agz ricardo-agz commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Add sync and async clients for the project routes API, exposed as
Vercel.project_routes and AsyncVercel.project_routes.

Everything in and out is a frozen Pydantic model with snake_case fields; an
alias generator handles the camelCase wire format. Changes stage first, and
promoting the staged version publishes them:

from vercel.client import Vercel
from vercel.project_routes import RewriteRoute

vercel = Vercel(access_token="...")

added = vercel.project_routes.add_route(
    project_id="prj_123",
    route=RewriteRoute(name="Rewrite /old to /new", source="/old", destination="/new"),
)

vercel.project_routes.update_route_version(
    project_id="prj_123", version_id=added.version.id, action="promote"
)

Results round-trip back into the API. Anything the authoring models
(RewriteRoute, RedirectRoute, SetStatusRoute) don't cover can be passed
as a vercel.json-shaped mapping and is validated into a model:

result = vercel.project_routes.get_routes(project_id="prj_123")

vercel.project_routes.stage_routes(
    project_id="prj_123",
    routes=[r for r in result.routes if r.enabled],
    overwrite=True,
)

vercel.project_routes.add_route(
    project_id="prj_123",
    route={
        "name": "Beta users only",
        "srcSyntax": "path-to-regexp",
        "route": {
            "src": "/beta/:path*",
            "dest": "/app/:path*",
            "has": [{"type": "cookie", "key": "beta", "value": "1"}],
        },
    },
)

Notes

  • All eight operations are covered, including edit_route(restore=True) to
    roll a rule back to production, get_routes(diff="only") to preview staged
    changes, and generate_route, which returns a GeneratedRoute suggestion
    from a prompt and accepts a previous suggestion to refine.
  • Server constraints fail fast as ValueError: route xor restore,
    before/after placement needs reference_id, diff excludes search/filter,
    redirect statuses limited to 301/302/303/307/308.
  • Failed requests raise ProjectRoutesError with status_code, the API error
    code, and the parsed body. Response types match the api-project-routes
    schemas.

Validation

uv run poe test vercel (872 passed, 27 skipped), plus lint and typecheck.

Expose routing-rule and version operations through sync and async clients so Python users can manage project routes without raw requests.
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vercel-py Ready Ready Preview Aug 5, 2026 7:41pm

Request Review

Expose RewriteRoute and semantic operation arguments so Python users can author routing rules without constructing REST request bodies.

@scotttrinh scotttrinh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good! Seems funny to add iter_coroutine and our transport to this old API, but that works for me anyway.

Return frozen snake_case dataclasses from every operation instead of
camelCase wire mappings, following the blob and sandbox conventions.
Version envelopes unwrap: stage_routes and update_route_version return
RouteVersion, and get_route_versions returns list[RouteVersion].

Add RedirectRoute and SetStatusRoute alongside RewriteRoute, and
round-trip fetched routes back into staging via
ProjectRoute.to_staged_input(). Rename q, filter, and
update_route_versions to search, route_type, and update_route_version,
flatten position into placement and reference_id, and validate
client-side what the server would reject (route xor restore, empty
route_ids, diff combined with search or filtering, placement
references, redirect statuses).

Align response types with the API: add diff_count, allow a null
version, make the edited route optional, and trim RouteDefinition to
the fields the API accepts. generate_route now raises on failure, and
ProjectRoutesError carries the API error code.
Replace the dataclass results and TypedDict inputs with frozen
Pydantic models, per the SDK-wide decision to standardize on Pydantic.
A camelCase alias generator handles the wire format, so models are
constructed and read in snake_case while validating and serializing
the API shapes. Plain vercel.json-shaped mappings are still accepted
anywhere a route is expected and are validated into models.

The inner routing rule is now a typed RouteDefinition model rather
than a mapping, and the hand-written response parsers are replaced by
model validation. Per-field aliases are avoided deliberately: under
dataclass_transform they would force alias keywords in constructors.
@ricardo-agz
ricardo-agz merged commit c617539 into main Aug 5, 2026
18 of 19 checks passed
@ricardo-agz
ricardo-agz deleted the ricardo/project-routes-api branch August 5, 2026 20:23
This was referenced Aug 5, 2026
This was referenced Aug 7, 2026
nsidnev added a commit that referenced this pull request Aug 7, 2026
Release Packages

vercel-internal-core
--------------------

0.1.2 - 2026-08-07
------------------

Internal
--------

- Key session service options by logical service so synchronous and asynchronous variants share configuration safely. (#242)
- Absorb `typeutils` from `vercel-queue`: the annotation predicates and runtime forward-reference resolution now live in `vercel._internal.core.typeutils`, where more than one package can reach them. (#261)

vercel-oidc
-----------

0.8.0 - 2026-08-07
------------------

Features
--------

- Add OIDC token signature verification. `vercel.oidc.verify_vercel_oidc_token` and its async twin `vercel.oidc.aio.verify_vercel_oidc_token` verify a Vercel OIDC token against the JWKS at `oidc.vercel.com`, pinning the issuer, requiring RS256, and checking the project, environment, owner, and audience claims. `vercel.oidc.extract_bearer_token` reads the credential out of request headers. Verification fails closed: when the expected project or environment cannot be resolved from the arguments or the environment, every token is rejected. (#205)
- Claims are compared for equality only. There is no project wildcard: `"*"` is an ordinary string, so a token cannot widen its own scope to every project in a team. (#205)
- The issuer is pinned to Vercel's OIDC service and is not configurable. Both the root issuer `https://oidc.vercel.com` and the team-scoped `https://oidc.vercel.com/<team>` are accepted, since Vercel mints both and one global key signs them; the JWKS URL is a constant, so a token can never influence where signing keys come from. (#205)
- `vercel.oidc.resolve_vercel_oidc_token_identity`, and its async twin, return an opaque, stable identity for a token. A token is a signature over an identity plus an expiry, so one identity is issued many tokens over time; this is what to key identity-scoped client state on. The signature, issuer and expiry are verified before anything is read, but no claim is checked and none is returned, so it is not an authorization check. (#205)
- This requires the new `verify` extra, which pulls in `pyjwt[crypto]`: (#205)
- pip install "vercel-oidc[verify]" (#205)
- The extra keeps `cryptography` off installs that do not verify tokens. (#205)

Bug Fixes
---------

- Record JWKS refetch outcomes before allowing another caller to fetch, avoiding duplicate requests under concurrency. (#242)

vercel-connect
--------------

0.1.0 - 2026-08-07
------------------

Features
--------

- Add `vercel.connect`, a Python SDK for Vercel Connect: short-lived third-party credentials brokered through the deployment's Vercel OIDC identity, with token caching, authorization flows, connector metadata, and inbound trigger verification. (#205)

vercel-internal-telemetry
-------------------------

0.7.2 - 2026-08-07
------------------

- Update dependencies.

vercel-queue
------------

0.7.3 - 2026-08-07
------------------

Internal
--------

- Take `typeutils` from `vercel._internal.core` rather than carrying a private copy. Adds a dependency on `vercel-internal-core`. (#261)

vercel-sandbox
--------------

0.4.0 - 2026-08-07
------------------

Breaking Changes
----------------

- Require synchronous credential factories when configuring `vercel.sandbox.sync`; use asynchronous factories only with the async Sandbox API. (#242)
- Replace the legacy `runtime` selector with `image` when creating sandboxes. Sandbox creation now uses API v3, defaults to `vercel/sandbox/universal:latest`, and supports custom Vercel Container Registry images. (#252)

Internal
--------

- Run Sandbox examples through the package-owned workspace Poe task. (#234)

vercel-cache
------------

0.7.2 - 2026-08-07
------------------

- Update dependencies.

vercel
------

0.9.0 - 2026-08-07
------------------

Breaking Changes
----------------

- The local workflow world now stores its `.workflow-data` files as JSON in the same format the TypeScript `@workflow/world-local` package uses, instead of CBOR. Runs, steps, hooks and events written by either SDK are now readable by the other. Existing `.workflow-data` directories are not readable in the new format and should be deleted. (#226)
- Workflow payloads now use the devalue wire format of the TypeScript `@workflow/core` package. (#243)
- Workflow steps now ride the `__wkf_workflow_*` queue as a `stepId` on the workflow invoke payload, matching the TypeScript SDK; the separate `__wkf_step_*` queue is gone. (#251)

Features
--------

- Workflow payloads can now carry native `Decimal`, `UUID`, `date`, `time`, `timedelta` and `Path`, and `@serializable` (or `register_serializable()`) is offered for custom classes. (#224)
- Add sync and async clients with typed models for managing project-level routing rules and versions. (#219)

Bug Fixes
---------

- Allow workflows on Python 3.12 and earlier to import `uuid` by safely exposing `platform.system()` while continuing to block host-specific platform inspection. (#242)
- Prevent errors when tasks waiting on steps or hooks are cancelled. (#250)
- The Vercel world now honours `VERCEL_WORKFLOW_SERVER_URL` and `WORKFLOW_VERCEL_BACKEND_URL`, which previously had no effect in Python, so a preview deployment reaches the same workflow-server as its TypeScript peers. (#248)

Internal
--------

- Use a consistent isolated event-loop lifecycle for workflow execution on Python 3.10. (#242)
- Run workflows on a dedicated event loop that advances execution when the loop becomes idle. (#242)
- Avoid invoking the workflow event loop's idle hook after the loop begins stopping. (#242)

vercel-apscheduler
------------------

0.1.0 - 2026-08-07
------------------

Features
--------

- Add the durable Redis driver for running APScheduler schedules through delayed Vercel Queue messages. (#242)
- Add Redis-backed APScheduler subscribers for Vercel Queues. The integration patches `scheduler.start()`, `scheduler.pause()`, and `scheduler.resume()` with durable, deployment-scoped lifecycle transitions and atomic single-chain fencing. Paused occurrences are skipped on resume, and interrupted successor publication is repaired on retry. Production schedules activate on the first request, and opted-in previews stop after a durable idle timeout. Jobs that do not choose a `misfire_grace_time` run their occurrences whenever the wake arrives: the stock one-second grace assumes in-process wakeup precision that queue delivery cannot meet. (#238)
- Add a Vercel Runtime Cache backend and use it by default when Redis is not configured, so schedulers run with zero infrastructure. Jobs stay defined in code; the cache document only coordinates the chain (generation, start and wake bookkeeping, lifecycle flags). Because cache entries are evictable and per-region, the queue messages remain the authority: an evicted document is rebuilt from the arriving wake, idempotency keys still fence duplicate starts, and pause/resume flags additionally ride the start topic. Scheduler identity comes from the builder-assigned subscriber id, with a declared-subscriber lookup for web processes. Under `vercel dev` the backend falls back to a per-process in-memory cache and activates on the first request like production, using a stable deployment id derived from the project directory. (#245)

Bug Fixes
---------

- Fix the Runtime Cache backend to work under `vc dev`. (#253)

vercel-celery
-------------

0.7.3 - 2026-08-07
------------------

- Update dependencies.

vercel-dramatiq
---------------

0.7.2 - 2026-08-07
------------------

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants