@igstack/app-catalog-backend-core 6.10.3 → 6.11.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 (104) hide show
  1. package/dist/db/syncAppCatalog.mjs +1 -1
  2. package/dist/generated/prisma/client.d.mts +1 -1
  3. package/dist/generated/prisma/client.mjs.map +1 -1
  4. package/dist/generated/prisma/commonInputTypes.d.mts +33 -3
  5. package/dist/generated/prisma/commonInputTypes.d.mts.map +1 -1
  6. package/dist/generated/prisma/enums.d.mts +6 -1
  7. package/dist/generated/prisma/enums.d.mts.map +1 -1
  8. package/dist/generated/prisma/internal/class.d.mts +84 -0
  9. package/dist/generated/prisma/internal/class.d.mts.map +1 -1
  10. package/dist/generated/prisma/internal/class.mjs +4 -4
  11. package/dist/generated/prisma/internal/class.mjs.map +1 -1
  12. package/dist/generated/prisma/internal/prismaNamespace.d.mts +617 -4
  13. package/dist/generated/prisma/internal/prismaNamespace.d.mts.map +1 -1
  14. package/dist/generated/prisma/models/DbCommunityTool.d.mts +2852 -0
  15. package/dist/generated/prisma/models/DbCommunityTool.d.mts.map +1 -0
  16. package/dist/generated/prisma/models/DbCommunityToolLike.d.mts +1102 -0
  17. package/dist/generated/prisma/models/DbCommunityToolLike.d.mts.map +1 -0
  18. package/dist/generated/prisma/models/DbCommunityToolNamedOwner.d.mts +1034 -0
  19. package/dist/generated/prisma/models/DbCommunityToolNamedOwner.d.mts.map +1 -0
  20. package/dist/generated/prisma/models/DbCommunityToolOwner.d.mts +1034 -0
  21. package/dist/generated/prisma/models/DbCommunityToolOwner.d.mts.map +1 -0
  22. package/dist/generated/prisma/models/DbCommunityToolPin.d.mts +1110 -0
  23. package/dist/generated/prisma/models/DbCommunityToolPin.d.mts.map +1 -0
  24. package/dist/generated/prisma/models/DbCommunityToolTag.d.mts +1073 -0
  25. package/dist/generated/prisma/models/DbCommunityToolTag.d.mts.map +1 -0
  26. package/dist/generated/prisma/models/DbCommunityToolView.d.mts +1149 -0
  27. package/dist/generated/prisma/models/DbCommunityToolView.d.mts.map +1 -0
  28. package/dist/generated/prisma/models/DbFeedback.d.mts +361 -2
  29. package/dist/generated/prisma/models/DbFeedback.d.mts.map +1 -1
  30. package/dist/generated/prisma/models.d.mts +9 -2
  31. package/dist/index.d.mts +5 -2
  32. package/dist/index.mjs +3 -1
  33. package/dist/middleware/createAcMiddleware.d.mts.map +1 -1
  34. package/dist/middleware/createAcMiddleware.mjs +15 -1
  35. package/dist/middleware/createAcMiddleware.mjs.map +1 -1
  36. package/dist/middleware/database.d.mts +1 -1
  37. package/dist/middleware/types.d.mts +20 -1
  38. package/dist/middleware/types.d.mts.map +1 -1
  39. package/dist/modules/communityTools/capture.d.mts +27 -0
  40. package/dist/modules/communityTools/capture.d.mts.map +1 -0
  41. package/dist/modules/communityTools/capture.mjs +192 -0
  42. package/dist/modules/communityTools/capture.mjs.map +1 -0
  43. package/dist/modules/communityTools/healthJob.mjs +132 -0
  44. package/dist/modules/communityTools/healthJob.mjs.map +1 -0
  45. package/dist/modules/communityTools/router.d.mts +150 -0
  46. package/dist/modules/communityTools/router.d.mts.map +1 -0
  47. package/dist/modules/communityTools/router.mjs +91 -0
  48. package/dist/modules/communityTools/router.mjs.map +1 -0
  49. package/dist/modules/communityTools/service.mjs +252 -0
  50. package/dist/modules/communityTools/service.mjs.map +1 -0
  51. package/dist/modules/communityTools/toView.mjs +81 -0
  52. package/dist/modules/communityTools/toView.mjs.map +1 -0
  53. package/dist/modules/communityTools/writeService.d.mts +55 -0
  54. package/dist/modules/communityTools/writeService.d.mts.map +1 -0
  55. package/dist/modules/communityTools/writeService.mjs +280 -0
  56. package/dist/modules/communityTools/writeService.mjs.map +1 -0
  57. package/dist/modules/feedback/feedbackRouter.d.mts +3 -0
  58. package/dist/modules/feedback/feedbackRouter.mjs +6 -2
  59. package/dist/modules/feedback/feedbackRouter.mjs.map +1 -1
  60. package/dist/modules/feedback/service.d.mts +3 -0
  61. package/dist/modules/feedback/service.d.mts.map +1 -1
  62. package/dist/modules/feedback/service.mjs +50 -17
  63. package/dist/modules/feedback/service.mjs.map +1 -1
  64. package/dist/server/controller.d.mts +143 -0
  65. package/dist/server/controller.d.mts.map +1 -1
  66. package/dist/server/controller.mjs +2 -0
  67. package/dist/server/controller.mjs.map +1 -1
  68. package/dist/server/trpcSetup.mjs +1 -1
  69. package/package.json +12 -5
  70. package/prisma/schema.prisma +161 -0
  71. package/src/__tests__/communityTools.test.ts +781 -0
  72. package/src/__tests__/communityToolsCapture.test.ts +319 -0
  73. package/src/__tests__/communityToolsHealth.test.ts +154 -0
  74. package/src/__tests__/communityToolsRouter.test.ts +58 -0
  75. package/src/__tests__/communityToolsWrite.test.ts +561 -0
  76. package/src/__tests__/feedbackService.test.ts +160 -0
  77. package/src/generated/prisma/browser.ts +35 -0
  78. package/src/generated/prisma/client.ts +35 -0
  79. package/src/generated/prisma/commonInputTypes.ts +34 -0
  80. package/src/generated/prisma/enums.ts +8 -0
  81. package/src/generated/prisma/internal/class.ts +74 -4
  82. package/src/generated/prisma/internal/prismaNamespace.ts +635 -2
  83. package/src/generated/prisma/internal/prismaNamespaceBrowser.ts +95 -1
  84. package/src/generated/prisma/models/DbCommunityTool.ts +3135 -0
  85. package/src/generated/prisma/models/DbCommunityToolLike.ts +1313 -0
  86. package/src/generated/prisma/models/DbCommunityToolNamedOwner.ts +1243 -0
  87. package/src/generated/prisma/models/DbCommunityToolOwner.ts +1243 -0
  88. package/src/generated/prisma/models/DbCommunityToolPin.ts +1325 -0
  89. package/src/generated/prisma/models/DbCommunityToolTag.ts +1283 -0
  90. package/src/generated/prisma/models/DbCommunityToolView.ts +1361 -0
  91. package/src/generated/prisma/models/DbFeedback.ts +379 -1
  92. package/src/generated/prisma/models.ts +7 -0
  93. package/src/index.ts +16 -0
  94. package/src/middleware/createAcMiddleware.ts +20 -0
  95. package/src/middleware/types.ts +21 -0
  96. package/src/modules/communityTools/capture.ts +332 -0
  97. package/src/modules/communityTools/healthJob.ts +191 -0
  98. package/src/modules/communityTools/router.ts +172 -0
  99. package/src/modules/communityTools/service.ts +380 -0
  100. package/src/modules/communityTools/toView.ts +112 -0
  101. package/src/modules/communityTools/writeService.ts +408 -0
  102. package/src/modules/feedback/feedbackRouter.ts +20 -6
  103. package/src/modules/feedback/service.ts +68 -12
  104. package/src/server/controller.ts +8 -1
