Skip to content

feat: align client with project-scoped permissions API#11

Merged
ABujalance merged 4 commits into
mainfrom
feat/permissions-checks-improvements
Apr 21, 2026
Merged

feat: align client with project-scoped permissions API#11
ABujalance merged 4 commits into
mainfrom
feat/permissions-checks-improvements

Conversation

@ABujalance

@ABujalance ABujalance commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Mirrors the backend permissions rework. The backend now enforces project scope on endpoints that carry a projectId; this PR brings the client surface in line. Also introduces a dedicated PlatformClient for apps / frontend code so JWT-authenticated callers have a typed entry point for the routes API tokens can't reach.

Changes

  • executeComponent: executionParams.projectId is now typed as a reserved key. Foreign project ids are rejected 403 by the backend.
  • listExecutions(componentId, projectId?): forwards the projectId query param to the scoped backend route.
  • Vitest harness covering the HTTP contract.
  • CONTEXT.md: "Permissions contract" section documenting the projectId invariant.

v2 updates

  • New PlatformClient — extends EngineServicesClient with a bearer-only constructor. On top of the inherited API-token-compatible surface, it owns getProject, getProjectData, checkPermission, and checkPermissionBatch. Those hit ProjectController in the backend (guarded by JWT) and are not reachable via an access token, so having them on the API-token-compatible parent class was a typing lie — API-token callers got compile-success and runtime-401. Now they get a compile error instead.
  • Token-provider supportPlatformClient constructor accepts either a static JWT or a provider function () => string | Promise<string>. When a function is passed, it's called on every request, so Auth0's getAccessTokenSilently() and similar refreshing sources Just Work; expired JWTs no longer stick around.
  • PlatformClient.fromPlatformContext() static factory for apps running inside the platform iframe.
  • Project-scoped listings via projectId querylistFiles({ projectId }), listFolders({ projectId }), listApps({ projectId }), listComponents({ projectId }) now forward the param to GET /item?projectId=X / GET /item/folder?projectId=X on the backend. Per-entity filtering applied server-side.
  • Removed the v1 listProjectFiles / listProjectFolders / listProjectApps / listProjectComponents convenience helpers — they pointed at JWT-only /project/:id/* routes, wrong target for an API-token library.
  • Changeset (.changeset/bright-permissions-unlocked.md, minor bump) with the breaking-note on the removed helpers.

Related

Mirrors backend changes from thatopen/backend-api
feat/permissions-checks-improvements. Clients that assert a projectId
now match what the backend expects; new project-scoped list helpers
unlock use cases where components want to enumerate resources inside a
specific project.

- executeComponent: typed projectId as a reserved key on executionParams.
  The backend now rejects foreign projectIds with 403.
- listExecutions(componentId, projectId?) forwards the projectId query
  param to the scoped endpoint.
- checkPermission returns { hasPermission, scope }; add
  checkPermissionBatch for batch checks.
- New listProjectFiles / listProjectFolders / listProjectApps /
  listProjectComponents wrappers.
- Vitest harness for the HTTP client with contract coverage of the
  methods above.
- CONTEXT.md gains a "Permissions contract" section.
… listFiles/Folders/Apps/Components

- New PlatformClient (bearer-only) for apps / frontends / JWT users.
  Composes EngineServicesClient under the hood — zero duplication.
- EngineServicesClient now supports projectId on listFiles / listFolders /
  listApps / listComponents, hitting the new public routes
  GET /item?projectId and GET /item/folder?projectId.
- Removed the v1 listProjectFiles / listProjectFolders / listProjectApps /
  listProjectComponents helpers that pointed at JWT-only /project routes;
  those were the wrong target for a component client.
- CONTEXT.md: documents the two-client split (components vs apps/FE).
- Vitest: surface-contract tests for PlatformClient (authoritative list of
  what it exposes and what it doesn't) plus query-string checks for the
  new projectId path.
Instead of wrapping EngineServicesClient behind a narrowed surface,
PlatformClient now subclasses it and only swaps the constructor to
force Bearer auth. The full method vocabulary is inherited — apps and
frontends that need executeComponent or other methods can use them
from the same client, with the user's JWT.

- PlatformClient constructor: (bearerToken, apiUrl, props?) with
  useBearer removed from the prop surface.
- Vitest: replace "does not expose" assertions with instanceof +
  ts-expect-error contract tests that lock the constructor shape.
- CONTEXT.md: simplify the two-client split description.
- Add .changeset/bright-permissions-unlocked.md — minor bump with
  breaking-note on the removed listProject* helpers.
- getProject / getProjectData / checkPermission / checkPermissionBatch
  cannot be reached with an API token (ProjectController is JWT-guarded
  on the backend). Moved from EngineServicesClient to PlatformClient so
  the types reflect that reality — API-token callers get a compile error
  instead of a runtime 401.
- PlatformClient constructor accepts string | () => string | Promise<string>.
  When a function is passed, it's called on every request — Auth0's
  getAccessTokenSilently() and similar refreshing sources Just Work,
  so an expired JWT no longer sticks.
- Added PlatformClient.fromPlatformContext() for apps running inside the
  platform iframe.
- EngineServicesClient now exposes a protected resolveAccessToken() hook;
  #requestApi and #requestFile route through it.
@ABujalance ABujalance merged commit b108648 into main Apr 21, 2026
1 check passed
@agviegas agviegas deleted the feat/permissions-checks-improvements branch June 4, 2026 21:52
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.

1 participant