@bentoforge/umami-iam 0.1.1 → 0.2.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.
- package/LICENSE +21 -0
- package/dist/client.d.ts +44 -36
- package/dist/client.js +125 -72
- package/dist/types.d.ts +126 -96
- package/package.json +1 -1
- package/src/client.ts +144 -91
- package/src/types.ts +134 -104
package/dist/types.d.ts
CHANGED
|
@@ -5,9 +5,7 @@ export interface AccessClaims {
|
|
|
5
5
|
aud?: string;
|
|
6
6
|
/** The active tenant this token is scoped to. */
|
|
7
7
|
tenant: string;
|
|
8
|
-
name: string;
|
|
9
8
|
email: string;
|
|
10
|
-
locale: string;
|
|
11
9
|
permissions: string[];
|
|
12
10
|
iat: number;
|
|
13
11
|
exp: number;
|
|
@@ -49,9 +47,25 @@ export interface TotpSetup {
|
|
|
49
47
|
secret: string;
|
|
50
48
|
/** `otpauth://` URL for QR rendering. */
|
|
51
49
|
otpauthUrl: string;
|
|
50
|
+
/** Ready-to-render QR-code SVG of `otpauthUrl` (dark on white). */
|
|
51
|
+
qrSvg: string;
|
|
52
|
+
}
|
|
53
|
+
/** How to address a user; the rendered word is composed server-side from the config labels. */
|
|
54
|
+
export type Salutation = "" | "SIR" | "MADAM";
|
|
55
|
+
/** Structured name parts (editable) plus the server-composed display names (read-only). */
|
|
56
|
+
export interface NameParts {
|
|
57
|
+
title: string | null;
|
|
58
|
+
salutation: Salutation;
|
|
59
|
+
firstname: string | null;
|
|
60
|
+
lastname: string | null;
|
|
61
|
+
/** `title firstname lastname`. */
|
|
62
|
+
name: string;
|
|
63
|
+
/** `salutation title firstname lastname`. */
|
|
64
|
+
fullName: string;
|
|
65
|
+
/** `salutation title lastname`. */
|
|
66
|
+
addressableName: string;
|
|
52
67
|
}
|
|
53
|
-
export
|
|
54
|
-
export interface UserView {
|
|
68
|
+
export interface UserView extends NameParts {
|
|
55
69
|
userId: string;
|
|
56
70
|
tenantId: string;
|
|
57
71
|
roles: string[];
|
|
@@ -59,111 +73,133 @@ export interface UserView {
|
|
|
59
73
|
username: string;
|
|
60
74
|
/** Optional contact email — not unique, may be null/absent. */
|
|
61
75
|
email: string | null;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
status: UserStatus;
|
|
76
|
+
/** Admin lock — a locked user cannot log in. */
|
|
77
|
+
locked: boolean;
|
|
65
78
|
customFields: Record<string, unknown>;
|
|
66
79
|
/** RFC3339 creation timestamp. */
|
|
67
80
|
created: string;
|
|
68
|
-
/** RFC3339 timestamp of the
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
/** RFC3339 timestamp of the last change to this record. */
|
|
82
|
+
lastUpdated: string;
|
|
83
|
+
/** RFC3339 timestamp of the user's last authentication (login/refresh); null until first active. */
|
|
84
|
+
lastSeen: string | null;
|
|
85
|
+
/** User id that created / last changed this user (audit; not surfaced in the UI yet). */
|
|
86
|
+
createdBy?: string | null;
|
|
87
|
+
lastChangedBy?: string | null;
|
|
88
|
+
/** Whether TOTP MFA is configured (never exposes the secret). */
|
|
89
|
+
mfaEnabled: boolean;
|
|
90
|
+
/** Whether the current password came from an admin reset and hasn't been changed since. */
|
|
91
|
+
passwordGenerated: boolean;
|
|
92
|
+
/** Whether the user has at least one registered passkey. */
|
|
93
|
+
hasPasskey: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** The editable structured name parts (all optional; omitted = unset, `""` clears). */
|
|
96
|
+
export interface NameInput {
|
|
97
|
+
title?: string;
|
|
98
|
+
salutation?: Salutation;
|
|
99
|
+
firstname?: string;
|
|
100
|
+
lastname?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface CreateUserRequest extends NameInput {
|
|
72
103
|
/** Login username (unique). If omitted, `email` is used as the username. */
|
|
73
104
|
username?: string;
|
|
74
105
|
/** Optional contact email (not unique). */
|
|
75
106
|
email?: string;
|
|
76
|
-
password
|
|
77
|
-
|
|
78
|
-
|
|
107
|
+
/** Optional initial password. Omit (the normal case) to have a temporary one generated and
|
|
108
|
+
* returned once in {@link CreateUserResponse.temporaryPassword}. */
|
|
109
|
+
password?: string;
|
|
79
110
|
roles?: string[];
|
|
80
111
|
customFields?: Record<string, unknown>;
|
|
81
112
|
}
|
|
82
|
-
|
|
113
|
+
/** The created user, plus the one-time temporary password when one was generated. */
|
|
114
|
+
export type CreateUserResponse = UserView & {
|
|
115
|
+
/** Present only when the server generated the initial password — shown once. */
|
|
116
|
+
temporaryPassword?: string | null;
|
|
117
|
+
};
|
|
118
|
+
export interface PatchUserRequest extends NameInput {
|
|
119
|
+
/** New login username (globally unique). Omit to leave unchanged; must not be empty. */
|
|
120
|
+
username?: string;
|
|
121
|
+
/** Contact email. Omit to leave unchanged; empty string clears it. */
|
|
122
|
+
email?: string;
|
|
83
123
|
roles?: string[];
|
|
84
|
-
|
|
124
|
+
locked?: boolean;
|
|
85
125
|
customFields?: Record<string, unknown>;
|
|
86
126
|
}
|
|
127
|
+
export interface MeUser extends NameParts {
|
|
128
|
+
userId: string;
|
|
129
|
+
tenantId: string;
|
|
130
|
+
roles: string[];
|
|
131
|
+
username: string;
|
|
132
|
+
email: string | null;
|
|
133
|
+
locked: boolean;
|
|
134
|
+
customFields: Record<string, unknown>;
|
|
135
|
+
/** Whether TOTP MFA is configured (never exposes the secret). */
|
|
136
|
+
mfaEnabled: boolean;
|
|
137
|
+
/** Whether the caller has at least one registered passkey. */
|
|
138
|
+
hasPasskey: boolean;
|
|
139
|
+
}
|
|
87
140
|
export interface MeResponse {
|
|
88
|
-
user:
|
|
89
|
-
userId: string;
|
|
90
|
-
tenantId: string;
|
|
91
|
-
roles: string[];
|
|
92
|
-
username: string;
|
|
93
|
-
email: string | null;
|
|
94
|
-
name: string;
|
|
95
|
-
locale: string;
|
|
96
|
-
status: UserStatus;
|
|
97
|
-
};
|
|
141
|
+
user: MeUser;
|
|
98
142
|
tenant: Tenant | null;
|
|
99
143
|
}
|
|
100
|
-
|
|
101
|
-
export
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
144
|
+
/** One of the caller's active login sessions (device). Never exposes the refresh secret. */
|
|
145
|
+
export interface SessionView {
|
|
146
|
+
sessionId: string;
|
|
147
|
+
userAgent?: string;
|
|
148
|
+
ip?: string;
|
|
149
|
+
/** RFC3339 creation timestamp. */
|
|
150
|
+
created: string;
|
|
151
|
+
/** RFC3339 timestamp of the last refresh. */
|
|
152
|
+
lastSeen: string;
|
|
153
|
+
/** RFC3339 absolute expiry. */
|
|
154
|
+
expiresAt: string;
|
|
155
|
+
/** Whether this is the session making the request. */
|
|
156
|
+
current: boolean;
|
|
110
157
|
}
|
|
111
158
|
export interface Tenant {
|
|
112
159
|
tenantId: string;
|
|
113
160
|
version: number;
|
|
114
|
-
packages: PackageAssignment[];
|
|
115
|
-
limitOverrides: Record<string, string>;
|
|
116
|
-
featureOverrides: Record<string, FeatureToggle>;
|
|
117
161
|
/** Authorization features granted to the tenant (`feature:*`), fed to the token broker. */
|
|
118
162
|
features: string[];
|
|
119
163
|
customFields: Record<string, unknown>;
|
|
120
164
|
name: string;
|
|
121
165
|
slug: string;
|
|
122
|
-
status: TenantStatus;
|
|
123
|
-
plan: string;
|
|
124
|
-
billedUntil?: string | null;
|
|
125
|
-
seatsLimit?: number | null;
|
|
126
166
|
created: string;
|
|
127
167
|
lastUpdated: string;
|
|
168
|
+
/** RFC3339 timestamp of the last token activity (refresh / exchange) scoped to this tenant;
|
|
169
|
+
* null until the first activity. */
|
|
170
|
+
lastActive?: string | null;
|
|
171
|
+
/** Sort key backing the tenant listing: `lastActive` when present, else `created`. */
|
|
172
|
+
lastActiveOrCreated?: string;
|
|
173
|
+
/** User id that created this tenant (audit; not surfaced in the UI yet). */
|
|
174
|
+
createdBy?: string | null;
|
|
175
|
+
/** User id of the last change to this tenant (audit; not surfaced in the UI yet). */
|
|
176
|
+
lastChangedBy?: string | null;
|
|
128
177
|
}
|
|
129
178
|
export interface CreateTenantRequest {
|
|
130
179
|
name: string;
|
|
131
|
-
owner
|
|
180
|
+
/** Optional first owner. Omit to create an empty tenant (add users afterwards by impersonating
|
|
181
|
+
* it on the Tenants screen). */
|
|
182
|
+
owner?: {
|
|
132
183
|
/** Owner login username (unique). If omitted, `email` is used as the username. */
|
|
133
184
|
username?: string;
|
|
134
185
|
/** Optional contact email (not unique). */
|
|
135
186
|
email?: string;
|
|
136
187
|
password: string;
|
|
137
|
-
name: string;
|
|
138
|
-
locale?: string;
|
|
139
188
|
};
|
|
140
189
|
/** Custom-field values, validated against `customTenantFields`. */
|
|
141
190
|
customFields?: Record<string, unknown>;
|
|
142
191
|
}
|
|
143
192
|
export interface CreateTenantResponse {
|
|
144
193
|
tenantId: string;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
export interface EntitlementsResponse {
|
|
148
|
-
limits: Record<string, string>;
|
|
149
|
-
features: string[];
|
|
150
|
-
monthlyTotal: string;
|
|
151
|
-
packages: PackageAssignment[];
|
|
152
|
-
}
|
|
153
|
-
export interface MetricUsage {
|
|
154
|
-
metric: string;
|
|
155
|
-
used: number;
|
|
156
|
-
limit?: string;
|
|
157
|
-
overQuota: boolean;
|
|
158
|
-
}
|
|
159
|
-
export interface UsageResponse {
|
|
160
|
-
period: string;
|
|
161
|
-
metrics: MetricUsage[];
|
|
194
|
+
/** The created owner's user id — only present when an `owner` was supplied. */
|
|
195
|
+
ownerUserId: string | null;
|
|
162
196
|
}
|
|
163
197
|
/** A role assignable to a user (`role:*`). Permissions come from the per-API rules, not here. */
|
|
164
198
|
export interface RoleDef {
|
|
165
199
|
code: string;
|
|
166
200
|
name: string;
|
|
201
|
+
/** Optional human-readable description (shown muted under the name in the admin UI). */
|
|
202
|
+
description?: string | null;
|
|
167
203
|
/** Boolean expression over the tenant's `feature:*`/`is:*` gating whether it may be assigned. */
|
|
168
204
|
assignableIf?: string | null;
|
|
169
205
|
}
|
|
@@ -171,38 +207,21 @@ export interface RoleDef {
|
|
|
171
207
|
export interface ScopeDef {
|
|
172
208
|
code: string;
|
|
173
209
|
name: string;
|
|
210
|
+
/** Optional human-readable description (shown muted under the name in the admin UI). */
|
|
211
|
+
description?: string | null;
|
|
174
212
|
assignableIf?: string | null;
|
|
175
213
|
}
|
|
176
214
|
/** An authorization feature granted to a tenant (`feature:*`). */
|
|
177
215
|
export interface FeatureDef {
|
|
178
216
|
code: string;
|
|
179
217
|
name: string;
|
|
218
|
+
/** Optional human-readable description (shown muted under the name in the admin UI). */
|
|
219
|
+
description?: string | null;
|
|
180
220
|
/** Boolean expression over the tenant's current features gating whether it may be granted. */
|
|
181
221
|
assignableIf?: string | null;
|
|
182
222
|
}
|
|
183
|
-
export interface LimitDef {
|
|
184
|
-
code: string;
|
|
185
|
-
name: string;
|
|
186
|
-
unit?: string;
|
|
187
|
-
default?: string;
|
|
188
|
-
}
|
|
189
|
-
export interface PackageLimit {
|
|
190
|
-
code: string;
|
|
191
|
-
value: string;
|
|
192
|
-
}
|
|
193
|
-
export interface PriceEntry {
|
|
194
|
-
validFrom: string;
|
|
195
|
-
price: string;
|
|
196
|
-
}
|
|
197
|
-
export interface PackageDef {
|
|
198
|
-
code: string;
|
|
199
|
-
name: string;
|
|
200
|
-
features: string[];
|
|
201
|
-
limits: PackageLimit[];
|
|
202
|
-
prices: PriceEntry[];
|
|
203
|
-
}
|
|
204
223
|
export interface CustomFieldDef {
|
|
205
|
-
|
|
224
|
+
code: string;
|
|
206
225
|
label: string;
|
|
207
226
|
/** `"string"` | `"number"` | `"bool"` | `"select"`. */
|
|
208
227
|
type: string;
|
|
@@ -211,6 +230,8 @@ export interface CustomFieldDef {
|
|
|
211
230
|
required: boolean;
|
|
212
231
|
/** Whether admin list tables surface this field as a column. */
|
|
213
232
|
showInTable?: boolean;
|
|
233
|
+
/** Whether the user may edit this field on themselves via `PATCH /auth/me`. */
|
|
234
|
+
selfEditable?: boolean;
|
|
214
235
|
}
|
|
215
236
|
/** The custom-field schemas for rendering user/tenant forms (`GET /config/custom-fields`). */
|
|
216
237
|
export interface CustomFieldsSchema {
|
|
@@ -239,7 +260,9 @@ export interface ApiDef {
|
|
|
239
260
|
eligibility?: string | null;
|
|
240
261
|
/** Ordered rules mapping subjects → granted permissions (accumulated top-to-bottom). */
|
|
241
262
|
permissions: PermissionRule[];
|
|
242
|
-
/** Claim mapping: claimName → source
|
|
263
|
+
/** Claim mapping: claimName → source. A source is a literal string, a `$user.<field>` /
|
|
264
|
+
* `$tenant.<field>` reference (`id`, `username`, `email`, `name`, `fullName`, `addressableName`,
|
|
265
|
+
* `roles`, `name`/`slug`/`features`, …), or `$user.custom.<key>` / `$tenant.custom.<key>`. */
|
|
243
266
|
claims?: Record<string, string>;
|
|
244
267
|
}
|
|
245
268
|
export interface Config {
|
|
@@ -248,10 +271,10 @@ export interface Config {
|
|
|
248
271
|
/** Scopes assignable to M2M service keys. */
|
|
249
272
|
scopes: ScopeDef[];
|
|
250
273
|
features: FeatureDef[];
|
|
251
|
-
limits: LimitDef[];
|
|
252
|
-
packages: PackageDef[];
|
|
253
274
|
customTenantFields: CustomFieldDef[];
|
|
254
275
|
customUserFields: CustomFieldDef[];
|
|
276
|
+
/** Salutation labels (`salutationCode → word`) in the deployment's language. */
|
|
277
|
+
salutations: Record<string, string>;
|
|
255
278
|
security: SecuritySettings;
|
|
256
279
|
/** Messaging integration (Telegram/WhatsApp) settings. */
|
|
257
280
|
messaging?: MessagingConfig;
|
|
@@ -271,8 +294,8 @@ export interface ApiKeyView {
|
|
|
271
294
|
roles: string[];
|
|
272
295
|
/** Service-key `scope:*` subjects (empty for PATs). */
|
|
273
296
|
scopes: string[];
|
|
274
|
-
/**
|
|
275
|
-
|
|
297
|
+
/** Whether the raw-secret (Mode 1) exchange is allowed; false ⇒ HMAC-only (Mode 2). */
|
|
298
|
+
allowSecretLogin: boolean;
|
|
276
299
|
status: ApiKeyStatus;
|
|
277
300
|
allowedOrigins: string[];
|
|
278
301
|
expiresAt?: string | null;
|
|
@@ -284,8 +307,8 @@ export interface CreateApiKeyRequest {
|
|
|
284
307
|
name: string;
|
|
285
308
|
/** The `scope:*` subjects this key carries (must be assignable given the tenant's features). */
|
|
286
309
|
scopes?: string[];
|
|
287
|
-
/**
|
|
288
|
-
|
|
310
|
+
/** Allow the raw-secret (Mode 1) exchange; omitted/false ⇒ HMAC-only (Mode 2). */
|
|
311
|
+
allowSecretLogin?: boolean;
|
|
289
312
|
allowedOrigins?: string[];
|
|
290
313
|
expiresAt?: string;
|
|
291
314
|
}
|
|
@@ -294,8 +317,6 @@ export interface CreatePatRequest {
|
|
|
294
317
|
name: string;
|
|
295
318
|
/** Restrict the token to this subset of your own `role:*` (empty = all your roles). */
|
|
296
319
|
roles?: string[];
|
|
297
|
-
/** Target API codes this PAT may mint for; defaults to `["umami"]`. */
|
|
298
|
-
apis?: string[];
|
|
299
320
|
expiresAt?: string;
|
|
300
321
|
}
|
|
301
322
|
export interface CreateApiKeyResponse {
|
|
@@ -315,6 +336,9 @@ export interface BrandingConfig {
|
|
|
315
336
|
/** Logo for dark backgrounds; falls back to logoLight, then default. */
|
|
316
337
|
logoDark?: string;
|
|
317
338
|
favicon?: string;
|
|
339
|
+
/** Browser tab title (document `<title>`); served at /app/branding.json, applied at runtime.
|
|
340
|
+
* Empty → "umami". */
|
|
341
|
+
title?: string;
|
|
318
342
|
}
|
|
319
343
|
/** Messaging integration settings (Telegram/WhatsApp). */
|
|
320
344
|
export interface MessagingConfig {
|
|
@@ -343,13 +367,16 @@ export interface MessagingLink {
|
|
|
343
367
|
export interface ResolvedMessagingUser {
|
|
344
368
|
userId: string;
|
|
345
369
|
tenantId: string;
|
|
346
|
-
name: string;
|
|
347
370
|
email?: string | null;
|
|
348
|
-
locale: string;
|
|
349
371
|
roles: string[];
|
|
350
372
|
}
|
|
351
373
|
/** Outcome flavour of an audited event. */
|
|
352
374
|
export type AuditSeverity = "good" | "neutral" | "bad";
|
|
375
|
+
/** One page of audit entries plus the cursor to fetch the next (absent when the trail is exhausted). */
|
|
376
|
+
export interface AuditPage {
|
|
377
|
+
entries: AuditEntry[];
|
|
378
|
+
nextCursor?: string;
|
|
379
|
+
}
|
|
353
380
|
export interface AuditEntry {
|
|
354
381
|
id: string;
|
|
355
382
|
/** RFC3339 event time. */
|
|
@@ -358,6 +385,9 @@ export interface AuditEntry {
|
|
|
358
385
|
user?: string | null;
|
|
359
386
|
severity: AuditSeverity;
|
|
360
387
|
message: string;
|
|
388
|
+
/** Best-effort client IP, present on security-relevant events (logins, credential/account
|
|
389
|
+
* changes). Absent on events with no request IP. */
|
|
390
|
+
ip?: string | null;
|
|
361
391
|
}
|
|
362
392
|
/** Result of an admin password reset — `temporaryPassword` is set (once) only when generated. */
|
|
363
393
|
export interface ResetPasswordResponse {
|