@serve.zone/appstore 0.3.1 → 1.1.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.
Files changed (30) hide show
  1. package/apps/adminer/versions/1.0.0/config.json +3 -1
  2. package/apps/cloudly/versions/1.0.0/config.json +3 -1
  3. package/apps/ghost/versions/1.0.0/config.json +3 -1
  4. package/apps/gitea/versions/1.0.0/config.json +3 -1
  5. package/apps/gitops/versions/1.0.0/config.json +3 -1
  6. package/apps/grafana/versions/1.0.0/config.json +3 -1
  7. package/apps/mariadb/versions/1.0.0/config.json +3 -1
  8. package/apps/mattermost/versions/1.0.0/config.json +3 -1
  9. package/apps/n8n/versions/1.0.0/config.json +3 -1
  10. package/apps/nextcloud/versions/1.0.0/config.json +3 -1
  11. package/apps/nginx/versions/1.0.0/config.json +3 -1
  12. package/apps/openbao/app.json +16 -0
  13. package/apps/openbao/versions/1.0.0/config.json +54 -0
  14. package/apps/plausible/versions/1.0.0/config.json +3 -1
  15. package/apps/portainer/versions/1.0.0/config.json +3 -1
  16. package/apps/postgres/versions/1.0.0/config.json +3 -1
  17. package/apps/rustdesk-server/versions/1.0.0/config.json +3 -1
  18. package/apps/siprouter/versions/1.0.0/config.json +14 -8
  19. package/apps/uptime-kuma/versions/1.0.0/config.json +3 -1
  20. package/apps/valkey/versions/1.0.0/config.json +3 -1
  21. package/apps/vaultwarden/versions/1.0.0/config.json +3 -1
  22. package/apps/wordpress/versions/1.0.0/config.json +3 -1
  23. package/appstore.json +10 -1
  24. package/changelog.md +19 -0
  25. package/dist_ts_client/classes.appstoreresolver.d.ts +2 -1
  26. package/dist_ts_client/classes.appstoreresolver.js +59 -3
  27. package/dist_ts_client/data.generated.js +299 -45
  28. package/package.json +3 -3
  29. package/ts_client/classes.appstoreresolver.ts +70 -3
  30. package/ts_client/data.generated.ts +298 -44
@@ -1,4 +1,4 @@
1
- import type * as interfaces from '@serve.zone/interfaces';
1
+ import * as interfaces from '@serve.zone/interfaces';
2
2
  import packageJson from '../package.json' with { type: 'json' };
3
3
  import { appStorePackageData } from './data.generated.js';
4
4
  import type {
@@ -213,18 +213,60 @@ export class AppStoreResolver {
213
213
  if (!configArg.image || typeof configArg.image !== 'string') {
214
214
  throw new Error(`Invalid ${labelArg}: image is required`);
215
215
  }
216
- this.assertValidPort(configArg.port, `${labelArg} port`);
216
+ if (configArg.port !== undefined) {
217
+ this.assertValidPort(configArg.port, `${labelArg} port`);
218
+ }
219
+ this.validateTargetPortModel(configArg, labelArg);
220
+ const containerArgErrors = interfaces.data.validateServiceContainerArgs(configArg.containerArgs);
221
+ if (containerArgErrors.length > 0) {
222
+ throw new Error(`Invalid ${labelArg}: ${containerArgErrors.join('; ')}`);
223
+ }
217
224
 
225
+ const envVarKeys = new Set<string>();
226
+ const secretEnvVarKeys = new Set<string>();
218
227
  for (const envVar of configArg.envVars || []) {
219
228
  if (!envVar.key || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(envVar.key)) {
220
229
  throw new Error(`Invalid ${labelArg}: env var key '${envVar.key}' is not valid`);
221
230
  }
231
+ if (envVarKeys.has(envVar.key)) {
232
+ throw new Error(`Invalid ${labelArg}: env var key '${envVar.key}' is duplicated`);
233
+ }
234
+ envVarKeys.add(envVar.key);
222
235
  if (envVar.value !== undefined && typeof envVar.value !== 'string') {
223
236
  throw new Error(`Invalid ${labelArg}: env var '${envVar.key}' value must be a string`);
224
237
  }
238
+ if (envVar.secret) {
239
+ secretEnvVarKeys.add(envVar.key);
240
+ if (envVar.value !== undefined) {
241
+ throw new Error(`Invalid ${labelArg}: secret '${envVar.key}' must not define a template value`);
242
+ }
243
+ }
244
+ if (envVar.generate) {
245
+ if (!envVar.secret
246
+ || envVar.generate.type !== 'randomHex'
247
+ || !Number.isInteger(envVar.generate.bytes)
248
+ || envVar.generate.bytes < 16
249
+ || envVar.generate.bytes > 64) {
250
+ throw new Error(`Invalid ${labelArg}: secret generator '${envVar.key}' is invalid`);
251
+ }
252
+ }
225
253
  }
226
254
 
227
- this.normalizeVolumes(configArg.volumes);
255
+ const normalizedVolumes = this.normalizeVolumes(configArg.volumes);
256
+ const secretFileErrors = interfaces.data.validateServiceSecretFiles(
257
+ configArg.secretFiles,
258
+ normalizedVolumes.map((volumeArg) => volumeArg.mountPath),
259
+ );
260
+ if (secretFileErrors.length > 0) {
261
+ throw new Error(`Invalid ${labelArg}: ${secretFileErrors.join('; ')}`);
262
+ }
263
+ for (const secretFile of configArg.secretFiles || []) {
264
+ if (!secretEnvVarKeys.has(secretFile.sourceKey)) {
265
+ throw new Error(
266
+ `Invalid ${labelArg}: secret file source '${secretFile.sourceKey}' must reference a declared secret input`,
267
+ );
268
+ }
269
+ }
228
270
  this.validatePublishedPorts(configArg.publishedPorts || [], labelArg);
229
271
  }
230
272
 
@@ -579,6 +621,31 @@ export class AppStoreResolver {
579
621
  }
580
622
  }
