From aa31ec0068893da94a785419d8c06695b7260d2f Mon Sep 17 00:00:00 2001 From: Jeroen Rinzema Date: Tue, 23 Jun 2026 00:00:38 +0200 Subject: [PATCH 1/5] feat!: require projectId and move client API under /projects/{projectId} 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}/...`. --- README.md | 32 ++++++++++++-- package.json | 1 + src/core/http.ts | 14 +++++- src/index.ts | 6 ++- src/types/common.ts | 5 +++ src/utils/crypto.ts | 6 ++- test/e2e.test.ts | 6 ++- test/url.test.ts | 101 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 test/url.test.ts diff --git a/README.md b/README.md index d0fc288..53e7df0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ npm install @lunogram/js-sdk ```typescript import { Lunogram } from '@lunogram/js-sdk' -const lunogram = new Lunogram('your-api-key') +// The project UUID is required and scopes every request to that project. +const lunogram = new Lunogram('your-api-key', 'your-project-uuid') // Identify a user await lunogram.user.upsert({ @@ -46,6 +47,27 @@ await lunogram.organization.upsert({ }) ``` +## Project Scoping + +Every Lunogram Client API request is scoped to a single **project**. You supply +the project UUID once, when constructing the client, and the SDK injects it into +every request path automatically — you never pass it per call. + +All Client API endpoints live under `/api/client/projects/{projectId}/...`: + +| Operation | Path | +| ------------------------ | ----------------------------------------------------------------- | +| Users | `/api/client/projects/{projectId}/users` | +| User events | `/api/client/projects/{projectId}/users/events` | +| User scheduled | `/api/client/projects/{projectId}/users/scheduled` | +| Organizations | `/api/client/projects/{projectId}/organizations` | +| Organization members | `/api/client/projects/{projectId}/organizations/users` | +| Organization events | `/api/client/projects/{projectId}/organizations/events` | +| Organization scheduled | `/api/client/projects/{projectId}/organizations/scheduled` | + +The `projectId` must be a valid UUID; the client throws a `ValidationError` at +construction time if it is missing, empty, or malformed. + ## Identity Model Users and organizations are identified by an array of `ExternalID` objects: @@ -69,7 +91,10 @@ The SDK automatically generates an anonymous identifier for each session. When y ```typescript import { BrowserClient } from '@lunogram/js-sdk' -const client = new BrowserClient({ apiKey: 'your-api-key' }) +const client = new BrowserClient({ + apiKey: 'your-api-key', + projectId: 'your-project-uuid', +}) // anonymousId is auto-generated client.user.anonymousId @@ -100,7 +125,7 @@ The SDK is also exposed on `window.Lunogram`: ```html