feat(GOV-009): 建立后端契约与健康检查
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
export interface MessageEnvelope<TPayload> {
|
||||
version: 1;
|
||||
eventType: string;
|
||||
idempotencyKey: string;
|
||||
occurredAt: string;
|
||||
payload: TPayload;
|
||||
}
|
||||
|
||||
type MessageEnvelopeInput<TPayload> = Omit<MessageEnvelope<TPayload>, 'version'> & {
|
||||
version: number;
|
||||
};
|
||||
|
||||
function deepFreeze<TValue>(value: TValue): Readonly<TValue> {
|
||||
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
||||
for (const child of Object.values(value as Record<string, unknown>)) deepFreeze(child);
|
||||
Object.freeze(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function createMessageEnvelope<TPayload>(
|
||||
input: MessageEnvelopeInput<TPayload>,
|
||||
): Readonly<MessageEnvelope<TPayload>> {
|
||||
if (input.version !== 1) throw new Error('version 只支持 1');
|
||||
if (!input.eventType.trim()) throw new Error('eventType 不能为空');
|
||||
if (!input.idempotencyKey.trim()) throw new Error('idempotencyKey 不能为空');
|
||||
if (!input.occurredAt.trim() || Number.isNaN(Date.parse(input.occurredAt))) {
|
||||
throw new Error('occurredAt 必须为合法 ISO 时间');
|
||||
}
|
||||
if (input.payload === undefined) throw new Error('payload 不能为空');
|
||||
|
||||
return deepFreeze({
|
||||
version: 1,
|
||||
eventType: input.eventType.trim(),
|
||||
idempotencyKey: input.idempotencyKey.trim(),
|
||||
occurredAt: new Date(input.occurredAt).toISOString(),
|
||||
payload: input.payload,
|
||||
}) as Readonly<MessageEnvelope<TPayload>>;
|
||||
}
|
||||
Reference in New Issue
Block a user