@igstack/app-catalog-backend-core 0.0.1

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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +1934 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +2539 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +84 -0
  7. package/prisma/migrations/20250526183023_init/migration.sql +71 -0
  8. package/prisma/migrations/migration_lock.toml +3 -0
  9. package/prisma/schema.prisma +149 -0
  10. package/src/__tests__/dummy.test.ts +7 -0
  11. package/src/db/client.ts +42 -0
  12. package/src/db/index.ts +21 -0
  13. package/src/db/syncAppCatalog.ts +312 -0
  14. package/src/db/tableSyncMagazine.ts +32 -0
  15. package/src/db/tableSyncPrismaAdapter.ts +203 -0
  16. package/src/index.ts +126 -0
  17. package/src/middleware/backendResolver.ts +42 -0
  18. package/src/middleware/createEhMiddleware.ts +171 -0
  19. package/src/middleware/database.ts +62 -0
  20. package/src/middleware/featureRegistry.ts +173 -0
  21. package/src/middleware/index.ts +43 -0
  22. package/src/middleware/types.ts +202 -0
  23. package/src/modules/admin/chat/createAdminChatHandler.ts +152 -0
  24. package/src/modules/admin/chat/createDatabaseTools.ts +261 -0
  25. package/src/modules/appCatalog/service.ts +130 -0
  26. package/src/modules/appCatalogAdmin/appCatalogAdminRouter.ts +187 -0
  27. package/src/modules/appCatalogAdmin/catalogBackupController.ts +213 -0
  28. package/src/modules/approvalMethod/approvalMethodRouter.ts +169 -0
  29. package/src/modules/approvalMethod/slugUtils.ts +17 -0
  30. package/src/modules/approvalMethod/syncApprovalMethods.ts +38 -0
  31. package/src/modules/assets/assetRestController.ts +271 -0
  32. package/src/modules/assets/assetUtils.ts +114 -0
  33. package/src/modules/assets/screenshotRestController.ts +195 -0
  34. package/src/modules/assets/screenshotRouter.ts +112 -0
  35. package/src/modules/assets/syncAssets.ts +277 -0
  36. package/src/modules/assets/upsertAsset.ts +46 -0
  37. package/src/modules/auth/auth.ts +51 -0
  38. package/src/modules/auth/authProviders.ts +40 -0
  39. package/src/modules/auth/authRouter.ts +75 -0
  40. package/src/modules/auth/authorizationUtils.ts +132 -0
  41. package/src/modules/auth/devMockUserUtils.ts +49 -0
  42. package/src/modules/auth/registerAuthRoutes.ts +33 -0
  43. package/src/modules/icons/iconRestController.ts +171 -0
  44. package/src/modules/icons/iconRouter.ts +180 -0
  45. package/src/modules/icons/iconService.ts +73 -0
  46. package/src/modules/icons/iconUtils.ts +46 -0
  47. package/src/prisma-json-types.d.ts +34 -0
  48. package/src/server/controller.ts +47 -0
  49. package/src/server/ehStaticControllerContract.ts +19 -0
  50. package/src/server/ehTrpcContext.ts +26 -0
  51. package/src/server/trpcSetup.ts +89 -0
  52. package/src/types/backend/api.ts +73 -0
  53. package/src/types/backend/common.ts +10 -0
  54. package/src/types/backend/companySpecificBackend.ts +5 -0
  55. package/src/types/backend/dataSources.ts +25 -0
  56. package/src/types/backend/deployments.ts +40 -0
  57. package/src/types/common/app/appTypes.ts +13 -0
  58. package/src/types/common/app/ui/appUiTypes.ts +12 -0
  59. package/src/types/common/appCatalogTypes.ts +65 -0
  60. package/src/types/common/approvalMethodTypes.ts +149 -0
  61. package/src/types/common/env/envTypes.ts +7 -0
  62. package/src/types/common/resourceTypes.ts +8 -0
  63. package/src/types/common/sharedTypes.ts +5 -0
  64. package/src/types/index.ts +21 -0
