@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,821 @@
1
+ import { Notification, Resource } from "@hestekumori/aurora-interfaces";
2
+ import { eventHelper } from "../backend-handler";
3
+
4
+ import {
5
+ initializeGlobalWebSocketClient,
6
+ getWebSocketStatus,
7
+ makeGlobalWebSocketRequest,
8
+ } from "../websocket-manager";
9
+
10
+ const createResourceBody = (
11
+ tenant: string,
12
+ resource: Resource,
13
+ kind: string,
14
+ data: any
15
+ ) => ({
16
+ tenant,
17
+ resource: resource.name,
18
+ kind,
19
+ spec: {
20
+ kind,
21
+ data,
22
+ },
23
+ });
24
+
25
+ export const createDomain = async (
26
+ tenant: string,
27
+ domain: Resource,
28
+ security: string
29
+ ) => {
30
+ try {
31
+ await initializeGlobalWebSocketClient(security);
32
+ const status = getWebSocketStatus();
33
+
34
+ const domainBody = createResourceBody(tenant, domain, "domain", {
35
+ domain: domain.value,
36
+ });
37
+
38
+ const response = await makeGlobalWebSocketRequest(
39
+ "resource:create_resource",
40
+ domainBody,
41
+ 30000,
42
+ "CREATE",
43
+ domain.name
44
+ );
45
+
46
+ // eventHelper.resource.publish.created(domain);
47
+ const resourceNotification: Notification = {
48
+ type: "success",
49
+ subtype: "resource-created",
50
+ date: Date.now().toString(),
51
+ status: "unread",
52
+ callToAction: false,
53
+ data: {
54
+ resource: domain.name,
55
+ tenant: tenant
56
+ }
57
+ };
58
+ eventHelper.notification.publish.creation(resourceNotification);
59
+ return response;
60
+ } catch (error) {
61
+ console.error("Error creating domain:", {
62
+ error,
63
+ tenant,
64
+ domain,
65
+ webSocketStatus: getWebSocketStatus(),
66
+ });
67
+ let contentMessage = "Unknown error";
68
+ let errorContent = "Unknown error";
69
+
70
+ if (
71
+ typeof error === "object" &&
72
+ error !== null &&
73
+ "error" in error &&
74
+ typeof (error as any).error === "object" &&
75
+ (error as any).error !== null
76
+ ) {
77
+ if ("code" in (error as any).error) {
78
+ contentMessage = (error as any).error.code;
79
+ }
80
+ if ("content" in (error as any).error) {
81
+ errorContent = (error as any).error.content;
82
+ }
83
+ }
84
+ const resourceErrorNotification: Notification = {
85
+ type: "error",
86
+ subtype: "resource-creation-error",
87
+ info_content: {
88
+ code: contentMessage,
89
+ message: errorContent,
90
+ },
91
+ date: Date.now().toString(),
92
+ status: "unread",
93
+ callToAction: false,
94
+ data: {
95
+ resource: domain.name,
96
+ tenant: tenant
97
+ }
98
+ };
99
+ eventHelper.notification.publish.creation(resourceErrorNotification);
100
+ throw error;
101
+ }
102
+ };
103
+
104
+ export const createPort = async (
105
+ tenant: string,
106
+ port: Resource,
107
+ security: string
108
+ ) => {
109
+ try {
110
+ await initializeGlobalWebSocketClient(security);
111
+ const status = getWebSocketStatus();
112
+
113
+ const portBody = createResourceBody(tenant, port, "port", {
114
+ port: Number(port.value),
115
+ });
116
+
117
+ const response = await makeGlobalWebSocketRequest(
118
+ "resource:create_resource",
119
+ portBody,
120
+ 30000,
121
+ "CREATE",
122
+ port.name
123
+ );
124
+
125
+ eventHelper.resource.publish.created(port);
126
+ const resourceNotification: Notification = {
127
+ type: "success",
128
+ subtype: "resource-created",
129
+ date: Date.now().toString(),
130
+ status: "unread",
131
+ callToAction: false,
132
+ data: {
133
+ resource: port.name,
134
+ tenant: tenant
135
+ }
136
+ };
137
+ eventHelper.notification.publish.creation(resourceNotification);
138
+ return response;
139
+ } catch (error) {
140
+ console.error("Error creating port:", {
141
+ error,
142
+ tenant,
143
+ port,
144
+ webSocketStatus: getWebSocketStatus(),
145
+ });
146
+ let contentMessage = "Unknown error";
147
+ let errorContent = "Unknown error";
148
+
149
+ if (
150
+ typeof error === "object" &&
151
+ error !== null &&
152
+ "error" in error &&
153
+ typeof (error as any).error === "object" &&
154
+ (error as any).error !== null
155
+ ) {
156
+ if ("code" in (error as any).error) {
157
+ contentMessage = (error as any).error.code;
158
+ }
159
+ if ("content" in (error as any).error) {
160
+ errorContent = (error as any).error.content;
161
+ }
162
+ }
163
+ const resourceErrorNotification: Notification = {
164
+ type: "error",
165
+ subtype: "resource-creation-error",
166
+ info_content: {
167
+ code: contentMessage,
168
+ message: errorContent,
169
+ },
170
+ date: Date.now().toString(),
171
+ status: "unread",
172
+ callToAction: false,
173
+ data: {
174
+ resource: port.name,
175
+ tenant: tenant
176
+ }
177
+ };
178
+ eventHelper.notification.publish.creation(resourceErrorNotification);
179
+ throw error;
180
+ }
181
+ };
182
+
183
+ export const createCA = async (
184
+ tenant: string,
185
+ ca: Resource,
186
+ security: string
187
+ ) => {
188
+ try {
189
+ await initializeGlobalWebSocketClient(security);
190
+ const status = getWebSocketStatus();
191
+
192
+ const caBody = createResourceBody(tenant, ca, "ca", {
193
+ ca: ca.value,
194
+ });
195
+
196
+ const response = await makeGlobalWebSocketRequest(
197
+ "resource:create_resource",
198
+ caBody,
199
+ 30000,
200
+ "CREATE",
201
+ ca.name
202
+ );
203
+
204
+ eventHelper.resource.publish.created(ca);
205
+ const resourceNotification: Notification = {
206
+ type: "success",
207
+ subtype: "resource-created",
208
+ date: Date.now().toString(),
209
+ status: "unread",
210
+ callToAction: false,
211
+ data: {
212
+ resource: ca.name,
213
+ tenant: tenant
214
+ }
215
+ };
216
+ eventHelper.notification.publish.creation(resourceNotification);
217
+ return response;
218
+ } catch (error) {
219
+ console.error("Error creating CA:", {
220
+ error,
221
+ tenant,
222
+ ca,
223
+ webSocketStatus: getWebSocketStatus(),
224
+ });
225
+ let contentMessage = "Unknown error";
226
+ let errorContent = "Unknown error";
227
+
228
+ if (
229
+ typeof error === "object" &&
230
+ error !== null &&
231
+ "error" in error &&
232
+ typeof (error as any).error === "object" &&
233
+ (error as any).error !== null
234
+ ) {
235
+ if ("code" in (error as any).error) {
236
+ contentMessage = (error as any).error.code;
237
+ }
238
+ if ("content" in (error as any).error) {
239
+ errorContent = (error as any).error.content;
240
+ }
241
+ }
242
+ const resourceErrorNotification: Notification = {
243
+ type: "error",
244
+ subtype: "resource-creation-error",
245
+ info_content: {
246
+ code: contentMessage,
247
+ message: errorContent,
248
+ },
249
+ date: Date.now().toString(),
250
+ status: "unread",
251
+ callToAction: false,
252
+ data: {
253
+ resource: ca.name,
254
+ tenant: tenant
255
+ }
256
+ };
257
+ eventHelper.notification.publish.creation(resourceErrorNotification);
258
+ throw error;
259
+ }
260
+ };
261
+
262
+ export const createCertificate = async (
263
+ tenant: string,
264
+ certificate: Resource,
265
+ security: string
266
+ ) => {
267
+ try {
268
+ await initializeGlobalWebSocketClient(security);
269
+ const status = getWebSocketStatus();
270
+
271
+ if (!certificate.key || !certificate.domain) {
272
+ throw new Error("Certificate requires both key and domain properties");
273
+ }
274
+
275
+ const certificateBody = createResourceBody(
276
+ tenant,
277
+ certificate,
278
+ "certificate",
279
+ {
280
+ certificate: {
281
+ cert: certificate.value,
282
+ key: certificate.key,
283
+ domain: certificate.domain,
284
+ },
285
+ }
286
+ );
287
+
288
+ const response = await makeGlobalWebSocketRequest(
289
+ "resource:create_resource",
290
+ certificateBody,
291
+ 30000,
292
+ "CREATE",
293
+ certificate.name
294
+ );
295
+
296
+ eventHelper.resource.publish.created(certificate);
297
+ const resourceNotification: Notification = {
298
+ type: "success",
299
+ subtype: "resource-created",
300
+ date: Date.now().toString(),
301
+ status: "unread",
302
+ callToAction: false,
303
+ data: {
304
+ resource: certificate.name,
305
+ tenant: tenant
306
+ }
307
+ };
308
+ eventHelper.notification.publish.creation(resourceNotification);
309
+ return response;
310
+ } catch (error) {
311
+ console.error("Error creating certificate:", {
312
+ error,
313
+ tenant,
314
+ certificate,
315
+ webSocketStatus: getWebSocketStatus(),
316
+ });
317
+ let contentMessage = "Unknown error";
318
+ let errorContent = "Unknown error";
319
+
320
+ if (
321
+ typeof error === "object" &&
322
+ error !== null &&
323
+ "error" in error &&
324
+ typeof (error as any).error === "object" &&
325
+ (error as any).error !== null
326
+ ) {
327
+ if ("code" in (error as any).error) {
328
+ contentMessage = (error as any).error.code;
329
+ }
330
+ if ("content" in (error as any).error) {
331
+ errorContent = (error as any).error.content;
332
+ }
333
+ }
334
+ const resourceErrorNotification: Notification = {
335
+ type: "error",
336
+ subtype: "resource-creation-error",
337
+ info_content: {
338
+ code: contentMessage,
339
+ message: errorContent,
340
+ },
341
+ date: Date.now().toString(),
342
+ status: "unread",
343
+ callToAction: false,
344
+ data: {
345
+ resource: certificate.name,
346
+ tenant: tenant
347
+ }
348
+ };
349
+ eventHelper.notification.publish.creation(resourceErrorNotification);
350
+ throw error;
351
+ }
352
+ };
353
+
354
+ export const createSecret = async (
355
+ tenant: string,
356
+ secret: Resource,
357
+ security: string
358
+ ) => {
359
+ try {
360
+ await initializeGlobalWebSocketClient(security);
361
+ const status = getWebSocketStatus();
362
+
363
+ const secretBody = createResourceBody(tenant, secret, "secret", {
364
+ secret: secret.value,
365
+ });
366
+
367
+ const response = await makeGlobalWebSocketRequest(
368
+ "resource:create_resource",
369
+ secretBody,
370
+ 30000,
371
+ "CREATE",
372
+ secret.name
373
+ );
374
+
375
+ eventHelper.resource.publish.created(secret);
376
+ const resourceNotification: Notification = {
377
+ type: "success",
378
+ subtype: "resource-created",
379
+ date: Date.now().toString(),
380
+ status: "unread",
381
+ callToAction: false,
382
+ data: {
383
+ resource: secret.name,
384
+ tenant: tenant
385
+ }
386
+ };
387
+ eventHelper.notification.publish.creation(resourceNotification);
388
+ return response;
389
+ } catch (error) {
390
+ console.error("Error creating secret:", {
391
+ error,
392
+ tenant,
393
+ secret,
394
+ webSocketStatus: getWebSocketStatus(),
395
+ });
396
+ let contentMessage = "Unknown error";
397
+ let errorContent = "Unknown error";
398
+
399
+ if (
400
+ typeof error === "object" &&
401
+ error !== null &&
402
+ "error" in error &&
403
+ typeof (error as any).error === "object" &&
404
+ (error as any).error !== null
405
+ ) {
406
+ if ("code" in (error as any).error) {
407
+ contentMessage = (error as any).error.code;
408
+ }
409
+ if ("content" in (error as any).error) {
410
+ errorContent = (error as any).error.content;
411
+ }
412
+ }
413
+ const resourceErrorNotification: Notification = {
414
+ type: "error",
415
+ subtype: "resource-creation-error",
416
+ info_content: {
417
+ code: contentMessage,
418
+ message: errorContent,
419
+ },
420
+ date: Date.now().toString(),
421
+ status: "unread",
422
+ callToAction: false,
423
+ data: {
424
+ resource: secret.name,
425
+ tenant: tenant
426
+ }
427
+ };
428
+ eventHelper.notification.publish.creation(resourceErrorNotification);
429
+ throw error;
430
+ }
431
+ };
432
+
433
+ export const createVolume = async (
434
+ tenant: string,
435
+ volume: Resource,
436
+ security: string
437
+ ) => {
438
+ try {
439
+ await initializeGlobalWebSocketClient(security);
440
+ const status = getWebSocketStatus();
441
+
442
+ let volumeKind: "persistent" | "nonreplicated" | "shared" = "persistent";
443
+ if (volume.kind === "nonReplicated") {
444
+ volumeKind = "nonreplicated";
445
+ } else if (volume.kind === "volatile") {
446
+ volumeKind = "persistent";
447
+ }
448
+
449
+ const volumeData: any = {
450
+ volume: {
451
+ kind: volumeKind,
452
+ size: Number(volume.value),
453
+ },
454
+ };
455
+
456
+ if (volume.maxItems !== undefined) {
457
+ volumeData.volume.maxitems = volume.maxItems;
458
+ }
459
+
460
+ // if (volumeKind === "persistent") {
461
+ // volumeData.volume.options = {};
462
+ // }
463
+
464
+ const volumeBody = createResourceBody(tenant, volume, "volume", volumeData);
465
+
466
+ const response = await makeGlobalWebSocketRequest(
467
+ "resource:create_resource",
468
+ volumeBody,
469
+ 30000,
470
+ "CREATE",
471
+ volume.name
472
+ );
473
+
474
+ eventHelper.resource.publish.created(volume);
475
+ const resourceNotification: Notification = {
476
+ type: "success",
477
+ subtype: "resource-created",
478
+ date: Date.now().toString(),
479
+ status: "unread",
480
+ callToAction: false,
481
+ data: {
482
+ resource: volume.name,
483
+ tenant: tenant
484
+ }
485
+ };
486
+ eventHelper.notification.publish.creation(resourceNotification);
487
+ return response;
488
+ } catch (error) {
489
+ console.error("Error creating volume:", {
490
+ error,
491
+ tenant,
492
+ volume,
493
+ webSocketStatus: getWebSocketStatus(),
494
+ });
495
+ let contentMessage = "Unknown error";
496
+ let errorContent = "Unknown error";
497
+
498
+ if (
499
+ typeof error === "object" &&
500
+ error !== null &&
501
+ "error" in error &&
502
+ typeof (error as any).error === "object" &&
503
+ (error as any).error !== null
504
+ ) {
505
+ if ("code" in (error as any).error) {
506
+ contentMessage = (error as any).error.code;
507
+ }
508
+ if ("content" in (error as any).error) {
509
+ errorContent = (error as any).error.content;
510
+ }
511
+ }
512
+ const resourceErrorNotification: Notification = {
513
+ type: "error",
514
+ subtype: "resource-creation-error",
515
+ info_content: {
516
+ code: contentMessage,
517
+ message: errorContent,
518
+ },
519
+ date: Date.now().toString(),
520
+ status: "unread",
521
+ callToAction: false,
522
+ data: {
523
+ resource: volume.name,
524
+ tenant: tenant
525
+ }
526
+ };
527
+ eventHelper.notification.publish.creation(resourceErrorNotification);
528
+ throw error;
529
+ }
530
+ };
531
+
532
+ export const createResource = async (
533
+ tenant: string,
534
+ resource: Resource,
535
+ security: string
536
+ ) => {
537
+ switch (resource.type) {
538
+ case "domain":
539
+ return createDomain(tenant, resource, security);
540
+ case "port":
541
+ return createPort(tenant, resource, security);
542
+ case "ca":
543
+ return createCA(tenant, resource, security);
544
+ case "certificate":
545
+ return createCertificate(tenant, resource, security);
546
+ case "secret":
547
+ return createSecret(tenant, resource, security);
548
+ case "volume":
549
+ return createVolume(tenant, resource, security);
550
+ default:
551
+ throw new Error(`Unsupported resource type: ${resource.type}`);
552
+ }
553
+ };
554
+
555
+ const deleteResourceBody = (
556
+ tenant: string,
557
+ resource: Resource,
558
+ kind: string
559
+ ) => ({
560
+ tenant,
561
+ resource: resource.name,
562
+ kind,
563
+ });
564
+
565
+ const deleteResourceBase = async (
566
+ tenant: string,
567
+ resource: Resource,
568
+ kind: string,
569
+ security: string
570
+ ) => {
571
+ try {
572
+ await initializeGlobalWebSocketClient(security);
573
+ const body = deleteResourceBody(tenant, resource, kind);
574
+
575
+ const response = await makeGlobalWebSocketRequest(
576
+ "resource:delete_resource",
577
+ body,
578
+ 30000,
579
+ "DELETE",
580
+ resource.name
581
+ );
582
+
583
+ //eventHelper.resource.publish.deleted(resource);
584
+ const resourceNotification: Notification = {
585
+ type: "success",
586
+ subtype: "resource-deleted",
587
+ date: Date.now().toString(),
588
+ status: "unread",
589
+ callToAction: false,
590
+ data: {
591
+ resource: resource.name,
592
+ type: resource.type,
593
+ tenant: tenant
594
+ }
595
+ };
596
+ eventHelper.notification.publish.creation(resourceNotification);
597
+ return response;
598
+ } catch (error) {
599
+ console.error(`Error deleting ${kind}:`, { error, tenant, resource });
600
+ let contentMessage = "Unknown error";
601
+ let errorContent = "Unknown error";
602
+
603
+ if (
604
+ typeof error === "object" &&
605
+ error !== null &&
606
+ "error" in error &&
607
+ typeof (error as any).error === "object" &&
608
+ (error as any).error !== null
609
+ ) {
610
+ if ("code" in (error as any).error) {
611
+ contentMessage = (error as any).error.code;
612
+ }
613
+ if ("content" in (error as any).error) {
614
+ errorContent = (error as any).error.content;
615
+ }
616
+ }
617
+ const resourceErrorNotification: Notification = {
618
+ type: "error",
619
+ subtype: "resource-deletion-error",
620
+ info_content: {
621
+ code: contentMessage,
622
+ message: errorContent,
623
+ },
624
+ date: Date.now().toString(),
625
+ status: "unread",
626
+ callToAction: false,
627
+ data: {
628
+ resource: resource.name,
629
+ type: resource.type,
630
+ tenant: tenant
631
+ }
632
+ };
633
+ eventHelper.notification.publish.creation(resourceErrorNotification);
634
+ throw error;
635
+ }
636
+ };
637
+
638
+ export const deleteResource = async (
639
+ tenant: string,
640
+ resource: Resource,
641
+ security: string
642
+ ) => {
643
+ const supportedKinds = [
644
+ "domain",
645
+ "port",
646
+ "ca",
647
+ "certificate",
648
+ "secret",
649
+ "volume",
650
+ ];
651
+ if (!supportedKinds.includes(resource.type)) {
652
+ throw new Error(`Unsupported resource type: ${resource.type}`);
653
+ }
654
+
655
+ return deleteResourceBase(tenant, resource, resource.type, security);
656
+ };
657
+
658
+ const updateResourceBase = async (
659
+ tenant: string,
660
+ resource: Resource,
661
+ kind: string,
662
+ data: any,
663
+ security: string
664
+ ) => {
665
+ try {
666
+ await initializeGlobalWebSocketClient(security);
667
+ const body = createResourceBody(tenant, resource, kind, data);
668
+
669
+ const response = await makeGlobalWebSocketRequest(
670
+ "resource:update_resource",
671
+ body,
672
+ 30000,
673
+ "UPDATE",
674
+ resource.name
675
+ );
676
+
677
+ // eventHelper.resource.publish.updated(resource);
678
+ const resourceNotification: Notification = {
679
+ type: "success",
680
+ subtype: "resource-updated",
681
+ date: Date.now().toString(),
682
+ status: "unread",
683
+ callToAction: false,
684
+ data: {
685
+ resource: resource.name,
686
+ type: resource.type,
687
+ tenant: tenant
688
+ }
689
+ };
690
+ eventHelper.notification.publish.creation(resourceNotification);
691
+ return response;
692
+ } catch (error) {
693
+ console.error(`Error updating ${kind}:`, { error, tenant, resource });
694
+ let contentMessage = "Unknown error";
695
+ let errorContent = "Unknown error";
696
+
697
+ if (
698
+ typeof error === "object" &&
699
+ error !== null &&
700
+ "error" in error &&
701
+ typeof (error as any).error === "object" &&
702
+ (error as any).error !== null
703
+ ) {
704
+ if ("code" in (error as any).error) {
705
+ contentMessage = (error as any).error.code;
706
+ }
707
+ if ("content" in (error as any).error) {
708
+ errorContent = (error as any).error.content;
709
+ }
710
+ }
711
+ const resourceErrorNotification: Notification = {
712
+ type: "error",
713
+ subtype: "resource-update-error",
714
+ info_content: {
715
+ code: contentMessage,
716
+ message: errorContent,
717
+ },
718
+ date: Date.now().toString(),
719
+ status: "unread",
720
+ callToAction: false,
721
+ data: {
722
+ resource: resource.name,
723
+ type: resource.type,
724
+ tenant: tenant
725
+ }
726
+ };
727
+ eventHelper.notification.publish.creation(resourceErrorNotification);
728
+ throw error;
729
+ }
730
+ };
731
+
732
+ export const updateResource = async (
733
+ tenant: string,
734
+ resource: Resource,
735
+ security: string
736
+ ) => {
737
+ switch (resource.type) {
738
+ case "domain":
739
+ return updateResourceBase(
740
+ tenant,
741
+ resource,
742
+ "domain",
743
+ { domain: resource.value },
744
+ security
745
+ );
746
+ case "port":
747
+ return updateResourceBase(
748
+ tenant,
749
+ resource,
750
+ "port",
751
+ { port: Number(resource.value) },
752
+ security
753
+ );
754
+ case "ca":
755
+ return updateResourceBase(
756
+ tenant,
757
+ resource,
758
+ "ca",
759
+ { ca: resource.value },
760
+ security
761
+ );
762
+ case "certificate":
763
+ if (!resource.key || !resource.domain) {
764
+ throw new Error("Certificate requires both key and domain");
765
+ }
766
+ return updateResourceBase(
767
+ tenant,
768
+ resource,
769
+ "certificate",
770
+ {
771
+ certificate: {
772
+ cert: resource.value,
773
+ key: resource.key,
774
+ domain: resource.domain,
775
+ },
776
+ },
777
+ security
778
+ );
779
+ case "secret":
780
+ return updateResourceBase(
781
+ tenant,
782
+ resource,
783
+ "secret",
784
+ { secret: resource.value },
785
+ security
786
+ );
787
+ case "volume":
788
+ let volumeKind: "persistent" | "nonreplicated" | "shared" = "persistent";
789
+ if (resource.kind === "nonReplicated") {
790
+ volumeKind = "nonreplicated";
791
+ } else if (resource.kind === "volatile") {
792
+ volumeKind = "shared";
793
+ }
794
+
795
+ const volumeData: any = {
796
+ volume: {
797
+ kind: volumeKind,
798
+ size: Number(resource.value),
799
+ },
800
+ };
801
+
802
+ if (resource.maxItems !== undefined) {
803
+ volumeData.volume.maxitems = resource.maxItems;
804
+ }
805
+
806
+ if (volumeKind === "shared") {
807
+ volumeData.volume.options = {};
808
+ }
809
+
810
+ return updateResourceBase(
811
+ tenant,
812
+ resource,
813
+ "volume",
814
+ volumeData,
815
+ security
816
+ );
817
+
818
+ default:
819
+ throw new Error(`Unsupported resource type: ${resource.type}`);
820
+ }
821
+ };