feat: complete cmpp platform phases 0-5

This commit is contained in:
hectorzhao
2026-07-01 13:22:04 +08:00
parent 824a8b334f
commit ee926fea04
86 changed files with 10490 additions and 14 deletions
@@ -0,0 +1,79 @@
import { readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
const examplesDir = join(process.cwd(), 'docs', 'contracts', 'examples');
const envelopeFields = ['schemaVersion', 'messageType', 'traceId', 'messageId', 'channelId', 'createdAt'];
const requiredByType = {
SubmitCommand: [
...envelopeFields,
'tenantId',
'applicationId',
'submitId',
'phoneNumber',
'content',
'signature',
'templateId',
'billingUnits',
'route',
'cmpp',
'retry',
],
SubmitResult: [...envelopeFields, 'sequenceId', 'gatewayMessageId', 'submitStatus', 'submittedAt'],
ReceiptEvent: [...envelopeFields, 'sequenceId', 'gatewayMessageId', 'receiptStatus', 'rawStatus', 'deliveredAt'],
UplinkEvent: [...envelopeFields, 'sequenceId', 'phoneNumber', 'destId', 'content', 'receivedAt'],
};
const validTypes = new Set(Object.keys(requiredByType));
const chinaMobileNumber = /^1[3-9][0-9]{9}$/;
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function assertIsoDateTime(value, field, file) {
assert(typeof value === 'string' && !Number.isNaN(Date.parse(value)), `${file}: ${field} must be ISO date-time`);
}
function validateExample(fileName) {
const fullPath = join(examplesDir, fileName);
const payload = JSON.parse(readFileSync(fullPath, 'utf8'));
const type = payload.messageType;
assert(validTypes.has(type), `${fileName}: unsupported messageType ${type}`);
assert(payload.schemaVersion === 'v1', `${fileName}: schemaVersion must be v1`);
for (const field of requiredByType[type]) {
assert(Object.hasOwn(payload, field), `${fileName}: missing ${field}`);
}
for (const dateField of ['createdAt', 'submittedAt', 'deliveredAt', 'receivedAt']) {
if (payload[dateField]) {
assertIsoDateTime(payload[dateField], dateField, fileName);
}
}
if (payload.phoneNumber) {
assert(chinaMobileNumber.test(payload.phoneNumber), `${fileName}: phoneNumber must be a mainland China mobile number`);
}
if (type === 'SubmitCommand') {
assert(payload.billingUnits >= 1, `${fileName}: billingUnits must be >= 1`);
assert(payload.route?.channelCode, `${fileName}: route.channelCode is required`);
assert(payload.route?.cmppAccountCode, `${fileName}: route.cmppAccountCode is required`);
assert([0, 1].includes(payload.cmpp?.registeredDelivery), `${fileName}: cmpp.registeredDelivery must be 0 or 1`);
assert([8, 15].includes(payload.cmpp?.msgFmt), `${fileName}: cmpp.msgFmt must be 8 or 15`);
assert(payload.retry?.maxAttempts >= 1, `${fileName}: retry.maxAttempts must be >= 1`);
}
return `${fileName}: ${type} ok`;
}
const exampleFiles = readdirSync(examplesDir).filter((file) => file.endsWith('.json')).sort();
assert(exampleFiles.length > 0, 'No queue contract examples found');
const results = exampleFiles.map(validateExample);
console.log(results.join('\n'));
console.log(`Validated ${results.length} gateway queue contract examples.`);