@@ -1,8 +1,11 @@
1
1
  import { AppCatalogData, Resource } from "../types/common/appCatalogTypes.mjs";
2
2
  import { AcTrpcContext } from "./acTrpcContext.mjs";
3
3
  import { BetterAuth } from "../modules/auth/auth.mjs";
4
+ import { CommunityToolsOptions } from "../middleware/types.mjs";
4
5
  import { FeedbackList, FeedbackView } from "../modules/feedback/service.mjs";
6
+ import { ToolPreview } from "../modules/communityTools/writeService.mjs";
5
7
  import * as _trpc_server0 from "@trpc/server";
8
+ import * as _igstack_app_catalog_shared_core0 from "@igstack/app-catalog-shared-core";
6
9
  import * as better_auth0 from "better-auth";
7
10
 
8
11
  //#region src/server/controller.d.ts
@@ -12,6 +15,7 @@ import * as better_auth0 from "better-auth";
12
15
  */
13
16
  declare function createTrpcRouter(auth?: BetterAuth, options?: {
14
17
  devLoginEnabled?: boolean;
18
+ communityTools?: CommunityToolsOptions;
15
19
  }): _trpc_server0.TRPCBuiltRouter<{
16
20
  ctx: AcTrpcContext;
17
21
  meta: object;
@@ -63,6 +67,8 @@ declare function createTrpcRouter(auth?: BetterAuth, options?: {
63
67
  list: _trpc_server0.TRPCQueryProcedure<{
64
68
  input: {
65
69
  resourceSlug: string;
70
+ } | {
71
+ communityToolSlug: string;
66
72
  };
67
73
  output: FeedbackList;
68
74
  meta: object;
@@ -75,6 +81,7 @@ declare function createTrpcRouter(auth?: BetterAuth, options?: {
75
81
  add: _trpc_server0.TRPCMutationProcedure<{
76
82
  input: {
77
83
  resourceSlug?: string | undefined;
84
+ communityToolSlug?: string | undefined;
78
85
  subject?: string | undefined;
79
86
  body?: string | undefined;
80
87
  attachmentIds?: string[] | undefined;
@@ -100,6 +107,142 @@ declare function createTrpcRouter(auth?: BetterAuth, options?: {
100
107
  meta: object;
101
108
  }>;
102
109
  }>>;
110
+ communityTools: _trpc_server0.TRPCBuiltRouter<{
111
+ ctx: AcTrpcContext;
112
+ meta: object;
113
+ errorShape: _trpc_server0.TRPCDefaultErrorShape;
114
+ transformer: false;
115
+ }, _trpc_server0.TRPCDecorateCreateRouterOptions<{
116
+ config: _trpc_server0.TRPCQueryProcedure<{
117
+ input: void;
118
+ output: {
119
+ enabled: boolean;
120
+ };
121
+ meta: object;
122
+ }>;
123
+ list: _trpc_server0.TRPCQueryProcedure<{
124
+ input: void;
125
+ output: _igstack_app_catalog_shared_core0.CommunityTool[];
126
+ meta: object;
127
+ }>;
128
+ countByApp: _trpc_server0.TRPCQueryProcedure<{
129
+ input: void;
130
+ output: Record<string, number>;
131
+ meta: object;
132
+ }>;
133
+ get: _trpc_server0.TRPCQueryProcedure<{
134
+ input: {
135
+ slug: string;
136
+ };
137
+ output: _igstack_app_catalog_shared_core0.CommunityTool;
138
+ meta: object;
139
+ }>;
140
+ recordView: _trpc_server0.TRPCMutationProcedure<{
141
+ input: {
142
+ slug: string;
143
+ };
144
+ output: {
145
+ views30d: number;
146
+ viewsAll: number;
147
+ };
148
+ meta: object;
149
+ }>;
150
+ pins: _trpc_server0.TRPCQueryProcedure<{
151
+ input: void;
152
+ output: _igstack_app_catalog_shared_core0.CommunityTool[];
153
+ meta: object;
154
+ }>;
155
+ pin: _trpc_server0.TRPCMutationProcedure<{
156
+ input: {
157
+ slug: string;
158
+ };
159
+ output: void;
160
+ meta: object;
161
+ }>;
162
+ like: _trpc_server0.TRPCMutationProcedure<{
163
+ input: {
164
+ slug: string;
165
+ };
166
+ output: void;
167
+ meta: object;
168
+ }>;
169
+ unlike: _trpc_server0.TRPCMutationProcedure<{
170
+ input: {
171
+ slug: string;
172
+ };
173
+ output: void;
174
+ meta: object;
175
+ }>;
176
+ unpin: _trpc_server0.TRPCMutationProcedure<{
177
+ input: {
178
+ slug: string;
179
+ };
180
+ output: void;
181
+ meta: object;
182
+ }>;
183
+ reorderPins: _trpc_server0.TRPCMutationProcedure<{
184
+ input: {
185
+ slugs: string[];
186
+ };
187
+ output: void;
188
+ meta: object;
189
+ }>;
190
+ preview: _trpc_server0.TRPCMutationProcedure<{
191
+ input: {
192
+ url: string;
193
+ };
194
+ output: ToolPreview;
195
+ meta: object;
196
+ }>;
197
+ add: _trpc_server0.TRPCMutationProcedure<{
198
+ input: {
199
+ url: string;
200
+ name: string;
201
+ summary: string;
202
+ descriptionMd: string;
203
+ ownerSlugs: string[];
204
+ tags: {
205
+ kind: "app" | "topic";
206
+ value: string;
207
+ }[];
208
+ ownerNames?: string[] | undefined;
209
+ };
210
+ output: _igstack_app_catalog_shared_core0.CommunityTool;
211
+ meta: object;
212
+ }>;
213
+ edit: _trpc_server0.TRPCMutationProcedure<{
214
+ input: {
215
+ url: string;
216
+ name: string;
217
+ summary: string;
218
+ descriptionMd: string;
219
+ ownerSlugs: string[];
220
+ tags: {
221
+ kind: "app" | "topic";
222
+ value: string;
223
+ }[];
224
+ slug: string;
225
+ ownerNames?: string[] | undefined;
226
+ };
227
+ output: _igstack_app_catalog_shared_core0.CommunityTool;
228
+ meta: object;
229
+ }>;
230
+ archive: _trpc_server0.TRPCMutationProcedure<{
231
+ input: {
232
+ slug: string;
233
+ reason: string;
234
+ };
235
+ output: void;
236
+ meta: object;
237
+ }>;
238
+ approve: _trpc_server0.TRPCMutationProcedure<{
239
+ input: {
240
+ slug: string;
241
+ };
242
+ output: void;
243
+ meta: object;
244
+ }>;
245
+ }>>;
103
246
  auth: _trpc_server0.TRPCBuiltRouter<{
104
247
  ctx: AcTrpcContext;
105
248
  meta: {};
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.mts","names":[],"sources":["../../src/server/controller.ts"],"mappings":";;;;;;;;;;;;iBAmCgB,gBAAA,CACd,IAAA,GAAO,UAAA,EACP,OAAA;EAAY,eAAA;AAAA,kBAA2B,eAAA;OADtB,aAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCP,UAAA,GAAa,UAAA,QAAkB,gBAAA"}
1
+ {"version":3,"file":"controller.d.mts","names":[],"sources":["../../src/server/controller.ts"],"mappings":";;;;;;;;;;;;;;;iBAqCgB,gBAAA,CACd,IAAA,GAAO,UAAA,EACP,OAAA;EACE,eAAA;EACA,cAAA,GAAiB,qBAAA;AAAA,kBAClB,eAAA;OADuC,aAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0C9B,UAAA,GAAa,UAAA,QAAkB,gBAAA"}
@@ -2,6 +2,7 @@ import { getAppCatalogData, updateAiMemory, updateApp } from "../modules/appCata
2
2
  import { createAuthRouter } from "../modules/auth/authRouter.mjs";
3
3
  import { publicProcedure, router, t } from "./trpcSetup.mjs";
4
4
  import { createFeedbackRouter } from "../modules/feedback/feedbackRouter.mjs";
5
+ import { createCommunityToolsRouter } from "../modules/communityTools/router.mjs";
5
6
  import { z } from "zod";
6
7
 
7
8
  //#region src/server/controller.ts
@@ -43,6 +44,7 @@ function createTrpcRouter(auth, options) {
43
44
  })
44
45
  }),
45
46
  feedback: createFeedbackRouter(),
47
+ communityTools: createCommunityToolsRouter(options?.communityTools),
46
48
  auth: createAuthRouter(t, auth, options)
47
49
  });
48
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"controller.mjs","names":["updateAppService","updateAiMemoryService"],"sources":["../../src/server/controller.ts"],"sourcesContent":["import {\n getAppCatalogData,\n updateAiMemory as updateAiMemoryService,\n updateApp as updateAppService,\n} from '../modules/appCatalog/service'\nimport type { AppCatalogData } from '../types'\nimport type { Resource } from '../types/common/appCatalogTypes'\n\nimport type { BetterAuth } from '../modules/auth/auth'\nimport { createAuthRouter } from '../modules/auth/authRouter.js'\nimport { createFeedbackRouter } from '../modules/feedback/feedbackRouter'\nimport { publicProcedure, router, t } from './trpcSetup'\nimport { z } from 'zod'\n\nconst updateAppInputSchema = z.object({\n id: z.string(),\n data: z\n .object({\n displayName: z.string().optional(),\n abbreviation: z.string().max(20).nullable().optional(),\n slug: z.string().optional(),\n appUrl: z.string().optional(),\n description: z.string().optional(),\n sources: z.array(z.string()).optional(),\n aiPrompt: z.string().nullable().optional(),\n })\n .refine((d) => Object.keys(d).length > 0, {\n message: 'At least one field required',\n }),\n})\n\n/**\n * Create the main tRPC router with optional auth instance\n * @param auth - Optional Better Auth instance for auth-related queries\n */\nexport function createTrpcRouter(\n auth?: BetterAuth,\n options?: { devLoginEnabled?: boolean },\n) {\n return router({\n appCatalog: router({\n getData: publicProcedure.query(\n async ({ ctx }): Promise<AppCatalogData> => {\n const baseData = await getAppCatalogData()\n const versions = await ctx.companySpecificBackend.getVersionInfo?.()\n\n return {\n ...baseData,\n ...(versions && { versions }),\n }\n },\n ),\n updateApp: publicProcedure\n .input(updateAppInputSchema)\n .mutation(async ({ input }): Promise<Resource> => {\n return updateAppService(input)\n }),\n updateAiMemory: publicProcedure\n .input(\n z.object({\n id: z.string(),\n aiMemory: z.string().nullable(),\n }),\n )\n .mutation(async ({ input }): Promise<Resource> => {\n return updateAiMemoryService(input)\n }),\n }),\n\n feedback: createFeedbackRouter(),\n\n // Auth routes (requires auth instance)\n auth: createAuthRouter(t, auth, options),\n })\n}\n\nexport type TRPCRouter = ReturnType<typeof createTrpcRouter>\n"],"mappings":";;;;;;;AAcA,MAAM,uBAAuB,EAAE,OAAO;CACpC,IAAI,EAAE,QAAQ;CACd,MAAM,EACH,OAAO;EACN,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,cAAc,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU;EACtD,MAAM,EAAE,QAAQ,CAAC,UAAU;EAC3B,QAAQ,EAAE,QAAQ,CAAC,UAAU;EAC7B,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;EACvC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU;EAC3C,CAAC,CACD,QAAQ,MAAM,OAAO,KAAK,EAAE,CAAC,SAAS,GAAG,EACxC,SAAS,+BACV,CAAC;CACL,CAAC;;;;;AAMF,SAAgB,iBACd,MACA,SACA;AACA,QAAO,OAAO;EACZ,YAAY,OAAO;GACjB,SAAS,gBAAgB,MACvB,OAAO,EAAE,UAAmC;IAC1C,MAAM,WAAW,MAAM,mBAAmB;IAC1C,MAAM,WAAW,MAAM,IAAI,uBAAuB,kBAAkB;AAEpE,WAAO;KACL,GAAG;KACH,GAAI,YAAY,EAAE,UAAU;KAC7B;KAEJ;GACD,WAAW,gBACR,MAAM,qBAAqB,CAC3B,SAAS,OAAO,EAAE,YAA+B;AAChD,WAAOA,UAAiB,MAAM;KAC9B;GACJ,gBAAgB,gBACb,MACC,EAAE,OAAO;IACP,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,QAAQ,CAAC,UAAU;IAChC,CAAC,CACH,CACA,SAAS,OAAO,EAAE,YAA+B;AAChD,WAAOC,eAAsB,MAAM;KACnC;GACL,CAAC;EAEF,UAAU,sBAAsB;EAGhC,MAAM,iBAAiB,GAAG,MAAM,QAAQ;EACzC,CAAC"}
1
+ {"version":3,"file":"controller.mjs","names":["updateAppService","updateAiMemoryService"],"sources":["../../src/server/controller.ts"],"sourcesContent":["import {\n getAppCatalogData,\n updateAiMemory as updateAiMemoryService,\n updateApp as updateAppService,\n} from '../modules/appCatalog/service'\nimport type { AppCatalogData } from '../types'\nimport type { Resource } from '../types/common/appCatalogTypes'\n\nimport type { BetterAuth } from '../modules/auth/auth'\nimport { createAuthRouter } from '../modules/auth/authRouter.js'\nimport { createFeedbackRouter } from '../modules/feedback/feedbackRouter'\nimport { createCommunityToolsRouter } from '../modules/communityTools/router'\nimport type { CommunityToolsOptions } from '../middleware/types'\nimport { publicProcedure, router, t } from './trpcSetup'\nimport { z } from 'zod'\n\nconst updateAppInputSchema = z.object({\n id: z.string(),\n data: z\n .object({\n displayName: z.string().optional(),\n abbreviation: z.string().max(20).nullable().optional(),\n slug: z.string().optional(),\n appUrl: z.string().optional(),\n description: z.string().optional(),\n sources: z.array(z.string()).optional(),\n aiPrompt: z.string().nullable().optional(),\n })\n .refine((d) => Object.keys(d).length > 0, {\n message: 'At least one field required',\n }),\n})\n\n/**\n * Create the main tRPC router with optional auth instance\n * @param auth - Optional Better Auth instance for auth-related queries\n */\nexport function createTrpcRouter(\n auth?: BetterAuth,\n options?: {\n devLoginEnabled?: boolean\n communityTools?: CommunityToolsOptions\n },\n) {\n return router({\n appCatalog: router({\n getData: publicProcedure.query(\n async ({ ctx }): Promise<AppCatalogData> => {\n const baseData = await getAppCatalogData()\n const versions = await ctx.companySpecificBackend.getVersionInfo?.()\n\n return {\n ...baseData,\n ...(versions && { versions }),\n }\n },\n ),\n updateApp: publicProcedure\n .input(updateAppInputSchema)\n .mutation(async ({ input }): Promise<Resource> => {\n return updateAppService(input)\n }),\n updateAiMemory: publicProcedure\n .input(\n z.object({\n id: z.string(),\n aiMemory: z.string().nullable(),\n }),\n )\n .mutation(async ({ input }): Promise<Resource> => {\n return updateAiMemoryService(input)\n }),\n }),\n\n feedback: createFeedbackRouter(),\n\n communityTools: createCommunityToolsRouter(options?.communityTools),\n\n // Auth routes (requires auth instance)\n auth: createAuthRouter(t, auth, options),\n })\n}\n\nexport type TRPCRouter = ReturnType<typeof createTrpcRouter>\n"],"mappings":";;;;;;;;AAgBA,MAAM,uBAAuB,EAAE,OAAO;CACpC,IAAI,EAAE,QAAQ;CACd,MAAM,EACH,OAAO;EACN,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,cAAc,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU;EACtD,MAAM,EAAE,QAAQ,CAAC,UAAU;EAC3B,QAAQ,EAAE,QAAQ,CAAC,UAAU;EAC7B,aAAa,EAAE,QAAQ,CAAC,UAAU;EAClC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;EACvC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU;EAC3C,CAAC,CACD,QAAQ,MAAM,OAAO,KAAK,EAAE,CAAC,SAAS,GAAG,EACxC,SAAS,+BACV,CAAC;CACL,CAAC;;;;;AAMF,SAAgB,iBACd,MACA,SAIA;AACA,QAAO,OAAO;EACZ,YAAY,OAAO;GACjB,SAAS,gBAAgB,MACvB,OAAO,EAAE,UAAmC;IAC1C,MAAM,WAAW,MAAM,mBAAmB;IAC1C,MAAM,WAAW,MAAM,IAAI,uBAAuB,kBAAkB;AAEpE,WAAO;KACL,GAAG;KACH,GAAI,YAAY,EAAE,UAAU;KAC7B;KAEJ;GACD,WAAW,gBACR,MAAM,qBAAqB,CAC3B,SAAS,OAAO,EAAE,YAA+B;AAChD,WAAOA,UAAiB,MAAM;KAC9B;GACJ,gBAAgB,gBACb,MACC,EAAE,OAAO;IACP,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,QAAQ,CAAC,UAAU;IAChC,CAAC,CACH,CACA,SAAS,OAAO,EAAE,YAA+B;AAChD,WAAOC,eAAsB,MAAM;KACnC;GACL,CAAC;EAEF,UAAU,sBAAsB;EAEhC,gBAAgB,2BAA2B,SAAS,eAAe;EAGnE,MAAM,iBAAiB,GAAG,MAAM,QAAQ;EACzC,CAAC"}
@@ -60,5 +60,5 @@ const adminProcedure = t.procedure.use(isAdminMiddleware);
60
60
  const protectedProcedure = t.procedure.use(isAuthenticated);
61
61
 
62
62
  //#endregion
63
- export { publicProcedure, router, t };
63
+ export { adminProcedure, protectedProcedure, publicProcedure, router, t };
64
64
  //# sourceMappingURL=trpcSetup.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igstack/app-catalog-backend-core",
3
- "version": "6.10.3",
3
+ "version": "6.11.0",
4
4
  "description": "Backend core library for App Catalog",
5
5
  "homepage": "https://github.com/lislon/app-catalog",
6
6
  "repository": {
@@ -44,8 +44,8 @@
44
44
  "tsyringe": "^4.10.0",
45
45
  "yaml": "^2.8.0",
46
46
  "zod": "^4.3.5",
47
- "@igstack/app-catalog-shared-core": "6.10.3",
48
- "@igstack/app-catalog-table-sync": "6.10.3"
47
+ "@igstack/app-catalog-shared-core": "6.11.0",
48
+ "@igstack/app-catalog-table-sync": "6.11.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@tanstack/vite-config": "^0.4.3",
@@ -57,6 +57,7 @@
57
57
  "@types/node": "^24.3.0",
58
58
  "@types/pg": "^8.18.0",
59
59
  "esbuild": "^0.25.5",
60
+ "playwright-core": "^1.59.0",
60
61
  "prisma": "^7.4.2",
61
62
  "prisma-json-types-generator": "^4.1.1",
62
63
  "tsdown": "^0.21.0",
@@ -67,12 +68,18 @@
67
68
  "peerDependencies": {
68
69
  "@prisma/adapter-pg": "^7.4.2",
69
70
  "@prisma/client": "^7.4.2",
70
- "pg": "^8.20.0"
71
+ "pg": "^8.20.0",
72
+ "playwright-core": ">=1.40.0"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "playwright-core": {
76
+ "optional": true
77
+ }
71
78
  },
72
79
  "engines": {
73
80
  "node": ">=24"
74
81
  },
75
- "gitHead": "980bbf4c4901132d351291df3522fa6b6eaaa123",
82
+ "gitHead": "f4c72c2178cd9a3ec6695cfbb243ff3d0737ad1b",
76
83
  "scripts": {
77
84
  "build": "tsdown",
78
85
  "build:lenient": "tsdown",
@@ -218,6 +218,10 @@ model DbFeedback {
218
218
  resourceId String?
219
219
  resource DbResource? @relation(fields: [resourceId], references: [id], onDelete: Cascade)
220
220
 
221
+ /// Feedback about a community tool rather than a catalog resource.
222
+ communityToolId String?
223
+ communityTool DbCommunityTool? @relation(fields: [communityToolId], references: [id], onDelete: Cascade)
224
+
221
225
  /// What the visitor was looking for when nothing matched. Set only when resourceId is
222
226
  /// null — it is the whole substance of a new-app ask, and the thing we research.
223
227
  subject String?
@@ -228,10 +232,19 @@ model DbFeedback {
228
232
  /// widening the wordlist later cannot rename everybody's history.
229
233
  authorAlias String
230
234
 
235
+ /// Optional: authenticated user id when feedback is submitted by a logged-in user.
236
+ authorUserId String?
237
+ /// Optional: authenticated user's name when feedback is submitted by a logged-in user.
238
+ authorName String?
239
+
231
240
  /// Optional: a bare flag with no words is a valid signal, and the cheapest one a
232
241
  /// passing visitor can send.
233
242
  body String?
234
243
 
244
+ /// 'marker' for a row the system writes when a community tool changes: it has no
245
+ /// author to edit or withdraw it. Null for a visitor's own feedback.
246
+ kind String?
247
+
235
248
  attachments DbFeedbackAttachment[]
236
249
 
237
250
  /// Set on a later edit, so the UI can mark it edited. Null when never edited.
@@ -248,6 +261,7 @@ model DbFeedback {
248
261
  updatedAt DateTime @updatedAt
249
262
 
250
263
  @@index([resourceId, createdAt])
264
+ @@index([communityToolId, createdAt])
251
265
  @@index([authorHash])
252
266
  /// Drives the unreviewed counts on both surfaces: open items, newest first.
253
267
  @@index([status, createdAt])
@@ -352,3 +366,150 @@ model SourceReference {
352
366
 
353
367
  @@unique([resourceId, url])
354
368
  }
369
+
370
+ // ========== Community Tools Models ==========
371
+
372
+ enum CommunityTagKind {
373
+ app
374
+ topic
375
+ }
376
+
377
+ /// A community-contributed tool or resource shared by catalog users.
378
+ model DbCommunityTool {
379
+ id String @id @default(cuid())
380
+
381
+ slug String @unique
382
+ name String
383
+ url String
384
+ /// Lowercase hostname extracted from url for fast host-based queries.
385
+ host String
386
+
387
+ summary String
388
+ descriptionMd String
389
+
390
+ addedByUserId String
391
+ addedByName String
392
+
393
+ /// Person slugs who maintain this tool.
394
+ owners DbCommunityToolOwner[]
395
+
396
+ /// Owners who are not in the person directory, by name only.
397
+ namedOwners DbCommunityToolNamedOwner[]
398
+
399
+ /// Categorization tags (app associations and topic labels).
400
+ tags DbCommunityToolTag[]
401
+
402
+ /// View tracking for ranking.
403
+ views DbCommunityToolView[]
404
+
405
+ /// User pins for personalized ordering.
406
+ pins DbCommunityToolPin[]
407
+
408
+ /// One per person who liked it.
409
+ likes DbCommunityToolLike[]
410
+
411
+ /// Feedback comments about this tool.
412
+ feedback DbFeedback[]
413
+
414
+ /// When a maintainer last reviewed this entry.
415
+ reviewedAt DateTime?
416
+ reviewedByName String?
417
+
418
+ /// Last automated check for availability.
419
+ lastCheckAt DateTime?
420
+
421
+ /// When the tool first started failing checks (null when healthy).
422
+ failingSince DateTime?
423
+
424
+ /// When archived (null when active).
425
+ archivedAt DateTime?
426
+ archivedReason String?
427
+ /// 'auto' for automated archival after prolonged failure, or user name for manual archival.
428
+ archivedBy String?
429
+
430
+ /// Asset references for screenshots and favicon.
431
+ screenshotAssetId String?
432
+ faviconAssetId String?
433
+ /// When screenshots were last captured.
434
+ capturedAt DateTime?
435
+ /// When the site itself last changed: its page's Last-Modified, at the last visit that sent one.
436
+ siteUpdatedAt DateTime?
437
+
438
+ createdAt DateTime @default(now())
439
+ updatedAt DateTime @updatedAt
440
+
441
+ @@index([host])
442
+ @@index([createdAt])
443
+ }
444
+
445
+ /// Many-to-many join between community tools and their owners.
446
+ model DbCommunityToolOwner {
447
+ toolId String
448
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
449
+ personSlug String
450
+
451
+ @@id([toolId, personSlug])
452
+ }
453
+
454
+ /// A signed-in person liked the tool; their name is kept for "Liked by".
455
+ model DbCommunityToolLike {
456
+ toolId String
457
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
458
+ userId String
459
+ userName String
460
+ createdAt DateTime @default(now())
461
+
462
+ @@id([toolId, userId])
463
+ }
464
+
465
+ /// An owner outside the person directory: shown by name, never an editor.
466
+ model DbCommunityToolNamedOwner {
467
+ toolId String
468
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
469
+ name String
470
+
471
+ @@id([toolId, name])
472
+ }
473
+
474
+ /// Tags attached to community tools (app associations and topics).
475
+ model DbCommunityToolTag {
476
+ toolId String
477
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
478
+
479
+ kind CommunityTagKind
480
+ value String
481
+
482
+ @@id([toolId, kind, value])
483
+ @@index([kind, value])
484
+ }
485
+
486
+ /// View tracking for community tools (one row per viewer per tool per day).
487
+ model DbCommunityToolView {
488
+ toolId String
489
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
490
+
491
+ /// Hash of actor id for anonymous view tracking.
492
+ actorHash String
493
+ /// Optional user id for authenticated views.
494
+ userId String?
495
+
496
+ /// Day this view occurred (UTC date, time truncated).
497
+ day DateTime @db.Date
498
+ /// Exact timestamp of the view.
499
+ at DateTime @default(now())
500
+
501
+ @@id([toolId, actorHash, day])
502
+ @@index([userId, at])
503
+ }
504
+
505
+ /// User-specific tool pins for personalized ordering.
506
+ model DbCommunityToolPin {
507
+ userId String
508
+ toolId String
509
+ tool DbCommunityTool @relation(fields: [toolId], references: [id], onDelete: Cascade)
510
+
511
+ /// Position in the user's pinned list (lower = higher in list).
512
+ position Int
513
+
514
+ @@id([userId, toolId])
515
+ }