@igstack/app-catalog-backend-core 0.1.1-alpha-20260304152616 → 0.3.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 (39) hide show
  1. package/dist/index.d.ts +11318 -1052
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4930 -1466
  4. package/dist/index.js.map +1 -1
  5. package/package.json +10 -7
  6. package/prisma/schema.prisma +2 -2
  7. package/prisma.config.ts +13 -0
  8. package/src/db/client.ts +20 -2
  9. package/src/db/prisma.ts +3 -0
  10. package/src/db/syncAppCatalog.ts +1 -1
  11. package/src/db/tableSyncMagazine.ts +1 -1
  12. package/src/db/tableSyncPrismaAdapter.ts +2 -3
  13. package/src/generated/prisma/browser.ts +59 -0
  14. package/src/generated/prisma/client.ts +83 -0
  15. package/src/generated/prisma/commonInputTypes.ts +658 -0
  16. package/src/generated/prisma/enums.ts +26 -0
  17. package/src/generated/prisma/internal/class.ts +274 -0
  18. package/src/generated/prisma/internal/prismaNamespace.ts +1506 -0
  19. package/src/generated/prisma/internal/prismaNamespaceBrowser.ts +250 -0
  20. package/src/generated/prisma/models/DbAppForCatalog.ts +1490 -0
  21. package/src/generated/prisma/models/DbAppTagDefinition.ts +1199 -0
  22. package/src/generated/prisma/models/DbApprovalMethod.ts +1181 -0
  23. package/src/generated/prisma/models/DbAsset.ts +1394 -0
  24. package/src/generated/prisma/models/account.ts +1632 -0
  25. package/src/generated/prisma/models/session.ts +1447 -0
  26. package/src/generated/prisma/models/user.ts +1562 -0
  27. package/src/generated/prisma/models/verification.ts +1180 -0
  28. package/src/generated/prisma/models.ts +19 -0
  29. package/src/generated/prisma/pjtg.ts +183 -0
  30. package/src/index.ts +0 -27
  31. package/src/middleware/database.ts +13 -2
  32. package/src/middleware/featureRegistry.ts +0 -38
  33. package/src/modules/assets/upsertAsset.ts +1 -1
  34. package/src/server/controller.ts +0 -16
  35. package/src/modules/appCatalogAdmin/appCatalogAdminRouter.ts +0 -187
  36. package/src/modules/appCatalogAdmin/catalogBackupController.ts +0 -213
  37. package/src/modules/approvalMethod/approvalMethodRouter.ts +0 -169
  38. package/src/modules/approvalMethod/slugUtils.ts +0 -17
  39. package/src/modules/approvalMethod/syncApprovalMethods.ts +0 -38
