refactor!: generate the Client API layer from the OpenAPI spec#8
Merged
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}/...`.
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 was referenced Jun 23, 2026
Cover the remaining Client API endpoints in the hand-written facade now that the low-level layer is generated from the OpenAPI spec: - user & organization inbox (create, query, count, read, archived) - user device registration for push subscriptions - project VAPID public key - end-user session token minting In the browser client, device registration inherits the session identifier the same way events and scheduled resources do. Pin the vendored spec to the v0.1.0-rc.1 release asset (a stable, immutable source) and drop the spec-sync workflow.
This was referenced Jun 25, 2026
The e2e suite requires a project ID now that the Client API is scoped
under /projects/{projectId}, but the workflow never passed one. Wire the
secret through so the suite can run once LUNOGRAM_PROJECT_ID is set in
repository secrets.
- url.test.ts: assert routing/method for the previously untested facade methods (user/org delete, schedule delete, org scheduled, removeUser, org inbox count/read/archived). - browser.test.ts (new): cover the browser SDK's signature feature — the auto anonymous id, sticky external id, identifier injection into events/ scheduled/devices, the match-event exemption, and identifier merging. - Run browser.test.ts in the `test` script alongside url.test.ts. - Let the browser devices.register omit the identifier (so injection is usable, matching events/scheduled).
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.
Migrates the JS SDK to the spec-driven pattern shared across the Lunogram SDKs (mirrors
go-sdk): the low-level layer is generated from the platform's OpenAPI spec and a thin hand-written facade keeps the ergonomic, namespaced API.This PR supersedes and folds in #7 (require
projectId+ move the Client API under/projects/{projectId}). It also supersedes #5 and #6 (see below).What's here
spec/client.yamlis vendored from the platformv0.1.0-rc.1release asset;src/gen/schema.tsis generated from it viaopenapi-typescript(pnpm generate). A thinopenapi-fetchtransport (src/core/transport.ts) centralizes auth, project scoping, snake_case body mapping and the error hierarchy.projectId—new Lunogram(apiKey, projectId)/new Client({ apiKey, projectId }); every request is scoped under/api/client/projects/{projectId}/.... ThrowsValidationErrorif missing/malformed.Supersedes
http.tswas replaced bytransport.ts, whoseunwrap()returnsundefinedfor no-content responses; closing.Notes
spec-syncbot workflow is not included; bumping the spec is a manual edit tospec/SOURCE.md+pnpm generate.pnpm build,pnpm lintandpnpm test(19 tests) all pass.