@igstack/app-catalog-backend-core 0.3.1-alpha-20260405015231 → 0.4.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.
- package/dist/db/syncAppCatalog.d.mts +3 -5
- package/dist/db/syncAppCatalog.d.mts.map +1 -1
- package/dist/db/syncAppCatalog.mjs +49 -57
- package/dist/db/syncAppCatalog.mjs.map +1 -1
- package/dist/db/tableSyncMagazine.d.mts +3 -7
- package/dist/db/tableSyncMagazine.d.mts.map +1 -1
- package/dist/db/tableSyncMagazine.mjs +3 -7
- package/dist/db/tableSyncMagazine.mjs.map +1 -1
- package/dist/db/tableSyncPrismaAdapter.mjs.map +1 -1
- package/dist/generated/prisma/client.mjs.map +1 -1
- package/dist/generated/prisma/internal/class.d.mts +5 -17
- package/dist/generated/prisma/internal/class.d.mts.map +1 -1
- package/dist/generated/prisma/internal/class.mjs +4 -4
- package/dist/generated/prisma/internal/class.mjs.map +1 -1
- package/dist/generated/prisma/internal/prismaNamespace.d.mts +46 -132
- package/dist/generated/prisma/internal/prismaNamespace.d.mts.map +1 -1
- package/dist/generated/prisma/models/DbResource.d.mts +2433 -0
- package/dist/generated/prisma/models/DbResource.d.mts.map +1 -0
- package/dist/generated/prisma/models/SourceReference.d.mts +90 -90
- package/dist/generated/prisma/models/SourceReference.d.mts.map +1 -1
- package/dist/generated/prisma/models.d.mts +2 -3
- package/dist/index.d.mts +3 -4
- package/dist/modules/appCatalog/checkLinks.mjs +1 -1
- package/dist/modules/appCatalog/checkLinks.mjs.map +1 -1
- package/dist/modules/appCatalog/service.mjs +26 -34
- package/dist/modules/appCatalog/service.mjs.map +1 -1
- package/dist/modules/assets/screenshotRestController.mjs +2 -2
- package/dist/modules/assets/screenshotRestController.mjs.map +1 -1
- package/dist/modules/assets/syncAssets.mjs +4 -4
- package/dist/modules/assets/syncAssets.mjs.map +1 -1
- package/dist/modules/lighthouseKeeper/tools.mjs +1 -1
- package/dist/modules/lighthouseKeeper/tools.mjs.map +1 -1
- package/dist/server/controller.d.mts +2 -2
- package/dist/server/controller.mjs.map +1 -1
- package/dist/types/common/appCatalogTypes.d.mts +26 -9
- package/dist/types/common/appCatalogTypes.d.mts.map +1 -1
- package/dist/types/common/approvalMethodTypes.d.mts +5 -1
- package/dist/types/common/approvalMethodTypes.d.mts.map +1 -1
- package/package.json +3 -3
- package/prisma/schema.prisma +53 -62
- package/src/db/syncAppCatalog.ts +68 -73
- package/src/db/tableSyncMagazine.ts +3 -7
- package/src/db/tableSyncPrismaAdapter.ts +1 -1
- package/src/generated/prisma/browser.ts +2 -7
- package/src/generated/prisma/client.ts +2 -7
- package/src/generated/prisma/internal/class.ts +8 -18
- package/src/generated/prisma/internal/prismaNamespace.ts +43 -131
- package/src/generated/prisma/internal/prismaNamespaceBrowser.ts +7 -20
- package/src/generated/prisma/models/DbResource.ts +2701 -0
- package/src/generated/prisma/models/SourceReference.ts +89 -89
- package/src/generated/prisma/models.ts +1 -2
- package/src/index.ts +1 -1
- package/src/modules/appCatalog/checkLinks.ts +7 -7
- package/src/modules/appCatalog/service.ts +51 -62
- package/src/modules/assets/screenshotRestController.ts +2 -2
- package/src/modules/assets/screenshotRouter.ts +2 -2
- package/src/modules/assets/syncAssets.ts +4 -4
- package/src/modules/lighthouseKeeper/tools.ts +1 -1
- package/src/prisma-json-types.d.ts +8 -8
- package/src/server/controller.ts +2 -2
- package/src/types/common/appCatalogTypes.ts +28 -9
- package/src/types/common/approvalMethodTypes.ts +6 -0
- package/src/types/index.ts +0 -1
- package/dist/generated/prisma/models/DbAppForCatalog.d.mts +0 -1778
- package/dist/generated/prisma/models/DbAppForCatalog.d.mts.map +0 -1
- package/dist/generated/prisma/models/DbSubResource.d.mts +0 -1468
- package/dist/generated/prisma/models/DbSubResource.d.mts.map +0 -1
- package/dist/types/common/subResourceTypes.d.mts +0 -24
- package/dist/types/common/subResourceTypes.d.mts.map +0 -1
- package/src/generated/prisma/models/DbAppForCatalog.ts +0 -2014
- package/src/generated/prisma/models/DbSubResource.ts +0 -1692
- package/src/types/common/subResourceTypes.ts +0 -20
package/src/db/syncAppCatalog.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
AppForCatalog,
|
|
3
2
|
GroupingTagDefinition,
|
|
3
|
+
Resource,
|
|
4
4
|
} from '../types/common/appCatalogTypes'
|
|
5
5
|
import { getDbClient } from './client'
|
|
6
6
|
import { TABLE_SYNC_MAGAZINE } from './tableSyncMagazine'
|
|
@@ -8,7 +8,7 @@ import { tableSyncPrisma } from './tableSyncPrismaAdapter'
|
|
|
8
8
|
import { readFile, readdir, stat } from 'node:fs/promises'
|
|
9
9
|
import { group } from 'radashi'
|
|
10
10
|
import { upsertAsset } from '../modules/assets/upsertAsset'
|
|
11
|
-
import type { ApprovalMethod, Group, Person
|
|
11
|
+
import type { ApprovalMethod, Group, Person } from '../types'
|
|
12
12
|
import type { PrismaClient } from '../generated/prisma/client'
|
|
13
13
|
import { naturalSort } from '../utils/naturalSort'
|
|
14
14
|
import { parseSourceSlug } from '../utils/parseSourceSlug'
|
|
@@ -103,12 +103,12 @@ async function syncAppAssets(
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
async function syncAssetsFromFileSystem(
|
|
106
|
-
|
|
106
|
+
resources: Resource[],
|
|
107
107
|
allAppsAssetsPath: string,
|
|
108
108
|
) {
|
|
109
109
|
const appDirectories = await readdir(allAppsAssetsPath)
|
|
110
110
|
const prisma = getDbClient()
|
|
111
|
-
const bySlug = group(
|
|
111
|
+
const bySlug = group(resources, (a) => a.slug)
|
|
112
112
|
|
|
113
113
|
for (const appDirName of appDirectories) {
|
|
114
114
|
try {
|
|
@@ -150,7 +150,7 @@ async function syncAssetsFromFileSystem(
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
if (Object.keys(updateData).length > 0) {
|
|
153
|
-
await prisma.
|
|
153
|
+
await prisma.dbResource.update({
|
|
154
154
|
where: { slug: appSlug },
|
|
155
155
|
data: updateData,
|
|
156
156
|
})
|
|
@@ -171,20 +171,19 @@ async function syncAssetsFromFileSystem(
|
|
|
171
171
|
export interface SyncAppCatalogOptions {
|
|
172
172
|
persons?: Person[]
|
|
173
173
|
groups?: Group[]
|
|
174
|
-
subResources?: SubResource[]
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
/**
|
|
178
177
|
* Syncs app catalog data to the database using table sync.
|
|
179
|
-
* This will create new
|
|
178
|
+
* This will create new resources, update existing ones, and delete any that are no longer in the input.
|
|
180
179
|
*
|
|
181
180
|
* Note: Call connectDb() before and disconnectDb() after if running in a script.
|
|
182
181
|
*/
|
|
183
182
|
export async function syncAppCatalog(
|
|
184
|
-
|
|
183
|
+
resources: Resource[],
|
|
185
184
|
tagsDefinitions: GroupingTagDefinition[],
|
|
186
185
|
approvalMethods: ApprovalMethod[],
|
|
187
|
-
|
|
186
|
+
screenshotsPath?: string,
|
|
188
187
|
options?: SyncAppCatalogOptions,
|
|
189
188
|
): Promise<SyncAppCatalogResult> {
|
|
190
189
|
try {
|
|
@@ -236,7 +235,7 @@ export async function syncAppCatalog(
|
|
|
236
235
|
|
|
237
236
|
const sync = tableSyncPrisma({
|
|
238
237
|
prisma,
|
|
239
|
-
...TABLE_SYNC_MAGAZINE.
|
|
238
|
+
...TABLE_SYNC_MAGAZINE.DbResource,
|
|
240
239
|
})
|
|
241
240
|
|
|
242
241
|
await tableSyncPrisma({
|
|
@@ -246,8 +245,8 @@ export async function syncAppCatalog(
|
|
|
246
245
|
|
|
247
246
|
// Collect all unique source slugs for sync
|
|
248
247
|
const uniqueSourceSlugs = new Set<string>()
|
|
249
|
-
for (const
|
|
250
|
-
for (const source of
|
|
248
|
+
for (const resource of resources) {
|
|
249
|
+
for (const source of resource.sources ?? []) {
|
|
251
250
|
const url = typeof source === 'string' ? source : source.url
|
|
252
251
|
const sourceSlug = parseSourceSlug(url)
|
|
253
252
|
uniqueSourceSlugs.add(sourceSlug)
|
|
@@ -264,67 +263,84 @@ export async function syncAppCatalog(
|
|
|
264
263
|
...TABLE_SYNC_MAGAZINE.Source,
|
|
265
264
|
}).sync(sources)
|
|
266
265
|
|
|
267
|
-
//
|
|
268
|
-
const
|
|
266
|
+
// Sort resources: parents first (no parentSlug), then children — for FK integrity
|
|
267
|
+
const sortedResources = [...resources].sort((a, b) => {
|
|
268
|
+
const aIsChild = a.parentSlug ? 1 : 0
|
|
269
|
+
const bIsChild = b.parentSlug ? 1 : 0
|
|
270
|
+
return aIsChild - bIsChild
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
// Transform Resource to DbResource format (scalar fields only)
|
|
274
|
+
const dbResources = sortedResources.map((resource) => {
|
|
269
275
|
const slug =
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
resource.slug ||
|
|
277
|
+
resource.displayName
|
|
272
278
|
.toLowerCase()
|
|
273
279
|
.replace(/[^a-z0-9]+/g, '-')
|
|
274
280
|
.replace(/^-+|-+$/g, '')
|
|
275
281
|
|
|
276
282
|
return {
|
|
277
283
|
slug,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
284
|
+
type: resource.type ?? 'application',
|
|
285
|
+
displayName: resource.displayName,
|
|
286
|
+
abbreviation: resource.abbreviation ?? null,
|
|
287
|
+
nicknames: resource.nicknames ?? [],
|
|
288
|
+
description: resource.description,
|
|
289
|
+
teams: resource.teams ?? [],
|
|
290
|
+
accessRequest: resource.accessRequest ?? null,
|
|
291
|
+
notes: resource.notes ?? null,
|
|
292
|
+
tags: resource.tags ?? [],
|
|
293
|
+
appUrl: resource.appUrl ?? null,
|
|
294
|
+
links: resource.links ?? null,
|
|
295
|
+
iconName: resource.iconName ?? null,
|
|
296
|
+
screenshotIds: resource.screenshotIds ?? [],
|
|
297
|
+
deprecated: resource.deprecated ?? null,
|
|
298
|
+
aiPrompt: resource.aiPrompt ?? null,
|
|
299
|
+
urlIssues: resource.urlIssues ?? [],
|
|
300
|
+
tiers: resource.tiers ?? null,
|
|
301
|
+
// Fields from former SubResource
|
|
302
|
+
parentSlug: resource.parentSlug ?? null,
|
|
303
|
+
tier: resource.tier ?? null,
|
|
304
|
+
familySlug: resource.familySlug ?? null,
|
|
305
|
+
aliases: resource.aliases ?? [],
|
|
306
|
+
ownerPersonSlug: resource.ownerPersonSlug ?? null,
|
|
307
|
+
accessMaintainerGroupSlugs: resource.accessMaintainerGroupSlugs ?? [],
|
|
308
|
+
accessComments: resource.accessComments ?? null,
|
|
309
|
+
extra: resource.extra ?? null,
|
|
294
310
|
}
|
|
295
311
|
})
|
|
296
312
|
|
|
297
|
-
// Sync
|
|
298
|
-
const result = await sync.sync(
|
|
313
|
+
// Sync resources
|
|
314
|
+
const result = await sync.sync(dbResources)
|
|
299
315
|
|
|
300
|
-
// Resolve slug -> id for synced
|
|
301
|
-
const slugs =
|
|
302
|
-
const
|
|
316
|
+
// Resolve slug -> id for synced resources so SourceReference can reference by resourceId
|
|
317
|
+
const slugs = dbResources.map((a) => a.slug)
|
|
318
|
+
const resourceRows = await prisma.dbResource.findMany({
|
|
303
319
|
where: { slug: { in: slugs } },
|
|
304
320
|
select: { slug: true, id: true },
|
|
305
321
|
})
|
|
306
|
-
const slugToId = Object.fromEntries(
|
|
322
|
+
const slugToId = Object.fromEntries(resourceRows.map((r) => [r.slug, r.id]))
|
|
307
323
|
|
|
308
|
-
// Build allSourceRefs with
|
|
309
|
-
const allSourceRefs =
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
324
|
+
// Build allSourceRefs with resourceId (slug already resolved to id)
|
|
325
|
+
const allSourceRefs = sortedResources.flatMap((resource) => {
|
|
326
|
+
const resourceSlug =
|
|
327
|
+
resource.slug ||
|
|
328
|
+
resource.displayName
|
|
313
329
|
.toLowerCase()
|
|
314
330
|
.replace(/[^a-z0-9]+/g, '-')
|
|
315
331
|
.replace(/^-+|-+$/g, '')
|
|
316
|
-
const
|
|
317
|
-
if (!
|
|
332
|
+
const resourceId = slugToId[resourceSlug]
|
|
333
|
+
if (!resourceId) {
|
|
318
334
|
throw new Error(
|
|
319
|
-
`
|
|
335
|
+
`Resource '${resourceSlug}' has no id after sync. Existing slugs: ${Object.keys(slugToId).join(', ')}`,
|
|
320
336
|
)
|
|
321
337
|
}
|
|
322
338
|
|
|
323
|
-
return (
|
|
339
|
+
return (resource.sources ?? []).map((source) => {
|
|
324
340
|
const url = typeof source === 'string' ? source : source.url
|
|
325
341
|
const sourceSlug = parseSourceSlug(url)
|
|
326
342
|
return {
|
|
327
|
-
|
|
343
|
+
resourceId,
|
|
328
344
|
sourceSlug,
|
|
329
345
|
url,
|
|
330
346
|
parseDate: null,
|
|
@@ -340,39 +356,18 @@ export async function syncAppCatalog(
|
|
|
340
356
|
...TABLE_SYNC_MAGAZINE.SourceReference,
|
|
341
357
|
}).sync(allSourceRefs)
|
|
342
358
|
|
|
343
|
-
// Sync SubResources (after apps, since they reference appSlug)
|
|
344
|
-
if (options?.subResources) {
|
|
345
|
-
const dbSubResources = options.subResources.map((sr) => ({
|
|
346
|
-
slug: sr.slug,
|
|
347
|
-
displayName: sr.displayName,
|
|
348
|
-
description: sr.description ?? null,
|
|
349
|
-
appSlug: sr.appSlug,
|
|
350
|
-
familySlug: sr.familySlug ?? null,
|
|
351
|
-
tierSlug: sr.tierSlug ?? null,
|
|
352
|
-
aliases: sr.aliases,
|
|
353
|
-
ownerPersonSlug: sr.ownerPersonSlug ?? null,
|
|
354
|
-
accessMaintainerGroupSlugs: sr.accessMaintainerGroupSlugs,
|
|
355
|
-
accessRequest: sr.accessRequest ?? null,
|
|
356
|
-
accessComments: sr.accessComments ?? null,
|
|
357
|
-
extra: sr.extra ?? null,
|
|
358
|
-
}))
|
|
359
|
-
await tableSyncPrisma({
|
|
360
|
-
prisma,
|
|
361
|
-
...TABLE_SYNC_MAGAZINE.DbSubResource,
|
|
362
|
-
}).sync(dbSubResources)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
359
|
// Get actual synced data to calculate stats
|
|
366
360
|
const actual = result.getActual()
|
|
367
361
|
|
|
368
|
-
if (
|
|
369
|
-
await syncAssetsFromFileSystem(
|
|
362
|
+
if (screenshotsPath) {
|
|
363
|
+
await syncAssetsFromFileSystem(resources, screenshotsPath)
|
|
370
364
|
} else {
|
|
371
365
|
console.warn('Do not sync screenhots')
|
|
372
366
|
}
|
|
373
367
|
|
|
374
368
|
return {
|
|
375
|
-
created:
|
|
369
|
+
created:
|
|
370
|
+
actual.length - resources.length + (resources.length - actual.length),
|
|
376
371
|
updated: 0, // TableSync doesn't expose this directly
|
|
377
372
|
deleted: 0, // TableSync doesn't expose this directly
|
|
378
373
|
total: actual.length,
|
|
@@ -27,8 +27,8 @@ export const TABLE_SYNC_MAGAZINE = {
|
|
|
27
27
|
prismaModelName: 'DbGroupMembership',
|
|
28
28
|
uniqColumns: ['groupSlug', 'personSlug'],
|
|
29
29
|
},
|
|
30
|
-
|
|
31
|
-
prismaModelName: '
|
|
30
|
+
DbResource: {
|
|
31
|
+
prismaModelName: 'DbResource',
|
|
32
32
|
uniqColumns: ['slug'],
|
|
33
33
|
},
|
|
34
34
|
DbAppTagDefinition: {
|
|
@@ -45,13 +45,9 @@ export const TABLE_SYNC_MAGAZINE = {
|
|
|
45
45
|
prismaModelName: 'Source',
|
|
46
46
|
uniqColumns: ['slug'],
|
|
47
47
|
},
|
|
48
|
-
DbSubResource: {
|
|
49
|
-
prismaModelName: 'DbSubResource',
|
|
50
|
-
uniqColumns: ['slug'],
|
|
51
|
-
},
|
|
52
48
|
SourceReference: {
|
|
53
49
|
prismaModelName: 'SourceReference',
|
|
54
|
-
uniqColumns: ['
|
|
50
|
+
uniqColumns: ['resourceId', 'url'],
|
|
55
51
|
},
|
|
56
52
|
} as const satisfies TableSyncMagazineType
|
|
57
53
|
|
|
@@ -12,7 +12,7 @@ export type ScalarFilter<TPrismaModelName extends Prisma.ModelName> = Partial<
|
|
|
12
12
|
>
|
|
13
13
|
|
|
14
14
|
export type GetOperationFns<TModel extends Prisma.ModelName> = {
|
|
15
|
-
[TOperation in keyof Prisma.TypeMap['model']['
|
|
15
|
+
[TOperation in keyof Prisma.TypeMap['model']['DbResource']['operations']]: (
|
|
16
16
|
args: Prisma.TypeMap['model'][TModel]['operations'][TOperation]['args'],
|
|
17
17
|
) => Promise<
|
|
18
18
|
Prisma.TypeMap['model'][TModel]['operations'][TOperation]['result']
|
|
@@ -58,15 +58,10 @@ export type DbGroupMembership = Prisma.DbGroupMembershipModel
|
|
|
58
58
|
*/
|
|
59
59
|
export type DbApprovalMethod = Prisma.DbApprovalMethodModel
|
|
60
60
|
/**
|
|
61
|
-
* Model
|
|
61
|
+
* Model DbResource
|
|
62
62
|
*
|
|
63
63
|
*/
|
|
64
|
-
export type
|
|
65
|
-
/**
|
|
66
|
-
* Model DbSubResource
|
|
67
|
-
*
|
|
68
|
-
*/
|
|
69
|
-
export type DbSubResource = Prisma.DbSubResourceModel
|
|
64
|
+
export type DbResource = Prisma.DbResourceModel
|
|
70
65
|
/**
|
|
71
66
|
* Model DbAppTagDefinition
|
|
72
67
|
*
|
|
@@ -82,15 +82,10 @@ export type DbGroupMembership = Prisma.DbGroupMembershipModel
|
|
|
82
82
|
*/
|
|
83
83
|
export type DbApprovalMethod = Prisma.DbApprovalMethodModel
|
|
84
84
|
/**
|
|
85
|
-
* Model
|
|
85
|
+
* Model DbResource
|
|
86
86
|
*
|
|
87
87
|
*/
|
|
88
|
-
export type
|
|
89
|
-
/**
|
|
90
|
-
* Model DbSubResource
|
|
91
|
-
*
|
|
92
|
-
*/
|
|
93
|
-
export type DbSubResource = Prisma.DbSubResourceModel
|
|
88
|
+
export type DbResource = Prisma.DbResourceModel
|
|
94
89
|
/**
|
|
95
90
|
* Model DbAppTagDefinition
|
|
96
91
|
*
|