@@ -0,0 +1,19 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
3
+ /* eslint-disable */
4
+ // biome-ignore-all lint: generated file
5
+ // @ts-nocheck
6
+ /*
7
+ * This is a barrel export file for all models and their related types.
8
+ *
9
+ * 🟢 You can import this file directly.
10
+ */
11
+ export type * from './models/user'
12
+ export type * from './models/session'
13
+ export type * from './models/account'
14
+ export type * from './models/verification'
15
+ export type * from './models/DbApprovalMethod'
16
+ export type * from './models/DbAppForCatalog'
17
+ export type * from './models/DbAppTagDefinition'
18
+ export type * from './models/DbAsset'
19
+ export type * from './commonInputTypes'
@@ -0,0 +1,183 @@
1
+ import * as Prisma from './internal/prismaNamespace';
2
+ declare global {
3
+ namespace PrismaJson {
4
+ // This namespace will always be empty. Definitions should be done by
5
+ // you manually, and merged automatically by typescript. Make sure that
6
+ // your declaration merging file is included in your tsconfig.json
7
+ //
8
+ // Learn more: https://github.com/arthurfiorette/prisma-json-types-generator/issues/143
9
+ // Declaration Merging: https://www.typescriptlang.org/docs/handbook/declaration-merging.html
10
+ }
11
+ }
12
+
13
+ /** A filter to be used against nullable List types. */
14
+ export type NullableListFilter<T> = {
15
+ equals?: T | T[] | null;
16
+ has?: T | null;
17
+ hasEvery?: T[];
18
+ hasSome?: T[];
19
+ isEmpty?: boolean;
20
+ };
21
+
22
+ /** A type to determine how to update a json field */
23
+ export type UpdateInput<T> = T extends object ? { [P in keyof T]?: UpdateInput<T[P]> } : T;
24
+
25
+ /** A type to determine how to update a json[] field */
26
+ export type UpdateManyInput<T> = T | T[] | { set?: T[]; push?: T | T[] };
27
+
28
+ /** A type to determine how to create a json[] input */
29
+ export type CreateManyInput<T> = T | T[] | { set?: T[] };
30
+
31
+ /**
32
+ * A typed version of NestedStringFilter, allowing narrowing of string types to
33
+ * discriminated unions.
34
+ */
35
+ export type TypedNestedStringFilter<S extends string> =
36
+ //@ts-ignore - When Prisma.StringFilter is not present, this type is not used
37
+ Prisma.StringFilter & {
38
+ equals?: S;
39
+ in?: S[];
40
+ notIn?: S[];
41
+ not?: TypedNestedStringFilter<S> | S;
42
+ };
43
+
44
+ /**
45
+ * A typed version of StringFilter, allowing narrowing of string types to discriminated
46
+ * unions.
47
+ */
48
+ export type TypedStringFilter<S extends string> =
49
+ //@ts-ignore - When Prisma.StringFilter is not present, this type is not used
50
+ Prisma.StringFilter & {
51
+ equals?: S;
52
+ in?: S[];
53
+ notIn?: S[];
54
+ not?: TypedNestedStringFilter<S> | S;
55
+ };
56
+
57
+ /**
58
+ * A typed version of NestedStringNullableFilter, allowing narrowing of string types to
59
+ * discriminated unions.
60
+ */
61
+ export type TypedNestedStringNullableFilter<S extends string> =
62
+ //@ts-ignore - When Prisma.StringNullableFilter is not present, this type is not used
63
+ Prisma.StringNullableFilter & {
64
+ equals?: S | null;
65
+ in?: S[] | null;
66
+ notIn?: S[] | null;
67
+ not?: TypedNestedStringNullableFilter<S> | S | null;
68
+ };
69
+
70
+ /**
71
+ * A typed version of StringNullableFilter, allowing narrowing of string types to
72
+ * discriminated unions.
73
+ */
74
+ export type TypedStringNullableFilter<S extends string> =
75
+ //@ts-ignore - When Prisma.StringNullableFilter is not present, this type is not used
76
+ Prisma.StringNullableFilter & {
77
+ equals?: S | null;
78
+ in?: S[] | null;
79
+ notIn?: S[] | null;
80
+ not?: TypedNestedStringNullableFilter<S> | S | null;
81
+ };
82
+
83
+ /**
84
+ * A typed version of NestedStringWithAggregatesFilter, allowing narrowing of string types
85
+ * to discriminated unions.
86
+ */
87
+ export type TypedNestedStringWithAggregatesFilter<S extends string> =
88
+ //@ts-ignore - When Prisma.NestedStringWithAggregatesFilter is not present, this type is not used
89
+ Prisma.NestedStringWithAggregatesFilter & {
90
+ equals?: S;
91
+ in?: S[];
92
+ notIn?: S[];
93
+ not?: TypedNestedStringWithAggregatesFilter<S> | S;
94
+ };
95
+
96
+ /**
97
+ * A typed version of StringWithAggregatesFilter, allowing narrowing of string types to
98
+ * discriminated unions.
99
+ */
100
+ export type TypedStringWithAggregatesFilter<S extends string> =
101
+ //@ts-ignore - When Prisma.StringWithAggregatesFilter is not present, this type is not used
102
+ Prisma.StringWithAggregatesFilter & {
103
+ equals?: S;
104
+ in?: S[];
105
+ notIn?: S[];
106
+ not?: TypedNestedStringWithAggregatesFilter<S> | S;
107
+ };
108
+
109
+ /**
110
+ * A typed version of NestedStringNullableWithAggregatesFilter, allowing narrowing of
111
+ * string types to discriminated unions.
112
+ */
113
+ export type TypedNestedStringNullableWithAggregatesFilter<S extends string> =
114
+ //@ts-ignore - When Prisma.NestedStringNullableWithAggregatesFilter is not present, this type is not used
115
+ Prisma.NestedStringNullableWithAggregatesFilter & {
116
+ equals?: S | null;
117
+ in?: S[] | null;
118
+ notIn?: S[] | null;
119
+ not?: TypedNestedStringNullableWithAggregatesFilter<S> | S | null;
120
+ };
121
+
122
+ /**
123
+ * A typed version of StringNullableWithAggregatesFilter, allowing narrowing of string
124
+ * types to discriminated unions.
125
+ */
126
+ export type TypedStringNullableWithAggregatesFilter<S extends string> =
127
+ //@ts-ignore - When Prisma.StringNullableWithAggregatesFilter is not present, this type is not used
128
+ Prisma.StringNullableWithAggregatesFilter & {
129
+ equals?: S | null;
130
+ in?: S[] | null;
131
+ notIn?: S[] | null;
132
+ not?: TypedNestedStringNullableWithAggregatesFilter<S> | S | null;
133
+ };
134
+
135
+ /**
136
+ * A typed version of StringFieldUpdateOperationsInput, allowing narrowing of string types
137
+ * to discriminated unions.
138
+ */
139
+ export type TypedStringFieldUpdateOperationsInput<S extends string> =
140
+ //@ts-ignore - When Prisma.StringFieldUpdateOperationsInput is not present, this type is not used
141
+ Prisma.StringFieldUpdateOperationsInput & {
142
+ set?: S;
143
+ };
144
+
145
+ /**
146
+ * A typed version of NullableStringFieldUpdateOperationsInput, allowing narrowing of
147
+ * string types to discriminated unions.
148
+ */
149
+ export type TypedNullableStringFieldUpdateOperationsInput<S extends string> =
150
+ //@ts-ignore - When Prisma.NullableStringFieldUpdateOperationsInput is not present, this type is not used
151
+ Prisma.NullableStringFieldUpdateOperationsInput & {
152
+ set?: S | null;
153
+ };
154
+
155
+ /**
156
+ * A typed version of StringNullableListFilter, allowing narrowing of string types to
157
+ * discriminated unions.
158
+ */
159
+ export type TypedStringNullableListFilter<S extends string> =
160
+ //@ts-ignore - When Prisma.StringNullableListFilter is not present, this type is not used
161
+ Prisma.StringNullableListFilter & {
162
+ equals?: S[] | null;
163
+ has?: S | null;
164
+ hasEvery?: S[];
165
+ hasSome?: S[];
166
+ };
167
+
168
+ /**
169
+ * A typed version of the input type to update a string[] field, allowing narrowing of
170
+ * string types to discriminated unions.
171
+ */
172
+ export type UpdateStringArrayInput<S extends string> = {
173
+ set?: S[];
174
+ push?: S | S[];
175
+ };
176
+
177
+ /**
178
+ * A typed version of the input type to create a string[] field, allowing narrowing of
179
+ * string types to discriminated unions.
180
+ */
181
+ export type CreateStringArrayInput<S extends string> = {
182
+ set?: S[];
183
+ };
package/src/index.ts CHANGED
@@ -39,20 +39,6 @@ export {
39
39
  type UserWithGroups,
40
40
  } from './modules/auth/authorizationUtils'
