56 lines
1.7 KiB
TypeScript
56 lines
1.7 KiB
TypeScript
import type { FastifyInstance } from 'fastify';
|
|
import { z } from 'zod';
|
|
import {
|
|
AmbiguousAppTenantError,
|
|
type PlatformBootstrap
|
|
} from '../tenancy/platform-config-repository.js';
|
|
|
|
const headerSchema = z.object({
|
|
'x-wechat-appid': z.string().trim().min(6).max(64),
|
|
'tenant-id': z.string().regex(/^[1-9]\d{0,19}$/).optional()
|
|
});
|
|
|
|
export interface PlatformConfigResolver {
|
|
resolveBootstrap(appId: string, tenantId?: string): Promise<PlatformBootstrap | null>;
|
|
}
|
|
|
|
export async function registerPlatformBootstrapRoutes(
|
|
app: FastifyInstance,
|
|
repository: PlatformConfigResolver
|
|
): Promise<void> {
|
|
app.get('/app-api/bootstrap', async (request, reply) => {
|
|
const parsed = headerSchema.safeParse(request.headers);
|
|
if (!parsed.success) {
|
|
return reply.status(400).send({
|
|
code: 'INVALID_APP_CONTEXT',
|
|
message: 'x-wechat-appid is required and tenant-id must be a positive integer.',
|
|
traceId: request.traceId
|
|
});
|
|
}
|
|
|
|
try {
|
|
const bootstrap = await repository.resolveBootstrap(
|
|
parsed.data['x-wechat-appid'],
|
|
parsed.data['tenant-id']
|
|
);
|
|
if (!bootstrap) {
|
|
return reply.status(404).send({
|
|
code: 'APP_TENANT_NOT_FOUND',
|
|
message: 'The application and tenant binding is not active.',
|
|
traceId: request.traceId
|
|
});
|
|
}
|
|
return { code: 0, data: bootstrap, traceId: request.traceId };
|
|
} catch (error) {
|
|
if (error instanceof AmbiguousAppTenantError) {
|
|
return reply.status(409).send({
|
|
code: 'TENANT_SELECTION_REQUIRED',
|
|
message: error.message,
|
|
traceId: request.traceId
|
|
});
|
|
}
|
|
throw error;
|
|
}
|
|
});
|
|
}
|