feat(api): 搭建 API 与 Worker 骨架及契约基线
NestJS 11 + Fastify 统一错误体与 trace_id,/health 真实探活 DB/Redis,OpenAPI 3.1 契约含 20 个错误码;shared 包提供错误码、权限点、ULID、分页与通用 schema;worker 完成队列进程骨架。
This commit is contained in:
1 parent
09dbb27b66
commit
23067edb8f
70 files changed
+2445
No files matched your search
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* ULID 生成与解析(Crockford Base32,26 字符 = 48bit 时间 + 80bit 随机)
|
||||
* 主键统一由应用侧生成 char(26) ULID(工程规范 05)。
|
||||
*/
|
||||
import { ULID_LENGTH } from './constants.js';
|
||||
|
||||
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
||||
const ENCODING_LEN = 32;
|
||||
|
||||
export const ULID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
||||
|
||||
function randomBytes(length: number): Uint8Array {
|
||||
const bytes = new Uint8Array(length);
|
||||
globalThis.crypto.getRandomValues(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** 生成 ULID;同一毫秒内依靠 80bit 随机数避免碰撞 */
|
||||
export function ulid(timestamp: number = Date.now()): string {
|
||||
if (!Number.isInteger(timestamp) || timestamp < 0 || timestamp > 0xffffffffffff) {
|
||||
throw new RangeError('ULID 时间戳必须是 48bit 非负整数');
|
||||
}
|
||||
let time = timestamp;
|
||||
const timeChars: string[] = new Array<string>(10);
|
||||
for (let i = 9; i >= 0; i -= 1) {
|
||||
timeChars[i] = ENCODING[time % ENCODING_LEN] ?? '0';
|
||||
time = Math.floor(time / ENCODING_LEN);
|
||||
}
|
||||
const randomChars = Array.from(randomBytes(16), (byte) => ENCODING[byte & 31] ?? '0');
|
||||
return `${timeChars.join('')}${randomChars.join('')}`;
|
||||
}
|
||||
|
||||
export function isUlid(value: string): boolean {
|
||||
return value.length === ULID_LENGTH && ULID_PATTERN.test(value);
|
||||
}
|
||||
|
||||
/** 解析 ULID 前 10 位得到毫秒时间戳 */
|
||||
export function ulidToTimestamp(id: string): number {
|
||||
if (!isUlid(id)) {
|
||||
throw new TypeError(`不是合法 ULID:${id}`);
|
||||
}
|
||||
let timestamp = 0;
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
const char = id[i] ?? '';
|
||||
const value = ENCODING.indexOf(char);
|
||||
if (value < 0) {
|
||||
throw new TypeError(`ULID 含非法字符:${char}`);
|
||||
}
|
||||
timestamp = timestamp * ENCODING_LEN + value;
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
export function ulidToDate(id: string): Date {
|
||||
return new Date(ulidToTimestamp(id));
|
||||
}
|
||||
Reference in new issue
Block a user