41
41
 
42
- // Admin
43
- export {
44
- createAdminChatHandler,
45
- tool,
46
- type AdminChatHandlerOptions,
47
- } from './modules/admin/chat/createAdminChatHandler'
48
-
49
- export {
50
- createDatabaseTools,
51
- createPrismaDatabaseClient,
52
- DEFAULT_ADMIN_SYSTEM_PROMPT,
53
- type DatabaseClient,
54
- } from './modules/admin/chat/createDatabaseTools'
55
-
56
42
  // Icon management
57
43
  export {
58
44
  registerIconRestController,
@@ -77,26 +63,14 @@ export {
77
63
  type ScreenshotRestControllerConfig,
78
64
  } from './modules/assets/screenshotRestController'
79
65
 
80
- export { createScreenshotRouter } from './modules/assets/screenshotRouter'
81
-
82
66
  export { syncAssets, type SyncAssetsConfig } from './modules/assets/syncAssets'
83
67
 
84
- // App Catalog Admin
85
- export { createAppCatalogAdminRouter } from './modules/appCatalogAdmin/appCatalogAdminRouter'
86
-
87
68
  // App Catalog utilities
88
69
  export {
89
70
  checkAllLinks,
90
71
  printLinkCheckReport,
91
72
  } from './modules/appCatalog/checkLinks'
92
73
 
93
- // Approval Methods
94
- export { createApprovalMethodRouter } from './modules/approvalMethod/approvalMethodRouter'
95
- export {
96
- syncApprovalMethods,
97
- type ApprovalMethodSyncInput,
98
- } from './modules/approvalMethod/syncApprovalMethods'
99
-
100
74
  // Database utilities
101
75
  export {
102
76
  connectDb,
@@ -123,7 +97,6 @@ export {
123
97
  injectCustomScripts,
124
98
  type EhDatabaseConfig,
125
99
  type EhAuthConfig,
126
- type EhAdminChatConfig,
127
100
  type EhFeatureToggles,
128
101
  type EhBackendProvider,
129
102
  type EhLifecycleHooks,
@@ -1,4 +1,6 @@
1
- import { PrismaClient } from '@prisma/client'
1
+ import { PrismaClient } from '../db/prisma'
2
+ import { PrismaPg } from '@prisma/adapter-pg'
3
+ import pg from 'pg'
2
4
  import type { EhDatabaseConfig } from './types'
3
5
  import { setDbClient } from '../db/client'
4
6
 
@@ -20,6 +22,7 @@ function formatConnectionUrl(config: EhDatabaseConfig): string {
20
22
  */
21
23
  export class EhDatabaseManager {
22
24
  private client: PrismaClient | null = null
25
+ private pool: pg.Pool | null = null
23
26
  private config: EhDatabaseConfig
24
27
 
25
28
  constructor(config: EhDatabaseConfig) {
@@ -34,8 +37,12 @@ export class EhDatabaseManager {
34
37
  if (!this.client) {
35
38
  const datasourceUrl = formatConnectionUrl(this.config)
36
39
 
40
+ // Prisma 7 with adapter: Create pg pool and wrap with adapter
41
+ this.pool = new pg.Pool({ connectionString: datasourceUrl })
42
+ const adapter = new PrismaPg(this.pool)
43
+
37
44
  this.client = new PrismaClient({
38
- datasourceUrl,
45
+ adapter,
39
46
  log:
40
47
  process.env.NODE_ENV === 'development'
41
48
  ? ['warn', 'error']
@@ -58,5 +65,9 @@ export class EhDatabaseManager {
58
65
  await this.client.$disconnect()
59
66
  this.client = null
60
67
  }
68
+ if (this.pool) {
69
+ await this.pool.end()
70
+ this.pool = null
71
+ }
61
72
  }
62
73
  }
@@ -8,16 +8,7 @@ import type {
8
8
  import { registerIconRestController } from '../modules/icons/iconRestController'
9
9
  import { registerAssetRestController } from '../modules/assets/assetRestController'
10
10
  import { registerScreenshotRestController } from '../modules/assets/screenshotRestController'
11
- import { createAdminChatHandler } from '../modules/admin/chat/createAdminChatHandler'
12
11
  import { getAssetByName } from '../modules/icons/iconService'
13
- import {
14
- exportAsset,
15
- exportCatalog,
16
- importAsset,
17
- importCatalog,
18
- listAssets,
19
- } from '../modules/appCatalogAdmin/catalogBackupController'
20
- import multer from 'multer'
21
12
  import { createMockSessionResponse } from '../modules/auth/devMockUserUtils'
22
13
 
23
14
  interface FeatureRegistration {
@@ -70,18 +61,6 @@ const FEATURES: Array<FeatureRegistration> = [
70
61
  router.all(`${basePath}/auth/{*any}`, authHandler)
71
62
  },
72
63
  },
73
- {
74
- name: 'adminChat',
75
- defaultEnabled: false, // Only enabled if adminChat config is provided
76
- register: (router, options) => {
77
- if (options.adminChat) {
78
- router.post(
79
- `${options.basePath}/admin/chat`,
80
- createAdminChatHandler(options.adminChat),
81
- )
82
- }
83
- },
84
- },
85
64
  {
86
65
  name: 'legacyIconEndpoint',
87
66
  defaultEnabled: false,
@@ -143,29 +122,12 @@ export function registerFeatures(
143
122
  basePath: `${basePath}/screenshots`,
144
123
  })
145
124
 
146
- // Catalog backup/restore
147
- const upload = multer({ storage: multer.memoryStorage() })
148
- router.get(`${basePath}/catalog/backup/export`, exportCatalog)
149
- router.post(`${basePath}/catalog/backup/import`, importCatalog)
150
- router.get(`${basePath}/catalog/backup/assets`, listAssets)
151
- router.get(`${basePath}/catalog/backup/assets/:name`, exportAsset)
152
- router.post(
153
- `${basePath}/catalog/backup/assets`,
154
- upload.single('file'),
155
- importAsset,
156
- )
157
-
158
125
  // Optional toggleable features
159
126
  const toggles = options.features || {}
160
127
 
161
128
  for (const feature of FEATURES) {
162
129
  const isEnabled = toggles[feature.name] ?? feature.defaultEnabled
163
130
 
164
- // Special case: adminChat is only enabled if config is provided
165
- if (feature.name === 'adminChat' && !options.adminChat) {
166
- continue
167
- }
168
-
169
131
  if (isEnabled) {
170
132
  feature.register(router, options, context)
171
133
  }
@@ -1,5 +1,5 @@
1
1
  import { parseAssetMeta } from './assetUtils'
2
- import type { AssetType, PrismaClient } from '@prisma/client'
2
+ import type { AssetType, PrismaClient } from '../../db/prisma'
3
3
 
4
4
  export interface UpsertAssetParams {
5
5
  prisma: PrismaClient
@@ -1,12 +1,8 @@
1
1
  import { getAppCatalogData } from '../modules/appCatalog/service'
2
2
  import type { AppCatalogData } from '../types'
3
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
4
  import type { BetterAuth } from '../modules/auth/auth'
8
5
  import { createAuthRouter } from '../modules/auth/authRouter.js'
9
- import { createIconRouter } from '../modules/icons/iconRouter.js'
10
6
  import { publicProcedure, router, t } from './trpcSetup'
11
7
 
12
8
  /**
@@ -32,18 +28,6 @@ export function createTrpcRouter(auth?: BetterAuth) {
32
28
  },
33
29
  ),
34
30
 
35
- // Icon management routes
36
- icon: createIconRouter(),
37
-
38
- // Screenshot management routes
39
- screenshot: createScreenshotRouter(),
40
-
41
- // App catalog admin routes
42
- appCatalogAdmin: createAppCatalogAdminRouter(),
43
-
44
- // Approval method routes
45
- approvalMethod: createApprovalMethodRouter(),
46
-
47
31
  // Auth routes (requires auth instance)
48
32
  auth: createAuthRouter(t, auth),
49
33
  })
@@ -1,187 +0,0 @@
1
- import { z } from 'zod'
2
- import { getDbClient } from '../../db'
3
- import { adminProcedure, router } from '../../server/trpcSetup'
4
- import type { AppAccessRequest } from '../../types'
5
-
6
- // Zod schema for access method (simplified for now - you can expand this)
7
- const AccessMethodSchema = z
8
- .object({
9
- type: z.enum([
10
- 'bot',
11
- 'ticketing',
12
- 'email',
13
- 'self-service',
14
- 'documentation',
15
- 'manual',
16
- ]),
17
- })
18
- .loose()
19
-
20
- const AppLinkSchema = z.object({
21
- displayName: z.string().optional(),
22
- url: z.url(),
23
- })
24
-
25
- // New AppAccessRequest schema
26
- const AppRoleSchema = z.object({
27
- name: z.string(),
28
- description: z.string().optional(),
29
- })
30
-
31
- const ApproverContactSchema = z.object({
32
- displayName: z.string(),
33
- contact: z.string().optional(),
34
- })
35
-
36
- const ApprovalUrlSchema = z.object({
37
- label: z.string().optional(),
38
- url: z.url(),
39
- })
40
-
41
- const AppAccessRequestSchema = z.object({
42
- approvalMethodId: z.string(),
43
- comments: z.string().optional(),
44
- requestPrompt: z.string().optional(),
45
- postApprovalInstructions: z.string().optional(),
46
- roles: z.array(AppRoleSchema).optional(),
47
- approvers: z.array(ApproverContactSchema).optional(),
48
- urls: z.array(ApprovalUrlSchema).optional(),
49
- whoToReachOut: z.string().optional(),
50
- })
51
-
52
- const CreateAppForCatalogSchema = z.object({
53
- slug: z
54
- .string()
55
- .min(1)
56
- .regex(/^[a-z0-9-]+$/, 'Slug must be lowercase alphanumeric with hyphens'),
57
- displayName: z.string().min(1),
58
- description: z.string(),
59
- access: AccessMethodSchema.optional(),
60
- teams: z.array(z.string()).optional(),
61
- accessRequest: AppAccessRequestSchema.optional(),
62
- notes: z.string().optional(),
63
- tags: z.array(z.string()).optional(),
64
- appUrl: z.url().optional(),
65
- links: z.array(AppLinkSchema).optional(),
66
- iconName: z.string().optional(),
67
- screenshotIds: z.array(z.string()).optional(),
68
- })
69
-
70
- const UpdateAppForCatalogSchema = CreateAppForCatalogSchema.partial().extend({
71
- id: z.string(),
72
- })
73
-
74
- export function createAppCatalogAdminRouter() {
75
- const prisma = getDbClient()
76
- return router({
77
- list: adminProcedure.query(async () => {
78
- return prisma.dbAppForCatalog.findMany({
79
- orderBy: { displayName: 'asc' },
80
- })
81
- }),
82
-
83
- getById: adminProcedure
84
- .input(z.object({ id: z.string() }))
85
- .query(async ({ input }) => {
86
- return prisma.dbAppForCatalog.findUnique({
87
- where: { id: input.id },
88
- })
89
- }),
90
-
91
- getBySlug: adminProcedure
92
- .input(z.object({ slug: z.string() }))
93
- .query(async ({ input }) => {
94
- return prisma.dbAppForCatalog.findUnique({
95
- where: { slug: input.slug },
96
- })
97
- }),
98
-
99
- create: adminProcedure
100
- .input(CreateAppForCatalogSchema)
101
- .mutation(async ({ input }) => {
102
- // Type assertion needed because Zod's passthrough() creates index signatures
103
- // that don't structurally match Prisma's typed JSON fields.
104
- // This is safe because Zod validates the input shape.
105
- return prisma.dbAppForCatalog.create({
106
- data: {
107
- slug: input.slug,
108
- displayName: input.displayName,
109
- description: input.description,
110
- teams: input.teams ?? [],
111
- accessRequest: input.accessRequest as AppAccessRequest | undefined,
112
- notes: input.notes,
113
- tags: input.tags ?? [],
114
- appUrl: input.appUrl,
115
- links: input.links as Array<{ displayName?: string; url: string }>,
116
- iconName: input.iconName,
117
- screenshotIds: input.screenshotIds ?? [],
118
- },
119
- })
120
- }),
121
-
122
- update: adminProcedure
123
- .input(UpdateAppForCatalogSchema)
124
- .mutation(async ({ input }) => {
125
- const { id, ...updateData } = input
126
-
127
- // Type assertion needed because Zod's passthrough() creates index signatures
128
- return prisma.dbAppForCatalog.update({
129
- where: { id },
130
- data: {
131
- ...(updateData.slug !== undefined && { slug: updateData.slug }),
132
- ...(updateData.displayName !== undefined && {
133
- displayName: updateData.displayName,
134
- }),
135
- ...(updateData.description !== undefined && {
136
- description: updateData.description,
137
- }),
138
- ...(updateData.teams !== undefined && { teams: updateData.teams }),
139
- ...(updateData.accessRequest !== undefined && {
140
- accessRequest: updateData.accessRequest as
141
- | AppAccessRequest
142
- | undefined,
143
- }),
144
- ...(updateData.notes !== undefined && { notes: updateData.notes }),
145
- ...(updateData.tags !== undefined && { tags: updateData.tags }),
146
- ...(updateData.appUrl !== undefined && {
147
- appUrl: updateData.appUrl,
148
- }),
149
- ...(updateData.links !== undefined && {
150
- links: updateData.links as Array<{
151
- displayName?: string
152
- url: string
153
- }>,
154
- }),
155
- ...(updateData.iconName !== undefined && {
156
- iconName: updateData.iconName,
157
- }),
158
- ...(updateData.screenshotIds !== undefined && {
159
- screenshotIds: updateData.screenshotIds,
160
- }),
161
- },
162
- })
163
- }),
164
-
165
- updateScreenshots: adminProcedure
166
- .input(
167
- z.object({
168
- id: z.string(),
169
- screenshotIds: z.array(z.string()),
170
- }),
171
- )
172
- .mutation(async ({ input }) => {
173
- return prisma.dbAppForCatalog.update({
174
- where: { id: input.id },
175
- data: { screenshotIds: input.screenshotIds },
176
- })
177
- }),
178
-
179
- delete: adminProcedure
180
- .input(z.object({ id: z.string() }))
181
- .mutation(async ({ input }) => {
182
- return prisma.dbAppForCatalog.delete({
183
- where: { id: input.id },
184
- })
185
- }),
186
- })
187
- }