@env-hopper/backend-core 2.0.1-alpha

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/dist/esm/__tests__/dummy.test.d.ts +1 -0
  3. package/dist/esm/index.d.ts +7 -0
  4. package/dist/esm/index.js +9 -0
  5. package/dist/esm/index.js.map +1 -0
  6. package/dist/esm/server/controller.d.ts +32 -0
  7. package/dist/esm/server/controller.js +35 -0
  8. package/dist/esm/server/controller.js.map +1 -0
  9. package/dist/esm/server/db.d.ts +2 -0
  10. package/dist/esm/server/ehStaticControllerContract.d.ts +9 -0
  11. package/dist/esm/server/ehStaticControllerContract.js +12 -0
  12. package/dist/esm/server/ehStaticControllerContract.js.map +1 -0
  13. package/dist/esm/server/ehTrpcContext.d.ts +8 -0
  14. package/dist/esm/server/ehTrpcContext.js +11 -0
  15. package/dist/esm/server/ehTrpcContext.js.map +1 -0
  16. package/dist/esm/types/backend/api.d.ts +71 -0
  17. package/dist/esm/types/backend/common.d.ts +9 -0
  18. package/dist/esm/types/backend/dataSources.d.ts +20 -0
  19. package/dist/esm/types/backend/deployments.d.ts +34 -0
  20. package/dist/esm/types/common/app/appTypes.d.ts +12 -0
  21. package/dist/esm/types/common/app/ui/appUiTypes.d.ts +10 -0
  22. package/dist/esm/types/common/appCatalogTypes.d.ts +16 -0
  23. package/dist/esm/types/common/dataRootTypes.d.ts +32 -0
  24. package/dist/esm/types/common/env/envTypes.d.ts +6 -0
  25. package/dist/esm/types/common/resourceTypes.d.ts +8 -0
  26. package/dist/esm/types/common/sharedTypes.d.ts +4 -0
  27. package/dist/esm/types/index.d.ts +11 -0
  28. package/package.json +69 -0
  29. package/src/__tests__/dummy.test.ts +7 -0
  30. package/src/index.ts +18 -0
  31. package/src/server/controller.ts +54 -0
  32. package/src/server/db.ts +4 -0
  33. package/src/server/ehStaticControllerContract.ts +12 -0
  34. package/src/server/ehTrpcContext.ts +23 -0
  35. package/src/types/backend/api.ts +97 -0
  36. package/src/types/backend/common.ts +10 -0
  37. package/src/types/backend/dataSources.ts +25 -0
  38. package/src/types/backend/deployments.ts +40 -0
  39. package/src/types/common/app/appTypes.ts +13 -0
  40. package/src/types/common/app/ui/appUiTypes.ts +12 -0
  41. package/src/types/common/appCatalogTypes.ts +19 -0
  42. package/src/types/common/dataRootTypes.ts +38 -0
  43. package/src/types/common/env/envTypes.ts +7 -0
  44. package/src/types/common/resourceTypes.ts +8 -0
  45. package/src/types/common/sharedTypes.ts +5 -0
  46. package/src/types/index.ts +19 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Igor Golovin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export { trpcRouter } from './server/controller.js';
