@seliseblocks/client 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,427 @@
1
+ export class BlocksAuthenticationClient {
2
+ clientConfig;
3
+ fetchImpl;
4
+ constructor(clientConfig, fetchImpl = globalThis.fetch) {
5
+ this.clientConfig = clientConfig;
6
+ this.fetchImpl = fetchImpl;
7
+ if (!this.fetchImpl)
8
+ throw new Error("Blocks client requires fetch.");
9
+ }
10
+ /**
11
+ * What: discovers tenant login options through `GET /iam/v4/auth/login-options`.
12
+ * Why: login screens need to know which login methods the tenant supports before rendering controls.
13
+ * How: call it before showing your login UI; it is public and still sends `x-blocks-key`.
14
+ */
15
+ loginOptions() {
16
+ return this.json("/iam/v4/auth/login-options", { auth: false });
17
+ }
18
+ /**
19
+ * What: executes username/password login through `POST /iam/v4/auth/login`.
20
+ * Why: apps that own their login UI need a direct AuthController login call.
21
+ * How: pass IAM's expected login payload; the SDK returns IAM's response as-is and does not store tokens.
22
+ */
23
+ login(request) {
24
+ return this.json("/iam/v4/auth/login", {
25
+ auth: false,
26
+ body: request
27
+ });
28
+ }
29
+ /**
30
+ * What: starts social login through `GET /iam/v4/auth/social/initiate`.
31
+ * Why: custom login screens may offer social providers while keeping the app in charge of UI.
32
+ * How: provide the public browser client id and redirect URI, then follow IAM's returned social-login response.
33
+ */
34
+ socialInitiate(clientId, redirectUri) {
35
+ return this.json("/iam/v4/auth/social/initiate", {
36
+ auth: false,
37
+ query: { clientId, redirectUri }
38
+ });
39
+ }
40
+ /**
41
+ * What: completes social login through `POST /iam/v4/auth/social/callback`.
42
+ * Why: the app receives the provider callback but IAM owns the token/session response contract.
43
+ * How: pass the callback payload your app received; store returned tokens in your app layer if IAM returns tokens.
44
+ */
45
+ socialCallback(request) {
46
+ return this.json("/iam/v4/auth/social/callback", {
47
+ auth: false,
48
+ body: request
49
+ });
50
+ }
51
+ /**
52
+ * What: refreshes an AuthController token through `POST /iam/v4/auth/refresh`.
53
+ * Why: direct AuthController sessions refresh through AuthController instead of the OIDC token endpoint.
54
+ * How: pass the refresh payload your app owns; the SDK does not read or write token storage.
55
+ */
56
+ refresh(request = {}) {
57
+ return this.json("/iam/v4/auth/refresh", {
58
+ auth: false,
59
+ body: request
60
+ });
61
+ }
62
+ /**
63
+ * What: switches the active organization through `POST /iam/v4/auth/switch-org`.
64
+ * Why: multi-organization users need a new IAM response for the selected organization context.
65
+ * How: pass `organizationId` plus the refresh/session fields IAM expects; then replace app-owned session state with the response if needed.
66
+ */
67
+ switchOrganization(request) {
68
+ return this.json("/iam/v4/auth/switch-org", { body: request });
69
+ }
70
+ /**
71
+ * What: reads OIDC-style current-user info through `GET /iam/v4/auth/me`.
72
+ * Why: apps may need profile claims from AuthController, separate from full IAM `iam.me()`.
73
+ * How: call after `accessToken` is available on `createBlocksClient`.
74
+ */
75
+ userInfo() {
76
+ return this.json("/iam/v4/auth/me");
77
+ }
78
+ /**
79
+ * What: logs out the current session through `POST /iam/v4/auth/logout`.
80
+ * Why: the app can ask IAM to invalidate the current session/refresh token while clearing its own local state.
81
+ * How: pass IAM's logout payload, commonly including `refreshToken`.
82
+ */
83
+ logout(request = {}) {
84
+ return this.json("/iam/v4/auth/logout", { body: request });
85
+ }
86
+ /**
87
+ * What: logs out all supported sessions through `POST /iam/v4/auth/logout-all`.
88
+ * Why: security-sensitive apps may offer a sign-out-everywhere action.
89
+ * How: pass IAM's logout-all payload and clear app-owned session state after success.
90
+ */
91
+ logoutAll(request = {}) {
92
+ return this.json("/iam/v4/auth/logout-all", { body: request });
93
+ }
94
+ /**
95
+ * What: registers a user through `POST /iam/v4/auth/signup`.
96
+ * Why: apps may own their signup page while IAM owns account creation rules.
97
+ * How: send IAM's signup payload and render IAM's response/errors directly.
98
+ */
99
+ signup(request) {
100
+ return this.json("/iam/v4/auth/signup", { auth: false, body: request });
101
+ }
102
+ /**
103
+ * What: starts account/password recovery through `POST /iam/v4/auth/recover`.
104
+ * Why: apps need a public recovery entry point.
105
+ * How: pass the email or recovery payload IAM expects and return IAM's response to the UI.
106
+ */
107
+ recover(request) {
108
+ return this.json("/iam/v4/auth/recover", { auth: false, body: request });
109
+ }
110
+ /**
111
+ * What: completes password reset through `POST /iam/v4/auth/reset-password`.
112
+ * Why: IAM owns reset-token validation and password policy enforcement.
113
+ * How: pass the reset payload from your reset form and show IAM's response/errors.
114
+ */
115
+ resetPassword(request) {
116
+ return this.json("/iam/v4/auth/reset-password", { auth: false, body: request });
117
+ }
118
+ /**
119
+ * What: changes password through `POST /iam/v4/auth/change-password`.
120
+ * Why: authenticated users need an account-security action inside your app.
121
+ * How: pass IAM's change-password payload after an access token is available.
122
+ */
123
+ changePassword(request) {
124
+ return this.json("/iam/v4/auth/change-password", { body: request });
125
+ }
126
+ /**
127
+ * What: activates an account through `POST /iam/v4/auth/activate`.
128
+ * Why: signup or invitation flows may require an activation step.
129
+ * How: pass the activation code/token payload IAM expects.
130
+ */
131
+ activate(request) {
132
+ return this.json("/iam/v4/auth/activate", { auth: false, body: request });
133
+ }
134
+ /**
135
+ * What: requests another activation message through `POST /iam/v4/auth/resend-activation`.
136
+ * Why: users may need a new activation link/code.
137
+ * How: pass IAM's resend payload; this call uses the active bearer token when configured.
138
+ */
139
+ resendActivation(request) {
140
+ return this.json("/iam/v4/auth/resend-activation", { body: request });
141
+ }
142
+ /**
143
+ * What: validates an activation payload through `POST /iam/v4/auth/validate-activation`.
144
+ * Why: apps can check activation state before committing the final activation UI step.
145
+ * How: pass the activation validation payload and render IAM's response.
146
+ */
147
+ validateActivation(request) {
148
+ return this.json("/iam/v4/auth/validate-activation", { auth: false, body: request });
149
+ }
150
+ idp = {
151
+ /**
152
+ * What: starts the Blocks IAM IdP-controller browser/provider flow through `GET /iam/v4/idp/initiate`.
153
+ * Why: hosted login should rely on IAM's IdP controller instead of manually constructing `oidc/authorize`.
154
+ * How: pass optional `clientId`, `redirectUri`, or `forwardedTo`; otherwise the SDK uses `createBlocksClient().oidc` defaults and returns IAM's redirect response.
155
+ */
156
+ initiate: (request = {}) => {
157
+ const oidc = this.oidcDefaults;
158
+ return this.json("/iam/v4/idp/initiate", {
159
+ auth: false,
160
+ query: {
161
+ clientId: request.clientId ?? oidc.clientId,
162
+ forwardedTo: request.forwardedTo,
163
+ redirectUri: request.redirectUri ?? oidc.redirectUri
164
+ }
165
+ });
166
+ },
167
+ /**
168
+ * What: starts hosted login and redirects the browser to IAM's returned provider URL.
169
+ * Why: browser apps often need one call that handles initiate plus navigation.
170
+ * How: call it from a login button handler; the function throws if IAM does not return `redirect_uri`.
171
+ */
172
+ redirectToProvider: async (request = {}) => {
173
+ const response = await this.idp.initiate(request);
174
+ const redirectUri = response.redirect_uri ?? response.redirectUri;
175
+ if (!redirectUri)
176
+ throw new Error("Blocks IdP initiate response did not include redirect_uri.");
177
+ window.location.assign(redirectUri);
178
+ },
179
+ /**
180
+ * What: completes the Blocks IAM IdP-controller callback through `GET /iam/v4/idp/callback`.
181
+ * Why: IAM owns the hosted callback contract and returns the auth response shape.
182
+ * How: pass `window.location.href` or an object with `code`, `state`, and optional OIDC error fields; store the returned tokens in your app layer if IAM returns tokens.
183
+ */
184
+ callback: (callback) => {
185
+ const params = typeof callback === "string" ? callbackParams(callback) : callback;
186
+ return this.json("/iam/v4/idp/callback", {
187
+ auth: false,
188
+ query: {
189
+ code: params.code,
190
+ error: params.error,
191
+ error_description: params.error_description,
192
+ state: params.state
193
+ }
194
+ });
195
+ },
196
+ /**
197
+ * What: reads public UI configuration from `GET /iam/v4/idp/oidc-ui-config`.
198
+ * Why: hosted auth pages may need tenant login settings such as captcha or UI config before authentication.
199
+ * How: call before rendering hosted-auth support UI; the SDK returns IAM's response body without reshaping.
200
+ */
201
+ uiConfig: () => this.json("/iam/v4/idp/oidc-ui-config", { auth: false })
202
+ };
203
+ oidc = {
204
+ /**
205
+ * What: refreshes an OIDC-flow token through `POST /iam/v4/oidc/token` with `grant_type=refresh_token`.
206
+ * Why: hosted IdP login relies on IdPController for browser login, but token refresh still belongs to the OIDC token endpoint.
207
+ * How: pass the refresh token your app owns; the SDK always sends `client_id` from the request or client OIDC config and returns IAM's token response without storing it.
208
+ */
209
+ refreshToken: (request = {}) => {
210
+ const clientId = request.clientId ?? this.clientConfig.oidc?.clientId;
211
+ if (!clientId)
212
+ throw new Error("Blocks OIDC clientId is required for refreshToken.");
213
+ return this.form("/iam/v4/oidc/token", {
214
+ client_id: clientId,
215
+ grant_type: "refresh_token",
216
+ refresh_token: request.refreshToken,
217
+ scope: request.scope
218
+ });
219
+ },
220
+ /**
221
+ * What: requests a machine token through `POST /iam/v4/oidc/token` with `grant_type=client_credentials`.
222
+ * Why: backend jobs or trusted server-side adapters may need service access to Blocks APIs.
223
+ * How: call only outside public browser code because it requires `clientSecret`.
224
+ */
225
+ clientCredentials: (request) => this.form("/iam/v4/oidc/token", {
226
+ client_id: request.clientId,
227
+ client_secret: request.clientSecret,
228
+ grant_type: "client_credentials",
229
+ scope: request.scope
230
+ })
231
+ };
232
+ identityProviders = {
233
+ /**
234
+ * What: lists configured identity providers through `GET /iam/v4/auth/identity-providers`.
235
+ * Why: admin UI can show available IdP configurations.
236
+ * How: call with a type parameter when your app has a specific response model.
237
+ */
238
+ list: () => this.json("/iam/v4/auth/identity-providers"),
239
+ /**
240
+ * What: reads one identity provider through `GET /iam/v4/auth/identity-providers/{id}`.
241
+ * Why: admin UI needs one record before edit/detail rendering.
242
+ * How: pass the IdP id from IAM.
243
+ */
244
+ get: (id) => this.json(`/iam/v4/auth/identity-providers/${encodeURIComponent(id)}`),
245
+ /**
246
+ * What: creates an identity provider through `POST /iam/v4/auth/identity-providers`.
247
+ * Why: authorized apps can configure tenant IdP options.
248
+ * How: pass IAM's IdP payload and receive IAM's response as-is.
249
+ */
250
+ create: (request) => this.json("/iam/v4/auth/identity-providers", { body: request }),
251
+ /**
252
+ * What: updates an identity provider through `PUT /iam/v4/auth/identity-providers/{id}`.
253
+ * Why: authorized apps can edit tenant IdP options.
254
+ * How: pass the IdP id and IAM's update payload.
255
+ */
256
+ update: (id, request) => this.json(`/iam/v4/auth/identity-providers/${encodeURIComponent(id)}`, {
257
+ body: request,
258
+ method: "PUT"
259
+ }),
260
+ /**
261
+ * What: changes identity-provider status through `PATCH /iam/v4/auth/identity-providers/{id}/status`.
262
+ * Why: admin UI can enable or disable an IdP without editing the whole configuration.
263
+ * How: pass the IdP id and status payload IAM expects.
264
+ */
265
+ updateStatus: (id, request) => this.json(`/iam/v4/auth/identity-providers/${encodeURIComponent(id)}/status`, {
266
+ body: request,
267
+ method: "PATCH"
268
+ }),
269
+ /**
270
+ * What: deletes an identity provider through `DELETE /iam/v4/auth/identity-providers/{id}`.
271
+ * Why: admin UI can remove tenant IdP configuration.
272
+ * How: pass the IdP id; IAM decides whether deletion is allowed.
273
+ */
274
+ delete: (id) => this.json(`/iam/v4/auth/identity-providers/${encodeURIComponent(id)}`, { method: "DELETE" })
275
+ };
276
+ config = {
277
+ /**
278
+ * What: reads auth configuration through `GET /iam/v4/auth/config`.
279
+ * Why: admin/settings UI can render current AuthController configuration.
280
+ * How: call after an authorized token is available.
281
+ */
282
+ get: () => this.json("/iam/v4/auth/config"),
283
+ /**
284
+ * What: saves auth configuration through `POST /iam/v4/auth/config`.
285
+ * Why: admin/settings UI can update AuthController behavior.
286
+ * How: pass IAM's config payload and receive IAM's response as-is.
287
+ */
288
+ update: (request) => this.json("/iam/v4/auth/config", { body: request })
289
+ };
290
+ userCodes = {
291
+ /**
292
+ * What: lists user codes through `GET /iam/v4/auth/user-codes`.
293
+ * Why: apps using user-code auth/admin flows can show existing generated codes.
294
+ * How: call from an authorized surface.
295
+ */
296
+ list: () => this.json("/iam/v4/auth/user-codes"),
297
+ /**
298
+ * What: generates a user code through `POST /iam/v4/auth/user-codes`.
299
+ * Why: apps using user-code flows need IAM to create the code.
300
+ * How: pass IAM's generation payload.
301
+ */
302
+ generate: (request) => this.json("/iam/v4/auth/user-codes", { body: request })
303
+ };
304
+ clientCredentials = {
305
+ /**
306
+ * What: lists client credentials through `GET /iam/v4/auth/client-credentials`.
307
+ * Why: authorized admin UIs can manage service credentials.
308
+ * How: call from a trusted/authorized management surface.
309
+ */
310
+ list: () => this.json("/iam/v4/auth/client-credentials"),
311
+ /**
312
+ * What: creates or updates client credentials through `POST /iam/v4/auth/client-credentials`.
313
+ * Why: authorized admin UIs can provision service credentials.
314
+ * How: pass IAM's credential payload; do not expose generated secrets in public UI longer than necessary.
315
+ */
316
+ save: (request) => this.json("/iam/v4/auth/client-credentials", { body: request }),
317
+ /**
318
+ * What: deletes a client credential through `DELETE /iam/v4/auth/client-credentials/{id}`.
319
+ * Why: authorized admin UIs can revoke service credentials.
320
+ * How: pass the credential id from IAM.
321
+ */
322
+ delete: (id) => this.json(`/iam/v4/auth/client-credentials/${encodeURIComponent(id)}`, { method: "DELETE" })
323
+ };
324
+ /**
325
+ * What: resolves the caller-owned bearer token configured on `createBlocksClient`.
326
+ * Why: the SDK must not own browser sessions or token storage, but protected API calls still need the active token.
327
+ * How: provide `accessToken` as a string or callback in client config; call this when adapters need to inspect the resolved token.
328
+ */
329
+ async accessToken() {
330
+ return typeof this.clientConfig.accessToken === "function"
331
+ ? await this.clientConfig.accessToken()
332
+ : this.clientConfig.accessToken;
333
+ }
334
+ /**
335
+ * What: checks whether `accessToken()` currently resolves a non-empty token.
336
+ * Why: apps may need a lightweight UI/session guard before rendering protected areas.
337
+ * How: use it as a convenience only; real authorization still comes from Blocks API responses and IAM permissions.
338
+ */
339
+ async isAuthenticated() {
340
+ return Boolean(await this.accessToken());
341
+ }
342
+ /**
343
+ * What: sends a JSON Auth/IdPController request and returns the parsed response body.
344
+ * Why: auth endpoints can return protocol-shaped errors, so this layer intentionally does not reshape non-2xx bodies.
345
+ * How: SDK methods call this with the exact IAM route, method, query, and payload.
346
+ */
347
+ async json(path, options = {}) {
348
+ const response = await this.raw(path, {
349
+ auth: options.auth,
350
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
351
+ headers: options.body === undefined ? undefined : { "Content-Type": "application/json" },
352
+ method: options.method ?? (options.body === undefined ? "GET" : "POST"),
353
+ query: options.query
354
+ });
355
+ return parseResponse(response);
356
+ }
357
+ /**
358
+ * What: sends an `application/x-www-form-urlencoded` OIDC token request.
359
+ * Why: `/iam/v4/oidc/token` follows OAuth/OIDC form-post semantics rather than JSON body semantics.
360
+ * How: OIDC token helpers pass grant fields here; the response body is returned exactly as IAM sends it.
361
+ */
362
+ async form(path, form) {
363
+ const body = new URLSearchParams();
364
+ for (const [key, value] of Object.entries(form)) {
365
+ if (value !== undefined)
366
+ body.set(key, value);
367
+ }
368
+ const response = await this.raw(path, {
369
+ auth: false,
370
+ body,
371
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
372
+ method: "POST"
373
+ });
374
+ return parseResponse(response);
375
+ }
376
+ async raw(path, options) {
377
+ const url = buildUrl(this.clientConfig.apiUrl, path, options.query);
378
+ const headers = new Headers(options.headers);
379
+ headers.set("Accept", "application/json");
380
+ headers.set("x-blocks-key", this.clientConfig.xBlocksKey);
381
+ if (options.auth !== false) {
382
+ const token = await this.accessToken();
383
+ if (token)
384
+ headers.set("Authorization", `Bearer ${token}`);
385
+ }
386
+ return this.fetchImpl(url, {
387
+ body: options.body,
388
+ headers,
389
+ method: options.method
390
+ });
391
+ }
392
+ get oidcDefaults() {
393
+ if (!this.clientConfig.oidc)
394
+ throw new Error("Blocks OIDC config is required.");
395
+ return this.clientConfig.oidc;
396
+ }
397
+ }
398
+ function callbackParams(callbackUrl) {
399
+ const url = new URL(callbackUrl);
400
+ return {
401
+ code: url.searchParams.get("code") ?? undefined,
402
+ error: url.searchParams.get("error") ?? undefined,
403
+ error_description: url.searchParams.get("error_description") ?? undefined,
404
+ state: url.searchParams.get("state") ?? undefined
405
+ };
406
+ }
407
+ function buildUrl(baseUrl, path, query) {
408
+ const url = new URL(path.replace(/^\/+/, ""), `${baseUrl.replace(/\/+$/, "")}/`);
409
+ for (const [key, value] of Object.entries(query ?? {})) {
410
+ if (value !== undefined)
411
+ url.searchParams.set(key, value);
412
+ }
413
+ return url.toString();
414
+ }
415
+ async function parseResponse(response) {
416
+ const text = await response.text();
417
+ const body = text ? parseJson(text) : undefined;
418
+ return body;
419
+ }
420
+ function parseJson(text) {
421
+ try {
422
+ return JSON.parse(text);
423
+ }
424
+ catch {
425
+ return text;
426
+ }
427
+ }
@@ -0,0 +1,77 @@
1
+ export type BlocksAuthResponse<T = Record<string, unknown>> = T & {
2
+ access_token?: string;
3
+ accessToken?: string;
4
+ data?: Record<string, unknown>;
5
+ error?: string;
6
+ error_description?: string;
7
+ expires_in?: number;
8
+ expiresIn?: number;
9
+ id_token?: string;
10
+ idToken?: string;
11
+ refresh_token?: string;
12
+ refreshToken?: string;
13
+ scope?: string;
14
+ token_type?: string;
15
+ tokenType?: string;
16
+ };
17
+ export type BlocksIdpInitiateRequest = {
18
+ clientId?: string;
19
+ forwardedTo?: string;
20
+ redirectUri?: string;
21
+ };
22
+ export type BlocksIdpInitiateResponse = {
23
+ redirect_uri?: string;
24
+ redirectUri?: string;
25
+ };
26
+ export type BlocksIdpCallbackRequest = {
27
+ code?: string;
28
+ error?: string;
29
+ error_description?: string;
30
+ state?: string;
31
+ };
32
+ export type BlocksLoginOption = Record<string, unknown>;
33
+ export type BlocksOidcUserInfo = Record<string, unknown> & {
34
+ email?: string;
35
+ name?: string;
36
+ picture?: string;
37
+ sub?: string;
38
+ };
39
+ export type BlocksAuthLoginRequest = Record<string, unknown> & {
40
+ captchaCode?: string;
41
+ language?: string;
42
+ password?: string;
43
+ rememberMe?: boolean;
44
+ username?: string;
45
+ };
46
+ export type BlocksSocialLoginRequest = Record<string, unknown> & {
47
+ code?: string;
48
+ redirectUri?: string;
49
+ state?: string;
50
+ };
51
+ export type BlocksRefreshRequest = Record<string, unknown> & {
52
+ refreshToken?: string;
53
+ };
54
+ export type BlocksLogoutRequest = Record<string, unknown> & {
55
+ refreshToken?: string;
56
+ };
57
+ export type BlocksSwitchOrganizationRequest = Record<string, unknown> & {
58
+ organizationId?: string;
59
+ refreshToken?: string;
60
+ };
61
+ export type BlocksOidcRefreshRequest = {
62
+ clientId?: string;
63
+ refreshToken?: string;
64
+ scope?: string;
65
+ };
66
+ export type BlocksClientCredentialsRequest = {
67
+ clientId: string;
68
+ clientSecret: string;
69
+ scope?: string;
70
+ };
71
+ export type BlocksAuthPassThroughResponse = Record<string, unknown>;
72
+ export type BlocksAuthJsonOptions = {
73
+ auth?: boolean;
74
+ body?: unknown;
75
+ method?: string;
76
+ query?: Record<string, string | undefined>;
77
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ import { BlocksAuthenticationClient } from "./auth/auth-client.js";
2
+ import { BlocksDataClient } from "./data/data-client.js";
3
+ import { BlocksHttpClient } from "./http/http-client.js";
4
+ import { BlocksIAMClient } from "./iam/iam-client.js";
5
+ import { BlocksLocalizationClient } from "./localization/localization-client.js";
6
+ export type BlocksOidcConfig = {
7
+ /**
8
+ * Public browser OIDC client id used by Blocks IAM IdpController and refresh-token calls.
9
+ */
10
+ clientId: string;
11
+ /**
12
+ * Browser callback URL registered for the client. Defaults to `<origin>/login/callback` in browsers.
13
+ */
14
+ redirectUri?: string;
15
+ /**
16
+ * OIDC scope used by default for hosted login/refresh helpers. Defaults to `openid profile`.
17
+ */
18
+ scope?: string;
19
+ /**
20
+ * IAM/OIDC authority URL kept for app-level metadata. Blocks API calls in this SDK use `apiUrl`.
21
+ */
22
+ url: string;
23
+ };
24
+ export type BlocksClientConfig = {
25
+ /**
26
+ * Caller-owned bearer token or token resolver.
27
+ * The SDK reads it before protected API calls, but never stores, refreshes, or clears it.
28
+ */
29
+ accessToken?: string | (() => Promise<string | undefined> | string | undefined);
30
+ /**
31
+ * Blocks API base URL, for example `https://api.seliseblocks.com`.
32
+ */
33
+ apiUrl: string;
34
+ /**
35
+ * Optional Blocks application domain for consumer app metadata.
36
+ */
37
+ appDomain?: string;
38
+ /**
39
+ * Optional fetch-compatible function for tests, SSR, or custom runtimes.
40
+ */
41
+ fetch?: typeof fetch;
42
+ /**
43
+ * Optional hosted IdP/OIDC browser-flow configuration.
44
+ */
45
+ oidc?: BlocksOidcConfig;
46
+ /**
47
+ * Required Blocks tenant key. The SDK sends this as the `x-blocks-key` header on every request.
48
+ */
49
+ xBlocksKey: string;
50
+ };
51
+ export type BlocksClient = {
52
+ auth: BlocksAuthenticationClient;
53
+ config: Readonly<RequiredConfig>;
54
+ data: BlocksDataClient;
55
+ http: BlocksHttpClient;
56
+ iam: BlocksIAMClient;
57
+ localization: BlocksLocalizationClient;
58
+ };
59
+ export type RequiredConfig = {
60
+ accessToken?: string | (() => Promise<string | undefined> | string | undefined);
61
+ apiUrl: string;
62
+ appDomain?: string;
63
+ oidc?: BlocksOidcConfig & {
64
+ redirectUri: string;
65
+ scope: string;
66
+ };
67
+ xBlocksKey: string;
68
+ };
69
+ /**
70
+ * What: creates a framework-neutral Blocks SDK instance for one tenant/app runtime.
71
+ * Why: frontend code needs a single configured entry point for IAM, Auth, Data, and Localization APIs.
72
+ * How: pass `apiUrl` and `xBlocksKey`; optionally pass an `accessToken` callback and OIDC config. The SDK never adds `ProjectKey` and never stores tokens.
73
+ */
74
+ export declare function createBlocksClient(config: BlocksClientConfig): BlocksClient;
package/dist/client.js ADDED
@@ -0,0 +1,49 @@
1
+ import { BlocksAuthenticationClient } from "./auth/auth-client.js";
2
+ import { BlocksDataClient } from "./data/data-client.js";
3
+ import { BlocksHttpClient } from "./http/http-client.js";
4
+ import { BlocksIAMClient } from "./iam/iam-client.js";
5
+ import { BlocksLocalizationClient } from "./localization/localization-client.js";
6
+ /**
7
+ * What: creates a framework-neutral Blocks SDK instance for one tenant/app runtime.
8
+ * Why: frontend code needs a single configured entry point for IAM, Auth, Data, and Localization APIs.
9
+ * How: pass `apiUrl` and `xBlocksKey`; optionally pass an `accessToken` callback and OIDC config. The SDK never adds `ProjectKey` and never stores tokens.
10
+ */
11
+ export function createBlocksClient(config) {
12
+ const normalized = normalizeConfig(config);
13
+ const auth = new BlocksAuthenticationClient(normalized, config.fetch);
14
+ const http = new BlocksHttpClient(normalized, auth, config.fetch);
15
+ return {
16
+ auth,
17
+ config: normalized,
18
+ data: new BlocksDataClient(http),
19
+ http,
20
+ iam: new BlocksIAMClient(http),
21
+ localization: new BlocksLocalizationClient(http)
22
+ };
23
+ }
24
+ function normalizeConfig(config) {
25
+ if (!config.apiUrl)
26
+ throw new Error("Blocks client requires apiUrl.");
27
+ if (!config.xBlocksKey)
28
+ throw new Error("Blocks client requires xBlocksKey.");
29
+ return {
30
+ accessToken: config.accessToken,
31
+ apiUrl: trimTrailingSlash(config.apiUrl),
32
+ appDomain: config.appDomain,
33
+ oidc: config.oidc ? {
34
+ ...config.oidc,
35
+ redirectUri: config.oidc.redirectUri ?? browserRedirectUri(),
36
+ scope: config.oidc.scope ?? "openid profile"
37
+ } : undefined,
38
+ xBlocksKey: config.xBlocksKey
39
+ };
40
+ }
41
+ function browserRedirectUri() {
42
+ if (typeof window === "undefined") {
43
+ throw new Error("OIDC redirectUri is required outside a browser.");
44
+ }
45
+ return `${window.location.origin}/login/callback`;
46
+ }
47
+ function trimTrailingSlash(value) {
48
+ return value.replace(/\/+$/, "");
49
+ }