@env-hopper/backend-core 2.0.1-alpha → 2.0.1-alpha.2

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 (66) hide show
  1. package/dist/index.d.ts +1584 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +1806 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +26 -11
  6. package/prisma/migrations/20250526183023_init/migration.sql +71 -0
  7. package/prisma/migrations/migration_lock.toml +3 -0
  8. package/prisma/schema.prisma +121 -0
  9. package/src/db/client.ts +34 -0
  10. package/src/db/index.ts +17 -0
  11. package/src/db/syncAppCatalog.ts +67 -0
  12. package/src/db/tableSyncMagazine.ts +22 -0
  13. package/src/db/tableSyncPrismaAdapter.ts +202 -0
  14. package/src/index.ts +96 -3
  15. package/src/modules/admin/chat/createAdminChatHandler.ts +152 -0
  16. package/src/modules/admin/chat/createDatabaseTools.ts +261 -0
  17. package/src/modules/appCatalog/service.ts +79 -0
  18. package/src/modules/appCatalogAdmin/appCatalogAdminRouter.ts +113 -0
  19. package/src/modules/assets/assetRestController.ts +309 -0
  20. package/src/modules/assets/assetUtils.ts +81 -0
  21. package/src/modules/assets/screenshotRestController.ts +195 -0
  22. package/src/modules/assets/screenshotRouter.ts +116 -0
  23. package/src/modules/assets/syncAssets.ts +261 -0
  24. package/src/modules/auth/auth.ts +51 -0
  25. package/src/modules/auth/authProviders.ts +108 -0
  26. package/src/modules/auth/authRouter.ts +77 -0
  27. package/src/modules/auth/authorizationUtils.ts +114 -0
  28. package/src/modules/auth/registerAuthRoutes.ts +33 -0
  29. package/src/modules/icons/iconRestController.ts +190 -0
  30. package/src/modules/icons/iconRouter.ts +157 -0
  31. package/src/modules/icons/iconService.ts +73 -0
  32. package/src/server/controller.ts +102 -29
  33. package/src/server/ehStaticControllerContract.ts +8 -1
  34. package/src/server/ehTrpcContext.ts +0 -6
  35. package/src/types/backend/api.ts +1 -14
  36. package/src/types/backend/companySpecificBackend.ts +17 -0
  37. package/src/types/common/appCatalogTypes.ts +167 -0
  38. package/src/types/common/dataRootTypes.ts +72 -10
  39. package/src/types/index.ts +2 -0
  40. package/dist/esm/__tests__/dummy.test.d.ts +0 -1
  41. package/dist/esm/index.d.ts +0 -7
  42. package/dist/esm/index.js +0 -9
  43. package/dist/esm/index.js.map +0 -1
  44. package/dist/esm/server/controller.d.ts +0 -32
  45. package/dist/esm/server/controller.js +0 -35
  46. package/dist/esm/server/controller.js.map +0 -1
  47. package/dist/esm/server/db.d.ts +0 -2
  48. package/dist/esm/server/ehStaticControllerContract.d.ts +0 -9
  49. package/dist/esm/server/ehStaticControllerContract.js +0 -12
  50. package/dist/esm/server/ehStaticControllerContract.js.map +0 -1
  51. package/dist/esm/server/ehTrpcContext.d.ts +0 -8
  52. package/dist/esm/server/ehTrpcContext.js +0 -11
  53. package/dist/esm/server/ehTrpcContext.js.map +0 -1
  54. package/dist/esm/types/backend/api.d.ts +0 -71
  55. package/dist/esm/types/backend/common.d.ts +0 -9
  56. package/dist/esm/types/backend/dataSources.d.ts +0 -20
  57. package/dist/esm/types/backend/deployments.d.ts +0 -34
  58. package/dist/esm/types/common/app/appTypes.d.ts +0 -12
  59. package/dist/esm/types/common/app/ui/appUiTypes.d.ts +0 -10
  60. package/dist/esm/types/common/appCatalogTypes.d.ts +0 -16
  61. package/dist/esm/types/common/dataRootTypes.d.ts +0 -32
  62. package/dist/esm/types/common/env/envTypes.d.ts +0 -6
  63. package/dist/esm/types/common/resourceTypes.d.ts +0 -8
  64. package/dist/esm/types/common/sharedTypes.d.ts +0 -4
  65. package/dist/esm/types/index.d.ts +0 -11
  66. package/src/server/db.ts +0 -4