2
+ export type { TRPCRouter } from './server/controller.js';
3
+ export { createEhTrpcContext } from './server/ehTrpcContext.js';
4
+ export type { EhTrpcContext, EhTrpcContextOptions, } from './server/ehTrpcContext.js';
5
+ export { staticControllerContract } from './server/ehStaticControllerContract.js';
6
+ export type { EhStaticControllerContract } from './server/ehStaticControllerContract.js';
7
+ export * from './types/index.js';
@@ -0,0 +1,9 @@
1
+ import { trpcRouter } from "./server/controller.js";
2
+ import { createEhTrpcContext } from "./server/ehTrpcContext.js";
3
+ import { staticControllerContract } from "./server/ehStaticControllerContract.js";
4
+ export {
5
+ createEhTrpcContext,
6
+ staticControllerContract,
7
+ trpcRouter
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -0,0 +1,32 @@
1
+ import { EhTrpcContext } from './ehTrpcContext.js';
2
+ export declare const trpcRouter: import('@trpc/server').TRPCBuiltRouter<{
3
+ ctx: EhTrpcContext;
4
+ meta: {};
5
+ errorShape: import('@trpc/server').TRPCDefaultErrorShape;
6
+ transformer: false;
7
+ }, import('@trpc/server').TRPCDecorateCreateRouterOptions<{
8
+ bootstrap: import('@trpc/server').TRPCQueryProcedure<{
9
+ input: void;
10
+ output: import('..').BootstrapConfigData;
11
+ meta: {};
12
+ }>;
13
+ availabilityMatrix: import('@trpc/server').TRPCQueryProcedure<{
14
+ input: void;
15
+ output: import('..').AvailiabilityMatrixData;
16
+ meta: {};
17
+ }>;
18
+ tryFindRenameRule: import('@trpc/server').TRPCQueryProcedure<{
19
+ input: {
20
+ envSlug?: string | undefined;
21
+ resourceSlug?: string | undefined;
22
+ };
23
+ output: false | import('..').RenameRule;
24
+ meta: {};
25
+ }>;
26
+ resourceJumps: import('@trpc/server').TRPCQueryProcedure<{
27
+ input: void;
28
+ output: import('..').ResourceJumpsData;
29
+ meta: {};
30
+ }>;
31
+ }>>;
32
+ export type TRPCRouter = typeof trpcRouter;
@@ -0,0 +1,35 @@
1
+ import { initTRPC } from "@trpc/server";
2
+ import z from "zod";
3
+ const t = initTRPC.context().create();
4
+ const router = t.router;
5
+ const publicProcedure = t.procedure;
6
+ const trpcRouter = router({
7
+ bootstrap: publicProcedure.query(async ({ ctx }) => {
8
+ return await ctx.companySpecificBackend.getBootstrapData();
9
+ }),
10
+ availabilityMatrix: publicProcedure.query(async ({ ctx }) => {
11
+ return await ctx.companySpecificBackend.getAvailabilityMatrix();
12
+ }),
13
+ tryFindRenameRule: publicProcedure.input(
14
+ z.object({
15
+ envSlug: z.string().optional(),
16
+ resourceSlug: z.string().optional()
17
+ })
18
+ ).query(async ({ input, ctx }) => {
19
+ return await ctx.companySpecificBackend.getNameMigrations(input);
20
+ }),
21
+ resourceJumps: publicProcedure.query(async ({ ctx }) => {
22
+ return await ctx.companySpecificBackend.getResourceJumps();
23
+ })
24
+ // specificEnvs: publicProcedure
25
+ // .query(async ({ctx}) => {
26
+ // return await ctx.companySpecificBackend.getDeployments({
27
+ // envNames: ['dev', 'prod'],
28
+ // appNames: ['app1', 'app2'],
29
+ // })
30
+ // }),
31
+ });
32
+ export {
33
+ trpcRouter
34
+ };
35
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sources":["../../../src/server/controller.ts"],"sourcesContent":["import { initTRPC } from '@trpc/server'\nimport z from 'zod'\nimport type { EhTrpcContext } from './ehTrpcContext'\nimport type { TRPCRootObject } from '@trpc/server'\n\n/**\n * Initialization of tRPC backend\n * Should be done only once per backend!\n */\nconst t: TRPCRootObject<EhTrpcContext, {}, {}> = initTRPC\n .context<EhTrpcContext>()\n .create()\n\n/**\n * Export reusable router and procedure helpers\n * that can be used throughout the router\n */\nconst router: typeof t.router = t.router\nconst publicProcedure: typeof t.procedure = t.procedure\n\nexport const trpcRouter = router({\n bootstrap: publicProcedure.query(async ({ ctx }) => {\n return await ctx.companySpecificBackend.getBootstrapData()\n }),\n\n availabilityMatrix: publicProcedure.query(async ({ ctx }) => {\n return await ctx.companySpecificBackend.getAvailabilityMatrix()\n }),\n\n tryFindRenameRule: publicProcedure\n .input(\n z.object({\n envSlug: z.string().optional(),\n resourceSlug: z.string().optional(),\n }),\n )\n .query(async ({ input, ctx }) => {\n return await ctx.companySpecificBackend.getNameMigrations(input)\n }),\n\n resourceJumps: publicProcedure.query(async ({ ctx }) => {\n return await ctx.companySpecificBackend.getResourceJumps()\n }),\n\n // specificEnvs: publicProcedure\n // .query(async ({ctx}) => {\n // return await ctx.companySpecificBackend.getDeployments({\n // envNames: ['dev', 'prod'],\n // appNames: ['app1', 'app2'],\n // })\n // }),\n})\n\nexport type TRPCRouter = typeof trpcRouter\n"],"names":[],"mappings":";;AASA,MAAM,IAA2C,SAC9C,QAAA,EACA,OAAA;AAMH,MAAM,SAA0B,EAAE;AAClC,MAAM,kBAAsC,EAAE;AAEvC,MAAM,aAAa,OAAO;AAAA,EAC/B,WAAW,gBAAgB,MAAM,OAAO,EAAE,UAAU;AAClD,WAAO,MAAM,IAAI,uBAAuB,iBAAA;AAAA,EAC1C,CAAC;AAAA,EAED,oBAAoB,gBAAgB,MAAM,OAAO,EAAE,UAAU;AAC3D,WAAO,MAAM,IAAI,uBAAuB,sBAAA;AAAA,EAC1C,CAAC;AAAA,EAED,mBAAmB,gBAChB;AAAA,IACC,EAAE,OAAO;AAAA,MACP,SAAS,EAAE,OAAA,EAAS,SAAA;AAAA,MACpB,cAAc,EAAE,OAAA,EAAS,SAAA;AAAA,IAAS,CACnC;AAAA,EAAA,EAEF,MAAM,OAAO,EAAE,OAAO,UAAU;AAC/B,WAAO,MAAM,IAAI,uBAAuB,kBAAkB,KAAK;AAAA,EACjE,CAAC;AAAA,EAEH,eAAe,gBAAgB,MAAM,OAAO,EAAE,UAAU;AACtD,WAAO,MAAM,IAAI,uBAAuB,iBAAA;AAAA,EAC1C,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASH,CAAC;"}
@@ -0,0 +1,2 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ export declare const db: PrismaClient<import("@prisma/client").Prisma.PrismaClientOptions, never, import('@prisma/client/runtime/library').DefaultArgs>;
@@ -0,0 +1,9 @@
1
+ export interface EhStaticControllerContract {
2
+ methods: {
3
+ getIcon: {
4
+ method: string;
5
+ url: string;
6
+ };
7
+ };
8
+ }
9
+ export declare const staticControllerContract: EhStaticControllerContract;
@@ -0,0 +1,12 @@
1
+ const staticControllerContract = {
2
+ methods: {
3
+ getIcon: {
4
+ method: "get",
5
+ url: "icon/:icon"
6
+ }
7
+ }
8
+ };
9
+ export {
10
+ staticControllerContract
11
+ };
12
+ //# sourceMappingURL=ehStaticControllerContract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ehStaticControllerContract.js","sources":["../../../src/server/ehStaticControllerContract.ts"],"sourcesContent":["export interface EhStaticControllerContract {\n methods: { getIcon: { method: string; url: string } }\n}\n\nexport const staticControllerContract: EhStaticControllerContract = {\n methods: {\n getIcon: {\n method: 'get',\n url: 'icon/:icon',\n },\n },\n}\n"],"names":[],"mappings":"AAIO,MAAM,2BAAuD;AAAA,EAClE,SAAS;AAAA,IACP,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,KAAK;AAAA,IAAA;AAAA,EACP;AAEJ;"}
@@ -0,0 +1,8 @@
1
+ import { EhBackendCompanySpecificBackend } from '../types.js';
2
+ export interface EhTrpcContext {
3
+ companySpecificBackend: EhBackendCompanySpecificBackend;
4
+ }
5
+ export interface EhTrpcContextOptions {
6
+ companySpecificBackend: EhBackendCompanySpecificBackend;
7
+ }
8
+ export declare function createEhTrpcContext({ companySpecificBackend, }: EhTrpcContextOptions): EhTrpcContext;
@@ -0,0 +1,11 @@
1
+ function createEhTrpcContext({
2
+ companySpecificBackend
3
+ }) {
4
+ return {
5
+ companySpecificBackend
6
+ };
7
+ }
8
+ export {
9
+ createEhTrpcContext
10
+ };
11
+ //# sourceMappingURL=ehTrpcContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ehTrpcContext.js","sources":["../../../src/server/ehTrpcContext.ts"],"sourcesContent":["import type { EhBackendCompanySpecificBackend } from '../types'\n\nexport interface EhTrpcContext {\n companySpecificBackend: EhBackendCompanySpecificBackend\n}\n\nexport interface EhTrpcContextOptions {\n companySpecificBackend: EhBackendCompanySpecificBackend\n}\n\nexport function createEhTrpcContext({\n companySpecificBackend,\n}: EhTrpcContextOptions): EhTrpcContext {\n return {\n companySpecificBackend,\n }\n}\n\n// const createContext = ({\n// req,\n// res\n// }: trpcExpress.CreateExpressContextOptions) => ({}); // no context\n// type Context = Awaited<ReturnType<typeof createContext>>;\n"],"names":[],"mappings":"AAUO,SAAS,oBAAoB;AAAA,EAClC;AACF,GAAwC;AACtC,SAAO;AAAA,IACL;AAAA,EAAA;AAEJ;"}
@@ -0,0 +1,71 @@
1
+ import { AvailiabilityMatrixData, BootstrapConfigData, ResourceJumpsData } from '../common/dataRootTypes.js';
2
+ import { EhAppIndexed } from '../common/app/appTypes.js';
3
+ import { EhAppPageIndexed, EhAppUiIndexed } from '../common/app/ui/appUiTypes.js';
4
+ import { EhBackendCredentialInput, EhBackendUiDefaultsInput } from './common.js';
5
+ import { EhBackendDataSourceInput } from './dataSources.js';
6
+ export interface EhBackendVersionsRequestParams {
7
+ envNames: Array<string>;
8
+ appNames: Array<string>;
9
+ }
10
+ export interface EhBackendVersionsReturn {
11
+ envIds: Array<string>;
12
+ appIds: Array<string>;
13
+ }
14
+ export interface EhBackendPageInput extends EhAppPageIndexed {
15
+ slug: string;
16
+ title?: string;
17
+ url: string;
18
+ credentialsRefs?: Array<string>;
19
+ }
20
+ export interface EhBackendAppUIBaseInput {
21
+ credentials?: Array<EhBackendCredentialInput>;
22
+ defaults?: EhBackendUiDefaultsInput;
23
+ }
24
+ export interface EhBackendAppUIInput extends EhBackendAppUIBaseInput, EhAppUiIndexed {
25
+ pages: Array<EhBackendPageInput>;
26
+ }
27
+ export interface EhBackendTagsDescriptionDataIndexed {
28
+ descriptions: Array<EhBackendTagDescriptionDataIndexed>;
29
+ }
30
+ export interface EhBackendTagDescriptionDataIndexed {
31
+ tagKey: string;
32
+ displayName?: string;
33
+ fixedTagValues?: Array<EhBackendTagFixedTagValue>;
34
+ }
35
+ export interface EhBackendTagFixedTagValue {
36
+ tagValue: string;
37
+ displayName: string;
38
+ }
39
+ export interface EhBackendAppInput extends EhAppIndexed {
40
+ ui?: EhBackendAppUIInput;
41
+ dataSources?: Array<EhBackendDataSourceInput>;
42
+ }
43
+ export interface EhContextIndexed {
44
+ slug: string;
45
+ displayName: string;
46
+ /**
47
+ * The value is shared across envs (By default: false)
48
+ */
49
+ isSharedAcrossEnvs?: boolean;
50
+ defaultFixedValues?: Array<string>;
51
+ }
52
+ export type EhBackendAppDto = EhAppIndexed;
53
+ export interface EhAppsMeta {
54
+ defaultIcon?: string;
55
+ tags: EhBackendTagsDescriptionDataIndexed;
56
+ }
57
+ export interface RenameRuleParams {
58
+ envSlug?: string;
59
+ resourceSlug?: string;
60
+ }
61
+ export interface RenameRule {
62
+ type: 'resourceRename' | 'envRename';
63
+ oldSlug: string;
64
+ targetSlug: string;
65
+ }
66
+ export interface EhBackendCompanySpecificBackend {
67
+ getBootstrapData: () => Promise<BootstrapConfigData>;
68
+ getAvailabilityMatrix: () => Promise<AvailiabilityMatrixData>;
69
+ getNameMigrations: (params: RenameRuleParams) => Promise<RenameRule | false>;
70
+ getResourceJumps: () => Promise<ResourceJumpsData>;
71
+ }
@@ -0,0 +1,9 @@
1
+ export interface EhBackendUiDefaultsInput {
2
+ credentialsRefs: Array<string>;
3
+ }
4
+ export interface EhBackendCredentialInput {
5
+ slug: string;
6
+ desc?: string;
7
+ username: string;
8
+ password: string;
9
+ }
@@ -0,0 +1,20 @@
1
+ import { EhMetaDictionary } from '../common/sharedTypes.js';
2
+ export interface EhBackendDataSourceInputCommon {
3
+ meta?: EhMetaDictionary;
4
+ }
5
+ export interface EhBackendDataSourceInputDb {
6
+ slug?: string;
7
+ type: 'db';
8
+ url: string;
9
+ username: string;
10
+ password: string;
11
+ }
12
+ export interface EhBackendDataSourceInputKafka {
13
+ slug?: string;
14
+ type: 'kafka';
15
+ topics: {
16
+ consumer?: Array<string>;
17
+ producer?: Array<string>;
18
+ };
19
+ }
20
+ export type EhBackendDataSourceInput = EhBackendDataSourceInputCommon & (EhBackendDataSourceInputDb | EhBackendDataSourceInputKafka);
@@ -0,0 +1,34 @@
1
+ import { EhMetaDictionary } from '../common/sharedTypes.js';
2
+ export interface EhBackendEnvironmentInput {
3
+ slug: string;
4
+ displayName?: string;
5
+ description?: string;
6
+ meta?: EhMetaDictionary;
7
+ }
8
+ export interface EhBackendDeploymentInput {
9
+ envId: string;
10
+ appId: string;
11
+ displayVersion: string;
12
+ meta?: EhMetaDictionary;
13
+ }
14
+ export interface EhBackendDeployableInput {
15
+ slug: string;
16
+ meta?: {
17
+ config: string;
18
+ };
19
+ }
20
+ /**
21
+ * Latest - backend returned latest data.
22
+ * Cached - backend in process of updating data, but returned cached data.
23
+ */
24
+ export type EhBackendDataFreshness = 'latest' | 'cached';
25
+ export interface EhBackendDataVersion {
26
+ version: string;
27
+ freshness: EhBackendDataFreshness;
28
+ }
29
+ export interface EhBackendDeployment {
30
+ appName: string;
31
+ deployableServiceName: string;
32
+ envName: string;
33
+ version: EhBackendDataVersion;
34
+ }
@@ -0,0 +1,12 @@
1
+ import { EhMetaDictionary, Tag } from '../sharedTypes.js';
2
+ import { EhAppUiIndexed } from './ui/appUiTypes.js';
3
+ export interface EhAppIndexed {
4
+ slug: string;
5
+ displayName: string;
6
+ abbr?: string;
7
+ aliases?: Array<string>;
8
+ ui?: EhAppUiIndexed;
9
+ tags?: Array<Tag>;
10
+ iconName?: string;
11
+ meta?: EhMetaDictionary;
12
+ }
@@ -0,0 +1,10 @@
1
+ import { Tag } from '../../sharedTypes.js';
2
+ export interface EhAppPageIndexed {
3
+ slug: string;
4
+ displayName: string;
5
+ url: string;
6
+ tags?: Array<Tag>;
7
+ }
8
+ export interface EhAppUiIndexed {
9
+ pages: Array<EhAppPageIndexed>;
10
+ }
@@ -0,0 +1,16 @@
1
+ export interface EhAppCatalogData {
2
+ apps: Array<EhAppCatalogDto>;
3
+ }
4
+ export interface EhAppCatalogDto {
5
+ slug: string;
6
+ groups: Array<EhAppCatalogGroupDto>;
7
+ }
8
+ export interface EhAppCatalogGroupDto {
9
+ slug: string;
10
+ displayName: string;
11
+ pages: Array<EhAppCatalogPageDto>;
12
+ }
13
+ export interface EhAppCatalogPageDto {
14
+ slug: string;
15
+ displayName: string;
16
+ }
@@ -0,0 +1,32 @@
1
+ import { EhAppsMeta, EhContextIndexed } from '../backend/api.js';
2
+ import { EhEnvIndexed } from './env/envTypes.js';
3
+ import { EhAppIndexed } from './app/appTypes.js';
4
+ export type JumpResouceSlug = string;
5
+ export type EnvSlug = string;
6
+ export interface BootstrapConfigData {
7
+ envs: Record<EnvSlug, EhEnvIndexed>;
8
+ apps: Record<string, EhAppIndexed>;
9
+ appsMeta: EhAppsMeta;
10
+ contexts: Array<EhContextIndexed>;
11
+ defaults: {
12
+ envSlug: EnvSlug;
13
+ resourceJumpSlug: JumpResouceSlug;
14
+ };
15
+ }
16
+ export interface AvailiabilityMatrixData {
17
+ envSlugs: Array<EnvSlug>;
18
+ resourceJumpSlugs: Array<JumpResouceSlug>;
19
+ availabilityVariants: Array<AvailabilityVariant>;
20
+ matrix: Array<Array<number>>;
21
+ }
22
+ export interface AvailabilityVariant {
23
+ isDeployed: boolean;
24
+ isHealthy?: boolean;
25
+ hasData?: boolean;
26
+ }
27
+ export interface ResourceJumpsData {
28
+ baseResouceJumpUrls: Record<JumpResouceSlug, string>;
29
+ resourceJumpsData: Record<JumpResouceSlug, Record<string, string>>;
30
+ envData: Record<EnvSlug, Record<string, string>>;
31
+ overrideResoucesJumpsUrls: Record<EnvSlug, Record<JumpResouceSlug, string>>;
32
+ }
@@ -0,0 +1,6 @@
1
+ import { EhMetaDictionary } from '../sharedTypes.js';
2
+ export interface EhEnvIndexed {
3
+ slug: string;
4
+ displayName: string;
5
+ meta?: EhMetaDictionary;
6
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resources like kafka topics, database tables, etc.
3
+ */
4
+ export interface EhResourceIndexed {
5
+ slug: string;
6
+ displayName: string;
7
+ defaultFixedValues?: Array<string>;
8
+ }
@@ -0,0 +1,4 @@
1
+ export interface EhMetaDictionary {
2
+ [key: string]: string | null | Record<string, string | null>;
3
+ }
4
+ export type Tag = string;
@@ -0,0 +1,11 @@
1
+ export * from './common/sharedTypes.js';
2
+ export * from './common/resourceTypes.js';
3
+ export * from './common/dataRootTypes.js';
4
+ export * from './common/appCatalogTypes.js';
5
+ export * from './common/env/envTypes.js';
6
+ export * from './common/app/appTypes.js';
7
+ export * from './common/app/ui/appUiTypes.js';
8
+ export * from './backend/api.js';
9
+ export * from './backend/common.js';
10
+ export * from './backend/dataSources.js';
11
+ export * from './backend/deployments.js';
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@env-hopper/backend-core",
3
+ "version": "2.0.1-alpha",
4
+ "description": "Backend core library for Env Hopper",
5
+ "homepage": "https://github.com/lislon/env-hopper",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/lislon/env-hopper.git",
9
+ "directory": "packages/backend-core"
10
+ },
11
+ "license": "MIT",
12
+ "author": "Igor Golovin",
13
+ "sideEffects": false,
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "my-custom-condition": "./src/index.ts",
18
+ "import": {
19
+ "types": "./dist/esm/index.d.ts",
20
+ "default": "./dist/esm/index.js"
21
+ }
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "module": "dist/esm/index.js",
26
+ "types": "dist/esm/index.d.ts",
27
+ "files": [
28
+ "dist",
29
+ "src"
30
+ ],
31
+ "dependencies": {
32
+ "@kubernetes/client-node": "^1.2.0",
33
+ "@prisma/client": "^6.9.0",
34
+ "@trpc/client": "^11.4.2",
35
+ "@trpc/server": "^11.4.2",
36
+ "cors": "^2.8.5",
37
+ "dotenv-defaults": "5.0.2",
38
+ "express": "^5.1.0",
39
+ "jsonwebtoken": "^9.0.2",
40
+ "reflect-metadata": "^0.2.2",
41
+ "tsyringe": "^4.10.0",
42
+ "yaml": "^2.8.0",
43
+ "zod": "^3.25.49"
44
+ },
45
+ "devDependencies": {
46
+ "@types/cors": "^2.8.18",
47
+ "@types/dotenv-defaults": "^2.0.4",
48
+ "@types/jsonwebtoken": "^9.0.9",
49
+ "@types/node": "^24.3.0",
50
+ "esbuild": "^0.25.5",
51
+ "prisma": "^6.8.2",
52
+ "tsx": "^4.19.4",
53
+ "typescript": "5.8.3",
54
+ "vite-plugin-dts": "^4.5.4"
55
+ },
56
+ "engines": {
57
+ "node": ">=16"
58
+ },
59
+ "scripts": {
60
+ "build": "vite build",
61
+ "clean": "premove ./dist ./coverage ./dist-ts",
62
+ "compile": "tsc --build",
63
+ "dev": "tsx watch src/index.ts",
64
+ "prisma:generate": "prisma generate",
65
+ "test:eslint": "eslint ./src",
66
+ "test:unit": "vitest",
67
+ "test:unit:dev": "pnpm run test:unit --watch"
68
+ }
69
+ }
@@ -0,0 +1,7 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ describe('dummy', () => {
4
+ it('always passes', () => {
5
+ expect(true).toBe(true)
6
+ })
7
+ })
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ // common
2
+
3
+ export { trpcRouter } from './server/controller'
4
+ export type { TRPCRouter } from './server/controller'
5
+ export { createEhTrpcContext } from './server/ehTrpcContext'
6
+ export type {
7
+ EhTrpcContext,
8
+ EhTrpcContextOptions,
9
+ } from './server/ehTrpcContext'
10
+
11
+ export { staticControllerContract } from './server/ehStaticControllerContract'
12
+ export type { EhStaticControllerContract } from './server/ehStaticControllerContract'
13
+
14
+ // ui-only
15
+
16
+ // backend-only
17
+
18
+ export * from './types/index'
@@ -0,0 +1,54 @@
1
+ import { initTRPC } from '@trpc/server'
2
+ import z from 'zod'
3
+ import type { EhTrpcContext } from './ehTrpcContext'
4
+ import type { TRPCRootObject } from '@trpc/server'
5
+
6
+ /**
7
+ * Initialization of tRPC backend
8
+ * Should be done only once per backend!
9
+ */
10
+ const t: TRPCRootObject<EhTrpcContext, {}, {}> = initTRPC
11
+ .context<EhTrpcContext>()
12
+ .create()
13
+
14
+ /**
15
+ * Export reusable router and procedure helpers
16
+ * that can be used throughout the router
17
+ */
18
+ const router: typeof t.router = t.router
19
+ const publicProcedure: typeof t.procedure = t.procedure
20
+
21
+ export const trpcRouter = router({
22
+ bootstrap: publicProcedure.query(async ({ ctx }) => {
23
+ return await ctx.companySpecificBackend.getBootstrapData()
24
+ }),
25
+
26
+ availabilityMatrix: publicProcedure.query(async ({ ctx }) => {
27
+ return await ctx.companySpecificBackend.getAvailabilityMatrix()
28
+ }),
29
+
30
+ tryFindRenameRule: publicProcedure
31
+ .input(
32
+ z.object({
33
+ envSlug: z.string().optional(),
34
+ resourceSlug: z.string().optional(),
35
+ }),
36
+ )
37
+ .query(async ({ input, ctx }) => {
38
+ return await ctx.companySpecificBackend.getNameMigrations(input)
39
+ }),
40
+
41
+ resourceJumps: publicProcedure.query(async ({ ctx }) => {
42
+ return await ctx.companySpecificBackend.getResourceJumps()
43
+ }),
44
+
45
+ // specificEnvs: publicProcedure
46
+ // .query(async ({ctx}) => {
47
+ // return await ctx.companySpecificBackend.getDeployments({
48
+ // envNames: ['dev', 'prod'],
49
+ // appNames: ['app1', 'app2'],
50
+ // })
51
+ // }),
52
+ })
53
+
54
+ export type TRPCRouter = typeof trpcRouter
@@ -0,0 +1,4 @@
1
+ import { PrismaClient } from '@prisma/client'
2
+ import 'dotenv-defaults/config'
3
+
4
+ export const db = new PrismaClient()
@@ -0,0 +1,12 @@
1
+ export interface EhStaticControllerContract {
2
+ methods: { getIcon: { method: string; url: string } }
3
+ }
4
+
5
+ export const staticControllerContract: EhStaticControllerContract = {
6
+ methods: {
7
+ getIcon: {
8
+ method: 'get',
9
+ url: 'icon/:icon',
10
+ },
11
+ },
12
+ }
@@ -0,0 +1,23 @@
1
+ import type { EhBackendCompanySpecificBackend } from '../types'
2
+
3
+ export interface EhTrpcContext {
4
+ companySpecificBackend: EhBackendCompanySpecificBackend
5
+ }
6
+
7
+ export interface EhTrpcContextOptions {
8
+ companySpecificBackend: EhBackendCompanySpecificBackend
9
+ }
10
+
11
+ export function createEhTrpcContext({
12
+ companySpecificBackend,
13
+ }: EhTrpcContextOptions): EhTrpcContext {
14
+ return {
15
+ companySpecificBackend,
16
+ }
17
+ }
18
+
19
+ // const createContext = ({
20
+ // req,
21
+ // res
22
+ // }: trpcExpress.CreateExpressContextOptions) => ({}); // no context
23
+ // type Context = Awaited<ReturnType<typeof createContext>>;
@@ -0,0 +1,97 @@
1
+ import type {
2
+ AvailiabilityMatrixData,
3
+ BootstrapConfigData,
4
+ ResourceJumpsData,
5
+ } from '../common/dataRootTypes'
6
+ import type { EhAppIndexed } from '../common/app/appTypes'
7
+ import type {
8
+ EhAppPageIndexed,
9
+ EhAppUiIndexed,
10
+ } from '../common/app/ui/appUiTypes'
11
+ import type {
12
+ EhBackendCredentialInput,
13
+ EhBackendUiDefaultsInput,
14
+ } from './common'
15
+ import type { EhBackendDataSourceInput } from './dataSources'
16
+
17
+ export interface EhBackendVersionsRequestParams {
18
+ envNames: Array<string>
19
+ appNames: Array<string>
20
+ }
21
+
22
+ export interface EhBackendVersionsReturn {
23
+ envIds: Array<string>
24
+ appIds: Array<string>
25
+ }
26
+
27
+ export interface EhBackendPageInput extends EhAppPageIndexed {
28
+ slug: string
29
+ title?: string
30
+ url: string
31
+ credentialsRefs?: Array<string>
32
+ }
33
+
34
+ export interface EhBackendAppUIBaseInput {
35
+ credentials?: Array<EhBackendCredentialInput>
36
+ defaults?: EhBackendUiDefaultsInput
37
+ }
38
+
39
+ export interface EhBackendAppUIInput
40
+ extends EhBackendAppUIBaseInput,
41
+ EhAppUiIndexed {
42
+ pages: Array<EhBackendPageInput>
43
+ }
44
+
45
+ export interface EhBackendTagsDescriptionDataIndexed {
46
+ descriptions: Array<EhBackendTagDescriptionDataIndexed>
47
+ }
48
+
49
+ export interface EhBackendTagDescriptionDataIndexed {
50
+ tagKey: string
51
+ displayName?: string
52
+ fixedTagValues?: Array<EhBackendTagFixedTagValue>
53
+ }
54
+
55
+ export interface EhBackendTagFixedTagValue {
56
+ tagValue: string
57
+ displayName: string
58
+ }
59
+
60
+ export interface EhBackendAppInput extends EhAppIndexed {
61
+ ui?: EhBackendAppUIInput
62
+ dataSources?: Array<EhBackendDataSourceInput>
63
+ }
64
+
65
+ export interface EhContextIndexed {
66
+ slug: string
67
+ displayName: string
68
+ /**
69
+ * The value is shared across envs (By default: false)
70
+ */
71
+ isSharedAcrossEnvs?: boolean
72
+ defaultFixedValues?: Array<string>
73
+ }
74
+ export type EhBackendAppDto = EhAppIndexed
75
+
76
+ export interface EhAppsMeta {
77
+ defaultIcon?: string
78
+ tags: EhBackendTagsDescriptionDataIndexed
79
+ }
80
+
81
+ export interface RenameRuleParams {
82
+ envSlug?: string
83
+ resourceSlug?: string
84
+ }
85
+
86
+ export interface RenameRule {
87
+ type: 'resourceRename' | 'envRename'
88
+ oldSlug: string
89
+ targetSlug: string
90
+ }
91
+
92
+ export interface EhBackendCompanySpecificBackend {
93
+ getBootstrapData: () => Promise<BootstrapConfigData>
94
+ getAvailabilityMatrix: () => Promise<AvailiabilityMatrixData>
95
+ getNameMigrations: (params: RenameRuleParams) => Promise<RenameRule | false>
96
+ getResourceJumps: () => Promise<ResourceJumpsData>
97
+ }
@@ -0,0 +1,10 @@
1
+ export interface EhBackendUiDefaultsInput {
2
+ credentialsRefs: Array<string>
3
+ }
4
+
5
+ export interface EhBackendCredentialInput {
6
+ slug: string
7
+ desc?: string
8
+ username: string
9
+ password: string
10
+ }
@@ -0,0 +1,25 @@
1
+ import type { EhMetaDictionary } from '../common/sharedTypes'
2
+
3
+ export interface EhBackendDataSourceInputCommon {
4
+ meta?: EhMetaDictionary
5
+ }
6
+
7
+ export interface EhBackendDataSourceInputDb {
8
+ slug?: string
9
+ type: 'db'
10
+ url: string
11
+ username: string
12
+ password: string
13
+ }
14
+
15
+ export interface EhBackendDataSourceInputKafka {
16
+ slug?: string
17
+ type: 'kafka'
18
+ topics: {
19
+ consumer?: Array<string>
20
+ producer?: Array<string>
21
+ }
22
+ }
23
+
24
+ export type EhBackendDataSourceInput = EhBackendDataSourceInputCommon &
25
+ (EhBackendDataSourceInputDb | EhBackendDataSourceInputKafka)
@@ -0,0 +1,40 @@
1
+ import type { EhMetaDictionary } from '../common/sharedTypes'
2
+
3
+ export interface EhBackendEnvironmentInput {
4
+ slug: string
5
+ displayName?: string
6
+ description?: string
7
+ meta?: EhMetaDictionary
8
+ }
9
+
10
+ export interface EhBackendDeploymentInput {
11
+ envId: string
12
+ appId: string
13
+ displayVersion: string
14
+ meta?: EhMetaDictionary
15
+ }
16
+
17
+ export interface EhBackendDeployableInput {
18
+ slug: string
19
+ meta?: {
20
+ config: string
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Latest - backend returned latest data.
26
+ * Cached - backend in process of updating data, but returned cached data.
27
+ */
28
+ export type EhBackendDataFreshness = 'latest' | 'cached'
29
+
30
+ export interface EhBackendDataVersion {
31
+ version: string
32
+ freshness: EhBackendDataFreshness
33
+ }
34
+
35
+ export interface EhBackendDeployment {
36
+ appName: string
37
+ deployableServiceName: string
38
+ envName: string
39
+ version: EhBackendDataVersion
40
+ }
@@ -0,0 +1,13 @@
1
+ import type { EhMetaDictionary, Tag } from '../sharedTypes'
2
+ import type { EhAppUiIndexed } from './ui/appUiTypes'
3
+
4
+ export interface EhAppIndexed {
5
+ slug: string
6
+ displayName: string
7
+ abbr?: string
8
+ aliases?: Array<string>
9
+ ui?: EhAppUiIndexed
10
+ tags?: Array<Tag>
11
+ iconName?: string
12
+ meta?: EhMetaDictionary
13
+ }
@@ -0,0 +1,12 @@
1
+ import type { Tag } from '../../sharedTypes'
2
+
3
+ export interface EhAppPageIndexed {
4
+ slug: string
5
+ displayName: string
6
+ url: string
7
+ tags?: Array<Tag>
8
+ }
9
+
10
+ export interface EhAppUiIndexed {
11
+ pages: Array<EhAppPageIndexed>
12
+ }
@@ -0,0 +1,19 @@
1
+ export interface EhAppCatalogData {
2
+ apps: Array<EhAppCatalogDto>
3
+ }
4
+
5
+ export interface EhAppCatalogDto {
6
+ slug: string
7
+ groups: Array<EhAppCatalogGroupDto>
8
+ }
9
+
10
+ export interface EhAppCatalogGroupDto {
11
+ slug: string
12
+ displayName: string
13
+ pages: Array<EhAppCatalogPageDto>
14
+ }
15
+
16
+ export interface EhAppCatalogPageDto {
17
+ slug: string
18
+ displayName: string
19
+ }
@@ -0,0 +1,38 @@
1
+ import type { EhAppsMeta, EhContextIndexed } from '../backend/api.js'
2
+ import type { EhEnvIndexed } from './env/envTypes.js'
3
+ import type { EhAppIndexed } from './app/appTypes.js'
4
+
5
+ export type JumpResouceSlug = string
6
+ export type EnvSlug = string
7
+
8
+ export interface BootstrapConfigData {
9
+ envs: Record<EnvSlug, EhEnvIndexed>
10
+ apps: Record<string, EhAppIndexed>
11
+ appsMeta: EhAppsMeta
12
+ contexts: Array<EhContextIndexed>
13
+ defaults: {
14
+ envSlug: EnvSlug
15
+ resourceJumpSlug: JumpResouceSlug
16
+ }
17
+ }
18
+
19
+ export interface AvailiabilityMatrixData {
20
+ envSlugs: Array<EnvSlug>
21
+ resourceJumpSlugs: Array<JumpResouceSlug>
22
+ availabilityVariants: Array<AvailabilityVariant>
23
+ matrix: Array<Array<number>>
24
+ }
25
+
26
+ export interface AvailabilityVariant {
27
+ isDeployed: boolean
28
+ isHealthy?: boolean
29
+ hasData?: boolean
30
+ }
31
+
32
+ export interface ResourceJumpsData {
33
+ // key - jump Resouce
34
+ baseResouceJumpUrls: Record<JumpResouceSlug, string>
35
+ resourceJumpsData: Record<JumpResouceSlug, Record<string, string>>
36
+ envData: Record<EnvSlug, Record<string, string>>
37
+ overrideResoucesJumpsUrls: Record<EnvSlug, Record<JumpResouceSlug, string>>
38
+ }
@@ -0,0 +1,7 @@
1
+ import type { EhMetaDictionary } from '../sharedTypes'
2
+
3
+ export interface EhEnvIndexed {
4
+ slug: string
5
+ displayName: string
6
+ meta?: EhMetaDictionary
7
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resources like kafka topics, database tables, etc.
3
+ */
4
+ export interface EhResourceIndexed {
5
+ slug: string
6
+ displayName: string
7
+ defaultFixedValues?: Array<string>
8
+ }
@@ -0,0 +1,5 @@
1
+ export interface EhMetaDictionary {
2
+ [key: string]: string | null | Record<string, string | null>
3
+ }
4
+
5
+ export type Tag = string
@@ -0,0 +1,19 @@
1
+ // Export all common types
2
+ export * from './common/sharedTypes.js'
3
+ export * from './common/resourceTypes.js'
4
+ export * from './common/dataRootTypes.js'
5
+ export * from './common/appCatalogTypes.js'
6
+ export * from './common/env/envTypes.js'
7
+ export * from './common/app/appTypes.js'
8
+ export * from './common/app/ui/appUiTypes.js'
9
+
10
+ // Main API interfaces
11
+ export * from './backend/api.js'
12
+
13
+ // Common types
14
+ export * from './backend/common.js'
15
+ // Data source types
16
+ export * from './backend/dataSources.js'
17
+
18
+ // Deployment and version types
19
+ export * from './backend/deployments.js'