@nizam-os/dashboard-sdk 4.1.0 → 5.0.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.
@@ -16,6 +16,8 @@ export declare class OrganizationsClient {
16
16
  /**
17
17
  * Creates a brand-new tenant with the calling user as the founding admin. The id is assigned by Keycloak so the same value identifies the organization in both systems. Slug is derived from the name when not supplied.
18
18
  *
19
+ * Supports the standard `Idempotency-Key` header — submit a UUID v4 per logical attempt (same value on retry). Cached responses replay for matching request bodies; mismatching fingerprints surface as 409 `idempotency.key_conflict`.
20
+ *
19
21
  * @param {NizamDashboard.CreateOrganizationRequest} request
20
22
  * @param {OrganizationsClient.RequestOptions} requestOptions - Request-specific configuration.
21
23
  *
@@ -52,6 +52,8 @@ class OrganizationsClient {
52
52
  /**
53
53
  * Creates a brand-new tenant with the calling user as the founding admin. The id is assigned by Keycloak so the same value identifies the organization in both systems. Slug is derived from the name when not supplied.
54
54
  *
55
+ * Supports the standard `Idempotency-Key` header — submit a UUID v4 per logical attempt (same value on retry). Cached responses replay for matching request bodies; mismatching fingerprints surface as 409 `idempotency.key_conflict`.
56
+ *
55
57
  * @param {NizamDashboard.CreateOrganizationRequest} request
56
58
  * @param {OrganizationsClient.RequestOptions} requestOptions - Request-specific configuration.
57
59
  *
@@ -37,7 +37,7 @@ export declare class UsersClient {
37
37
  me(requestOptions?: UsersClient.RequestOptions): core.HttpResponsePromise<NizamDashboard.User>;
38
38
  private __me;
39
39
  /**
40
- * Dashboard sees co-members of the caller's active organization (tenant-scoped via the organization_users join). Platform staff bypass RLS and see across tenants, and may sort by `deleted_at`. RFC 8288 Link header carries `first`, `prev`, `next` rels alongside the body's bidirectional cursors.
40
+ * Dashboard sees co-members of the caller's active organization (tenant-scoped via the organization_users join). Platform staff bypass RLS and see across tenants. Allowed sort fields: `created_at`, `name` (prefix with `-` for descending). RFC 8288 Link header carries `first`, `prev`, `next` rels alongside the body's bidirectional cursors.
41
41
  *
42
42
  * @param {NizamDashboard.ListUsersRequest} request
43
43
  * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -75,44 +75,4 @@ export declare class UsersClient {
75
75
  */
76
76
  inviteUser(request: NizamDashboard.InviteUserRequest, requestOptions?: UsersClient.RequestOptions): core.HttpResponsePromise<NizamDashboard.UserResource>;
77
77
  private __inviteUser;
78
- /**
79
- * Tenant-admin operation. Sets `deleted_at = NOW()`. Subsequent dashboard reads filter the row out; platform staff can still surface and act on it.
80
- *
81
- * @param {NizamDashboard.SoftDeleteUserRequest} request
82
- * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
83
- *
84
- * @throws {@link NizamDashboard.UnauthorizedError}
85
- * @throws {@link NizamDashboard.ForbiddenError}
86
- * @throws {@link NizamDashboard.NotFoundError}
87
- * @throws {@link NizamDashboard.InternalServerError}
88
- *
89
- * @example
90
- * await client.users.softDeleteUser({
91
- * id: "00000000-0000-0000-0000-000000000000"
92
- * })
93
- */
94
- softDeleteUser(request: NizamDashboard.SoftDeleteUserRequest, requestOptions?: UsersClient.RequestOptions): core.HttpResponsePromise<void>;
95
- private __softDeleteUser;
96
- /**
97
- * Tenant-admin operation. Body has no `status` — lifecycle changes go through the platform-staff surface.
98
- *
99
- * @param {NizamDashboard.UserUpdateRequest} request
100
- * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
101
- *
102
- * @throws {@link NizamDashboard.UnauthorizedError}
103
- * @throws {@link NizamDashboard.ForbiddenError}
104
- * @throws {@link NizamDashboard.NotFoundError}
105
- * @throws {@link NizamDashboard.ConflictError}
106
- * @throws {@link NizamDashboard.UnprocessableEntityError}
107
- * @throws {@link NizamDashboard.InternalServerError}
108
- *
109
- * @example
110
- * await client.users.updateUser({
111
- * id: "00000000-0000-0000-0000-000000000000",
112
- * email: "renamed@acme.example",
113
- * name: "Ali Issa"
114
- * })
115
- */
116
- updateUser(request: NizamDashboard.UserUpdateRequest, requestOptions?: UsersClient.RequestOptions): core.HttpResponsePromise<NizamDashboard.UserResource>;
117
- private __updateUser;
118
78
  }
