feat(service-integrations): phase 1 — integration architecture foundation

- Add Integration interfaces, registry, cache, encryption, and base helpers
- Add integrationType, integrationConfig, integrationEnabled to App model
- Add integration widget type to constants and validators
- Add integration fields to AppRecord, CreateAppInput, UpdateAppInput
- Update appService with encryption/decryption for integration config
- Add API routes: list integrations, test connection, fetch endpoint data
This commit is contained in:
2026-03-25 22:02:34 +03:00
parent c62ca79adb
commit 114dee57a8
12 changed files with 445 additions and 6 deletions
+15
View File
@@ -0,0 +1,15 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { requireAuth } from '$lib/server/middleware/authenticate.js';
import { listInfo } from '$lib/server/integrations/registry.js';
import { success } from '$lib/server/utils/response.js';
/**
* GET /api/integrations — List available integration types.
*/
export const GET: RequestHandler = async (event) => {
requireAuth(event);
const integrations = listInfo();
return json(success(integrations));
};
@@ -0,0 +1,46 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { z } from 'zod';
import { requireAuth } from '$lib/server/middleware/authenticate.js';
import * as registry from '$lib/server/integrations/registry.js';
import { success, error } from '$lib/server/utils/response.js';
const testConnectionSchema = z.object({
integrationType: z.string().min(1, 'Integration type is required'),
appUrl: z.string().url('Invalid app URL'),
config: z.record(z.unknown())
});
/**
* POST /api/integrations/test — Test an integration connection.
*/
export const POST: RequestHandler = async (event) => {
requireAuth(event);
let body: unknown;
try {
body = await event.request.json();
} catch {
return json(error('Invalid JSON body'), { status: 400 });
}
const parsed = testConnectionSchema.safeParse(body);
if (!parsed.success) {
return json(error(parsed.error.errors[0]?.message ?? 'Invalid input'), { status: 400 });
}
const { integrationType, appUrl, config } = parsed.data;
const integration = registry.get(integrationType);
if (!integration) {
return json(error(`Unknown integration type: ${integrationType}`), { status: 404 });
}
try {
const result = await integration.testConnection(appUrl, config);
return json(success(result));
} catch (err) {
const message = err instanceof Error ? err.message : 'Connection test failed';
return json(error(message), { status: 500 });
}
};