@@ -0,0 +1,180 @@
1
+ import { z } from 'zod'
2
+ import { getDbClient } from '../../db'
3
+ import { generateChecksum, getImageDimensions } from '../assets/assetUtils'
4
+ import { getExtensionFromMimeType } from './iconUtils'
5
+ import { adminProcedure, publicProcedure, router } from '../../server/trpcSetup'
6
+
7
+ export function createIconRouter() {
8
+ return router({
9
+ list: publicProcedure.query(async () => {
10
+ const prisma = getDbClient()
11
+ return prisma.dbAsset.findMany({
12
+ where: { assetType: 'icon' },
13
+ select: {
14
+ id: true,
15
+ name: true,
16
+ mimeType: true,
17
+ fileSize: true,
18
+ createdAt: true,
19
+ updatedAt: true,
20
+ },
21
+ orderBy: { name: 'asc' },
22
+ })
23
+ }),
24
+
25
+ getOne: publicProcedure
26
+ .input(z.object({ id: z.string() }))
27
+ .query(async ({ input }) => {
28
+ const prisma = getDbClient()
29
+ return prisma.dbAsset.findFirst({
30
+ where: {
31
+ id: input.id,
32
+ assetType: 'icon',
33
+ },
34
+ select: {
35
+ id: true,
36
+ name: true,
37
+ mimeType: true,
38
+ fileSize: true,
39
+ createdAt: true,
40
+ updatedAt: true,
41
+ },
42
+ })
43
+ }),
44
+
45
+ create: adminProcedure
46
+ .input(
47
+ z.object({
48
+ name: z.string().min(1), // Name with extension (e.g., "jira.svg")
49
+ content: z.string(), // base64 encoded binary
50
+ mimeType: z.string(),
51
+ fileSize: z.number().int().positive(),
52
+ }),
53
+ )
54
+ .mutation(async ({ input }) => {
55
+ const prisma = getDbClient()
56
+ // Convert base64 to Buffer
57
+ const buffer = Buffer.from(input.content, 'base64')
58
+
59
+ // Generate checksum and extract dimensions
60
+ const checksum = generateChecksum(buffer)
61
+ const { width, height } = await getImageDimensions(buffer)
62
+
63
+ let name = input.name
64
+ // Add extension if not already present in name
65
+ if (!name.includes('.')) {
66
+ const extension = getExtensionFromMimeType(input.mimeType)
67
+ name = `${name}.${extension}`
68
+ }
69
+
70
+ // Check if asset with same checksum already exists
71
+ const existing = await prisma.dbAsset.findFirst({
72
+ where: { checksum, assetType: 'icon' },
73
+ })
74
+
75
+ if (existing) {
76
+ // Return existing asset if content is identical
77
+ return existing
78
+ }
79
+
80
+ return prisma.dbAsset.create({
81
+ data: {
82
+ name,
83
+ assetType: 'icon',
84
+ content: new Uint8Array(buffer),
85
+ checksum,
86
+ mimeType: input.mimeType,
87
+ fileSize: input.fileSize,
88
+ width,
89
+ height,
90
+ },
91
+ })
92
+ }),
93
+
94
+ update: adminProcedure
95
+ .input(
96
+ z.object({
97
+ id: z.string(),
98
+ name: z.string().min(1).optional(), // Name with extension (e.g., "jira.svg")
99
+ content: z.string().optional(), // base64 encoded binary
100
+ mimeType: z.string().optional(),
101
+ fileSize: z.number().int().positive().optional(),
102
+ }),
103
+ )
104
+ .mutation(async ({ input }) => {
105
+ const prisma = getDbClient()
106
+ const { id, content, name, ...rest } = input
107
+
108
+ const data: Record<string, unknown> = { ...rest }
109
+
110
+ if (content) {
111
+ const buffer = Buffer.from(content, 'base64')
112
+ data.content = new Uint8Array(buffer)
113
+ data.checksum = generateChecksum(buffer)
114
+
115
+ const { width, height } = await getImageDimensions(buffer)
116
+ data.width = width
117
+ data.height = height
118
+ }
119
+
120
+ // If name is being updated and doesn't have extension, add it
121
+ if (name) {
122
+ if (!name.includes('.') && input.mimeType) {
123
+ const extension = getExtensionFromMimeType(input.mimeType)
124
+ data.name = `${name}.${extension}`
125
+ } else {
126
+ data.name = name
127
+ }
128
+ }
129
+
130
+ return prisma.dbAsset.update({
131
+ where: { id },
132
+ data,
133
+ })
134
+ }),
135
+
136
+ delete: adminProcedure
137
+ .input(z.object({ id: z.string() }))
138
+ .mutation(async ({ input }) => {
139
+ const prisma = getDbClient()
140
+ return prisma.dbAsset.delete({
141
+ where: { id: input.id },
142
+ })
143
+ }),
144
+
145
+ deleteMany: adminProcedure
146
+ .input(z.object({ ids: z.array(z.string()) }))
147
+ .mutation(async ({ input }) => {
148
+ const prisma = getDbClient()
149
+ return prisma.dbAsset.deleteMany({
150
+ where: {
151
+ id: { in: input.ids },
152
+ assetType: 'icon',
153
+ },
154
+ })
155
+ }),
156
+
157
+ // Serve icon binary content
158
+ getContent: publicProcedure
159
+ .input(z.object({ id: z.string() }))
160
+ .query(async ({ input }) => {
161
+ const prisma = getDbClient()
162
+ const asset = await prisma.dbAsset.findFirst({
163
+ where: {
164
+ id: input.id,
165
+ assetType: 'icon',
166
+ },
167
+ select: { content: true, mimeType: true, name: true },
168
+ })
169
+ if (!asset) {
170
+ throw new Error('Icon not found')
171
+ }
172
+ // Return base64 encoded content
173
+ return {
174
+ content: Buffer.from(asset.content).toString('base64'),
175
+ mimeType: asset.mimeType,
176
+ name: asset.name,
177
+ }
178
+ }),
179
+ })
180
+ }
@@ -0,0 +1,73 @@
1
+ import { getDbClient } from '../../db'
2
+ import { generateChecksum, getImageDimensions } from '../assets/assetUtils'
3
+
4
+ export interface UpsertIconInput {
5
+ name: string
6
+ content: Buffer
7
+ mimeType: string
8
+ fileSize: number
9
+ }
10
+
11
+ /**
12
+ * Upsert an icon to the database.
13
+ * If an icon with the same name exists, it will be updated.
14
+ * Otherwise, a new icon will be created.
15
+ */
16
+ export async function upsertIcon(input: UpsertIconInput) {
17
+ const prisma = getDbClient()
18
+
19
+ const checksum = generateChecksum(input.content)
20
+ const { width, height } = await getImageDimensions(input.content)
21
+
22
+ return prisma.dbAsset.upsert({
23
+ where: { name: input.name },
24
+ update: {
25
+ content: new Uint8Array(input.content),
26
+ checksum,
27
+ mimeType: input.mimeType,
28
+ fileSize: input.fileSize,
29
+ width,
30
+ height,
31
+ },
32
+ create: {
33
+ name: input.name,
34
+ assetType: 'icon',
35
+ content: new Uint8Array(input.content),
36
+ checksum,
37
+ mimeType: input.mimeType,
38
+ fileSize: input.fileSize,
39
+ width,
40
+ height,
41
+ },
42
+ })
43
+ }
44
+
45
+ /**
46
+ * Upsert multiple icons to the database.
47
+ * This is more efficient than calling upsertIcon multiple times.
48
+ */
49
+ export async function upsertIcons(icons: Array<UpsertIconInput>) {
50
+ const results: Array<Awaited<ReturnType<typeof upsertIcon>>> = []
51
+ for (const icon of icons) {
52
+ const result = await upsertIcon(icon)
53
+ results.push(result)
54
+ }
55
+ return results
56
+ }
57
+
58
+ /**
59
+ * Get an asset (icon or screenshot) by name from the database.
60
+ * Returns the asset content, mimeType, and name if found.
61
+ */
62
+ export async function getAssetByName(name: string) {
63
+ const prisma = getDbClient()
64
+
65
+ return prisma.dbAsset.findUnique({
66
+ where: { name },
67
+ select: {
68
+ content: true,
69
+ mimeType: true,
70
+ name: true,
71
+ },
72
+ })
73
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Get file extension from MIME type
3
+ */
4
+ export function getExtensionFromMimeType(mimeType: string): string {
5
+ const mimeMap: Record<string, string> = {
6
+ 'image/svg+xml': 'svg',
7
+ 'image/png': 'png',
8
+ 'image/jpeg': 'jpg',
9
+ 'image/jpg': 'jpg',
10
+ 'image/webp': 'webp',
11
+ 'image/gif': 'gif',
12
+ 'image/bmp': 'bmp',
13
+ 'image/tiff': 'tiff',
14
+ 'image/x-icon': 'ico',
15
+ 'image/vnd.microsoft.icon': 'ico',
16
+ }
17
+
18
+ return mimeMap[mimeType.toLowerCase()] || 'bin'
19
+ }
20
+
21
+ /**
22
+ * Get file extension from filename
23
+ */
24
+ export function getExtensionFromFilename(filename: string): string {
25
+ const match = filename.match(/\.([^.]+)$/)
26
+ return match?.[1]?.toLowerCase() || ''
27
+ }
28
+
29
+ /**
30
+ * Get MIME type from extension
31
+ */
32
+ export function getMimeTypeFromExtension(extension: string): string {
33
+ const extMap: Record<string, string> = {
34
+ svg: 'image/svg+xml',
35
+ png: 'image/png',
36
+ jpg: 'image/jpeg',
37
+ jpeg: 'image/jpeg',
38
+ webp: 'image/webp',
39
+ gif: 'image/gif',
40
+ bmp: 'image/bmp',
41
+ tiff: 'image/tiff',
42
+ ico: 'image/x-icon',
43
+ }
44
+
45
+ return extMap[extension.toLowerCase()] || 'application/octet-stream'
46
+ }
@@ -0,0 +1,34 @@
1
+ /* eslint-disable @typescript-eslint/consistent-type-imports */
2
+ /**
3
+ * Prisma JSON Types Declaration
4
+ *
5
+ * This file provides type definitions for JSON fields in Prisma models.
6
+ * The prisma-json-types-generator reads JSDoc comments like `/// [TypeName]`
7
+ * on JSON fields and references them as `PrismaJson.TypeName`.
8
+ *
9
+ * We must declare these types in the global PrismaJson namespace for
10
+ * TypeScript to properly infer types throughout the tRPC chain.
11
+ *
12
+ * @see https://github.com/arthurfiorette/prisma-json-types-generator
13
+ */
14
+
15
+ declare global {
16
+ namespace PrismaJson {
17
+ // DbApprovalMethod.config - Type-specific configuration
18
+ type ApprovalMethodConfig = import('./types/index').ApprovalMethodConfig
19
+
20
+ // DbAppForCatalog.accessRequest - Per-app approval configuration
21
+ type AppAccessRequest = import('./types/index').AppAccessRequest
22
+
23
+ // DbAppForCatalog.links - Array of links
24
+ interface AppLink {
25
+ displayName?: string
26
+ url: string
27
+ }
28
+
29
+ // AppRole used within accessRequest
30
+ type AppRole = import('./types/index').AppRole
31
+ }
32
+ }
33
+
34
+ export {}
@@ -0,0 +1,47 @@
1
+ import { getAppCatalogData } from '../modules/appCatalog/service'
2
+ import type { AppCatalogData } from '../types'
3
+
4
+ import { createAppCatalogAdminRouter } from '../modules/appCatalogAdmin/appCatalogAdminRouter.js'
5
+ import { createApprovalMethodRouter } from '../modules/approvalMethod/approvalMethodRouter.js'
6
+ import { createScreenshotRouter } from '../modules/assets/screenshotRouter.js'
7
+ import type { BetterAuth } from '../modules/auth/auth'
8
+ import { createAuthRouter } from '../modules/auth/authRouter.js'
9
+ import { createIconRouter } from '../modules/icons/iconRouter.js'
10
+ import { publicProcedure, router, t } from './trpcSetup'
11
+
12
+ /**
13
+ * Create the main tRPC router with optional auth instance
14
+ * @param auth - Optional Better Auth instance for auth-related queries
15
+ */
16
+ export function createTrpcRouter(auth?: BetterAuth) {
17
+ return router({
18
+ authConfig: publicProcedure.query(async ({ ctx }) => {
19
+ return {
20
+ adminGroups: ctx.adminGroups,
21
+ }
22
+ }),
23
+
24
+ appCatalog: publicProcedure.query(
25
+ async ({ ctx }): Promise<AppCatalogData> => {
26
+ return await getAppCatalogData(ctx.companySpecificBackend.getApps)
27
+ },
28
+ ),
29
+
30
+ // Icon management routes
31
+ icon: createIconRouter(),
32
+
33
+ // Screenshot management routes
34
+ screenshot: createScreenshotRouter(),
35
+
36
+ // App catalog admin routes
37
+ appCatalogAdmin: createAppCatalogAdminRouter(),
38
+
39
+ // Approval method routes
40
+ approvalMethod: createApprovalMethodRouter(),
41
+
42
+ // Auth routes (requires auth instance)
43
+ auth: createAuthRouter(t, auth),
44
+ })
45
+ }
46
+
47
+ export type TRPCRouter = ReturnType<typeof createTrpcRouter>
@@ -0,0 +1,19 @@
1
+ export interface EhStaticControllerContract {
2
+ methods: {
3
+ getIcon: { method: string; url: string }
4
+ getScreenshot: { method: string; url: string }
5
+ }
6
+ }
7
+
8
+ export const staticControllerContract: EhStaticControllerContract = {
9
+ methods: {
10
+ getIcon: {
11
+ method: 'get',
12
+ url: 'icon/:icon',
13
+ },
14
+ getScreenshot: {
15
+ method: 'get',
16
+ url: 'screenshot/:id',
17
+ },
18
+ },
19
+ }
@@ -0,0 +1,26 @@
1
+ import type { AppCatalogCompanySpecificBackend } from '../types'
2
+ import type { User } from 'better-auth/types'
3
+
4
+ export interface EhTrpcContext {
5
+ companySpecificBackend: AppCatalogCompanySpecificBackend
6
+ user: User | null
7
+ adminGroups: Array<string>
8
+ }
9
+
10
+ export interface EhTrpcContextOptions {
11
+ companySpecificBackend: AppCatalogCompanySpecificBackend
12
+ user?: User | null
13
+ adminGroups: Array<string>
14
+ }
15
+
16
+ export function createEhTrpcContext({
17
+ companySpecificBackend,
18
+ user = null,
19
+ adminGroups,
20
+ }: EhTrpcContextOptions): EhTrpcContext {
21
+ return {
22
+ companySpecificBackend,
23
+ user,
24
+ adminGroups,
25
+ }
26
+ }
@@ -0,0 +1,89 @@
1
+ import { TRPCError, initTRPC } from '@trpc/server'
2
+ import type { EhTrpcContext } from './ehTrpcContext'
3
+ import { isAdmin } from '../modules/auth/authorizationUtils'
4
+
5
+ /**
6
+ * Initialization of tRPC backend
7
+ * Should be done only once per backend!
8
+ */
9
+ export const t = initTRPC.context<EhTrpcContext>().create({
10
+ errorFormatter({ error, shape }: { error: unknown; shape: unknown }) {
11
+ // Log all tRPC errors to console
12
+ console.error('[tRPC Error]', {
13
+ path: (shape as { data?: { path?: string } }).data?.path,
14
+ code: (error as { code?: string }).code,
15
+ message: (error as { message?: string }).message,
16
+ cause: (error as { cause?: unknown }).cause,
17
+ stack: (error as { stack?: string }).stack,
18
+ })
19
+ return shape
20
+ },
21
+ })
22
+
23
+ /**
24
+ * Export reusable router and procedure helpers
25
+ */
26
+ export const router = t.router
27
+ export const publicProcedure = t.procedure
28
+
29
+ /**
30
+ * Middleware to check if user is authenticated
31
+ */
32
+ const isAuthenticated = t.middleware(({ ctx, next }) => {
33
+ if (!ctx.user) {
34
+ throw new TRPCError({
35
+ code: 'UNAUTHORIZED',
36
+ message: 'You must be logged in to access this resource',
37
+ })
38
+ }
39
+ return next({
40
+ ctx: {
41
+ ...ctx,
42
+ user: ctx.user,
43
+ },
44
+ })
45
+ })
46
+
47
+ /**
48
+ * Middleware to check if user is an admin
49
+ */
50
+ const isAdminMiddleware = t.middleware(({ ctx, next }) => {
51
+ if (!ctx.user) {
52
+ throw new TRPCError({
53
+ code: 'UNAUTHORIZED',
54
+ message: 'You must be logged in to access this resource',
55
+ })
56
+ }
57
+
58
+ console.log('[isAdminMiddleware] === ADMIN CHECK DEBUG ===')
59
+ console.log('[isAdminMiddleware] User:', ctx.user.email)
60
+ console.log('[isAdminMiddleware] Required admin groups:', ctx.adminGroups)
61
+ console.log('[isAdminMiddleware] Calling isAdmin()...')
62
+
63
+ const hasAdminAccess = isAdmin(ctx.user, ctx.adminGroups)
64
+ console.log('[isAdminMiddleware] Has admin access:', hasAdminAccess)
65
+
66
+ if (!hasAdminAccess) {
67
+ throw new TRPCError({
68
+ code: 'FORBIDDEN',
69
+ message: `You must be an admin to access this resource. Required groups: ${ctx.adminGroups.join(', ') || 'env_hopper_ui_super_admins'}`,
70
+ })
71
+ }
72
+
73
+ return next({
74
+ ctx: {
75
+ ...ctx,
76
+ user: ctx.user,
77
+ },
78
+ })
79
+ })
80
+
81
+ /**
82
+ * Admin procedure that requires admin permissions
83
+ */
84
+ export const adminProcedure = t.procedure.use(isAdminMiddleware)
85
+
86
+ /**
87
+ * Protected procedure that requires authentication (but not admin)
88
+ */
89
+ export const protectedProcedure = t.procedure.use(isAuthenticated)
@@ -0,0 +1,73 @@
1
+ import type { EhAppIndexed } from '../common/app/appTypes'
2
+ import type {
3
+ EhAppPageIndexed,
4
+ EhAppUiIndexed,
5
+ } from '../common/app/ui/appUiTypes'
6
+ import type {
7
+ EhBackendCredentialInput,
8
+ EhBackendUiDefaultsInput,
9
+ } from './common'
10
+ import type { EhBackendDataSourceInput } from './dataSources'
11
+
12
+ export interface EhBackendVersionsRequestParams {
13
+ envNames: Array<string>
14
+ appNames: Array<string>
15
+ }
16
+
17
+ export interface EhBackendVersionsReturn {
18
+ envIds: Array<string>
19
+ appIds: Array<string>
20
+ }
21
+
22
+ export interface EhBackendPageInput extends EhAppPageIndexed {
23
+ slug: string
24
+ title?: string
25
+ url: string
26
+ credentialsRefs?: Array<string>
27
+ }
28
+
29
+ export interface EhBackendAppUIBaseInput {
30
+ credentials?: Array<EhBackendCredentialInput>
31
+ defaults?: EhBackendUiDefaultsInput
32
+ }
33
+
34
+ export interface EhBackendAppUIInput
35
+ extends EhBackendAppUIBaseInput, EhAppUiIndexed {
36
+ pages: Array<EhBackendPageInput>
37
+ }
38
+
39
+ export interface EhBackendTagsDescriptionDataIndexed {
40
+ descriptions: Array<EhBackendTagDescriptionDataIndexed>
41
+ }
42
+
43
+ export interface EhBackendTagDescriptionDataIndexed {
44
+ tagKey: string
45
+ displayName?: string
46
+ fixedTagValues?: Array<EhBackendTagFixedTagValue>
47
+ }
48
+
49
+ export interface EhBackendTagFixedTagValue {
50
+ tagValue: string
51
+ displayName: string
52
+ }
53
+
54
+ export interface EhBackendAppInput extends EhAppIndexed {
55
+ ui?: EhBackendAppUIInput
56
+ dataSources?: Array<EhBackendDataSourceInput>
57
+ }
58
+
59
+ export interface EhContextIndexed {
60
+ slug: string
61
+ displayName: string
62
+ /**
63
+ * The value is shared across envs (By default: false)
64
+ */
65
+ isSharedAcrossEnvs?: boolean
66
+ defaultFixedValues?: Array<string>
67
+ }
68
+ export type EhBackendAppDto = EhAppIndexed
69
+
70
+ export interface EhAppsMeta {
71
+ defaultIcon?: string
72
+ tags: EhBackendTagsDescriptionDataIndexed
73
+ }
@@ -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,5 @@
1
+ import type { AppForCatalog } from '../common/appCatalogTypes'
2
+
3
+ export interface AppCatalogCompanySpecificBackend {
4
+ getApps?: () => Promise<Array<AppForCatalog>>
5
+ }
@@ -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
+ }