@@ -113,7 +113,7 @@ class UsersClient {
113
113
  return (0, handleNonStatusCodeError_js_1.handleNonStatusCodeError)(_response.error, _response.rawResponse, "GET", "/v1/me");
114
114
  }
115
115
  /**
116
- * Dashboard sees co-members of the caller's active organization (tenant-scoped via the organization_users join). Platform staff bypass RLS and see across tenants, and may sort by `deleted_at`. RFC 8288 Link header carries `first`, `prev`, `next` rels alongside the body's bidirectional cursors.
116
+ * Dashboard sees co-members of the caller's active organization (tenant-scoped via the organization_users join). Platform staff bypass RLS and see across tenants. Allowed sort fields: `created_at`, `name` (prefix with `-` for descending). RFC 8288 Link header carries `first`, `prev`, `next` rels alongside the body's bidirectional cursors.
117
117
  *
118
118
  * @param {NizamDashboard.ListUsersRequest} request
119
119
  * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -250,134 +250,5 @@ class UsersClient {
250
250
  }
251
251
  return (0, handleNonStatusCodeError_js_1.handleNonStatusCodeError)(_response.error, _response.rawResponse, "POST", "/v1/users");
252
252
  }
253
- /**
254
- * Tenant-admin operation. Sets `deleted_at = NOW()`. Subsequent dashboard reads filter the row out; platform staff can still surface and act on it.
255
- *
256
- * @param {NizamDashboard.SoftDeleteUserRequest} request
257
- * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
258
- *
259
- * @throws {@link NizamDashboard.UnauthorizedError}
260
- * @throws {@link NizamDashboard.ForbiddenError}
261
- * @throws {@link NizamDashboard.NotFoundError}
262
- * @throws {@link NizamDashboard.InternalServerError}
263
- *
264
- * @example
265
- * await client.users.softDeleteUser({
266
- * id: "00000000-0000-0000-0000-000000000000"
267
- * })
268
- */
269
- softDeleteUser(request, requestOptions) {
270
- return core.HttpResponsePromise.fromPromise(this.__softDeleteUser(request, requestOptions));
271
- }
272
- async __softDeleteUser(request, requestOptions) {
273
- const { id } = request;
274
- const _authRequest = await this._options.authProvider.getAuthRequest();
275
- const _headers = (0, headers_js_1.mergeHeaders)(_authRequest.headers, this._options?.headers, requestOptions?.headers);
276
- const _response = await core.fetcher({
277
- url: core.url.join((await core.Supplier.get(this._options.baseUrl)) ??
278
- (await core.Supplier.get(this._options.environment)) ??
279
- environments.NizamDashboardEnvironment.Production, `v1/users/${core.url.encodePathParam(id)}`),
280
- method: "DELETE",
281
- headers: _headers,
282
- queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
283
- timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
284
- maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
285
- abortSignal: requestOptions?.abortSignal,
286
- fetchFn: this._options?.fetch,
287
- logging: this._options.logging,
288
- });
289
- if (_response.ok) {
290
- return { data: undefined, rawResponse: _response.rawResponse };
291
- }
292
- if (_response.error.reason === "status-code") {
293
- switch (_response.error.statusCode) {
294
- case 401:
295
- throw new NizamDashboard.UnauthorizedError(_response.error.body, _response.rawResponse);
296
- case 403:
297
- throw new NizamDashboard.ForbiddenError(_response.error.body, _response.rawResponse);
298
- case 404:
299
- throw new NizamDashboard.NotFoundError(_response.error.body, _response.rawResponse);
300
- case 500:
301
- throw new NizamDashboard.InternalServerError(_response.error.body, _response.rawResponse);
302
- default:
303
- throw new errors.NizamDashboardError({
304
- statusCode: _response.error.statusCode,
305
- body: _response.error.body,
306
- rawResponse: _response.rawResponse,
307
- });
308
- }
309
- }
310
- return (0, handleNonStatusCodeError_js_1.handleNonStatusCodeError)(_response.error, _response.rawResponse, "DELETE", "/v1/users/{id}");
311
- }
312
- /**
313
- * Tenant-admin operation. Body has no `status` — lifecycle changes go through the platform-staff surface.
314
- *
315
- * @param {NizamDashboard.UserUpdateRequest} request
316
- * @param {UsersClient.RequestOptions} requestOptions - Request-specific configuration.
317
- *
318
- * @throws {@link NizamDashboard.UnauthorizedError}
319
- * @throws {@link NizamDashboard.ForbiddenError}
320
- * @throws {@link NizamDashboard.NotFoundError}
321
- * @throws {@link NizamDashboard.ConflictError}
322
- * @throws {@link NizamDashboard.UnprocessableEntityError}
323
- * @throws {@link NizamDashboard.InternalServerError}
324
- *
325
- * @example
326
- * await client.users.updateUser({
327
- * id: "00000000-0000-0000-0000-000000000000",
328
- * email: "renamed@acme.example",
329
- * name: "Ali Issa"
330
- * })
331
- */
332
- updateUser(request, requestOptions) {
333
- return core.HttpResponsePromise.fromPromise(this.__updateUser(request, requestOptions));
334
- }
335
- async __updateUser(request, requestOptions) {
336
- const { id, ..._body } = request;
337
- const _authRequest = await this._options.authProvider.getAuthRequest();
338
- const _headers = (0, headers_js_1.mergeHeaders)(_authRequest.headers, this._options?.headers, requestOptions?.headers);
339
- const _response = await core.fetcher({
340
- url: core.url.join((await core.Supplier.get(this._options.baseUrl)) ??
341
- (await core.Supplier.get(this._options.environment)) ??
342
- environments.NizamDashboardEnvironment.Production, `v1/users/${core.url.encodePathParam(id)}`),
343
- method: "PATCH",
344
- headers: _headers,
345
- contentType: "application/json",
346
- queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
347
- requestType: "json",
348
- body: _body,
349
- timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
350
- maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
351
- abortSignal: requestOptions?.abortSignal,
352
- fetchFn: this._options?.fetch,
353
- logging: this._options.logging,
354
- });
355
- if (_response.ok) {
356
- return { data: _response.body, rawResponse: _response.rawResponse };
357
- }
358
- if (_response.error.reason === "status-code") {
359
- switch (_response.error.statusCode) {
360
- case 401:
361
- throw new NizamDashboard.UnauthorizedError(_response.error.body, _response.rawResponse);
362
- case 403:
363
- throw new NizamDashboard.ForbiddenError(_response.error.body, _response.rawResponse);
364
- case 404:
365
- throw new NizamDashboard.NotFoundError(_response.error.body, _response.rawResponse);
366
- case 409:
367
- throw new NizamDashboard.ConflictError(_response.error.body, _response.rawResponse);
368
- case 422:
369
- throw new NizamDashboard.UnprocessableEntityError(_response.error.body, _response.rawResponse);
370
- case 500:
371
- throw new NizamDashboard.InternalServerError(_response.error.body, _response.rawResponse);
372
- default:
373
- throw new errors.NizamDashboardError({
374
- statusCode: _response.error.statusCode,
375
- body: _response.error.body,
376
- rawResponse: _response.rawResponse,
377
- });
378
- }
379
- }
380
- return (0, handleNonStatusCodeError_js_1.handleNonStatusCodeError)(_response.error, _response.rawResponse, "PATCH", "/v1/users/{id}");
381
- }
382
253
  }