581
623
 
624
+ private validateTargetPortModel(
625
+ configArg: TAppStoreVersionConfig,
626
+ labelArg: string,
627
+ ): void {
628
+ const config = configArg as TAppStoreVersionConfig & {
629
+ targetPorts?: any[];
630
+ domains?: any[];
631
+ publicPortMappings?: any[];
632
+ };
633
+ if (config.port === undefined && (!config.targetPorts || config.targetPorts.length === 0)) {
634
+ throw new Error(`Invalid ${labelArg}: either port or targetPorts is required`);
635
+ }
636
+ try {
637
+ (interfaces.data as any).normalizeServicePortConfig({
638
+ name: labelArg,
639
+ ports: config.port !== undefined ? { web: config.port } : undefined,
640
+ targetPorts: config.targetPorts,
641
+ domains: config.domains,
642
+ publicPortMappings: config.publicPortMappings,
643
+ });
644
+ } catch (error) {
645
+ throw new Error(`Invalid ${labelArg}: ${(error as Error).message}`);
646
+ }
647
+ }
648
+
582
649
  private assertValidPort(portArg: number, labelArg: string): void {
583
650
  if (!Number.isInteger(portArg) || portArg < 1 || portArg > 65535) {
584
651
  throw new Error(`Invalid ${labelArg}: ${portArg}. Expected an integer port between 1 and 65535.`);
@@ -19,7 +19,14 @@ export const appStorePackageData: IAppStorePackageData = {
19
19
  },
20
20
  "apps/adminer/versions/1.0.0/config.json": {
21
21
  "image": "adminer:latest",
22
- "port": 8080
22
+ "targetPorts": [
23
+ {
24
+ "name": "web",
25
+ "port": 8080,
26
+ "protocol": "http",
27
+ "default": true
28
+ }
29
+ ]
23
30
  },
24
31
  "apps/cloudly/app.json": {
25
32
  "id": "cloudly",
@@ -39,7 +46,14 @@ export const appStorePackageData: IAppStorePackageData = {
39
46
  },
40
47
  "apps/cloudly/versions/1.0.0/config.json": {
41
48
  "image": "code.foss.global/serve.zone/cloudly:latest",
42
- "port": 3000,
49
+ "targetPorts": [
50
+ {
51
+ "name": "web",
52
+ "port": 3000,
53
+ "protocol": "http",
54
+ "default": true
55
+ }
56
+ ],
43
57
  "envVars": [
44
58
  {
45
59
  "key": "SERVEZONE_ENVIRONMENT",
@@ -146,7 +160,14 @@ export const appStorePackageData: IAppStorePackageData = {
146
160
  },
147
161
  "apps/ghost/versions/1.0.0/config.json": {
148
162
  "image": "ghost:latest",
149
- "port": 2368,
163
+ "targetPorts": [
164
+ {
165
+ "name": "web",
166
+ "port": 2368,
167
+ "protocol": "http",
168
+ "default": true
169
+ }
170
+ ],
150
171
  "envVars": [
151
172
  {
152
173
  "key": "database__client",
@@ -202,7 +223,14 @@ export const appStorePackageData: IAppStorePackageData = {
202
223
  },
203
224
  "apps/gitea/versions/1.0.0/config.json": {
204
225
  "image": "gitea/gitea:latest",
205
- "port": 3000,
226
+ "targetPorts": [
227
+ {
228
+ "name": "web",
229
+ "port": 3000,
230
+ "protocol": "http",
231
+ "default": true
232
+ }
233
+ ],
206
234
  "envVars": [
207
235
  {
208
236
  "key": "GITEA__database__DB_TYPE",
@@ -252,7 +280,14 @@ export const appStorePackageData: IAppStorePackageData = {
252
280
  },
253
281
  "apps/gitops/versions/1.0.0/config.json": {
254
282
  "image": "code.foss.global/serve.zone/gitops:2.13.0",
255
- "port": 3000,
283
+ "targetPorts": [
284
+ {
285
+ "name": "web",
286
+ "port": 3000,
287
+ "protocol": "http",
288
+ "default": true
289
+ }
290
+ ],
256
291
  "envVars": [
257
292
  {
258
293
  "key": "GITOPS_PORT",
@@ -292,7 +327,14 @@ export const appStorePackageData: IAppStorePackageData = {
292
327
  },
293
328
  "apps/grafana/versions/1.0.0/config.json": {
294
329
  "image": "grafana/grafana:latest",
295
- "port": 3000,
330
+ "targetPorts": [
331
+ {
332
+ "name": "web",
333
+ "port": 3000,
334
+ "protocol": "http",
335
+ "default": true
336
+ }
337
+ ],
296
338
  "envVars": [
297
339
  {
298
340
  "key": "GF_SECURITY_ADMIN_PASSWORD",
@@ -316,7 +358,14 @@ export const appStorePackageData: IAppStorePackageData = {
316
358
  },
317
359
  "apps/mariadb/versions/1.0.0/config.json": {
318
360
  "image": "mariadb:latest",
319
- "port": 3306,
361
+ "targetPorts": [
362
+ {
363
+ "name": "db",
364
+ "port": 3306,
365
+ "protocol": "tcp",
366
+ "default": true
367
+ }
368
+ ],
320
369
  "envVars": [
321
370
  {
322
371
  "key": "MARIADB_ROOT_PASSWORD",
@@ -340,7 +389,14 @@ export const appStorePackageData: IAppStorePackageData = {
340
389
  },
341
390
  "apps/mattermost/versions/1.0.0/config.json": {
342
391
  "image": "mattermost/mattermost-team-edition:latest",
343
- "port": 8065
392
+ "targetPorts": [
393
+ {
394
+ "name": "web",
395
+ "port": 8065,
396
+ "protocol": "http",
397
+ "default": true
398
+ }
399
+ ]
344
400
  },
345
401
  "apps/n8n/app.json": {
346
402
  "id": "n8n",
@@ -356,7 +412,14 @@ export const appStorePackageData: IAppStorePackageData = {
356
412
  },
357
413
  "apps/n8n/versions/1.0.0/config.json": {
358
414
  "image": "n8nio/n8n:latest",
359
- "port": 5678
415
+ "targetPorts": [
416
+ {
417
+ "name": "web",
418
+ "port": 5678,
419
+ "protocol": "http",
420
+ "default": true
421
+ }
422
+ ]
360
423
  },
361
424
  "apps/nextcloud/app.json": {
362
425
  "id": "nextcloud",
@@ -372,7 +435,14 @@ export const appStorePackageData: IAppStorePackageData = {
372
435
  },
373
436
  "apps/nextcloud/versions/1.0.0/config.json": {
374
437
  "image": "nextcloud:latest",
375
- "port": 80,
438
+ "targetPorts": [
439
+ {
440
+ "name": "web",
441
+ "port": 80,
442
+ "protocol": "http",
443
+ "default": true
444
+ }
445
+ ],
376
446
  "envVars": [
377
447
  {
378
448
  "key": "MYSQL_HOST",
@@ -414,7 +484,84 @@ export const appStorePackageData: IAppStorePackageData = {
414
484
  },
415
485
  "apps/nginx/versions/1.0.0/config.json": {
416
486
  "image": "nginx:alpine",
417
- "port": 80
487
+ "targetPorts": [
488
+ {
489
+ "name": "web",
490
+ "port": 80,
491
+ "protocol": "http",
492
+ "default": true
493
+ }
494
+ ]
495
+ },
496
+ "apps/openbao/app.json": {
497
+ "id": "openbao",
498
+ "name": "OpenBao",
499
+ "description": "Open-source secrets management, encryption, and identity security platform",
500
+ "category": "Security",
501
+ "iconName": "shield",
502
+ "latestVersion": "1.0.0",
503
+ "versions": [
504
+ "1.0.0"
505
+ ],
506
+ "maintainer": "serve.zone",
507
+ "links": {
508
+ "documentation": "https://openbao.org/docs/",
509
+ "source": "https://github.com/openbao/openbao"
510
+ }
511
+ },
512
+ "apps/openbao/versions/1.0.0/config.json": {
513
+ "image": "openbao/openbao:2.6.0",
514
+ "containerArgs": [
515
+ "server"
516
+ ],
517
+ "targetPorts": [
518
+ {
519
+ "name": "web",
520
+ "port": 8200,
521
+ "protocol": "http",
522
+ "default": true
523
+ }
524
+ ],
525
+ "envVars": [
526
+ {
527
+ "key": "BAO_LOCAL_CONFIG",
528
+ "value": "{\"ui\":true,\"disable_mlock\":true,\"api_addr\":\"http://127.0.0.1:8200\",\"cluster_addr\":\"http://127.0.0.1:8201\",\"storage\":{\"raft\":{\"path\":\"/openbao/file\",\"node_id\":\"openbao-1\",\"performance_multiplier\":1}},\"listener\":[{\"tcp\":{\"address\":\"0.0.0.0:8200\",\"cluster_address\":\"0.0.0.0:8201\",\"tls_disable\":true}}],\"seal\":{\"static\":{\"current_key_id\":\"cloudly-v1\",\"current_key\":\"file:///run/secrets/openbao-static-seal-key\"}}}",
529
+ "description": "OpenBao server configuration for single-node Raft storage and static auto-unseal.",
530
+ "required": true
531
+ },
532
+ {
533
+ "key": "BAO_STATIC_SEAL_KEY",
534
+ "description": "Cloudly generates 32 random bytes and stores them only in this service's secret bundle.",
535
+ "required": true,
536
+ "secret": true,
537
+ "generate": {
538
+ "type": "randomHex",
539
+ "bytes": 32
540
+ }
541
+ }
542
+ ],
543
+ "secretFiles": [
544
+ {
545
+ "sourceKey": "BAO_STATIC_SEAL_KEY",
546
+ "targetPath": "/run/secrets/openbao-static-seal-key",
547
+ "uid": 100,
548
+ "gid": 1000,
549
+ "mode": 256
550
+ }
551
+ ],
552
+ "volumes": [
553
+ {
554
+ "name": "openbao-data",
555
+ "mountPath": "/openbao/file",
556
+ "backup": true
557
+ }
558
+ ],
559
+ "minCloudlyVersion": "13.4.0",
560
+ "healthCheck": {
561
+ "path": "/v1/sys/health?standbyok=true&sealedcode=200&uninitcode=200",
562
+ "port": 8200,
563
+ "expectedStatus": 200
564
+ }
418
565
  },
419
566
  "apps/plausible/app.json": {
420
567
  "id": "plausible",
@@ -430,7 +577,14 @@ export const appStorePackageData: IAppStorePackageData = {
430
577
  },
431
578
  "apps/plausible/versions/1.0.0/config.json": {
432
579
  "image": "plausible/analytics:latest",
433
- "port": 8000,
580
+ "targetPorts": [
581
+ {
582
+ "name": "web",
583
+ "port": 8000,
584
+ "protocol": "http",
585
+ "default": true
586
+ }
587
+ ],
434
588
  "platformRequirements": {
435
589
  "clickhouse": true
436
590
  }
@@ -449,7 +603,14 @@ export const appStorePackageData: IAppStorePackageData = {
449
603
  },
450
604
  "apps/portainer/versions/1.0.0/config.json": {
451
605
  "image": "portainer/portainer-ce:latest",
452
- "port": 9000
606
+ "targetPorts": [
607
+ {
608
+ "name": "web",
609
+ "port": 9000,
610
+ "protocol": "http",
611
+ "default": true
612
+ }
613
+ ]
453
614
  },
454
615
  "apps/postgres/app.json": {
455
616
  "id": "postgres",
@@ -465,7 +626,14 @@ export const appStorePackageData: IAppStorePackageData = {
465
626
  },
466
627
  "apps/postgres/versions/1.0.0/config.json": {
467
628
  "image": "postgres:16-alpine",
468
- "port": 5432,
629
+ "targetPorts": [
630
+ {
631
+ "name": "db",
632
+ "port": 5432,
633
+ "protocol": "tcp",
634
+ "default": true
635
+ }
636
+ ],
469
637
  "envVars": [
470
638
  {
471
639
  "key": "POSTGRES_PASSWORD",
@@ -503,7 +671,14 @@ export const appStorePackageData: IAppStorePackageData = {
503
671
  },
504
672
  "apps/rustdesk-server/versions/1.0.0/config.json": {
505
673
  "image": "rustdesk/rustdesk-server-s6:latest",
506
- "port": 21116,
674
+ "targetPorts": [
675
+ {
676
+ "name": "relay",
677
+ "port": 21116,
678
+ "protocol": "tcp",
679
+ "default": true
680
+ }
681
+ ],
507
682
  "envVars": [
508
683
  {
509
684
  "key": "RELAY",
@@ -536,7 +711,40 @@ export const appStorePackageData: IAppStorePackageData = {
536
711
  },
537
712
  "apps/siprouter/versions/1.0.0/config.json": {
538
713
  "image": "code.foss.global/serve.zone/siprouter:1.28.0",
539
- "port": 3060,
714
+ "targetPorts": [
715
+ {
716
+ "name": "web",
717
+ "port": 3060,
718
+ "protocol": "http",
719
+ "default": true
720
+ },
721
+ {
722
+ "name": "sip-udp",
723
+ "port": 5070,
724
+ "protocol": "udp"
725
+ },
726
+ {
727
+ "name": "sip-tcp",
728
+ "port": 5070,
729
+ "protocol": "tcp"
730
+ },
731
+ {
732
+ "name": "sips-udp",
733
+ "port": 5061,
734
+ "protocol": "udp"
735
+ },
736
+ {
737
+ "name": "sips-tcp",
738
+ "port": 5061,
739
+ "protocol": "tcp"
740
+ },
741
+ {
742
+ "name": "rtp",
743
+ "port": 20000,
744
+ "portEnd": 20200,
745
+ "protocol": "udp"
746
+ }
747
+ ],
540
748
  "envVars": [
541
749
  {
542
750
  "key": "SIPROUTER_LAN_IP",
@@ -598,38 +806,42 @@ export const appStorePackageData: IAppStorePackageData = {
598
806
  "required": true
599
807
  }
600
808
  ],
601
- "publishedPorts": [
809
+ "publicPortMappings": [
602
810
  {
603
- "targetPort": 3060,
604
- "publishedPort": 3060,
605
- "protocol": "tcp"
811
+ "name": "sip-udp",
812
+ "publicPort": 5070,
813
+ "targetPort": "sip-udp",
814
+ "protocol": "udp",
815
+ "exclusive": true
606
816
  },
607
817
  {
608
- "targetPort": 5070,
609
- "publishedPort": 5070,
610
- "protocol": "udp"
818
+ "name": "sip-tcp",
819
+ "publicPort": 5070,
820
+ "targetPort": "sip-tcp",
821
+ "protocol": "tcp",
822
+ "exclusive": true
611
823
  },
612
824
  {
613
- "targetPort": 5070,
614
- "publishedPort": 5070,
615
- "protocol": "tcp"
825
+ "name": "sips-udp",
826
+ "publicPort": 5061,
827
+ "targetPort": "sips-udp",
828
+ "protocol": "udp",
829
+ "exclusive": true
616
830
  },
617
831
  {
618
- "targetPort": 5061,
619
- "publishedPort": 5061,
620
- "protocol": "udp"
832
+ "name": "sips-tcp",
833
+ "publicPort": 5061,
834
+ "targetPort": "sips-tcp",
835
+ "protocol": "tcp",
836
+ "exclusive": true
621
837
  },
622
838
  {
623
- "targetPort": 5061,
624
- "publishedPort": 5061,
625
- "protocol": "tcp"
626
- },
627
- {
628
- "targetPort": 20000,
629
- "targetPortEnd": 20200,
630
- "publishedPort": 20000,
631
- "publishedPortEnd": 20200,
632
- "protocol": "udp"
839
+ "name": "rtp",
840
+ "publicPort": 20000,
841
+ "publicPortEnd": 20200,
842
+ "targetPort": "rtp",
843
+ "protocol": "udp",
844
+ "exclusive": true
633
845
  }
634
846
  ],
635
847
  "platformRequirements": {
@@ -652,7 +864,14 @@ export const appStorePackageData: IAppStorePackageData = {
652
864
  },
653
865
  "apps/uptime-kuma/versions/1.0.0/config.json": {
654
866
  "image": "louislam/uptime-kuma:latest",
655
- "port": 3001
867
+ "targetPorts": [
868
+ {
869
+ "name": "web",
870
+ "port": 3001,
871
+ "protocol": "http",
872
+ "default": true
873
+ }
874
+ ]
656
875
  },
657
876
  "apps/valkey/app.json": {
658
877
  "id": "valkey",
@@ -668,7 +887,14 @@ export const appStorePackageData: IAppStorePackageData = {
668
887
  },
669
888
  "apps/valkey/versions/1.0.0/config.json": {
670
889
  "image": "valkey/valkey:9.1.0-alpine",
671
- "port": 6379
890
+ "targetPorts": [
891
+ {
892
+ "name": "cache",
893
+ "port": 6379,
894
+ "protocol": "tcp",
895
+ "default": true
896
+ }
897
+ ]
672
898
  },
673
899
  "apps/vaultwarden/app.json": {
674
900
  "id": "vaultwarden",
@@ -684,7 +910,14 @@ export const appStorePackageData: IAppStorePackageData = {
684
910
  },
685
911
  "apps/vaultwarden/versions/1.0.0/config.json": {
686
912
  "image": "vaultwarden/server:latest",
687
- "port": 80
913
+ "targetPorts": [
914
+ {
915
+ "name": "web",
916
+ "port": 80,
917
+ "protocol": "http",
918
+ "default": true
919
+ }
920
+ ]
688
921
  },
689
922
  "apps/wordpress/app.json": {
690
923
  "id": "wordpress",
@@ -700,7 +933,14 @@ export const appStorePackageData: IAppStorePackageData = {
700
933
  },
701
934
  "apps/wordpress/versions/1.0.0/config.json": {
702
935
  "image": "wordpress:latest",
703
- "port": 80,
936
+ "targetPorts": [
937
+ {
938
+ "name": "web",
939
+ "port": 80,
940
+ "protocol": "http",
941
+ "default": true
942
+ }
943
+ ],
704
944
  "envVars": [
705
945
  {
706
946
  "key": "WORDPRESS_DB_HOST",
@@ -729,7 +969,7 @@ export const appStorePackageData: IAppStorePackageData = {
729
969
  },
730
970
  "appstore.json": {
731
971
  "schemaVersion": 1,
732
- "updatedAt": "2026-06-07T00:00:00Z",
972
+ "updatedAt": "2026-07-21T00:00:00Z",
733
973
  "apps": [
734
974
  {
735
975
  "id": "nginx",
@@ -853,6 +1093,20 @@ export const appStorePackageData: IAppStorePackageData = {
853
1093
  "passwords"
854
1094
  ]
855
1095
  },
1096
+ {
1097
+ "id": "openbao",
1098
+ "name": "OpenBao",
1099
+ "description": "Open-source secrets management, encryption, and identity security platform.",
1100
+ "category": "Security",
1101
+ "iconName": "shield",
1102
+ "latestVersion": "1.0.0",
1103
+ "tags": [
1104
+ "security",
1105
+ "secrets",
1106
+ "encryption",
1107
+ "identity"
1108
+ ]
1109
+ },
856
1110
  {
857
1111
  "id": "n8n",
858
1112
  "name": "N8N",