@@ -0,0 +1,190 @@
1
+ import type { Request, Response, Router } from 'express'
2
+ import multer from 'multer'
3
+ import { createHash } from 'node:crypto'
4
+ import { getDbClient } from '../../db'
5
+
6
+ // Configure multer for memory storage
7
+ const upload = multer({
8
+ storage: multer.memoryStorage(),
9
+ limits: {
10
+ fileSize: 10 * 1024 * 1024, // 10MB limit
11
+ },
12
+ fileFilter: (_req, file, cb) => {
13
+ // Accept images only
14
+ if (!file.mimetype.startsWith('image/')) {
15
+ cb(new Error('Only image files are allowed'))
16
+ return
17
+ }
18
+ cb(null, true)
19
+ },
20
+ })
21
+
22
+ export interface IconRestControllerConfig {
23
+ /**
24
+ * Base path for icon endpoints (e.g., '/api/icons')
25
+ */
26
+ basePath: string
27
+ }
28
+
29
+ /**
30
+ * Registers REST endpoints for icon upload and retrieval
31
+ *
32
+ * Endpoints:
33
+ * - POST {basePath}/upload - Upload a new icon (multipart/form-data with 'icon' field and 'name' field)
34
+ * - GET {basePath}/:id - Get icon binary by ID
35
+ * - GET {basePath}/:id/metadata - Get icon metadata only
36
+ */
37
+ export function registerIconRestController(
38
+ router: Router,
39
+ config: IconRestControllerConfig,
40
+ ): void {
41
+ const { basePath } = config
42
+
43
+ // Upload endpoint - accepts multipart/form-data
44
+ router.post(
45
+ `${basePath}/upload`,
46
+ upload.single('icon'),
47
+ async (req: Request, res: Response) => {
48
+ try {
49
+ if (!req.file) {
50
+ res.status(400).json({ error: 'No file uploaded' })
51
+ return
52
+ }
53
+
54
+ const name = req.body['name'] as string
55
+ if (!name) {
56
+ res.status(400).json({ error: 'Name is required' })
57
+ return
58
+ }
59
+
60
+ const prisma = getDbClient()
61
+ const checksum = createHash('sha256')
62
+ .update(req.file.buffer)
63
+ .digest('hex')
64
+ const icon = await prisma.dbAsset.create({
65
+ data: {
66
+ name,
67
+ assetType: 'icon',
68
+ content: new Uint8Array(req.file.buffer),
69
+ mimeType: req.file.mimetype,
70
+ fileSize: req.file.size,
71
+ checksum,
72
+ },
73
+ })
74
+
75
+ res.status(201).json({
76
+ id: icon.id,
77
+ name: icon.name,
78
+ mimeType: icon.mimeType,
79
+ fileSize: icon.fileSize,
80
+ createdAt: icon.createdAt,
81
+ })
82
+ } catch (error) {
83
+ console.error('Error uploading icon:', error)
84
+ res.status(500).json({ error: 'Failed to upload icon' })
85
+ }
86
+ },
87
+ )
88
+
89
+ // Get icon binary by ID
90
+ router.get(`${basePath}/:id`, async (req: Request, res: Response) => {
91
+ try {
92
+ const { id } = req.params
93
+
94
+ const prisma = getDbClient()
95
+ const icon = await prisma.dbAsset.findUnique({
96
+ where: { id },
97
+ select: {
98
+ content: true,
99
+ mimeType: true,
100
+ name: true,
101
+ },
102
+ })
103
+
104
+ if (!icon) {
105
+ res.status(404).json({ error: 'Icon not found' })
106
+ return
107
+ }
108
+
109
+ // Set appropriate headers
110
+ res.setHeader('Content-Type', icon.mimeType)
111
+ res.setHeader('Content-Disposition', `inline; filename="${icon.name}"`)
112
+ res.setHeader('Cache-Control', 'public, max-age=86400') // Cache for 1 day
113
+
114
+ // Send binary content
115
+ res.send(icon.content)
116
+ } catch (error) {
117
+ console.error('Error fetching icon:', error)
118
+ res.status(500).json({ error: 'Failed to fetch icon' })
119
+ }
120
+ })
121
+
122
+ // Get icon metadata only (no binary content)
123
+ router.get(
124
+ `${basePath}/:id/metadata`,
125
+ async (req: Request, res: Response) => {
126
+ try {
127
+ const { id } = req.params
128
+
129
+ const prisma = getDbClient()
130
+ const icon = await prisma.dbAsset.findUnique({
131
+ where: { id },
132
+ select: {
133
+ id: true,
134
+ name: true,
135
+ mimeType: true,
136
+ fileSize: true,
137
+ createdAt: true,
138
+ updatedAt: true,
139
+ },
140
+ })
141
+
142
+ if (!icon) {
143
+ res.status(404).json({ error: 'Icon not found' })
144
+ return
145
+ }
146
+
147
+ res.json(icon)
148
+ } catch (error) {
149
+ console.error('Error fetching icon metadata:', error)
150
+ res.status(500).json({ error: 'Failed to fetch icon metadata' })
151
+ }
152
+ },
153
+ )
154
+
155
+ // Get icon binary by name
156
+ router.get(
157
+ `${basePath}/by-name/:name`,
158
+ async (req: Request, res: Response) => {
159
+ try {
160
+ const { name } = req.params
161
+
162
+ const prisma = getDbClient()
163
+ const icon = await prisma.dbAsset.findUnique({
164
+ where: { name },
165
+ select: {
166
+ content: true,
167
+ mimeType: true,
168
+ name: true,
169
+ },
170
+ })
171
+
172
+ if (!icon) {
173
+ res.status(404).json({ error: 'Icon not found' })
174
+ return
175
+ }
176
+
177
+ // Set appropriate headers
178
+ res.setHeader('Content-Type', icon.mimeType)
179
+ res.setHeader('Content-Disposition', `inline; filename="${icon.name}"`)
180
+ res.setHeader('Cache-Control', 'public, max-age=86400') // Cache for 1 day
181
+
182
+ // Send binary content
183
+ res.send(icon.content)
184
+ } catch (error) {
185
+ console.error('Error fetching icon by name:', error)
186
+ res.status(500).json({ error: 'Failed to fetch icon' })
187
+ }
188
+ },
189
+ )
190
+ }
@@ -0,0 +1,157 @@
1
+ import type { TRPCRootObject } from '@trpc/server'
2
+ import { z } from 'zod'
3
+ import { getDbClient } from '../../db'
4
+ import type { EhTrpcContext } from '../../server/ehTrpcContext'
5
+ import { generateChecksum, getImageDimensions } from '../assets/assetUtils'
6
+
7
+ export function createIconRouter(t: TRPCRootObject<EhTrpcContext, {}, {}>) {
8
+ const router = t.router
9
+ const publicProcedure = t.procedure
10
+
11
+ return router({
12
+ list: publicProcedure.query(async () => {
13
+ const prisma = getDbClient()
14
+ return prisma.dbAsset.findMany({
15
+ where: { assetType: 'icon' },
16
+ select: {
17
+ id: true,
18
+ name: true,
19
+ mimeType: true,
20
+ fileSize: true,
21
+ createdAt: true,
22
+ updatedAt: true,
23
+ },
24
+ orderBy: { name: 'asc' },
25
+ })
26
+ }),
27
+
28
+ getOne: publicProcedure
29
+ .input(z.object({ id: z.string() }))
30
+ .query(async ({ input }) => {
31
+ const prisma = getDbClient()
32
+ return prisma.dbAsset.findFirst({
33
+ where: {
34
+ id: input.id,
35
+ assetType: 'icon',
36
+ },
37
+ })
38
+ }),
39
+
40
+ create: publicProcedure
41
+ .input(
42
+ z.object({
43
+ name: z.string().min(1),
44
+ content: z.string(), // base64 encoded binary
45
+ mimeType: z.string(),
46
+ fileSize: z.number().int().positive(),
47
+ }),
48
+ )
49
+ .mutation(async ({ input }) => {
50
+ const prisma = getDbClient()
51
+ // Convert base64 to Buffer
52
+ const buffer = Buffer.from(input.content, 'base64')
53
+
54
+ // Generate checksum and extract dimensions
55
+ const checksum = generateChecksum(buffer)
56
+ const { width, height } = await getImageDimensions(buffer)
57
+
58
+ // Check if asset with same checksum already exists
59
+ const existing = await prisma.dbAsset.findFirst({
60
+ where: { checksum, assetType: 'icon' },
61
+ })
62
+
63
+ if (existing) {
64
+ // Return existing asset if content is identical
65
+ return existing
66
+ }
67
+
68
+ return prisma.dbAsset.create({
69
+ data: {
70
+ name: input.name,
71
+ assetType: 'icon',
72
+ content: new Uint8Array(buffer),
73
+ checksum,
74
+ mimeType: input.mimeType,
75
+ fileSize: input.fileSize,
76
+ width,
77
+ height,
78
+ },
79
+ })
80
+ }),
81
+
82
+ update: publicProcedure
83
+ .input(
84
+ z.object({
85
+ id: z.string(),
86
+ name: z.string().min(1).optional(),
87
+ content: z.string().optional(), // base64 encoded binary
88
+ mimeType: z.string().optional(),
89
+ fileSize: z.number().int().positive().optional(),
90
+ }),
91
+ )
92
+ .mutation(async ({ input }) => {
93
+ const prisma = getDbClient()
94
+ const { id, content, ...rest } = input
95
+
96
+ const data: Record<string, unknown> = { ...rest }
97
+
98
+ if (content) {
99
+ const buffer = Buffer.from(content, 'base64')
100
+ data.content = new Uint8Array(buffer)
101
+ data.checksum = generateChecksum(buffer)
102
+
103
+ const { width, height } = await getImageDimensions(buffer)
104
+ data.width = width
105
+ data.height = height
106
+ }
107
+
108
+ return prisma.dbAsset.update({
109
+ where: { id },
110
+ data,
111
+ })
112
+ }),
113
+
114
+ delete: publicProcedure
115
+ .input(z.object({ id: z.string() }))
116
+ .mutation(async ({ input }) => {
117
+ const prisma = getDbClient()
118
+ return prisma.dbAsset.delete({
119
+ where: { id: input.id },
120
+ })
121
+ }),
122
+
123
+ deleteMany: publicProcedure
124
+ .input(z.object({ ids: z.array(z.string()) }))
125
+ .mutation(async ({ input }) => {
126
+ const prisma = getDbClient()
127
+ return prisma.dbAsset.deleteMany({
128
+ where: {
129
+ id: { in: input.ids },
130
+ assetType: 'icon',
131
+ },
132
+ })
133
+ }),
134
+
135
+ // Serve icon binary content
136
+ getContent: publicProcedure
137
+ .input(z.object({ id: z.string() }))
138
+ .query(async ({ input }) => {
139
+ const prisma = getDbClient()
140
+ const asset = await prisma.dbAsset.findFirst({
141
+ where: {
142
+ id: input.id,
143
+ assetType: 'icon',
144
+ },
145
+ select: { content: true, mimeType: true },
146
+ })
147
+ if (!asset) {
148
+ throw new Error('Icon not found')
149
+ }
150
+ // Return base64 encoded content
151
+ return {
152
+ content: Buffer.from(asset.content).toString('base64'),
153
+ mimeType: asset.mimeType,
154
+ }
155
+ }),
156
+ })
157
+ }
@@ -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 = []
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
+ }
@@ -1,15 +1,37 @@
1
1
  import { initTRPC } from '@trpc/server'