383
254
  exports.UsersClient = UsersClient;
@@ -1,4 +1,2 @@
1
1
  export type { InviteUserRequest } from "./InviteUserRequest.js";
2
2
  export type { ListUsersRequest } from "./ListUsersRequest.js";
3
- export type { SoftDeleteUserRequest } from "./SoftDeleteUserRequest.js";
4
- export type { UserUpdateRequest } from "./UserUpdateRequest.js";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * One org with divergent membership sets.
3
+ */
4
+ export interface MembershipDriftResponse {
5
+ /** Nizam organization id. */
6
+ organization_id?: string | undefined;
7
+ /** Matching Keycloak organization id. */
8
+ keycloak_id?: string | undefined;
9
+ /** User ids present in the Nizam member set but not in KC. */
10
+ in_nizam_only?: string[] | undefined;
11
+ /** User ids present in the KC member set but not in Nizam. */
12
+ in_kc_only?: string[] | undefined;
13
+ }
@@ -16,6 +16,8 @@ export interface Organization {
16
16
  owner_user_id?: string | undefined;
17
17
  /** When this organization was created. */
18
18
  created_at?: string | undefined;
19
+ /** Populated ONLY on the POST /v1/organizations create response — the active organization id Nizam pinned for the founder as part of the same transaction that created the org. Null on every other endpoint (GET, list, membership embeds). Per issue #67 phase 1, the SPA writes its active-org cookie from this field instead of issuing a follow-up PATCH /v1/me/active-organization. */
20
+ active_organization_id?: string | undefined;
19
21
  /** Object type discriminator (Stripe pattern). */
20
22
  object?: Organization.Object_ | undefined;
21
23
  }
