@anjianshi/utils 2.3.10 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/env-node/crypto-random.d.ts +13 -0
  2. package/env-node/{random.js → crypto-random.js} +5 -5
  3. package/env-node/index.d.ts +2 -2
  4. package/env-node/index.js +2 -2
  5. package/env-node/logging/handlers.d.ts +1 -1
  6. package/env-service/controllers.d.ts +29 -0
  7. package/env-service/controllers.js +39 -0
  8. package/{env-node → env-service}/env-reader.d.ts +1 -1
  9. package/{env-node → env-service}/env-reader.js +1 -0
  10. package/env-service/index.d.ts +7 -0
  11. package/env-service/index.js +7 -0
  12. package/env-service/tasks.d.ts +12 -0
  13. package/env-service/tasks.js +37 -0
  14. package/logging/index.d.ts +1 -1
  15. package/logging/index.js +1 -1
  16. package/package.json +13 -12
  17. package/env-node/random.d.ts +0 -13
  18. /package/{env-node → env-service}/prisma/extensions/exist.d.ts +0 -0
  19. /package/{env-node → env-service}/prisma/extensions/exist.js +0 -0
  20. /package/{env-node → env-service}/prisma/extensions/find-and-count.d.ts +0 -0
  21. /package/{env-node → env-service}/prisma/extensions/find-and-count.js +0 -0
  22. /package/{env-node → env-service}/prisma/extensions/soft-delete.d.ts +0 -0
  23. /package/{env-node → env-service}/prisma/extensions/soft-delete.js +0 -0
  24. /package/{env-node → env-service}/prisma/extensions/with-transaction.d.ts +0 -0
  25. /package/{env-node → env-service}/prisma/extensions/with-transaction.js +0 -0
  26. /package/{env-node → env-service}/prisma/index.d.ts +0 -0
  27. /package/{env-node → env-service}/prisma/index.js +0 -0
  28. /package/{env-node → env-service}/prisma/transaction-contexted.d.ts +0 -0
  29. /package/{env-node → env-service}/prisma/transaction-contexted.js +0 -0
  30. /package/{env-node → env-service}/redis-cache.d.ts +0 -0
  31. /package/{env-node → env-service}/redis-cache.js +0 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 返回随机数,包含 min 和 max
3
+ */
4
+ export declare function getCryptoRandomInt(min: number, max: number): number;
5
+ /**
6
+ * 返回随机字符串
7
+ */
8
+ export declare function getCryptoRandomString(length?: number, seed?: string): string;
9
+ /**
10
+ * 从给定的选择中随机选中一项
11
+ * 如果数组为空,会返回 undefined
12
+ */
13
+ export declare function cryptoChoiceRandom<T>(choices: T[]): T | undefined;
@@ -5,7 +5,7 @@ import crypto from 'node:crypto';
5
5
  /**
6
6
  * 返回随机数,包含 min 和 max
7
7
  */
