@kumori/aurora-backend-handler 1.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.
@@ -0,0 +1,1260 @@
1
+ import { Notification, Registry, Tenant, tenantRole } from "@hestekumori/aurora-interfaces";
2
+ import { eventHelper } from "../backend-handler";
3
+ import { environment } from "../environment";
4
+ import {
5
+ initializeGlobalWebSocketClient,
6
+ getWebSocketStatus,
7
+ makeGlobalWebSocketRequest,
8
+ } from "../websocket-manager";
9
+
10
+ type Security = string;
11
+ interface DregistryBody {
12
+ spec: {
13
+ labels?: { [key: string]: string };
14
+ docker_server: string;
15
+ docker_username: string;
16
+ docker_password: string;
17
+ };
18
+ }
19
+ /**
20
+ * Function to create a tenant using the global WebSocket connection
21
+ * @param tenant Tenant object with the data of the tenant
22
+ * @param security Authorization token
23
+ * @returns The response of the WebSocket API
24
+ */
25
+ export const createTenant = async (tenant: Tenant, security: Security) => {
26
+ try {
27
+ await initializeGlobalWebSocketClient(security);
28
+
29
+ const tenantBody =
30
+ tenant.npmRegistry && tenant.npmRegistry.endpoint !== ""
31
+ ? {
32
+ tenant: tenant.name,
33
+ provider: tenant.plan?.provider || "",
34
+ plan: tenant.plan?.name || "",
35
+ spec: {
36
+ registry: {
37
+ kind: "git",
38
+ endpoint: tenant.npmRegistry.endpoint,
39
+ domain: tenant.npmRegistry.domain,
40
+ credentials: tenant.npmRegistry.credentials,
41
+ public: tenant.npmRegistry.public,
42
+ },
43
+ },
44
+ }
45
+ : {
46
+ tenant: tenant.name,
47
+ provider: tenant.plan?.provider || "",
48
+ plan: tenant.plan?.name || "",
49
+ spec: {
50
+ registry: undefined,
51
+ },
52
+ };
53
+
54
+ const response = await makeGlobalWebSocketRequest(
55
+ "tenant:create_tenant",
56
+ tenantBody,
57
+ 30000,
58
+ "CREATE",
59
+ tenant.name
60
+ );
61
+ const updatedTenant = { ...tenant, status: "pending" };
62
+ eventHelper.tenant.publish.created(updatedTenant);
63
+ const tenantCreatedNotification: Notification = {
64
+ type: "success",
65
+ subtype: "tenant-created",
66
+ date: Date.now().toString(),
67
+ status: "unread",
68
+ callToAction: false,
69
+ data: {
70
+ tenant: tenant.name,
71
+ },
72
+ };
73
+ eventHelper.notification.publish.creation(tenantCreatedNotification);
74
+ return response;
75
+ } catch (error) {
76
+ console.error("Error creating tenant:", {
77
+ error,
78
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
79
+ tenant: tenant.name,
80
+ webSocketStatus: getWebSocketStatus(),
81
+ });
82
+ let contentMessage = "Unknown error";
83
+ let errorContent = "Unknown error";
84
+
85
+ if (
86
+ typeof error === "object" &&
87
+ error !== null &&
88
+ "error" in error &&
89
+ typeof (error as any).error === "object" &&
90
+ (error as any).error !== null
91
+ ) {
92
+ if ("code" in (error as any).error) {
93
+ contentMessage = (error as any).error.code;
94
+ }
95
+ if ("content" in (error as any).error) {
96
+ errorContent = (error as any).error.content;
97
+ }
98
+ }
99
+ const tenantCreationErrorNotification: Notification = {
100
+ type: "error",
101
+ subtype: "tenant-creation-error",
102
+ info_content: {
103
+ code: contentMessage,
104
+ message: errorContent,
105
+ },
106
+ date: Date.now().toString(),
107
+ status: "unread",
108
+ callToAction: false,
109
+ data: {
110
+ tenant: tenant.name,
111
+ },
112
+ };
113
+ eventHelper.notification.publish.creation(tenantCreationErrorNotification);
114
+ throw error;
115
+ }
116
+ };
117
+
118
+ export const deleteTenant = async (tenant: Tenant, security: string) => {
119
+ try {
120
+ await initializeGlobalWebSocketClient(security);
121
+
122
+ const deleteBody = {
123
+ tenant: tenant.name,
124
+ force: true,
125
+ };
126
+
127
+ const response = await makeGlobalWebSocketRequest(
128
+ "tenant:delete_tenant",
129
+ deleteBody,
130
+ 30000,
131
+ "DELETE",
132
+ tenant.name
133
+ );
134
+
135
+ // const updatedTenant = { ...tenant, status: "pending" };
136
+ // eventHelper.tenant.publish.deleted(updatedTenant);
137
+ // const tenantDeletedNotification: Notification = {
138
+ // type: "success",
139
+ // subtype: "tenant-deleted",
140
+ // date: Date.now().toString(),
141
+ // status: "unread",
142
+ // callToAction: false,
143
+ // };
144
+ // eventHelper.notification.publish.creation(tenantDeletedNotification);
145
+ return response;
146
+ } catch (err) {
147
+ console.error("Error in tenant deletion WebSocket request:", err);
148
+ eventHelper.tenant.publish.deletionError(tenant);
149
+ let contentMessage = "Unknown error";
150
+ let errorContent = "Unknown error";
151
+
152
+ if (
153
+ typeof err === "object" &&
154
+ err !== null &&
155
+ "error" in err &&
156
+ typeof (err as any).error === "object" &&
157
+ (err as any).error !== null
158
+ ) {
159
+ if ("code" in (err as any).error) {
160
+ contentMessage = (err as any).error.code;
161
+ }
162
+ if ("content" in (err as any).error) {
163
+ errorContent = (err as any).error.content;
164
+ }
165
+ }
166
+ const tenantDeletionErrorNotification: Notification = {
167
+ type: "error",
168
+ subtype: "tenant-deletion-error",
169
+ info_content: {
170
+ code: contentMessage,
171
+ message: errorContent,
172
+ },
173
+ date: Date.now().toString(),
174
+ status: "unread",
175
+ callToAction: false,
176
+ data: {
177
+ tenant: tenant.name,
178
+ },
179
+ };
180
+ eventHelper.notification.publish.creation(tenantDeletionErrorNotification);
181
+ throw err;
182
+ }
183
+ };
184
+
185
+ export const updateTenant = async (tenant: Tenant, security: string) => {
186
+ try {
187
+ await initializeGlobalWebSocketClient(security);
188
+
189
+ const hasNpmRegistry =
190
+ tenant.npmRegistry && tenant.npmRegistry.endpoint !== "";
191
+ const hasPlan = tenant.plan?.name;
192
+
193
+ const updateBody: Record<string, any> = {
194
+ tenant: tenant.name,
195
+ spec: {
196
+ registry: hasNpmRegistry
197
+ ? {
198
+ kind: "git",
199
+ endpoint: tenant.npmRegistry!.endpoint,
200
+ domain: tenant.npmRegistry!.domain,
201
+ credentials: tenant.npmRegistry!.credentials,
202
+ public: tenant.npmRegistry!.public,
203
+ }
204
+ : undefined,
205
+ },
206
+ };
207
+
208
+ if (hasPlan) {
209
+ updateBody.provider = tenant.plan!.provider || "";
210
+ updateBody.plan = tenant.plan!.name;
211
+ }
212
+
213
+ const response = await makeGlobalWebSocketRequest(
214
+ "tenant:update_tenant",
215
+ updateBody,
216
+ 30000,
217
+ "UPDATE",
218
+ tenant.name
219
+ );
220
+
221
+ const updatedTenant = { ...tenant, status: "pending" };
222
+ eventHelper.tenant.publish.updated(updatedTenant);
223
+ const tenantCreatedNotification: Notification = {
224
+ type: "success",
225
+ subtype: "tenant-updated",
226
+ date: Date.now().toString(),
227
+ status: "unread",
228
+ callToAction: false,
229
+ data: {
230
+ tenant: tenant.name,
231
+ },
232
+ };
233
+ eventHelper.notification.publish.creation(tenantCreatedNotification);
234
+ return response;
235
+ } catch (err) {
236
+ console.error("Error in tenant update WebSocket request:", err);
237
+ eventHelper.tenant.publish.updateError(tenant);
238
+ let contentMessage = "Unknown error";
239
+ let errorContent = "Unknown error";
240
+
241
+ if (
242
+ typeof err === "object" &&
243
+ err !== null &&
244
+ "error" in err &&
245
+ typeof (err as any).error === "object" &&
246
+ (err as any).error !== null
247
+ ) {
248
+ if ("code" in (err as any).error) {
249
+ contentMessage = (err as any).error.code;
250
+ }
251
+ if ("content" in (err as any).error) {
252
+ errorContent = (err as any).error.content;
253
+ }
254
+ }
255
+ const tenantUpdateErrorNotification: Notification = {
256
+ type: "error",
257
+ subtype: "tenant-update-error",
258
+ info_content: {
259
+ code: contentMessage,
260
+ message: errorContent,
261
+ },
262
+ date: Date.now().toString(),
263
+ status: "unread",
264
+ callToAction: false,
265
+ data: {
266
+ tenant: tenant.name,
267
+ },
268
+ };
269
+ eventHelper.notification.publish.creation(tenantUpdateErrorNotification);
270
+ throw err;
271
+ }
272
+ };
273
+
274
+ /**
275
+ * Function to create a tenant
276
+ * @param tenant Tenant object with the data of the tenant
277
+ * @returns The response of the API.
278
+ */
279
+ export const createTenantHTTP = async (tenant: Tenant) => {
280
+ const createTenantUrl = new URL(
281
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}`
282
+ );
283
+ if (tenant.plan && tenant.plan?.name !== "" && tenant.plan?.provider !== "") {
284
+ createTenantUrl.searchParams.append("plan", tenant.plan?.name || "");
285
+ createTenantUrl.searchParams.append(
286
+ "provider",
287
+ tenant.plan?.provider || ""
288
+ );
289
+ }
290
+ const tenantBody =
291
+ tenant.npmRegistry && tenant.npmRegistry.endpoint !== ""
292
+ ? {
293
+ tenant: tenant.name,
294
+ provider: tenant.plan?.provider || "",
295
+ plan: tenant.plan?.name || "",
296
+ spec: {
297
+ registry: {
298
+ kind: "git",
299
+ endpoint: tenant.npmRegistry.endpoint,
300
+ domain: tenant.npmRegistry.domain,
301
+ credentials: tenant.npmRegistry.credentials,
302
+ public: tenant.npmRegistry.public,
303
+ },
304
+ },
305
+ }
306
+ : {
307
+ tenant: tenant.name,
308
+ spec: {
309
+ registry: undefined,
310
+ },
311
+ };
312
+ const response = await fetch(createTenantUrl, {
313
+ method: "POST",
314
+ headers: {
315
+ "Content-Type": "application/json",
316
+ },
317
+ body: JSON.stringify(tenantBody),
318
+ });
319
+ if (response.ok) {
320
+ const updatedTenant = { ...tenant, status: "pending" };
321
+ eventHelper.tenant.publish.created(updatedTenant);
322
+ const tenantCreatedNotification: Notification = {
323
+ type: "success",
324
+ subtype: "tenant-created",
325
+ date: Date.now().toString(),
326
+ status: "unread",
327
+ callToAction: false,
328
+ data: {
329
+ tenant: tenant.name,
330
+ },
331
+ };
332
+ eventHelper.notification.publish.creation(tenantCreatedNotification);
333
+ } else {
334
+ eventHelper.tenant.publish.creationError(tenant);
335
+
336
+ let errorCode = "Unknown error";
337
+ let errorMessage = "Unknown error";
338
+
339
+ try {
340
+ const errorBody = await response.json();
341
+ if (errorBody?.code) {
342
+ errorCode = errorBody.code;
343
+ }
344
+ if (errorBody?.content) {
345
+ errorMessage = errorBody.content;
346
+ } else {
347
+ errorMessage = JSON.stringify(errorBody, null, 2);
348
+ }
349
+ } catch (e) {
350
+ const text = await response.text();
351
+ errorMessage = text || "Unknown error";
352
+ }
353
+
354
+ const tenantCreationErrorNotification: Notification = {
355
+ type: "error",
356
+ subtype: "tenant-creation-error",
357
+ info_content: {
358
+ code: errorCode,
359
+ message: errorMessage,
360
+ },
361
+ date: Date.now().toString(),
362
+ status: "unread",
363
+ callToAction: false,
364
+ data: {
365
+ tenant: tenant.name,
366
+ },
367
+ };
368
+
369
+ eventHelper.notification.publish.creation(tenantCreationErrorNotification);
370
+ }
371
+ };
372
+
373
+ export const deleteTenantHTTP = async (tenant: Tenant) => {
374
+ const url = new URL(
375
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}`
376
+ );
377
+ url.searchParams.append("force", "true");
378
+
379
+ const response = await fetch(url.toString(), {
380
+ method: "DELETE",
381
+ });
382
+
383
+ if (response.ok) {
384
+ const tenantDeletedNotification: Notification = {
385
+ type: "success",
386
+ subtype: "tenant-deleting",
387
+ date: Date.now().toString(),
388
+ status: "unread",
389
+ callToAction: false,
390
+ data: {
391
+ tenant: tenant.name,
392
+ },
393
+ };
394
+ eventHelper.notification.publish.creation(tenantDeletedNotification);
395
+ } else {
396
+ eventHelper.tenant.publish.deletionError(tenant);
397
+
398
+ let errorCode = "Unknown error";
399
+ let errorMessage = "Unknown error";
400
+ try {
401
+ const errorBody = await response.json();
402
+ if (errorBody?.code) {
403
+ errorCode = errorBody.code;
404
+ }
405
+ if (errorBody?.content) {
406
+ errorMessage = errorBody.content;
407
+ }
408
+ } catch (e) {
409
+ const text = await response.text();
410
+ errorMessage = text || "Unknown error";
411
+ }
412
+
413
+ const tenantDeletionErrorNotification: Notification = {
414
+ type: "error",
415
+ subtype: "tenant-deletion-error",
416
+ info_content: {
417
+ code: errorCode,
418
+ message: errorMessage,
419
+ },
420
+ date: Date.now().toString(),
421
+ status: "unread",
422
+ callToAction: false,
423
+ data: {
424
+ tenant: tenant.name,
425
+ },
426
+ };
427
+ eventHelper.notification.publish.creation(tenantDeletionErrorNotification);
428
+ }
429
+ };
430
+
431
+ export const updateTenantHTTP = async (tenant: Tenant) => {
432
+ const updateTenantUrl = new URL(
433
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}`
434
+ );
435
+ if (tenant.plan && tenant.plan?.name !== "" && tenant.plan?.provider !== "") {
436
+ updateTenantUrl.searchParams.append("plan", tenant.plan?.name || "");
437
+ updateTenantUrl.searchParams.append(
438
+ "provider",
439
+ tenant.plan?.provider || ""
440
+ );
441
+ }
442
+ const tenantBody =
443
+ tenant.npmRegistry && tenant.npmRegistry.endpoint !== ""
444
+ ? {
445
+ tenant: tenant.name,
446
+ provider: tenant.plan?.provider || "",
447
+ plan: tenant.plan?.name || "",
448
+ spec: {
449
+ registry: {
450
+ kind: "git",
451
+ endpoint: tenant.npmRegistry.endpoint,
452
+ domain: tenant.npmRegistry.domain,
453
+ credentials: tenant.npmRegistry.credentials,
454
+ public: tenant.npmRegistry.public,
455
+ },
456
+ },
457
+ }
458
+ : {
459
+ tenant: tenant.name,
460
+ spec: {
461
+ registry: undefined,
462
+ },
463
+ };
464
+ const response = await fetch(updateTenantUrl, {
465
+ method: "PATCH",
466
+ headers: {
467
+ "Content-Type": "application/json",
468
+ },
469
+ body: JSON.stringify(tenantBody),
470
+ });
471
+
472
+ if (response.ok) {
473
+ const updatedTenant = { ...tenant, status: "pending" };
474
+ eventHelper.tenant.publish.updated(updatedTenant);
475
+ const tenantCreatedNotification: Notification = {
476
+ type: "success",
477
+ subtype: "tenant-updated",
478
+ date: Date.now().toString(),
479
+ status: "unread",
480
+ callToAction: false,
481
+ data: {
482
+ tenant: tenant.name,
483
+ },
484
+ };
485
+ eventHelper.notification.publish.creation(tenantCreatedNotification);
486
+ } else {
487
+ eventHelper.tenant.publish.updateError(tenant);
488
+
489
+ let errorCode = "Unknown error";
490
+ let errorMessage = "Unknown error";
491
+ try {
492
+ const errorBody = await response.json();
493
+ if (errorBody?.code) {
494
+ errorCode = errorBody.code;
495
+ }
496
+ if (errorBody?.content) {
497
+ errorMessage = errorBody.content;
498
+ }
499
+ } catch (e) {
500
+ const text = await response.text();
501
+ errorMessage = text || "Unknown error";
502
+ }
503
+
504
+ const tenantUpdateErrorNotification: Notification = {
505
+ type: "error",
506
+ subtype: "tenant-update-error",
507
+ info_content: {
508
+ code: errorCode,
509
+ message: errorMessage,
510
+ },
511
+ date: Date.now().toString(),
512
+ status: "unread",
513
+ callToAction: false,
514
+ data: {
515
+ tenant: tenant.name,
516
+ },
517
+ };
518
+ eventHelper.notification.publish.creation(tenantUpdateErrorNotification);
519
+ }
520
+ };
521
+
522
+ export const createRegistry = async (
523
+ tenant: Tenant,
524
+ security: Security,
525
+ registry: Registry
526
+ ) => {
527
+ try {
528
+ await initializeGlobalWebSocketClient(security);
529
+ const dregistryBody: DregistryBody = {
530
+ spec: {
531
+ labels: { logo: registry.extra },
532
+ docker_server: registry.domain,
533
+ docker_username: registry.credentials,
534
+ docker_password: registry.password || "",
535
+ },
536
+ };
537
+ const queryParams = {
538
+ tenant: tenant.name,
539
+ dregistry: registry.name,
540
+ };
541
+
542
+ const response = await makeGlobalWebSocketRequest(
543
+ "dregistry:create_dregistry",
544
+ {
545
+ ...dregistryBody,
546
+ ...queryParams,
547
+ },
548
+ 30000,
549
+ "CREATE",
550
+ `${tenant.name}/${registry.domain}`
551
+ );
552
+
553
+ const dregistryCreatedNotification: Notification = {
554
+ type: "success",
555
+ subtype: "registry-created",
556
+ date: Date.now().toString(),
557
+ status: "unread",
558
+ callToAction: false,
559
+ data: {
560
+ tenant: tenant.name,
561
+ },
562
+ };
563
+ eventHelper.notification.publish.creation(dregistryCreatedNotification);
564
+ return response;
565
+ } catch (error) {
566
+ console.error("Error creating dregistry:", {
567
+ error,
568
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
569
+ tenant: tenant.name,
570
+ registry: registry.domain,
571
+ webSocketStatus: getWebSocketStatus(),
572
+ });
573
+
574
+ let contentMessage = "Unknown error";
575
+ let errorContent = "Unknown error";
576
+
577
+ if (
578
+ typeof error === "object" &&
579
+ error !== null &&
580
+ "error" in error &&
581
+ typeof (error as any).error === "object" &&
582
+ (error as any).error !== null
583
+ ) {
584
+ if ("code" in (error as any).error) {
585
+ contentMessage = (error as any).error.code;
586
+ }
587
+ if ("content" in (error as any).error) {
588
+ errorContent = (error as any).error.content;
589
+ }
590
+ }
591
+
592
+ const dregistryCreationErrorNotification: Notification = {
593
+ type: "error",
594
+ subtype: "registry-creation-error",
595
+ info_content: {
596
+ code: contentMessage,
597
+ message: errorContent,
598
+ },
599
+ date: Date.now().toString(),
600
+ status: "unread",
601
+ callToAction: false,
602
+ data: {
603
+ tenant: tenant.name,
604
+ },
605
+ };
606
+ eventHelper.notification.publish.creation(
607
+ dregistryCreationErrorNotification
608
+ );
609
+ throw error;
610
+ }
611
+ };
612
+
613
+ /**
614
+ * Function to update a dregistry using the global WebSocket connection
615
+ * @param tenant Tenant object with registry information
616
+ * @param security Authorization token
617
+ * @param force Force update flag (default: false)
618
+ * @returns The response of the WebSocket API
619
+ */
620
+ export const updateRegistry = async (
621
+ tenant: Tenant,
622
+ registry: Registry,
623
+ security: Security,
624
+ force: boolean = false
625
+ ) => {
626
+ try {
627
+ await initializeGlobalWebSocketClient(security);
628
+ const dregistryBody: DregistryBody = {
629
+ spec: {
630
+ labels: { logo: registry.extra },
631
+ docker_server: registry.domain,
632
+ docker_username: registry.credentials,
633
+ docker_password: registry.password || "",
634
+ },
635
+ };
636
+ const queryParams = {
637
+ tenant: tenant.name,
638
+ dregistry: registry.name,
639
+ force: force,
640
+ };
641
+
642
+ const response = await makeGlobalWebSocketRequest(
643
+ "dregistry:update_dregistry",
644
+ {
645
+ ...dregistryBody,
646
+ ...queryParams,
647
+ },
648
+ 30000,
649
+ "UPDATE",
650
+ `${tenant.name}/${registry.domain}`
651
+ );
652
+ const dregistryUpdatedNotification: Notification = {
653
+ type: "success",
654
+ subtype: "registry-updated",
655
+ date: Date.now().toString(),
656
+ status: "unread",
657
+ callToAction: false,
658
+ data: {
659
+ tenant: tenant.name,
660
+ },
661
+ };
662
+ eventHelper.notification.publish.creation(dregistryUpdatedNotification);
663
+
664
+ return response;
665
+ } catch (error) {
666
+ console.error("Error updating dregistry:", {
667
+ error,
668
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
669
+ tenant: tenant.name,
670
+ registry: registry.domain,
671
+ force,
672
+ webSocketStatus: getWebSocketStatus(),
673
+ });
674
+
675
+ let contentMessage = "Unknown error";
676
+ let errorContent = "Unknown error";
677
+
678
+ if (
679
+ typeof error === "object" &&
680
+ error !== null &&
681
+ "error" in error &&
682
+ typeof (error as any).error === "object" &&
683
+ (error as any).error !== null
684
+ ) {
685
+ if ("code" in (error as any).error) {
686
+ contentMessage = (error as any).error.code;
687
+ }
688
+ if ("content" in (error as any).error) {
689
+ errorContent = (error as any).error.content;
690
+ }
691
+ }
692
+
693
+ const dregistryUpdateErrorNotification: Notification = {
694
+ type: "error",
695
+ subtype: "registry-update-error",
696
+ info_content: {
697
+ code: contentMessage,
698
+ message: errorContent,
699
+ },
700
+ date: Date.now().toString(),
701
+ status: "unread",
702
+ callToAction: false,
703
+ data: {
704
+ tenant: tenant.name,
705
+ },
706
+ };
707
+ eventHelper.notification.publish.creation(dregistryUpdateErrorNotification);
708
+ throw error;
709
+ }
710
+ };
711
+
712
+ export const deleteRegistry = async (
713
+ tenant: Tenant,
714
+ registry: Registry,
715
+ security: Security,
716
+ force: boolean = false
717
+ ) => {
718
+ try {
719
+ await initializeGlobalWebSocketClient(security);
720
+
721
+ const queryParams = {
722
+ tenant: tenant.name,
723
+ dregistry: registry.name,
724
+ force: force,
725
+ };
726
+
727
+ const response = await makeGlobalWebSocketRequest(
728
+ "dregistry:delete_dregistry",
729
+ queryParams,
730
+ 30000,
731
+ "DELETE",
732
+ `${tenant.name}/${registry.domain}`
733
+ );
734
+
735
+ const dregistryDeletedNotification: Notification = {
736
+ type: "success",
737
+ subtype: "registry-deleted",
738
+ date: Date.now().toString(),
739
+ status: "unread",
740
+ callToAction: false,
741
+ data: {
742
+ tenant: tenant.name,
743
+ },
744
+ };
745
+ eventHelper.notification.publish.creation(dregistryDeletedNotification);
746
+ return response;
747
+ } catch (error) {
748
+ console.error("Error deleting dregistry:", {
749
+ error,
750
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
751
+ tenant: tenant.name,
752
+ registry: registry.domain,
753
+ force,
754
+ webSocketStatus: getWebSocketStatus(),
755
+ });
756
+
757
+ let contentMessage = "Unknown error";
758
+ let errorContent = "Unknown error";
759
+
760
+ if (
761
+ typeof error === "object" &&
762
+ error !== null &&
763
+ "error" in error &&
764
+ typeof (error as any).error === "object" &&
765
+ (error as any).error !== null
766
+ ) {
767
+ if ("code" in (error as any).error) {
768
+ contentMessage = (error as any).error.code;
769
+ }
770
+ if ("content" in (error as any).error) {
771
+ errorContent = (error as any).error.content;
772
+ }
773
+ }
774
+
775
+ const dregistryDeletionErrorNotification: Notification = {
776
+ type: "error",
777
+ subtype: "registry-deletion-error",
778
+ info_content: {
779
+ code: contentMessage,
780
+ message: errorContent,
781
+ },
782
+ date: Date.now().toString(),
783
+ status: "unread",
784
+ callToAction: false,
785
+ data: {
786
+ tenant: tenant.name,
787
+ },
788
+ };
789
+ eventHelper.notification.publish.creation(
790
+ dregistryDeletionErrorNotification
791
+ );
792
+ throw error;
793
+ }
794
+ };
795
+
796
+ export const inviteUser = async (
797
+ tenant: string,
798
+ email: string,
799
+ role: tenantRole,
800
+ security: string
801
+ ) => {
802
+ try {
803
+ await initializeGlobalWebSocketClient(security);
804
+
805
+ const queryParams = {
806
+ tenant: tenant,
807
+ user: email,
808
+ role: role,
809
+ };
810
+
811
+ const response = await makeGlobalWebSocketRequest(
812
+ "tenant:propose_user",
813
+ queryParams,
814
+ 30000,
815
+ "CREATE",
816
+ `${tenant}/${email}`
817
+ );
818
+ const tenantInvitedNotification: Notification = {
819
+ type: "success",
820
+ subtype: "tenant-user-invited",
821
+ date: Date.now().toString(),
822
+ status: "unread",
823
+ callToAction: false,
824
+ data: {
825
+ tenant: tenant,
826
+ email: email,
827
+ role,
828
+ tenantRole,
829
+ },
830
+ };
831
+ eventHelper.notification.publish.creation(tenantInvitedNotification);
832
+ return response;
833
+ } catch (error) {
834
+ console.error("Error inviting user:", {
835
+ error,
836
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
837
+ tenant: tenant,
838
+ email: email,
839
+ role: role,
840
+ webSocketStatus: getWebSocketStatus(),
841
+ });
842
+ let contentMessage = "Unknown error";
843
+ let errorContent = "Unknown error";
844
+
845
+ if (
846
+ typeof error === "object" &&
847
+ error !== null &&
848
+ "error" in error &&
849
+ typeof (error as any).error === "object" &&
850
+ (error as any).error !== null
851
+ ) {
852
+ if ("code" in (error as any).error) {
853
+ contentMessage = (error as any).error.code;
854
+ }
855
+ if ("content" in (error as any).error) {
856
+ errorContent = (error as any).error.content;
857
+ }
858
+ }
859
+ const tenantInviteErrorNotification: Notification = {
860
+ type: "error",
861
+ subtype: "tenant-user-invite-error",
862
+ info_content: {
863
+ code: contentMessage,
864
+ message: errorContent,
865
+ },
866
+ date: Date.now().toString(),
867
+ status: "unread",
868
+ callToAction: false,
869
+ data: {
870
+ tenant: tenant,
871
+ email: email,
872
+ role,
873
+ tenantRole,
874
+ },
875
+ };
876
+ eventHelper.notification.publish.creation(tenantInviteErrorNotification);
877
+ throw error;
878
+ }
879
+ };
880
+
881
+ export const removeUser = async (
882
+ tenant: string,
883
+ userId: string,
884
+ security: string
885
+ ) => {
886
+ try {
887
+ await initializeGlobalWebSocketClient(security);
888
+ const queryParams = {
889
+ tenant: tenant,
890
+ user: userId,
891
+ };
892
+ const response = await makeGlobalWebSocketRequest(
893
+ "tenant:exclude_user",
894
+ queryParams,
895
+ 30000,
896
+ "DELETE",
897
+ `${tenant}/${userId}`
898
+ );
899
+ const tenantUserRemovedNotification: Notification = {
900
+ type: "success",
901
+ subtype: "tenant-user-removed",
902
+ date: Date.now().toString(),
903
+ status: "unread",
904
+ callToAction: false,
905
+ data: {
906
+ tenant: tenant,
907
+ user: userId,
908
+ },
909
+ };
910
+ eventHelper.notification.publish.creation(tenantUserRemovedNotification);
911
+ return response;
912
+ } catch (error) {
913
+ console.error("Error removing user from tenant:", {
914
+ error,
915
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
916
+ tenant: tenant,
917
+ userId: userId,
918
+ webSocketStatus: getWebSocketStatus(),
919
+ });
920
+ let contentMessage = "Unknown error";
921
+ let errorContent = "Unknown error";
922
+
923
+ if (
924
+ typeof error === "object" &&
925
+ error !== null &&
926
+ "error" in error &&
927
+ typeof (error as any).error === "object" &&
928
+ (error as any).error !== null
929
+ ) {
930
+ if ("code" in (error as any).error) {
931
+ contentMessage = (error as any).error.code;
932
+ }
933
+ if ("content" in (error as any).error) {
934
+ errorContent = (error as any).error.content;
935
+ }
936
+ }
937
+ const tenantUserRemovedErrorNotification: Notification = {
938
+ type: "error",
939
+ subtype: "tenant-user-removed-error",
940
+ info_content: {
941
+ code: contentMessage,
942
+ message: errorContent,
943
+ },
944
+ date: Date.now().toString(),
945
+ status: "unread",
946
+ callToAction: false,
947
+ data: {
948
+ tenant: tenant,
949
+ user: userId,
950
+ },
951
+ };
952
+ eventHelper.notification.publish.creation(
953
+ tenantUserRemovedErrorNotification
954
+ );
955
+ throw error;
956
+ }
957
+ };
958
+
959
+ export const updateUserRole = async (
960
+ tenant: string,
961
+ userId: string,
962
+ role: tenantRole,
963
+ security: string
964
+ ) => {
965
+ try {
966
+ await initializeGlobalWebSocketClient(security);
967
+ const queryParams = {
968
+ tenant: tenant,
969
+ user: userId,
970
+ role: role,
971
+ };
972
+ const response = await makeGlobalWebSocketRequest(
973
+ "tenant:modify_user_role",
974
+ queryParams,
975
+ 30000,
976
+ "PATCH",
977
+ `${tenant}/${userId}`
978
+ );
979
+ const tenantUserUpdatedNotification: Notification = {
980
+ type: "success",
981
+ subtype: "user-role-updated",
982
+ date: Date.now().toString(),
983
+ status: "unread",
984
+ callToAction: false,
985
+ data: {
986
+ tenant: tenant,
987
+ user: userId,
988
+ role: role,
989
+ },
990
+ };
991
+ eventHelper.notification.publish.creation(tenantUserUpdatedNotification);
992
+ return response;
993
+ } catch (error) {
994
+ console.error("Error updating user in tenant:", {
995
+ error,
996
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
997
+ tenant: tenant,
998
+ userId: userId,
999
+ role: role,
1000
+ webSocketStatus: getWebSocketStatus(),
1001
+ });
1002
+ let contentMessage = "Unknown error";
1003
+ let errorContent = "Unknown error";
1004
+
1005
+ if (
1006
+ typeof error === "object" &&
1007
+ error !== null &&
1008
+ "error" in error &&
1009
+ typeof (error as any).error === "object" &&
1010
+ (error as any).error !== null
1011
+ ) {
1012
+ if ("code" in (error as any).error) {
1013
+ contentMessage = (error as any).error.code;
1014
+ }
1015
+ if ("content" in (error as any).error) {
1016
+ errorContent = (error as any).error.content;
1017
+ }
1018
+ }
1019
+ const tenantUserUpdatedErrorNotification: Notification = {
1020
+ type: "error",
1021
+ subtype: "user-role-updated-error",
1022
+ info_content: {
1023
+ code: contentMessage,
1024
+ message: errorContent,
1025
+ },
1026
+ date: Date.now().toString(),
1027
+ status: "unread",
1028
+ callToAction: false,
1029
+ data: {
1030
+ tenant: tenant,
1031
+ user: userId,
1032
+ role: role,
1033
+ },
1034
+ };
1035
+ eventHelper.notification.publish.creation(
1036
+ tenantUserUpdatedErrorNotification
1037
+ );
1038
+ throw error;
1039
+ }
1040
+ };
1041
+
1042
+ export const acceptInvite = async (tenant: string, security: string) => {
1043
+ try {
1044
+ await initializeGlobalWebSocketClient(security);
1045
+ const queryParams = { tenant: tenant };
1046
+ const response = await makeGlobalWebSocketRequest(
1047
+ "tenant:accept_proposal_user",
1048
+ queryParams,
1049
+ 30000,
1050
+ "PUT",
1051
+ `${tenant}/accept`
1052
+ );
1053
+ const tenantInviteAcceptedNotification: Notification = {
1054
+ type: "success",
1055
+ subtype: "tenant-invite-accepted",
1056
+ date: Date.now().toString(),
1057
+ status: "unread",
1058
+ callToAction: false,
1059
+ data: {
1060
+ tenant: tenant,
1061
+ },
1062
+ };
1063
+ eventHelper.notification.publish.creation(tenantInviteAcceptedNotification);
1064
+ return response;
1065
+ } catch (error) {
1066
+ console.error("Error accepting tenant invite:", {
1067
+ error,
1068
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
1069
+ tenant: tenant,
1070
+ webSocketStatus: getWebSocketStatus(),
1071
+ });
1072
+ let contentMessage = "Unknown error";
1073
+ let errorContent = "Unknown error";
1074
+
1075
+ if (
1076
+ typeof error === "object" &&
1077
+ error !== null &&
1078
+ "error" in error &&
1079
+ typeof (error as any).error === "object" &&
1080
+ (error as any).error !== null
1081
+ ) {
1082
+ if ("code" in (error as any).error) {
1083
+ contentMessage = (error as any).error.code;
1084
+ }
1085
+ if ("content" in (error as any).error) {
1086
+ errorContent = (error as any).error.content;
1087
+ }
1088
+ }
1089
+ const tenantInviteAcceptedErrorNotification: Notification = {
1090
+ type: "error",
1091
+ subtype: "tenant-invite-accepted-error",
1092
+ info_content: {
1093
+ code: contentMessage,
1094
+ message: errorContent,
1095
+ },
1096
+ date: Date.now().toString(),
1097
+ status: "unread",
1098
+ callToAction: false,
1099
+ data: {
1100
+ tenant: tenant,
1101
+ },
1102
+ };
1103
+ eventHelper.notification.publish.creation(
1104
+ tenantInviteAcceptedErrorNotification
1105
+ );
1106
+ throw error;
1107
+ }
1108
+ };
1109
+
1110
+ export const rejectInvite = async (tenant: string, security: string) => {
1111
+ try {
1112
+ await initializeGlobalWebSocketClient(security);
1113
+ const queryParams = { tenant: tenant };
1114
+ const response = await makeGlobalWebSocketRequest(
1115
+ "tenant:reject_proposal_user",
1116
+ queryParams,
1117
+ 30000,
1118
+ "DELETE",
1119
+ `${tenant}/reject`
1120
+ );
1121
+ const tenantInviteRejectedNotification: Notification = {
1122
+ type: "success",
1123
+ subtype: "tenant-invite-rejected",
1124
+ date: Date.now().toString(),
1125
+ status: "unread",
1126
+ callToAction: false,
1127
+ data: {
1128
+ tenant: tenant,
1129
+ },
1130
+ };
1131
+ eventHelper.notification.publish.creation(tenantInviteRejectedNotification);
1132
+ return response;
1133
+ } catch (error) {
1134
+ console.error("Error rejecting tenant invite:", {
1135
+ error,
1136
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
1137
+ tenant: tenant,
1138
+ webSocketStatus: getWebSocketStatus(),
1139
+ });
1140
+ let contentMessage = "Unknown error";
1141
+ let errorContent = "Unknown error";
1142
+
1143
+ if (
1144
+ typeof error === "object" &&
1145
+ error !== null &&
1146
+ "error" in error &&
1147
+ typeof (error as any).error === "object" &&
1148
+ (error as any).error !== null
1149
+ ) {
1150
+ if ("code" in (error as any).error) {
1151
+ contentMessage = (error as any).error.code;
1152
+ }
1153
+ if ("content" in (error as any).error) {
1154
+ errorContent = (error as any).error.content;
1155
+ }
1156
+ }
1157
+ const tenantInviteRejectedErrorNotification: Notification = {
1158
+ type: "error",
1159
+ subtype: "tenant-invite-rejected-error",
1160
+ info_content: {
1161
+ code: contentMessage,
1162
+ message: errorContent,
1163
+ },
1164
+ date: Date.now().toString(),
1165
+ status: "unread",
1166
+ callToAction: false,
1167
+ data: {
1168
+ tenant: tenant,
1169
+ },
1170
+ };
1171
+ eventHelper.notification.publish.creation(
1172
+ tenantInviteRejectedErrorNotification
1173
+ );
1174
+ throw error;
1175
+ }
1176
+ };
1177
+ export const createToken = async (
1178
+ tenantName: string,
1179
+ tokenDescription: string,
1180
+ tokenExpiration: string,
1181
+ security: string
1182
+ ) => {
1183
+ try {
1184
+ await initializeGlobalWebSocketClient(security);
1185
+ const createTokenBody = {
1186
+ spec: {
1187
+ scopes: {
1188
+ tenant: { [tenantName]: { allow: ["*:*:*"] } },
1189
+ planprovider: { "*": { allow: ["*:*:*"] } },
1190
+ user: { "*": { allow: ["*:*:*"] } },
1191
+ idprovider: { "*": { allow: ["*:*:*"] } },
1192
+ },
1193
+ expiration: tokenExpiration,
1194
+ description: tokenDescription,
1195
+ labels: {
1196
+ tenant: tenantName,
1197
+ },
1198
+ },
1199
+ };
1200
+ const response = await makeGlobalWebSocketRequest(
1201
+ "token:create_token",
1202
+ createTokenBody,
1203
+ 30000,
1204
+ "CREATE",
1205
+ `${tenantName}/tokens`,
1206
+ "token"
1207
+ );
1208
+
1209
+ const tenantTokenCreatedNotification: Notification = {
1210
+ type: "success",
1211
+ subtype: "token-created",
1212
+ date: Date.now().toString(),
1213
+ status: "unread",
1214
+ callToAction: false,
1215
+ data: {
1216
+ tenant: tenantName,
1217
+ tokenName: tokenDescription,
1218
+ },
1219
+ };
1220
+ eventHelper.notification.publish.creation(tenantTokenCreatedNotification);
1221
+
1222
+ return response;
1223
+ } catch (error) {
1224
+ console.error("Error creating tenant token:", {
1225
+ error,
1226
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
1227
+ tenant: tenantName,
1228
+ webSocketStatus: getWebSocketStatus(),
1229
+ });
1230
+ throw error;
1231
+ }
1232
+ };
1233
+ export const deleteToken = async (
1234
+ tenantName: string,
1235
+ tokenID: string,
1236
+ security: string
1237
+ ) => {
1238
+ try {
1239
+ await initializeGlobalWebSocketClient(security);
1240
+ const queryParams = {
1241
+ token_jti: tokenID,
1242
+ };
1243
+ const response = await makeGlobalWebSocketRequest(
1244
+ "token:revoke_token",
1245
+ queryParams,
1246
+ 30000,
1247
+ "DELETE",
1248
+ `${tenantName}/tokens/${tokenID}`
1249
+ );
1250
+ return response;
1251
+ } catch (error) {
1252
+ console.error("Error deleting tenant token:", {
1253
+ error,
1254
+ errorMessage: error instanceof Error ? error.message : "Unknown error",
1255
+ tenant: tenantName,
1256
+ webSocketStatus: getWebSocketStatus(),
1257
+ });
1258
+ throw error;
1259
+ }
1260
+ };