96 lines
3.2 KiB
JavaScript
96 lines
3.2 KiB
JavaScript
import { RECIPES } from '../data/recipeCatalog.js';
|
|
import { analyzeInstaller } from './installerIntelService.js';
|
|
import { buildDetectionRule } from './detectionRuleService.js';
|
|
|
|
// Lists/searches the curated catalog and turns a recipe into the request bodies
|
|
// the models accept (PSADT profile + Intune deployment + winget-tracked app).
|
|
|
|
// installTask type enum is exe|msi|msp|script; everything EXE-based maps to exe.
|
|
function taskTypeFor(installerType = '') {
|
|
if (installerType === 'msi') return 'msi';
|
|
if (installerType === 'msp') return 'msp';
|
|
return 'exe';
|
|
}
|
|
|
|
function summarize(recipe) {
|
|
return {
|
|
id: recipe.id,
|
|
vendor: recipe.vendor,
|
|
name: recipe.name,
|
|
category: recipe.category || 'Other',
|
|
installerType: recipe.installerType,
|
|
fileName: recipe.fileName,
|
|
arch: recipe.arch || 'x64',
|
|
installArgs: recipe.installArgs || '',
|
|
detectionKind: recipe.detection?.type || '',
|
|
wingetId: recipe.wingetId || '',
|
|
homepage: recipe.homepage || ''
|
|
};
|
|
}
|
|
|
|
export function listRecipes() {
|
|
return RECIPES.map(summarize);
|
|
}
|
|
|
|
export function searchRecipes(query = '') {
|
|
const q = String(query).trim().toLowerCase();
|
|
if (!q) return listRecipes();
|
|
return RECIPES.filter((r) =>
|
|
[r.vendor, r.name, r.category, r.wingetId, r.id]
|
|
.some((field) => String(field || '').toLowerCase().includes(q))
|
|
).map(summarize);
|
|
}
|
|
|
|
export function getRecipe(id) {
|
|
return RECIPES.find((r) => r.id === id) || null;
|
|
}
|
|
|
|
// recipe → { profile, deployment, application }; application is null with no winget id.
|
|
export function buildRecipeArtifacts(recipe, { visibility = 'personal', groupId = null } = {}) {
|
|
if (!recipe) throw new Error('recipe is required');
|
|
const scope = { visibility, groupId: visibility === 'group' ? groupId || null : null };
|
|
const displayName = `${recipe.vendor} ${recipe.name}`.trim();
|
|
const analysis = analyzeInstaller({ fileName: recipe.fileName, productCode: recipe.productCode || '' });
|
|
const detection = buildDetectionRule(recipe.detection || {});
|
|
|
|
const profile = {
|
|
name: displayName,
|
|
appVendor: recipe.vendor,
|
|
appName: recipe.name,
|
|
appVersion: recipe.version || '',
|
|
appArch: recipe.arch === 'x86' ? 'x86' : 'x64',
|
|
closeProcesses: recipe.closeProcesses || [],
|
|
installTasks: [{
|
|
type: taskTypeFor(recipe.installerType),
|
|
phase: 'Install',
|
|
filePath: recipe.fileName,
|
|
arguments: recipe.installArgs || ''
|
|
}],
|
|
...scope
|
|
};
|
|
|
|
const deployment = {
|
|
name: displayName,
|
|
appType: 'Windows app (Win32)',
|
|
commandStyle: 'v4',
|
|
requirements: { architecture: recipe.arch === 'x86' ? 'x86' : 'x64' },
|
|
detectionType: detection.detectionType,
|
|
detectionRule: detection.detectionRule,
|
|
status: 'draft',
|
|
notes: `Created from the "${recipe.name}" recipe. Source: ${recipe.homepage || 'n/a'}`,
|
|
...scope
|
|
};
|
|
|
|
const application = recipe.wingetId ? {
|
|
name: displayName,
|
|
vendor: recipe.vendor,
|
|
versionSource: 'winget',
|
|
versionSourceRef: recipe.wingetId,
|
|
autoCheck: true,
|
|
notes: `Auto-tracking ${recipe.wingetId} via winget (from the "${recipe.name}" recipe).`,
|
|
...scope
|
|
} : null;
|
|
|
|
return { recipeId: recipe.id, displayName, profile, deployment, application, analysis, detection };
|
|
}
|