@devxcrew/platform 0.1.2

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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/index.d.ts +5 -0
  4. package/dist/index.js +2 -0
  5. package/dist/modules/identity/identity.administration-migration.d.ts +2 -0
  6. package/dist/modules/identity/identity.administration-migration.js +75 -0
  7. package/dist/modules/identity/identity.administration-repository.d.ts +19 -0
  8. package/dist/modules/identity/identity.administration-repository.js +102 -0
  9. package/dist/modules/identity/identity.administration-schema.d.ts +113 -0
  10. package/dist/modules/identity/identity.administration-schema.js +121 -0
  11. package/dist/modules/identity/identity.administration-service.d.ts +97 -0
  12. package/dist/modules/identity/identity.administration-service.js +517 -0
  13. package/dist/modules/identity/identity.controller.d.ts +22 -0
  14. package/dist/modules/identity/identity.controller.js +278 -0
  15. package/dist/modules/identity/identity.error.d.ts +6 -0
  16. package/dist/modules/identity/identity.error.js +15 -0
  17. package/dist/modules/identity/identity.lifecycle-schema.d.ts +19 -0
  18. package/dist/modules/identity/identity.lifecycle-schema.js +29 -0
  19. package/dist/modules/identity/identity.lifecycle-service.d.ts +64 -0
  20. package/dist/modules/identity/identity.lifecycle-service.js +395 -0
  21. package/dist/modules/identity/identity.membership-policy.d.ts +3 -0
  22. package/dist/modules/identity/identity.membership-policy.js +27 -0
  23. package/dist/modules/identity/identity.migration.d.ts +2 -0
  24. package/dist/modules/identity/identity.migration.js +79 -0
  25. package/dist/modules/identity/identity.password.d.ts +3 -0
  26. package/dist/modules/identity/identity.password.js +21 -0
  27. package/dist/modules/identity/identity.permission-declarations-migration.d.ts +5 -0
  28. package/dist/modules/identity/identity.permission-declarations-migration.js +15 -0
  29. package/dist/modules/identity/identity.permission-declarations.d.ts +23 -0
  30. package/dist/modules/identity/identity.permission-declarations.js +57 -0
  31. package/dist/modules/identity/identity.permission-labels-migration.d.ts +5 -0
  32. package/dist/modules/identity/identity.permission-labels-migration.js +9 -0
  33. package/dist/modules/identity/identity.presentation-service.d.ts +23 -0
  34. package/dist/modules/identity/identity.presentation-service.js +51 -0
  35. package/dist/modules/identity/identity.provider.d.ts +78 -0
  36. package/dist/modules/identity/identity.provider.js +119 -0
  37. package/dist/modules/identity/identity.public-schemas.d.ts +4 -0
  38. package/dist/modules/identity/identity.public-schemas.js +3 -0
  39. package/dist/modules/identity/identity.repository.d.ts +40 -0
  40. package/dist/modules/identity/identity.repository.js +196 -0
  41. package/dist/modules/identity/identity.request-context.d.ts +2 -0
  42. package/dist/modules/identity/identity.request-context.js +10 -0
  43. package/dist/modules/identity/identity.roles-migration.d.ts +2 -0
  44. package/dist/modules/identity/identity.roles-migration.js +64 -0
  45. package/dist/modules/identity/identity.roles-service.d.ts +49 -0
  46. package/dist/modules/identity/identity.roles-service.js +327 -0
  47. package/dist/modules/identity/identity.routes.d.ts +22 -0
  48. package/dist/modules/identity/identity.routes.js +11 -0
  49. package/dist/modules/identity/identity.schema.d.ts +27 -0
  50. package/dist/modules/identity/identity.schema.js +34 -0
  51. package/dist/modules/identity/identity.seed.d.ts +3 -0
  52. package/dist/modules/identity/identity.seed.js +81 -0
  53. package/dist/modules/identity/identity.service.d.ts +32 -0
  54. package/dist/modules/identity/identity.service.js +83 -0
  55. package/dist/modules/identity/identity.types.d.ts +150 -0
  56. package/dist/modules/identity/identity.types.js +1 -0
  57. package/dist/modules/identity/index.d.ts +12 -0
  58. package/dist/modules/identity/index.js +9 -0
  59. package/package.json +62 -0