2
2
  import z from 'zod'
3
- import type { EhTrpcContext } from './ehTrpcContext'
3
+
4
+ import { getAppCatalogData } from '../modules/appCatalog/service'
5
+ import type { AppCatalogData, BootstrapConfigData, ResourceJumpsData } from '../types'
6
+
4
7
  import type { TRPCRootObject } from '@trpc/server'
5
8
 
9
+ import { createAppCatalogAdminRouter } from '../modules/appCatalogAdmin/appCatalogAdminRouter.js'
10
+ import { createScreenshotRouter } from '../modules/assets/screenshotRouter.js'
11
+ import type { BetterAuth } from '../modules/auth/auth'
12
+ import { createAuthRouter } from '../modules/auth/authRouter.js'
13
+ import { createIconRouter } from '../modules/icons/iconRouter.js'
14
+ import type { EhTrpcContext } from './ehTrpcContext'
15
+
6
16
  /**
7
17
  * Initialization of tRPC backend
8
18
  * Should be done only once per backend!
9
19
  */
10
20
  const t: TRPCRootObject<EhTrpcContext, {}, {}> = initTRPC
11
21
  .context<EhTrpcContext>()
12
- .create()
22
+ .create({
23
+ errorFormatter({ error, shape }: { error: unknown; shape: unknown }) {
24
+ // Log all tRPC errors to console
25
+ console.error('[tRPC Error]', {
26
+ path: (shape as { data?: { path?: string } }).data?.path,
27
+ code: (error as { code?: string }).code,
28
+ message: (error as { message?: string }).message,
29
+ cause: (error as { cause?: unknown }).cause,
30
+ stack: (error as { stack?: string }).stack,
31
+ })
32
+ return shape
33
+ },
34
+ })
13
35
 
