feat!: require projectId and move Client API under /projects/{projectId}#7
Closed
jeroenrinzema wants to merge 1 commit into
Closed
feat!: require projectId and move Client API under /projects/{projectId}#7jeroenrinzema wants to merge 1 commit into
jeroenrinzema wants to merge 1 commit into
Conversation
The Lunogram Client API now scopes every authenticated endpoint to a
project: `/api/client/...` becomes `/api/client/projects/{projectId}/...`.
- Add required `projectId: string` to `ClientProps` (and as the new second
positional argument of the `Lunogram` constructor).
- Inject `/projects/{projectId}` centrally in `HttpHandler` so every current
and future resource path is scoped automatically.
- Validate `projectId` at construction: non-empty and a valid UUID, else
throw `ValidationError`.
- Update README, examples, and the e2e test; add a url.test.ts unit suite
asserting the new path prefix and validation behaviour.
BREAKING CHANGE: clients must now be constructed with a project UUID, and all
Client API requests target `/api/client/projects/{projectId}/...`.
This was referenced Jun 22, 2026
Contributor
Author
jeroenrinzema
added a commit
that referenced
this pull request
Jun 25, 2026
Migrate the SDK to spec-driven code generation with a layered design:
- Generated low-level layer (`src/gen/schema.ts`): all paths, operations and
payload types are generated from the vendored OpenAPI spec via
`openapi-typescript`. Committed, never hand-edited.
- Hand-written facade (`Lunogram` / `Client` / `BrowserClient` + resources):
keeps the stable public API, camelCase ergonomics, auth, projectId UUID
validation, browser support and the error hierarchy.
The transport is backed by `openapi-fetch` typed by the generated schema. The
`{projectID}` path param, `Bearer` auth header and camelCase->snake_case body
mapping are applied once in the transport/middleware, never per operation.
Spec is vendored at a pinned platform commit (no platform release needed); see
`spec/SOURCE.md`. CI gains a drift check (`pnpm generate` + `git diff`) and a
weekly `spec-sync` bump bot. Public API is unchanged from PR #7.
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
The Lunogram Client API now scopes every authenticated endpoint to a project. The project UUID becomes a path segment:
/api/client/...→/api/client/projects/{projectId}/...Auth is unchanged (same API key / token); only the URL gains the project. This is a hard cut — no backwards compatibility.
Per the locked design decision, the project is a required client-construction parameter, supplied once and injected into every Client API path automatically. Callers must NOT pass it per call.
Breaking change
ClientPropsgains a requiredprojectId: string. Omitting it is a TypeScript type error.Lunogramconvenience constructor signature changes from(apiKey, urlEndpoint?)to(apiKey, projectId, urlEndpoint?).projectIdis validated at construction: it must be non-empty and a valid UUID, otherwise aValidationErroris thrown.Before / after
Resource usage (
client.user.*,client.organization.*) is otherwise unchanged.Old → new paths
/api/client/users/api/client/projects/{projectId}/users/api/client/users/events/api/client/projects/{projectId}/users/events/api/client/users/scheduled/api/client/projects/{projectId}/users/scheduled/api/client/organizations/api/client/projects/{projectId}/organizations/api/client/organizations/users/api/client/projects/{projectId}/organizations/users/api/client/organizations/events/api/client/projects/{projectId}/organizations/events/api/client/organizations/scheduled/api/client/projects/{projectId}/organizations/scheduledThe platform contract also moves
users/inbox*,users/devices,organizations/inbox*,push/vapid, andauth-methods/{id}/sessionsunder/projects/{projectId}/.... Those endpoints are not implemented in this SDK, so no per-resource changes were needed — but the prefix is injected centrally inHttpHandler, so any future resource is scoped automatically with no double-prefix.Implementation
/projects/{projectId}segment is injected in exactly one place —HttpHandler.#requestinsrc/core/http.ts— where every request URL is built.Files touched
src/types/common.ts— add requiredprojectIdtoClientProps.src/core/http.ts— store, validate (non-empty + UUID), and inject the project segment.src/utils/crypto.ts— addisUuidhelper (uses the existinguuiddependency).src/index.ts—Lunogramconstructor takesprojectId.README.md— updated all examples + new "Project Scoping" section with the path table.test/e2e.test.ts— requireLUNOGRAM_PROJECT_ID, construct withprojectId.test/url.test.ts— new unit suite asserting the/client/projects/{projectId}/prefix for every resource, no double-prefix, andprojectIdvalidation.package.json— add offlinetestscript (vitest run test/url.test.ts).Validation
pnpm build✅pnpm lint✅pnpm test✅ (10 passed)pnpm test:e2erequires a live API +LUNOGRAM_API_KEY/LUNOGRAM_PROJECT_ID, not run here.Rollout
Depends on the platform Client API change that introduces the
/projects/{projectId}path. Merge once that ships.