Files
cnpmcore/app/core/service/HookTriggerService.ts
MK (fengmk2) e5162f20aa fix: improve TypeScript type definitions across codebase (#844)
This commit enhances type safety and fixes type-related issues
throughout the project including:
- Updated type definitions in entities, repositories, and models
- Improved type annotations in services and controllers
- Fixed type issues in adapters and utilities
- Enhanced test file type definitions
- Added typings/index.d.ts for global type declarations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-23 00:58:59 +08:00

143 lines
4.4 KiB
TypeScript

import { AccessLevel, Inject, SingletonProto } from '@eggjs/tegg';
import type { EggContextHttpClient } from 'egg';
import type { TriggerHookTask } from '../entity/Task.ts';
import type { HookEvent } from '../entity/HookEvent.ts';
import type { HookRepository } from '../../repository/HookRepository.ts';
import type { PackageRepository } from '../../repository/PackageRepository.ts';
import type { DistRepository } from '../../repository/DistRepository.ts';
import type { UserRepository } from '../../repository/UserRepository.ts';
import type { Hook } from '../entity/Hook.ts';
import { isoNow } from '../../common/LogUtil.ts';
import { TaskState } from '../../common/enum/Task.ts';
import type { TaskService } from './TaskService.ts';
import { getScopeAndName } from '../../common/PackageUtil.ts';
import type { Dist } from '../entity/Dist.ts';
@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
export class HookTriggerService {
@Inject()
private readonly hookRepository: HookRepository;
@Inject()
private readonly packageRepository: PackageRepository;
@Inject()
private readonly distRepository: DistRepository;
@Inject()
private readonly userRepository: UserRepository;
@Inject()
private readonly httpclient: EggContextHttpClient;
@Inject()
private readonly taskService: TaskService;
async executeTask(task: TriggerHookTask) {
const { hookId, hookEvent } = task.data;
const hook = await this.hookRepository.findHookById(hookId);
if (!hook) {
await this.taskService.finishTask(
task,
TaskState.Success,
`[${isoNow()}][TriggerHooks] hook ${hookId} not exits`
);
return;
}
try {
const payload = await this.createTriggerPayload(task, hookEvent, hook);
if (!payload) {
await this.taskService.finishTask(
task,
TaskState.Success,
`[${isoNow()}][TriggerHooks] generate payload failed \n`
);
return;
}
const status = await this.doExecuteTrigger(hook, payload);
hook.latestTaskId = task.taskId;
task.data.responseStatus = status;
await this.hookRepository.saveHook(hook);
await this.taskService.finishTask(
task,
TaskState.Success,
`[${isoNow()}][TriggerHooks] trigger hook succeed ${status} \n`
);
} catch (e) {
e.message = `trigger hook failed: ${e.message}`;
task.error = e.message;
await this.taskService.finishTask(
task,
TaskState.Fail,
`[${isoNow()}][TriggerHooks] ${e.stack} \n`
);
return;
}
}
async doExecuteTrigger(hook: Hook, payload: object): Promise<number> {
const { digest, payloadStr } = hook.signPayload(payload);
const url = new URL(hook.endpoint);
const res = await this.httpclient.request(hook.endpoint, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-npm-signature': `sha256=${digest}`,
host: url.host,
},
// webhook 场景下,由于 endpoint 都不同
// 因此几乎不存在连接复用的情况,因此这里不使用 keepAlive
// agent: false,
// httpsAgent: false,
data: payloadStr,
});
if (res.status >= 200 && res.status < 300) {
return res.status;
}
throw new Error(`hook response with ${res.status}`);
}
async createTriggerPayload(
task: TriggerHookTask,
hookEvent: HookEvent,
hook: Hook
): Promise<object | undefined> {
const [scope, name] = getScopeAndName(hookEvent.fullname);
const pkg = await this.packageRepository.findPackage(scope, name);
if (!pkg) {
await this.taskService.finishTask(
task,
TaskState.Success,
`[${isoNow()}][TriggerHooks] can not found pkg for ${hookEvent.fullname} \n`
);
return;
}
const user = await this.userRepository.findUserByUserId(hook.ownerId);
if (!user) {
await this.taskService.finishTask(
task,
TaskState.Success,
`[${isoNow()}][TriggerHooks] can not found user for ${hook.ownerId} \n`
);
return;
}
const manifest = await this.distRepository.readDistBytesToJSON(
pkg.manifestsDist as Dist
);
return {
event: hookEvent.event,
name: pkg.fullname,
type: 'package',
version: '1.0.0',
hookOwner: {
username: user.name,
},
payload: manifest,
change: hookEvent.change,
time: hookEvent.time,
};
}
}