@@ -0,0 +1,12 @@
1
+ import type * as NizamDashboard from "../index.js";
2
+ /**
3
+ * Drift report for a single aggregate reconciliation.
4
+ */
5
+ export interface ReconcileResponse {
6
+ /** Nizam org ids whose stored keycloak_id no longer resolves on the KC side. */
7
+ nizam_has_kc_missing?: string[] | undefined;
8
+ /** KC org ids with no matching Nizam organizations.keycloak_id row. */
9
+ kc_has_nizam_missing?: string[] | undefined;
10
+ /** Per-org membership-set divergences (KC vs Nizam). */
11
+ membership_divergent?: NizamDashboard.MembershipDriftResponse[] | undefined;
12
+ }
@@ -21,9 +21,11 @@ export * from "./ListResponseTimezone.js";
21
21
  export * from "./ListResponseUserResource.js";
22
22
  export * from "./Membership.js";
23
23
  export * from "./MembershipChoice.js";
24
+ export * from "./MembershipDriftResponse.js";
24
25
  export * from "./Operator.js";
25
26
  export * from "./Organization.js";
26
27
  export * from "./ProblemDetail.js";
28
+ export * from "./ReconcileResponse.js";
27
29
  export * from "./Timezone.js";
28
30
  export * from "./User.js";
29
31
  export * from "./UserResource.js";
@@ -37,9 +37,11 @@ __exportStar(require("./ListResponseTimezone.js"), exports);
37
37
  __exportStar(require("./ListResponseUserResource.js"), exports);
38
38
  __exportStar(require("./Membership.js"), exports);
39
39
  __exportStar(require("./MembershipChoice.js"), exports);
40
+ __exportStar(require("./MembershipDriftResponse.js"), exports);
40
41
  __exportStar(require("./Operator.js"), exports);
41
42
  __exportStar(require("./Organization.js"), exports);
42
43
  __exportStar(require("./ProblemDetail.js"), exports);
44
+ __exportStar(require("./ReconcileResponse.js"), exports);
43
45
  __exportStar(require("./Timezone.js"), exports);
44
46
  __exportStar(require("./User.js"), exports);
45
47
  __exportStar(require("./UserResource.js"), exports);
@@ -3,6 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getResponseBody = getResponseBody;
4
4
  const json_js_1 = require("../json.js");
5
5
  const BinaryResponse_js_1 = require("./BinaryResponse.js");
6
+ // Pins the upstream Response so undici's FinalizationRegistry can't GC it and cancel the body stream.
7
+ function retainResponse(target, response) {
8
+ Object.defineProperty(target, "__fern_response_ref", {
9
+ value: response,
10
+ enumerable: false,
11
+ configurable: true,
12
+ writable: false,
13
+ });
14
+ }
6
15
  async function getResponseBody(response, responseType) {
7
16
  switch (responseType) {
8
17
  case "binary-response":
@@ -21,6 +30,7 @@ async function getResponseBody(response, responseType) {
21
30
  },
22
31
  };
23
32
  }
33
+ retainResponse(response.body, response);
24
34
  return response.body;
25
35
  case "streaming":
26
36
  if (response.body == null) {
@@ -32,6 +42,7 @@ async function getResponseBody(response, responseType) {
32
42
  },
33
43
  };
34
44
  }
45
+ retainResponse(response.body, response);
35
46
  return response.body;
36
47
  case "text":
37
48
  return await response.text();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nizam-os/dashboard-sdk",
3
- "version": "4.1.0",
3
+ "version": "5.0.0",
4
4
  "description": "Nizam Dashboard API SDK for TypeScript / JavaScript.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -1,9 +0,0 @@
1
- /**
2
- * @example
3
- * {
4
- * id: "00000000-0000-0000-0000-000000000000"
5
- * }
6
- */
7
- export interface SoftDeleteUserRequest {
8
- id: string;
9
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * @example
3
- * {
4
- * id: "00000000-0000-0000-0000-000000000000",
5
- * email: "renamed@acme.example",
6
- * name: "Ali Issa"
7
- * }
8
- */
9
- export interface UserUpdateRequest {
10
- id: string;
11
- /** New email (optional). */
12
- email?: string;
13
- /** New display name (optional). */
14
- name?: string;
15
- }