8
- export function getRandomInt(min, max) {
8
+ export function getCryptoRandomInt(min, max) {
9
9
  // 如果传入的 max 小于 min,把它拉到和 min 一样。不然 crypto.randomInt 无法处理
10
10
  const fixedMax = Math.max(min, max);
11
11
  return crypto.randomInt(min, fixedMax + 1);
@@ -13,16 +13,16 @@ export function getRandomInt(min, max) {
13
13
  /**
14
14
  * 返回随机字符串
15
15
  */
16
- export function getRandomString(length = 6, seed = '0123456789abcdefghijklmnopqrstuvwxyz') {
16
+ export function getCryptoRandomString(length = 6, seed = '0123456789abcdefghijklmnopqrstuvwxyz') {
17
17
  let result = '';
18
18
  while (result.length < length)
19
- result += seed[getRandomInt(0, seed.length - 1)];
19
+ result += seed[getCryptoRandomInt(0, seed.length - 1)];
20
20
  return result;
21
21
  }
22
22
  /**
23
23
  * 从给定的选择中随机选中一项
24
24
  * 如果数组为空,会返回 undefined
25
25
  */
26
- export function choiceRandom(choices) {
27
- return choices[getRandomInt(0, choices.length - 1)];
26
+ export function cryptoChoiceRandom(choices) {
27
+ return choices[getCryptoRandomInt(0, choices.length - 1)];
28
28
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Node 环境下的工具函数
2
+ * Node.js 环境下的工具函数
3
3
  */
4
4
  export * from './fs.js';
5
- export * from './random.js';
5
+ export * from './crypto-random.js';
package/env-node/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Node 环境下的工具函数
2
+ * Node.js 环境下的工具函数
3
3
  */
4
4
  export * from './fs.js';
5
- export * from './random.js';
5
+ export * from './crypto-random.js';
@@ -30,7 +30,7 @@ export declare class ConsoleHandler extends LogHandler {
30
30
  };
31
31
  private static readonly loggerColors;
32
32
  private static readonly loggerColorMap;
33
- static getLoggerColor(logger: string): "blue" | "blueBright" | "cyan" | "cyanBright" | "green" | "greenBright" | "magenta" | "magentaBright" | "yellow" | "yellowBright";
33
+ static getLoggerColor(logger: string): "green" | "yellow" | "blue" | "cyan" | "magenta" | "greenBright" | "yellowBright" | "blueBright" | "cyanBright" | "magentaBright";
34
34
  }
35
35
  /**
36
36
  * 写入文件日志
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 把业务功能整理成各个 Controller,
3
+ * 并整合成一个 controllers 对象方便外部引用和 Controller 之间互相引用。
4
+ *
5
+ * 支持自定义 Controller 类,例如把 context 中的内容定义成属性。
6
+ */
7
+ type AnyObject = Record<string, unknown>;
8
+ type AnyController<Context> = Controller<Context, any>;
9
+ type AnyControllerClass<Context> = typeof Controller<Context, any>;
10
+ export type ControllersFrom<Context, T extends AnyObject> = {
11
+ [K in keyof T]: T[K] extends AnyControllerClass<Context> ? InstanceType<T[K]> : never;
12
+ };
13
+ /**
14
+ * Controller 基类
15
+ */
16
+ export declare class Controller<Context, AllControllers extends Record<string, AnyController<Context>>> {
17
+ /** 调用其他 controllers */
18
+ protected readonly controllers: AllControllers;
19
+ protected readonly context: Context;
20
+ constructor(
21
+ /** 调用其他 controllers */
22
+ controllers: AllControllers, context: Context);
23
+ }
24
+ /**
25
+ * 传入 Controller 类列表,返回 controller 实例集合。
26
+ * 为优化性能,每个 controller 只有在被使用到时才会实例化。
27
+ */
28
+ export declare function initializeControllers<Context, T extends AnyObject>(controllerClasses: T, context: Context): ControllersFrom<Context, T>;
29
+ export {};
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 把业务功能整理成各个 Controller,
3
+ * 并整合成一个 controllers 对象方便外部引用和 Controller 之间互相引用。
4
+ *
5
+ * 支持自定义 Controller 类,例如把 context 中的内容定义成属性。
6
+ */
7
+ /**
8
+ * Controller 基类
9
+ */
10
+ export class Controller {
11
+ controllers;
12
+ context;
13
+ constructor(
14
+ /** 调用其他 controllers */
15
+ controllers, context) {
16
+ this.controllers = controllers;
17
+ this.context = context;
18
+ }
19
+ }
20
+ /**
21
+ * 传入 Controller 类列表,返回 controller 实例集合。
22
+ * 为优化性能,每个 controller 只有在被使用到时才会实例化。
23
+ */
24
+ export function initializeControllers(controllerClasses, context) {
25
+ const proxy = new Proxy({}, {
26
+ get(controllers, prop) {
27
+ if (typeof prop !== 'string')
28
+ return;
29
+ if (prop in controllers)
30
+ return controllers[prop];
31
+ if (prop in controllerClasses) {
32
+ const Class = controllerClasses[prop];
33
+ controllers[prop] = new Class(proxy, context);
34
+ return controllers[prop];
35
+ }
36
+ },
37
+ });
38
+ return proxy;
39
+ }
@@ -35,7 +35,7 @@ export declare class EnvReader {
35
35
  * 同 envReader.get(),只不过是通过对象指定各 env 的默认值来批量获取
36
36
  * envReader.batchGet({ port: 8000, debug: false, mobiles: ['123', '456'] }
37
37
  */
38
- batchGet<Defs extends Record<string, EnvValue>>(definitions: Defs): Defs;
38
+ batchGet<Defs extends Record<string, EnvValue>>(definitions: Defs): { [K in keyof Defs]: Defs[K] extends string ? string : Defs[K] extends number ? number : Defs[K] extends boolean ? boolean : Defs[K]; };
39
39
  /**
40
40
  * 同 envReader.getByType(),只不过是通过对象指定各 env 的类型来批量获取。
41
41
  *
@@ -62,6 +62,7 @@ export class EnvReader {
62
62
  for (const [key, defaults] of Object.entries(definitions)) {
63
63
  result[key] = this.get(key, defaults);
64
64
  }
65
+ // 保证返回的值类型是“通用化”的,例如不是 `false` 而是 `boolean`
65
66
  return result;
66
67
  }
67
68
  batchGetByType(definitions, required = false) {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 开发后端服务能用到的工具库
3
+ */
4
+ export * from './env-reader.js';
5
+ export * from './redis-cache.js';
6
+ export * from './controllers.js';
7
+ export * from './tasks.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 开发后端服务能用到的工具库
3
+ */
4
+ export * from './env-reader.js';
5
+ export * from './redis-cache.js';
6
+ export * from './controllers.js';
7
+ export * from './tasks.js';
@@ -0,0 +1,12 @@
1
+ import { type Logger } from '../logging/index.js';
2
+ /** 返回 false 可结束任务 */
3
+ export type TaskExecutor<Context> = (context: Context) => Promise<undefined | false>;
4
+ /**
5
+ * 执行定期任务
6
+ */
7
+ export declare abstract class TaskManager<Context> {
8
+ protected baseLogger: Logger;
9
+ constructor(baseLogger?: Logger);
10
+ abstract getContext(taskName: string): Context;
11
+ run(name: string, interval: number, executor: TaskExecutor<Context>): Promise<void>;
12
+ }
@@ -0,0 +1,37 @@
1
+ import { sleep } from '../lang/async.js';
2
+ import { logger as rootLogger } from '../logging/index.js';
3
+ /**
4
+ * 执行定期任务
5
+ */
6
+ export class TaskManager {
7
+ baseLogger;
8
+ constructor(baseLogger = rootLogger.getChild('task')) {
9
+ this.baseLogger = baseLogger;
10
+ }
11
+ async run(name, interval, executor) {
12
+ await sleep(1000);
13
+ const logger = this.baseLogger.getChild(name);
14
+ let nextId = 1;
15
+ while (true) {
16
+ const id = nextId++;
17
+ if (id >= Number.MAX_SAFE_INTEGER)
18
+ nextId = 1;
19
+ const start = Date.now();
20
+ logger.info(`#${id} 任务开始`);
21
+ try {
22
+ const context = this.getContext(name);
23
+ const result = await executor(context);
24
+ const cost = (Date.now() - start) / 1000;
25
+ logger.info(`#${id} 任务完成,耗时 ${cost}s`);
26
+ if (result === false) {
27
+ logger.info('任务结束');
28
+ break;
29
+ }
30
+ }
31
+ catch (err) {
32
+ logger.error(`#${id} 任务失败`, err);
33
+ }
34
+ await sleep(interval);
35
+ }
36
+ }
37
+ }
@@ -1,6 +1,6 @@
1
+ import { type Dayjs } from 'dayjs';
1
2
  export { default as formatters } from './formatters.js';
2
3
  export * from './adapt.js';
3
- import { type Dayjs } from 'dayjs';
4
4
  export declare enum LogLevel {
5
5
  Debug = 1,
6
6
  Info = 2,
package/logging/index.js CHANGED
@@ -1,6 +1,6 @@
1
+ import dayjs from 'dayjs';
1
2
  export { default as formatters } from './formatters.js';
2
3
  export * from './adapt.js';
3
- import dayjs from 'dayjs';
4
4
  import { initDayJs } from '../init-dayjs.js';
5
5
  // 引入 logging 库会自动初始化 dayjs
6
6
  initDayJs();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anjianshi/utils",
3
- "version": "2.3.10",
3
+ "version": "2.4.0",
4
4
  "description": "Common JavaScript Utils",
5
5
  "homepage": "https://github.com/anjianshi/js-packages/utils",
6
6
  "bugs": {
@@ -20,17 +20,18 @@
20
20
  "lodash": "^4.17.21"
21
21
  },
22
22
  "devDependencies": {
23
- "@types/lodash": "^4.17.7",
24
- "@types/node": "^20.16.2",
25
- "@types/react": "^18.3.5",
23
+ "@types/lodash": "^4.17.10",
24
+ "@types/node": "^20.16.11",
25
+ "@types/react": "^18.3.11",
26
26
  "dotenv": "^16.4.5",
27
- "typescript": "^5.5.4",
27
+ "redis": "^4.7.0",
28
+ "typescript": "^5.6.3",
28
29
  "vconsole": "^3.15.1",
29
- "@anjianshi/presets-eslint-node": "4.0.8",
30
- "@anjianshi/presets-eslint-typescript": "5.0.5",
30
+ "@anjianshi/presets-eslint-react": "4.0.7",
31
31
  "@anjianshi/presets-typescript": "3.2.2",
32
32
  "@anjianshi/presets-prettier": "3.0.1",
33
- "@anjianshi/presets-eslint-react": "4.0.7"
33
+ "@anjianshi/presets-eslint-typescript": "5.0.5",
34
+ "@anjianshi/presets-eslint-node": "4.0.8"
34
35
  },
35
36
  "peerDependencies": {
36
37
  "@emotion/react": "^11.13.3",
@@ -39,8 +40,8 @@
39
40
  "@prisma/client": "^5.20.0",
40
41
  "chalk": "^5.3.0",
41
42
  "dayjs": "^1.11.10",
42
- "react": "^18.3.1",
43
- "redis": "^4.7.0"
43
+ "dotenv": "^16.4.5",
44
+ "react": "^18.3.1"
44
45
  },
45
46
  "peerDependenciesMeta": {
46
47
  "@emotion/react": {
@@ -61,10 +62,10 @@
61
62
  "dayjs": {
62
63
  "optional": true
63
64
  },
64
- "react": {
65
+ "dotenv": {
65
66
  "optional": true
66
67
  },
67
- "redis": {
68
+ "react": {
68
69
  "optional": true
69
70
  }
70
71
  },
@@ -1,13 +0,0 @@
1
- /**
2
- * 返回随机数,包含 min 和 max
3
- */
4
- export declare function getRandomInt(min: number, max: number): number;
5
- /**
6
- * 返回随机字符串
7
- */
8
- export declare function getRandomString(length?: number, seed?: string): string;
9
- /**
10
- * 从给定的选择中随机选中一项
11
- * 如果数组为空,会返回 undefined
12
- */
13
- export declare function choiceRandom<T>(choices: T[]): T | undefined;
File without changes
File without changes
File without changes
File without changes