@@ -0,0 +1,517 @@
1
+ import { validateDeclaredPermissions } from "./identity.permission-declarations.js";
2
+ import { randomUUID } from "node:crypto";
3
+ import { IdentityAdministrationRepository } from "./identity.administration-repository.js";
4
+ import { IdentityRolesService } from "./identity.roles-service.js";
5
+ import { protectAdministrators } from "./identity.membership-policy.js";
6
+ import { IdentityPresentationService } from "./identity.presentation-service.js";
7
+ import { checkIdentityRequest } from "./identity.request-context.js";
8
+ import { sql } from "kysely";
9
+ import { hashPassword } from "./identity.password.js";
10
+ import { IdentityError } from "./identity.error.js";
11
+ import { userCreateSchema, userUpdateSchema, organizationCreateSchema, organizationUpdateSchema, membershipSchema, roleUpdateSchema, profileSchema, settingsSchema, securitySettingsSchema, } from "./identity.administration-schema.js";
12
+ export class IdentityAdministrationService {
13
+ db;
14
+ appName;
15
+ repository;
16
+ roles;
17
+ presentationService;
18
+ constructor(db, appName) {
19
+ this.db = db;
20
+ this.appName = appName;
21
+ this.repository = new IdentityAdministrationRepository(db);
22
+ this.roles = new IdentityRolesService(db);
23
+ this.presentationService = new IdentityPresentationService(db, appName);
24
+ }
25
+ async list(actor, resource, query) {
26
+ this.allow(actor, resource, false);
27
+ return this.repository.list(actor, resource, query);
28
+ }
29
+ async show(actor, resource, id) {
30
+ this.allow(actor, resource, false);
31
+ const row = await this.repository.show(actor, resource, id);
32
+ if (!row)
33
+ throw new IdentityError(404, "Resource not found.");
34
+ return row;
35
+ }
36
+ async create(actor, resource, raw) {
37
+ if (resource === "roles")
38
+ return this.roles.create(actor, raw);
39
+ this.allow(actor, resource, true);
40
+ if (resource === "users") {
41
+ const input = userCreateSchema.parse(raw);
42
+ const tenantId = this.tenant(actor, input.tenantId);
43
+ await this.roles.resolve(this.db, actor, input.roleId, tenantId);
44
+ const passwordHash = await hashPassword(input.password);
45
+ return this.mutate(actor, resource, randomUUID(), async (trx, id) => {
46
+ await this.activeTenant(trx, tenantId);
47
+ const selected = await this.roles.resolve(trx, actor, input.roleId, tenantId);
48
+ if (await trx
49
+ .selectFrom("identity_users")
50
+ .select("id")
51
+ .where("email", "=", input.email)
52
+ .executeTakeFirst())
53
+ throw new IdentityError(409, "Email already exists.");
54
+ await trx
55
+ .insertInto("identity_users")
56
+ .values({
57
+ id,
58
+ email: input.email,
59
+ name: input.name,
60
+ active: 1,
61
+ password_hash: passwordHash,
62
+ })
63
+ .execute();
64
+ await trx
65
+ .insertInto("identity_memberships")
66
+ .values({
67
+ user_id: id,
68
+ tenant_id: tenantId,
69
+ role_id: selected.portal,
70
+ custom_role_id: selected.customRoleId,
71
+ })
72
+ .execute();
73
+ return {
74
+ id,
75
+ email: input.email,
76
+ name: input.name,
77
+ active: true,
78
+ version: 0,
79
+ };
80
+ }, tenantId);
81
+ }
82
+ if (resource === "organizations") {
83
+ const input = organizationCreateSchema.parse(raw);
84
+ return this.mutate(actor, resource, input.id, async (trx) => {
85
+ if (await trx
86
+ .selectFrom("identity_tenants")
87
+ .select("id")
88
+ .where("id", "=", input.id)
89
+ .executeTakeFirst())
90
+ throw new IdentityError(409, "Organization already exists.");
91
+ await trx
92
+ .insertInto("identity_tenants")
93
+ .values({
94
+ id: input.id,
95
+ name: input.name,
96
+ active: Number(input.active),
97
+ })
98
+ .execute();
99
+ return { ...input, version: 0 };
100
+ });
101
+ }
102
+ if (resource === "memberships") {
103
+ const input = membershipSchema.parse(raw);
104
+ const tenantId = this.tenant(actor, input.tenantId);
105
+ const selected = await this.roles.resolve(this.db, actor, input.roleId, tenantId);
106
+ await this.show(actor, "users", input.userId);
107
+ const id = `${input.userId}~${tenantId}~${selected.portal}`;
108
+ return this.mutate(actor, resource, id, async (trx) => {
109
+ await this.activeTenant(trx, tenantId);
110
+ const currentRole = await this.roles.resolve(trx, actor, input.roleId, tenantId);
111
+ if (await trx
112
+ .selectFrom("identity_memberships")
113
+ .select("user_id")
114
+ .where("user_id", "=", input.userId)
115
+ .where("tenant_id", "=", tenantId)
116
+ .where("role_id", "=", currentRole.portal)
117
+ .executeTakeFirst())
118
+ throw new IdentityError(409, "Membership already exists.");
119
+ await trx
120
+ .insertInto("identity_memberships")
121
+ .values({
122
+ user_id: input.userId,
123
+ tenant_id: tenantId,
124
+ role_id: currentRole.portal,
125
+ custom_role_id: currentRole.customRoleId,
126
+ })
127
+ .execute();
128
+ return {
129
+ id,
130
+ userId: input.userId,
131
+ tenantId,
132
+ roleId: input.roleId,
133
+ portal: currentRole.portal,
134
+ active: true,
135
+ version: 0,
136
+ };
137
+ });
138
+ }
139
+ throw new IdentityError(405, "Creation is not supported for this resource.");
140
+ }
141
+ async update(actor, resource, id, raw) {
142
+ if (resource === "memberships")
143
+ return this.roles.updateMembership(actor, id, raw);
144
+ if (resource === "roles" && !["user", "admin", "super-admin"].includes(id))
145
+ return this.roles.update(actor, id, raw);
146
+ this.allow(actor, resource, true);
147
+ await this.show(actor, resource, id);
148
+ if (resource === "users") {
149
+ const input = userUpdateSchema.parse(raw);
150
+ return this.mutate(actor, resource, id, async (trx) => {
151
+ const current = await trx
152
+ .selectFrom("identity_users")
153
+ .selectAll()
154
+ .where("id", "=", id)
155
+ .executeTakeFirstOrThrow();
156
+ this.revision(current.version, input.expectedVersion);
157
+ if (actor.portal !== "super-admin")
158
+ await this.unprivilegedUser(trx, id);
159
+ if (input.active === false) {
160
+ await protectAdministrators(trx, id);
161
+ await trx
162
+ .deleteFrom("identity_sessions")
163
+ .where("user_id", "=", id)
164
+ .execute();
165
+ }
166
+ if (input.email &&
167
+ (await trx
168
+ .selectFrom("identity_users")
169
+ .select("id")
170
+ .where("email", "=", input.email)
171
+ .where("id", "!=", id)
172
+ .executeTakeFirst()))
173
+ throw new IdentityError(409, "Email already exists.");
174
+ const { expectedVersion, ...fields } = input;
175
+ await trx
176
+ .updateTable("identity_users")
177
+ .set({
178
+ ...fields,
179
+ version: sql `version + 1`,
180
+ active: input.active === undefined
181
+ ? current.active
182
+ : Number(input.active),
183
+ })
184
+ .where("id", "=", id)
185
+ .execute();
186
+ return {
187
+ id,
188
+ name: input.name ?? current.name,
189
+ email: input.email ?? current.email,
190
+ active: input.active ?? Boolean(current.active),
191
+ version: expectedVersion + 1,
192
+ };
193
+ });
194
+ }
195
+ if (resource === "organizations") {
196
+ const input = organizationUpdateSchema.parse(raw);
197
+ return this.mutate(actor, resource, id, async (trx) => {
198
+ const current = await trx
199
+ .selectFrom("identity_tenants")
200
+ .select("version")
201
+ .where("id", "=", id)
202
+ .executeTakeFirstOrThrow();
203
+ this.revision(current.version, input.expectedVersion);
204
+ if (input.active === false && id === actor.tenant.id)
205
+ throw new IdentityError(409, "Cannot deactivate your current organization.");
206
+ const { expectedVersion, ...fields } = input;
207
+ await trx
208
+ .updateTable("identity_tenants")
209
+ .set({
210
+ ...fields,
211
+ version: sql `version + 1`,
212
+ active: input.active === undefined ? undefined : Number(input.active),
213
+ })
214
+ .where("id", "=", id)
215
+ .execute();
216
+ if (input.active === false)
217
+ await trx
218
+ .deleteFrom("identity_sessions")
219
+ .where("tenant_id", "=", id)
220
+ .execute();
221
+ const row = await trx
222
+ .selectFrom("identity_tenants")
223
+ .selectAll()
224
+ .where("id", "=", id)
225
+ .executeTakeFirstOrThrow();
226
+ return {
227
+ ...row,
228
+ active: Boolean(row.active),
229
+ version: Number(row.version),
230
+ };
231
+ });
232
+ }
233
+ if (resource === "roles") {
234
+ const input = roleUpdateSchema.parse(raw);
235
+ if (!input.permissionIds.includes(`desk.${id}`) ||
236
+ !input.permissionIds.includes("identity.password"))
237
+ throw new IdentityError(409, "Keep required portal and password permissions.");
238
+ if (id !== "user" && !input.permissionIds.includes("identity.manage"))
239
+ throw new IdentityError(409, "Keep administration permission on administrator roles.");
240
+ return this.mutate(actor, resource, id, async (trx) => {
241
+ const current = await trx
242
+ .selectFrom("identity_roles")
243
+ .select("version")
244
+ .where("id", "=", id)
245
+ .executeTakeFirstOrThrow();
246
+ this.revision(current.version, input.expectedVersion);
247
+ await validateDeclaredPermissions(trx, actor.appId, id, input.permissionIds);
248
+ const known = await trx
249
+ .selectFrom("identity_permissions")
250
+ .select("id")
251
+ .execute();
252
+ if (input.permissionIds.some((permission) => !known.some((row) => row.id === permission)))
253
+ throw new IdentityError(422, "Unknown permission.");
254
+ if (id === "user" &&
255
+ input.permissionIds.some((permission) => permission.startsWith("identity.manage")))
256
+ throw new IdentityError(403, "User roles cannot receive administration permissions.");
257
+ await trx
258
+ .deleteFrom("identity_role_permissions")
259
+ .where("role_id", "=", id)
260
+ .execute();
261
+ for (const permission of new Set(input.permissionIds))
262
+ await trx
263
+ .insertInto("identity_role_permissions")
264
+ .values({ role_id: id, permission_id: permission })
265
+ .execute();
266
+ await trx
267
+ .updateTable("identity_roles")
268
+ .set({ version: sql `version + 1` })
269
+ .where("id", "=", id)
270
+ .execute();
271
+ return {
272
+ id,
273
+ permissionIds: [...new Set(input.permissionIds)],
274
+ version: input.expectedVersion + 1,
275
+ };
276
+ });
277
+ }
278
+ throw new IdentityError(405, "Update is not supported for this resource.");
279
+ }
280
+ async remove(actor, resource, id, expectedVersion) {
281
+ if (resource === "memberships")
282
+ return this.roles.removeMembership(actor, id, expectedVersion);
283
+ this.allow(actor, resource, true);
284
+ const row = await this.show(actor, resource, id);
285
+ if (resource === "sessions") {
286
+ await this.mutate(actor, resource, id, async (trx) => {
287
+ await trx
288
+ .deleteFrom("identity_sessions")
289
+ .where("token_hash", "=", id)
290
+ .where("app_id", "=", actor.appId)
291
+ .execute();
292
+ });
293
+ return;
294
+ }
295
+ throw new IdentityError(405, "Deletion is not supported for this resource.");
296
+ }
297
+ async profile(actor, raw) {
298
+ if (!actor.permissions.includes("identity.self"))
299
+ throw new IdentityError(403, "Access denied.");
300
+ if (raw !== undefined) {
301
+ const input = profileSchema.parse(raw);
302
+ await this.mutate(actor, "profile", actor.user.id, async (trx) => {
303
+ const changed = await trx
304
+ .updateTable("identity_users")
305
+ .set({ name: input.name, version: sql `version + 1` })
306
+ .where("id", "=", actor.user.id)
307
+ .where("version", "=", input.expectedVersion)
308
+ .executeTakeFirst();
309
+ if (changed.numUpdatedRows !== 1n)
310
+ throw new IdentityError(409, "This record changed. Reload before saving.");
311
+ });
312
+ }
313
+ const user = await this.db
314
+ .selectFrom("identity_users")
315
+ .select(["id", "name", "email", "active", "version"])
316
+ .where("id", "=", actor.user.id)
317
+ .executeTakeFirstOrThrow();
318
+ return {
319
+ ...user,
320
+ active: Boolean(user.active),
321
+ version: Number(user.version),
322
+ };
323
+ }
324
+ async settings(actor, raw) {
325
+ if (raw !== undefined) {
326
+ this.allow(actor, "settings", true);
327
+ const input = settingsSchema.parse(raw);
328
+ await this.mutate(actor, "settings", actor.tenant.id, async (trx) => {
329
+ const current = await trx
330
+ .selectFrom("identity_settings")
331
+ .select("version")
332
+ .where("tenant_id", "=", actor.tenant.id)
333
+ .executeTakeFirst();
334
+ this.revision(current?.version ?? 0, input.expectedVersion);
335
+ await trx
336
+ .insertInto("identity_settings")
337
+ .values({
338
+ tenant_id: actor.tenant.id,
339
+ display_name: input.displayName,
340
+ locale: input.locale,
341
+ time_zone: input.timeZone,
342
+ version: input.expectedVersion + 1,
343
+ })
344
+ .onConflict((c) => c.column("tenant_id").doUpdateSet({
345
+ display_name: input.displayName,
346
+ locale: input.locale,
347
+ time_zone: input.timeZone,
348
+ version: input.expectedVersion + 1,
349
+ }))
350
+ .execute();
351
+ });
352
+ }
353
+ return this.presentationService.organizationSettings(actor);
354
+ }
355
+ async applicationSettings(actor, security, raw, fallbackSeconds) {
356
+ if (actor.portal === "user")
357
+ throw new IdentityError(403, "Access denied.");
358
+ if (raw !== undefined) {
359
+ if (actor.portal !== "super-admin" ||
360
+ !actor.permissions.includes("identity.manage"))
361
+ throw new IdentityError(403, "Access denied.");
362
+ const input = security
363
+ ? securitySettingsSchema.parse(raw)
364
+ : settingsSchema.parse(raw);
365
+ await this.mutate(actor, security ? "security-settings" : "application-settings", actor.appId, async (trx) => {
366
+ const current = await trx
367
+ .selectFrom("identity_app_settings")
368
+ .selectAll()
369
+ .where("app_id", "=", actor.appId)
370
+ .executeTakeFirst();
371
+ this.revision(current?.version ?? 0, input.expectedVersion);
372
+ const row = {
373
+ app_id: actor.appId,
374
+ display_name: current?.display_name ?? this.appName,
375
+ locale: current?.locale ?? "en",
376
+ time_zone: current?.time_zone ?? "UTC",
377
+ session_seconds: current?.session_seconds ?? fallbackSeconds,
378
+ version: input.expectedVersion + 1,
379
+ };
380
+ if ("sessionSeconds" in input)
381
+ row.session_seconds = input.sessionSeconds;
382
+ else {
383
+ row.display_name = input.displayName;
384
+ row.locale = input.locale;
385
+ row.time_zone = input.timeZone;
386
+ }
387
+ await trx
388
+ .insertInto("identity_app_settings")
389
+ .values(row)
390
+ .onConflict((c) => c.column("app_id").doUpdateSet(row))
391
+ .execute();
392
+ if (security)
393
+ await trx
394
+ .deleteFrom("identity_sessions")
395
+ .where("app_id", "=", actor.appId)
396
+ .execute();
397
+ });
398
+ }
399
+ const row = await this.db
400
+ .selectFrom("identity_app_settings")
401
+ .selectAll()
402
+ .where("app_id", "=", actor.appId)
403
+ .executeTakeFirst();
404
+ return security
405
+ ? {
406
+ sessionSeconds: Number(row?.session_seconds ?? fallbackSeconds),
407
+ version: Number(row?.version ?? 0),
408
+ }
409
+ : {
410
+ displayName: row?.display_name ?? this.appName,
411
+ locale: row?.locale ?? "en",
412
+ timeZone: row?.time_zone ?? "UTC",
413
+ version: Number(row?.version ?? 0),
414
+ };
415
+ }
416
+ revision(current, expected) {
417
+ if (Number(current) !== expected)
418
+ throw new IdentityError(409, "This record changed. Reload before saving.");
419
+ }
420
+ async presentation(actor) {
421
+ return this.presentationService.presentation(actor);
422
+ }
423
+ async configuration(appId, requiresOrganizationId) {
424
+ return this.presentationService.configuration(appId, requiresOrganizationId);
425
+ }
426
+ allow(actor, resource, write) {
427
+ if (!write &&
428
+ ["roles", "permissions", "organizations"].includes(resource) &&
429
+ actor.portal !== "user")
430
+ return;
431
+ if (resource === "sessions" && actor.portal === "user")
432
+ return;
433
+ if (actor.portal === "user" ||
434
+ !actor.permissions.includes("identity.manage"))
435
+ throw new IdentityError(403, "Access denied.");
436
+ if (write &&
437
+ ["roles", "permissions", "organizations"].includes(resource) &&
438
+ actor.portal !== "super-admin")
439
+ throw new IdentityError(403, "Only super administrators can change this resource.");
440
+ }
441
+ tenant(actor, requested) {
442
+ if (requested &&
443
+ requested !== actor.tenant.id &&
444
+ actor.portal !== "super-admin")
445
+ throw new IdentityError(403, "Access denied.");
446
+ return requested ?? actor.tenant.id;
447
+ }
448
+ assignableRole(actor, role) {
449
+ if (actor.portal !== "super-admin" && role !== "user")
450
+ throw new IdentityError(403, "Only super administrators can assign privileged roles.");
451
+ }
452
+ async activeTenant(trx, id) {
453
+ if (!(await trx
454
+ .selectFrom("identity_tenants")
455
+ .select("id")
456
+ .where("id", "=", id)
457
+ .where("active", "=", 1)
458
+ .executeTakeFirst()))
459
+ throw new IdentityError(422, "Organization is inactive or unavailable.");
460
+ }
461
+ async unprivilegedUser(trx, id) {
462
+ const privileged = await trx
463
+ .selectFrom("identity_memberships")
464
+ .select("role_id")
465
+ .where("user_id", "=", id)
466
+ .where("role_id", "in", ["admin", "super-admin"])
467
+ .executeTakeFirst();
468
+ if (privileged)
469
+ throw new IdentityError(403, "Only super administrators can change privileged accounts.");
470
+ const tenants = await trx
471
+ .selectFrom("identity_memberships")
472
+ .select("tenant_id")
473
+ .where("user_id", "=", id)
474
+ .distinct()
475
+ .execute();
476
+ if (tenants.length > 1)
477
+ throw new IdentityError(403, "Only super administrators can change shared accounts.");
478
+ }
479
+ async mutate(actor, resource, id, action, affectedTenant) {
480
+ return this.db.transaction().execute(async (trx) => {
481
+ checkIdentityRequest();
482
+ const result = await action(trx, id);
483
+ checkIdentityRequest();
484
+ const targetTenant = affectedTenant ??
485
+ (resource === "organizations"
486
+ ? id
487
+ : resource === "memberships"
488
+ ? id.split("~")[1]
489
+ : actor.tenant.id);
490
+ let targets = [targetTenant];
491
+ if (!affectedTenant && ["users", "profile"].includes(resource))
492
+ targets = (await trx
493
+ .selectFrom("identity_memberships")
494
+ .select("tenant_id")
495
+ .where("user_id", "=", id)
496
+ .distinct()
497
+ .execute()).map((row) => row.tenant_id);
498
+ if (["roles", "application-settings", "security-settings"].includes(resource))
499
+ targets = (await trx.selectFrom("identity_tenants").select("id").execute()).map((row) => row.id);
500
+ for (const tenant of new Set(targets))
501
+ await trx
502
+ .insertInto("identity_audit_events")
503
+ .values({
504
+ id: randomUUID(),
505
+ app_id: actor.appId,
506
+ actor_id: actor.user.id,
507
+ tenant_id: tenant,
508
+ action: `identity.${resource}.changed`,
509
+ resource_id: id,
510
+ created_at: new Date().toISOString(),
511
+ })
512
+ .execute();
513
+ checkIdentityRequest();
514
+ return result;
515
+ });
516
+ }
517
+ }
@@ -0,0 +1,22 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { IdentityService } from "./identity.service.js";
3
+ import type { IdentityConfig, Portal } from "./identity.types.js";
4
+ import { IdentityAdministrationService } from "./identity.administration-service.js";
5
+ import { IdentityLifecycleService } from "./identity.lifecycle-service.js";
6
+ export declare class IdentityController {
7
+ private readonly service;
8
+ private readonly config;
9
+ private readonly administration;
10
+ private readonly lifecycle;
11
+ constructor(service: IdentityService, config: IdentityConfig, administration: IdentityAdministrationService, lifecycle: IdentityLifecycleService);
12
+ handle(request: IncomingMessage, response: ServerResponse, signal?: AbortSignal): Promise<boolean>;
13
+ authenticateRequest(request: IncomingMessage, requestedPortal: Portal, signal?: AbortSignal): Promise<import("./identity.types.js").Principal>;
14
+ private handleRequest;
15
+ private adminRequest;
16
+ private wireList;
17
+ private cookie;
18
+ private cookieName;
19
+ private token;
20
+ private json;
21
+ private body;
22
+ }