14
36
  /**
15
37
  * Export reusable router and procedure helpers
@@ -18,37 +40,88 @@ const t: TRPCRootObject<EhTrpcContext, {}, {}> = initTRPC
18
40
  const router: typeof t.router = t.router
19
41
  const publicProcedure: typeof t.procedure = t.procedure
20
42
 
21
- export const trpcRouter = router({
22
- bootstrap: publicProcedure.query(async ({ ctx }) => {
23
- return await ctx.companySpecificBackend.getBootstrapData()
24
- }),
43
+ /**
44
+ * Create the main tRPC router with optional auth instance
45
+ * @param auth - Optional Better Auth instance for auth-related queries
46
+ */
47
+ export function createTrpcRouter(auth?: BetterAuth) {
48
+ return router({
49
+ bootstrap: publicProcedure.query(
50
+ async ({ ctx }): Promise<BootstrapConfigData> => {
51
+ return await ctx.companySpecificBackend.getBootstrapData()
52
+ },
53
+ ),
54
+
55
+ availabilityMatrix: publicProcedure.query(async ({ ctx }) => {
56
+ return await ctx.companySpecificBackend.getAvailabilityMatrix()
57
+ }),
58
+
59
+ tryFindRenameRule: publicProcedure
60
+ .input(
61
+ z.object({
62
+ envSlug: z.string().optional(),
63
+ resourceSlug: z.string().optional(),
64
+ }),
65
+ )
66
+ .query(async ({ input, ctx }) => {
67
+ return await ctx.companySpecificBackend.getNameMigrations(input)
68
+ }),
25
69
 
26
- availabilityMatrix: publicProcedure.query(async ({ ctx }) => {
27
- return await ctx.companySpecificBackend.getAvailabilityMatrix()
28
- }),
70
+ resourceJumps: publicProcedure.query(async ({ ctx }) => {
71
+ return await ctx.companySpecificBackend.getResourceJumps()
72
+ }),
29
73
 
30
- tryFindRenameRule: publicProcedure
31
- .input(
32
- z.object({
33
- envSlug: z.string().optional(),
34
- resourceSlug: z.string().optional(),
74
+ resourceJumpsExtended: publicProcedure.query(async ({ ctx }) => {
75
+ return await ctx.companySpecificBackend.getResourceJumpsExtended()
76
+ }),
77
+ resourceJumpBySlugAndEnv: publicProcedure
78
+ .input(
79
+ z.object({
80
+ jumpResourceSlug: z.string(),
81
+ envSlug: z.string(),
82
+ }),
83
+ )
84
+ .query(async ({ input, ctx }) => {
85
+ return filterSingleResourceJump(
86
+ await ctx.companySpecificBackend.getResourceJumps(),
87
+ input.jumpResourceSlug,
88
+ input.envSlug,
89
+ )
35
90
  }),
36
- )
37
- .query(async ({ input, ctx }) => {
38
- return await ctx.companySpecificBackend.getNameMigrations(input)
91
+
92
+ appCatalog: publicProcedure.query(async ({ ctx }): Promise<AppCatalogData> => {
93
+ return await getAppCatalogData(ctx.companySpecificBackend.getApps)
39
94
  }),
40
95
 
41
- resourceJumps: publicProcedure.query(async ({ ctx }) => {
42
- return await ctx.companySpecificBackend.getResourceJumps()
43
- }),
96
+ // Icon management routes
97
+ icon: createIconRouter(t),
98
+
99
+ // Screenshot management routes
100
+ screenshot: createScreenshotRouter(t),
101
+
102
+ // App catalog admin routes
103
+ appCatalogAdmin: createAppCatalogAdminRouter(t),
104
+
105
+ // Auth routes (requires auth instance)
106
+ auth: createAuthRouter(t, auth),
107
+ })
108
+ }
109
+
110
+ function filterSingleResourceJump(
111
+ resourceJumps: ResourceJumpsData,
112
+ jumpResourceSlug: string,
113
+ envSlug: string,
114
+ ): ResourceJumpsData {
115
+ const filteredResourceJump = resourceJumps.resourceJumps.find(
116
+ (item) => item.slug === jumpResourceSlug,
117
+ )
118
+ const filteredEnv = resourceJumps.envs.find((item) => item.slug === envSlug)
44
119
 
45
- // specificEnvs: publicProcedure
46
- // .query(async ({ctx}) => {
47
- // return await ctx.companySpecificBackend.getDeployments({
48
- // envNames: ['dev', 'prod'],
49
- // appNames: ['app1', 'app2'],
50
- // })
51
- // }),
52
- })
120
+ return {
121
+ resourceJumps: filteredResourceJump ? [filteredResourceJump] : [],
122
+ envs: filteredEnv ? [filteredEnv] : [],
123
+ lateResolvableParams: resourceJumps.lateResolvableParams,
124
+ }
125
+ }
53
126
 
54
- export type TRPCRouter = typeof trpcRouter
127
+ export type TRPCRouter = ReturnType<typeof createTrpcRouter>
@@ -1,5 +1,8 @@
1
1
  export interface EhStaticControllerContract {
2
- methods: { getIcon: { method: string; url: string } }
2
+ methods: {
3
+ getIcon: { method: string; url: string }
4
+ getScreenshot: { method: string; url: string }
5
+ }
3
6
  }
4
7
 
5
8
  export const staticControllerContract: EhStaticControllerContract = {
@@ -8,5 +11,9 @@ export const staticControllerContract: EhStaticControllerContract = {
8
11
  method: 'get',
9
12
  url: 'icon/:icon',
10
13
  },
14
+ getScreenshot: {
15
+ method: 'get',
16
+ url: 'screenshot/:id',
17
+ },
11
18
  },
12
19
  }
@@ -15,9 +15,3 @@ export function createEhTrpcContext({
15
15
  companySpecificBackend,
16
16
  }
17
17
  }
18
-
19
- // const createContext = ({
20
- // req,
21
- // res
22
- // }: trpcExpress.CreateExpressContextOptions) => ({}); // no context
23
- // type Context = Awaited<ReturnType<typeof createContext>>;
@@ -1,8 +1,3 @@
1
- import type {
2
- AvailiabilityMatrixData,
3
- BootstrapConfigData,
4
- ResourceJumpsData,
5
- } from '../common/dataRootTypes'
6
1
  import type { EhAppIndexed } from '../common/app/appTypes'
7
2
  import type {
8
3
  EhAppPageIndexed,
@@ -37,8 +32,7 @@ export interface EhBackendAppUIBaseInput {
37
32
  }
38
33
 
39
34
  export interface EhBackendAppUIInput
40
- extends EhBackendAppUIBaseInput,
41
- EhAppUiIndexed {
35
+ extends EhBackendAppUIBaseInput, EhAppUiIndexed {
42
36
  pages: Array<EhBackendPageInput>
43
37
  }
44
38
 
@@ -88,10 +82,3 @@ export interface RenameRule {
88
82
  oldSlug: string
89
83
  targetSlug: string
90
84
  }
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,17 @@
1
+ import type { AppForCatalog } from '../common/appCatalogTypes'
2
+ import type {
3
+ AvailabilityMatrixData,
4
+ BootstrapConfigData,
5
+ ResourceJumpsData,
6
+ ResourceJumpsExtendedData,
7
+ } from '../common/dataRootTypes'
8
+ import type { RenameRule, RenameRuleParams } from './api'
9
+
10
+ export interface EhBackendCompanySpecificBackend {
11
+ getBootstrapData: () => Promise<BootstrapConfigData>
12
+ getAvailabilityMatrix: () => Promise<AvailabilityMatrixData>
13
+ getNameMigrations: (params: RenameRuleParams) => Promise<RenameRule | false>
14
+ getResourceJumps: () => Promise<ResourceJumpsData>
15
+ getResourceJumpsExtended: () => Promise<ResourceJumpsExtendedData>
16
+ getApps?: () => Promise<Array<AppForCatalog>>
17
+ }