@wener/utils 1.1.20 → 1.1.22

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 (56) hide show
  1. package/dist/cjs/index.cjs +9 -9
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/server.cjs +1 -1
  4. package/dist/cjs/server.cjs.map +1 -1
  5. package/dist/esm/index.js +9 -9
  6. package/dist/esm/index.js.map +1 -1
  7. package/dist/esm/server.js +1 -1
  8. package/dist/esm/server.js.map +1 -1
  9. package/dist/system/index.js +9 -9
  10. package/dist/system/index.js.map +1 -1
  11. package/dist/system/server.js +1 -1
  12. package/dist/system/server.js.map +1 -1
  13. package/lib/asyncs/createAsyncIterator.js.map +1 -1
  14. package/lib/asyncs/createLazyPromise.js.map +1 -1
  15. package/lib/crypto/md5.js +123 -0
  16. package/lib/crypto/md5.js.map +1 -0
  17. package/lib/errors/Errors.js +137 -0
  18. package/lib/errors/Errors.js.map +1 -0
  19. package/lib/fetch/dumpResponse.js +1 -1
  20. package/lib/fetch/dumpResponse.js.map +1 -1
  21. package/lib/http/HttpStatus.js +85 -0
  22. package/lib/http/HttpStatus.js.map +1 -0
  23. package/lib/index.js +4 -1
  24. package/lib/index.js.map +1 -1
  25. package/lib/logging/createLogger.js.map +1 -1
  26. package/lib/server.js +0 -3
  27. package/lib/server.js.map +1 -1
  28. package/package.json +21 -7
  29. package/server/jsdom.ts +1 -0
  30. package/server/node-fetch.ts +1 -0
  31. package/server/ws.ts +1 -0
  32. package/src/asyncs/createAsyncIterator.ts +10 -7
  33. package/src/asyncs/createLazyPromise.test.ts +9 -8
  34. package/src/asyncs/createLazyPromise.ts +1 -1
  35. package/src/crypto/md5.bench.ts +31 -0
  36. package/src/crypto/md5.test.ts +8 -0
  37. package/src/errors/Errors.ts +199 -0
  38. package/src/fetch/dumpResponse.ts +3 -3
  39. package/src/http/HttpStatus.ts +96 -0
  40. package/src/index.ts +10 -1
  41. package/src/logging/createLogger.ts +9 -0
  42. package/src/server.ts +0 -3
  43. package/src/servers/jsdom.ts +1 -0
  44. package/src/servers/node-fetch.ts +2 -0
  45. package/src/servers/ws.ts +1 -0
  46. package/src/types/global.d.ts +11 -0
  47. package/src/types/index.d.ts +8 -0
  48. package/types.d.ts +1 -0
  49. package/lib/servers/polyfill/polyfillBrowser.js +0 -12
  50. package/lib/servers/polyfill/polyfillBrowser.js.map +0 -1
  51. package/lib/servers/polyfill/polyfillFetch.js +0 -24
  52. package/lib/servers/polyfill/polyfillFetch.js.map +0 -1
  53. package/lib/servers/polyfill/polyfillJsDom.js +0 -57
  54. package/lib/servers/polyfill/polyfillJsDom.js.map +0 -1
  55. package/lib/servers/polyfill/polyfillWebSocket.js +0 -16
  56. package/lib/servers/polyfill/polyfillWebSocket.js.map +0 -1
package/lib/index.js CHANGED
@@ -8,6 +8,7 @@ export { createLazyPromise } from './asyncs/createLazyPromise.js';
8
8
  export { clearAsyncInterval, setAsyncInterval } from './asyncs/AsyncInterval.js';
9
9
  export { createAsyncIterator } from './asyncs/createAsyncIterator.js';
10
10
  export { firstOfAsyncIterator } from './asyncs/firstOfAsyncIterator.js';
11
+ export { nextOfAsyncIterator } from './asyncs/nextOfAsyncIterator.js';
11
12
  export { isIterator } from './asyncs/isIterator.js';
12
13
  export { sleep } from './asyncs/sleep.js';
13
14
  export { TimeoutError, timeout } from './asyncs/timeout.js';
@@ -47,6 +48,7 @@ export { structuredClone } from './isomorphics/structuredClone.js';
47
48
  export { randomUUID } from './crypto/randomUUID.js';
48
49
  export { getRandomValues } from './crypto/getRandomValues.js';
49
50
  export { sha1, sha256, sha384, sha512 } from './crypto/hashing.js';
51
+ export { md5 } from './crypto/md5.js';
50
52
  export { hex } from './crypto/base.js';
51
53
  export { createULID, isULID, parseULID, ulid } from './crypto/ulid.js';
52
54
  export { PEM } from './crypto/pem/pem.js';
@@ -56,5 +58,6 @@ export { createFetchWithLogging } from './fetch/createFetchWithLogging.js';
56
58
  export { dumpRequest } from './fetch/dumpRequest.js';
57
59
  export { dumpResponse } from './fetch/dumpResponse.js';
58
60
  export { default as ms } from './libs/ms.js';
59
- export { nextOfAsyncIterator } from './asyncs/nextOfAsyncIterator.js';
61
+ export { DetailError, Errors } from './errors/Errors.js';
62
+ export { getHttpStatusText, isRetryableHttpStatus } from './http/HttpStatus.js';
60
63
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createLogger.js","sources":["../../src/logging/createLogger.ts"],"sourcesContent":["import type { LoggerWithChild, LogLevel } from './Logger';\n\nexport function createLogger(\n write: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void = ({\n level,\n values,\n ...ctx\n }) => {\n ({ values, ...ctx } = merge(ctx, values));\n console[level]?.(...values, ctx);\n },\n context: object = {},\n): LoggerWithChild {\n return {\n trace: (...values) => {\n write({ ...context, level: 'trace', values });\n },\n debug: (...values) => {\n write({ ...context, level: 'debug', values });\n },\n info: (...values) => {\n write({ ...context, level: 'info', values });\n },\n warn: (...values) => {\n write({ ...context, level: 'warn', values });\n },\n error: (...values) => {\n write({ ...context, level: 'error', values });\n },\n child: (ctx) => createLogger(write, { ...context, ...ctx }),\n };\n}\n\n// logger.info({name:'wener'},'message')\n// merge initial context with message object\nfunction merge(ctx: any, values: any[]) {\n if (values[0] && typeof values[0] === 'object') {\n return { ...ctx, ...values[0], values: values.slice(1) };\n }\n return { ...ctx, values };\n}\n"],"names":[],"mappings":"AAEgB,SAAA,YAAA,CACd,QAAwF,CAAC;AAAA,EACvF,KAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAG,GAAA;AACL,CAAM,KAAA;AAPR,EAAA,IAAA,EAAA,CAAA;AAQI,EAAA,CAAC,EAAE,MAAQ,EAAA,GAAG,KAAQ,GAAA,KAAA,CAAM,KAAK,MAAM,CAAA,EAAA;AACvC,EAAQ,CAAA,EAAA,GAAA,OAAA,CAAA,KAAA,CAAA,KAAR,IAAiB,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,IAAA,CAAA,OAAA,EAAA,GAAG,MAAQ,EAAA,GAAA,CAAA,CAAA;AAC9B,CACA,EAAA,OAAA,GAAkB,EACD,EAAA;AACjB,EAAO,OAAA;AAAA,IACL,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,IAAA,EAAM,IAAI,MAAW,KAAA;AACnB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,KAC7C;AAAA,IACA,IAAA,EAAM,IAAI,MAAW,KAAA;AACnB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,KAC7C;AAAA,IACA,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,KAAA,EAAO,CAAC,GAAA,KAAQ,YAAa,CAAA,KAAA,EAAO,EAAE,GAAG,OAAA,EAAS,GAAG,GAAA,EAAK,CAAA;AAAA,GAC5D,CAAA;AACF,CAAA;AAIA,SAAS,KAAA,CAAM,KAAU,MAAe,EAAA;AACtC,EAAA,IAAI,OAAO,CAAC,CAAA,IAAK,OAAO,MAAO,CAAA,CAAC,MAAM,QAAU,EAAA;AAC9C,IAAO,OAAA,EAAE,GAAG,GAAA,EAAK,GAAG,MAAA,CAAO,CAAC,CAAA,EAAG,MAAQ,EAAA,MAAA,CAAO,KAAM,CAAA,CAAC,CAAE,EAAA,CAAA;AAAA,GACzD;AACA,EAAO,OAAA,EAAE,GAAG,GAAA,EAAK,MAAO,EAAA,CAAA;AAC1B;;;;"}
1
+ {"version":3,"file":"createLogger.js","sources":["../../src/logging/createLogger.ts"],"sourcesContent":["import type { LoggerWithChild, LogLevel } from './Logger';\n\nexport interface CreateLoggerOptions {\n name?: string;\n handler?: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void;\n context?: Record<string, any>;\n levels?: LogLevel[];\n}\n\nexport function createLogger(\n write: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void = ({\n level,\n values,\n ...ctx\n }) => {\n ({ values, ...ctx } = merge(ctx, values));\n console[level]?.(...values, ctx);\n },\n context: object = {},\n): LoggerWithChild {\n return {\n trace: (...values) => {\n write({ ...context, level: 'trace', values });\n },\n debug: (...values) => {\n write({ ...context, level: 'debug', values });\n },\n info: (...values) => {\n write({ ...context, level: 'info', values });\n },\n warn: (...values) => {\n write({ ...context, level: 'warn', values });\n },\n error: (...values) => {\n write({ ...context, level: 'error', values });\n },\n child: (ctx) => createLogger(write, { ...context, ...ctx }),\n };\n}\n\n// logger.info({name:'wener'},'message')\n// merge initial context with message object\nfunction merge(ctx: any, values: any[]) {\n if (values[0] && typeof values[0] === 'object') {\n return { ...ctx, ...values[0], values: values.slice(1) };\n }\n return { ...ctx, values };\n}\n\n// https://github.com/nestjs/nest/blob/master/packages/common/services/console-logger.service.ts\n"],"names":[],"mappings":"AASgB,SAAA,YAAA,CACd,QAAwF,CAAC;AAAA,EACvF,KAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAG,GAAA;AACL,CAAM,KAAA;AAdR,EAAA,IAAA,EAAA,CAAA;AAeI,EAAA,CAAC,EAAE,MAAQ,EAAA,GAAG,KAAQ,GAAA,KAAA,CAAM,KAAK,MAAM,CAAA,EAAA;AACvC,EAAQ,CAAA,EAAA,GAAA,OAAA,CAAA,KAAA,CAAA,KAAR,IAAiB,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,IAAA,CAAA,OAAA,EAAA,GAAG,MAAQ,EAAA,GAAA,CAAA,CAAA;AAC9B,CACA,EAAA,OAAA,GAAkB,EACD,EAAA;AACjB,EAAO,OAAA;AAAA,IACL,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,IAAA,EAAM,IAAI,MAAW,KAAA;AACnB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,KAC7C;AAAA,IACA,IAAA,EAAM,IAAI,MAAW,KAAA;AACnB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AAAA,KAC7C;AAAA,IACA,KAAA,EAAO,IAAI,MAAW,KAAA;AACpB,MAAA,KAAA,CAAM,EAAE,GAAG,OAAA,EAAS,KAAO,EAAA,OAAA,EAAS,QAAQ,CAAA,CAAA;AAAA,KAC9C;AAAA,IACA,KAAA,EAAO,CAAC,GAAA,KAAQ,YAAa,CAAA,KAAA,EAAO,EAAE,GAAG,OAAA,EAAS,GAAG,GAAA,EAAK,CAAA;AAAA,GAC5D,CAAA;AACF,CAAA;AAIA,SAAS,KAAA,CAAM,KAAU,MAAe,EAAA;AACtC,EAAA,IAAI,OAAO,CAAC,CAAA,IAAK,OAAO,MAAO,CAAA,CAAC,MAAM,QAAU,EAAA;AAC9C,IAAO,OAAA,EAAE,GAAG,GAAA,EAAK,GAAG,MAAA,CAAO,CAAC,CAAA,EAAG,MAAQ,EAAA,MAAA,CAAO,KAAM,CAAA,CAAC,CAAE,EAAA,CAAA;AAAA,GACzD;AACA,EAAO,OAAA,EAAE,GAAG,GAAA,EAAK,MAAO,EAAA,CAAA;AAC1B;;;;"}
package/lib/server.js CHANGED
@@ -1,7 +1,4 @@
1
1
  export { polyfillCrypto } from './servers/polyfill/polyfillCrypto.js';
2
- export { polyfillJsDom } from './servers/polyfill/polyfillJsDom.js';
3
- export { polyfillBrowser } from './servers/polyfill/polyfillBrowser.js';
4
- export { polyfillWebSocket } from './servers/polyfill/polyfillWebSocket.js';
5
2
  export { createFetchWithProxyByUndici } from './servers/fetch/createFetchWithProxyByUndici.js';
6
3
  export { createFetchWithProxy } from './servers/fetch/createFetchWithProxy.js';
7
4
  export { createFetchWithRetry } from './servers/fetch/createFetchWithRetry.js';
package/lib/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
1
+ {"version":3,"file":"server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wener/utils",
3
- "version": "1.1.20",
3
+ "version": "1.1.22",
4
4
  "type": "module",
5
5
  "description": "Utils for daily use",
6
6
  "repository": {
@@ -14,9 +14,11 @@
14
14
  "dist",
15
15
  "index.ts",
16
16
  "lib",
17
+ "server",
17
18
  "server.ts",
18
19
  "src",
19
- "tsconfig.json"
20
+ "tsconfig.json",
21
+ "types.d.ts"
20
22
  ],
21
23
  "keywords": [
22
24
  "utils",
@@ -37,12 +39,12 @@
37
39
  }
38
40
  },
39
41
  "devDependencies": {
40
- "@types/lodash": "^4.14.196",
41
- "@types/ws": "^8.5.5",
42
- "https-proxy-agent": "^7.0.1",
42
+ "@types/lodash": "^4.14.199",
43
+ "@types/ws": "^8.5.7",
44
+ "https-proxy-agent": "^7.0.2",
43
45
  "lodash": "^4.17.21",
44
46
  "node-fetch": "^3.3.2",
45
- "undici": "^5.23.0"
47
+ "undici": "^5.25.4"
46
48
  },
47
49
  "publishConfig": {
48
50
  "registry": "https://registry.npmjs.org",
@@ -58,6 +60,7 @@
58
60
  "crypto",
59
61
  "jsdom",
60
62
  "node-fetch",
63
+ "ws",
61
64
  "undici"
62
65
  ]
63
66
  },
@@ -83,7 +86,18 @@
83
86
  "system": "./dist/system/server.js",
84
87
  "import": "./lib/server.js"
85
88
  },
86
- "./src/*": "./src/*",
89
+ "./server/node-fetch": {
90
+ "types": "./server/node-fetch.ts",
91
+ "default": "./lib/servers/node-fetch.js"
92
+ },
93
+ "./server/jsdom": {
94
+ "types": "./server/jsdom.ts",
95
+ "default": "./lib/servers/jsdom.js"
96
+ },
97
+ "./server/ws": {
98
+ "types": "./server/ws.ts",
99
+ "default": "./lib/servers/ws.js"
100
+ },
87
101
  "./package.json": "./package.json"
88
102
  }
89
103
  }
@@ -0,0 +1 @@
1
+ export * from '../src/servers/jsdom';
@@ -0,0 +1 @@
1
+ export * from '../src/servers/node-fetch';
package/server/ws.ts ADDED
@@ -0,0 +1 @@
1
+ export * from '../src/servers/ws';
@@ -1,12 +1,15 @@
1
- import { createLazyPromise, LazyPromise } from './createLazyPromise';
1
+ import { type MaybePromise } from './MaybePromise';
2
+ import { createLazyPromise, type LazyPromise } from './createLazyPromise';
3
+
4
+ type Val<T> = [val: MaybePromise<T> | undefined, done: boolean, err?: any];
2
5
 
3
6
  export function createAsyncIterator<T>(
4
- fn: (next: (val: [T | undefined, boolean] | undefined, err?: any) => void) => void,
5
- ) {
6
- const values: Array<Promise<[val: T | undefined, done: boolean, err?: any]>> = [];
7
- let recv: (val: [T | undefined, boolean] | undefined, err?: any) => void;
7
+ fn: (next: (val: [MaybePromise<T> | undefined, boolean] | undefined, err?: any) => void) => void,
8
+ ): AsyncGenerator<T, void, unknown> {
9
+ const values: Array<Promise<Val<T>>> = [];
10
+ let recv: (val: [MaybePromise<T> | undefined, boolean] | undefined, err?: any) => void;
8
11
  {
9
- let next: LazyPromise<[val: T | undefined, done: boolean, err?: any]>;
12
+ let next: LazyPromise<Val<T>>;
10
13
  values.push((next = createLazyPromise()));
11
14
  recv = (val, err) => {
12
15
  if (err !== undefined) {
@@ -23,7 +26,7 @@ export function createAsyncIterator<T>(
23
26
  fn(recv);
24
27
 
25
28
  return (async function* () {
26
- let value: T | undefined;
29
+ let value: Val<T>[0];
27
30
  let err: any;
28
31
  for (let i = 0, done = false; !done; i++) {
29
32
  let result = await values[i];
@@ -1,6 +1,5 @@
1
- import { test, expect } from 'vitest';
1
+ import { expect, test } from 'vitest';
2
2
  import { createLazyPromise } from './createLazyPromise';
3
- import { sleep } from './sleep';
4
3
 
5
4
  test('basic', async () => {
6
5
  const promise = createLazyPromise();
@@ -18,36 +17,38 @@ test('basic', async () => {
18
17
 
19
18
  test('manual resolve skip exec', async () => {
20
19
  const promise = createLazyPromise<number>(() => {
21
- expect.fail();
20
+ expect.fail('should not exec');
22
21
  });
23
22
  promise.resolve(-1);
24
23
  expect(await promise).toBe(-1);
25
24
  });
26
25
 
27
- test('exec', async () => {
26
+ test('lazy exec resolve by manual', async () => {
28
27
  let r = 0;
29
28
  const promise = createLazyPromise((resolve) => {
30
29
  r++;
31
30
  resolve(10);
32
31
  });
33
- await sleep(10);
32
+ await Promise.resolve();
34
33
  expect(r).toBe(0);
35
34
  expect(await promise).toBe(10);
36
35
  expect(r).toBe(1);
37
36
  promise.resolve(20);
38
37
  expect(await promise).toBe(10);
38
+ expect(r).toBe(1);
39
39
  });
40
40
 
41
- test('exec auto', async () => {
41
+ test('lazy exec resolve by return', async () => {
42
42
  let r = 0;
43
43
  const promise = createLazyPromise(() => {
44
44
  r++;
45
45
  return 10;
46
46
  });
47
- await sleep(10);
47
+ await Promise.resolve();
48
48
  expect(r).toBe(0);
49
49
  void promise.then(() => undefined);
50
- expect(await promise).toBe(10);
50
+ await Promise.resolve();
51
+ // already resolved
51
52
  expect(r).toBe(1);
52
53
  expect(await promise).toBe(10);
53
54
  expect(r).toBe(1);
@@ -3,7 +3,7 @@ import { isPromise } from './isPromise';
3
3
 
4
4
  export type LazyPromise<T> = Promise<T> & {
5
5
  reject(reason?: any): void;
6
- resolve(v?: T | PromiseLike<T>): void;
6
+ resolve(v?: MaybePromise<T>): void;
7
7
  };
8
8
 
9
9
  /**
@@ -0,0 +1,31 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { bench, describe } from 'vitest';
3
+ import { md5 } from './md5';
4
+
5
+ describe('md5', () => {
6
+ const dataset = new Array(10000).fill(0).map((_, i) => String(Math.random() * i));
7
+ let iterations = 0;
8
+ bench(
9
+ 'js',
10
+ function () {
11
+ iterations++;
12
+ md5(dataset[iterations % dataset.length]);
13
+ },
14
+ {
15
+ iterations: 10000,
16
+ },
17
+ );
18
+
19
+ bench(
20
+ 'native',
21
+ function () {
22
+ iterations++;
23
+ createHash('md5')
24
+ .update(dataset[iterations % dataset.length])
25
+ .digest('hex');
26
+ },
27
+ {
28
+ iterations: 10000,
29
+ },
30
+ );
31
+ });
@@ -0,0 +1,8 @@
1
+ import { assert, describe, test } from 'vitest';
2
+ import { md5 } from './md5';
3
+
4
+ describe('md5', () => {
5
+ test('js', () => {
6
+ assert.equal(md5(''), 'd41d8cd98f00b204e9800998ecf8427e');
7
+ });
8
+ });
@@ -0,0 +1,199 @@
1
+ import { getHttpStatusText } from '../http/HttpStatus';
2
+
3
+ export interface ErrorDetailInit {
4
+ message?: string;
5
+ status: number;
6
+ description?: string;
7
+ code?: number | string;
8
+ metadata?: Record<string, any>;
9
+ cause?: any;
10
+ }
11
+
12
+ export class DetailError extends Error {
13
+ readonly status: number;
14
+ readonly description?: string;
15
+
16
+ constructor(readonly detail: ErrorDetail) {
17
+ super(detail.message, {
18
+ cause: detail.cause,
19
+ });
20
+ this.status = detail.status;
21
+ this.description = detail.description;
22
+ }
23
+
24
+ toJSON() {
25
+ return {
26
+ code: this.detail.code,
27
+ message: this.message,
28
+ status: this.status,
29
+ description: this.description,
30
+ cause: this.cause,
31
+ };
32
+ }
33
+ }
34
+
35
+ class DetailHolder implements ErrorDetail {
36
+ readonly message: string;
37
+ readonly status: number;
38
+ readonly code: number | string;
39
+ readonly metadata?: Record<string, any>;
40
+ readonly description?: string;
41
+ readonly cause?: any;
42
+
43
+ constructor({
44
+ status,
45
+ message = getHttpStatusText(status),
46
+ code = status,
47
+ metadata,
48
+ description,
49
+ cause,
50
+ }: ErrorDetailInit) {
51
+ this.message = message ?? String(status);
52
+ this.status = status;
53
+ this.code = code;
54
+ this.description = description;
55
+ this.metadata = metadata;
56
+ this.cause = cause;
57
+ }
58
+
59
+ with(o?: Partial<ErrorDetailInit> | string): DetailHolder {
60
+ if (typeof o === 'string') {
61
+ o = { message: o };
62
+ }
63
+
64
+ if (o === undefined) {
65
+ return new DetailHolder(this);
66
+ }
67
+
68
+ return new DetailHolder({
69
+ status: this.status,
70
+ code: this.code,
71
+ message: this.message,
72
+ metadata: this.metadata,
73
+ cause: this.cause,
74
+ ...o,
75
+ });
76
+ }
77
+
78
+ asError(o?: Partial<ErrorDetailInit> | string): Error {
79
+ if (typeof o === 'string') {
80
+ o = { message: o };
81
+ }
82
+
83
+ return new DetailError(this.with(o));
84
+ }
85
+
86
+ require(v: any, o?: Partial<ErrorDetailInit> | string): any {
87
+ if (v === undefined || v === null) {
88
+ throw this.asError(o);
89
+ }
90
+
91
+ return v;
92
+ }
93
+
94
+ check(cond: any, o?: Partial<ErrorDetailInit> | string) {
95
+ switch (cond) {
96
+ case false:
97
+ case undefined:
98
+ case null: {
99
+ throw this.asError(o);
100
+ }
101
+ }
102
+ }
103
+
104
+ throw(o?: Partial<ErrorDetailInit>): never {
105
+ throw this.asError(o);
106
+ }
107
+ }
108
+
109
+ export interface ErrorDetail {
110
+ readonly message: string;
111
+ readonly status: number;
112
+ readonly code?: number | string;
113
+ readonly metadata?: Record<string, any>;
114
+ readonly description?: string;
115
+ readonly cause?: any;
116
+
117
+ with(message: string): ErrorDetail;
118
+
119
+ with(o?: Partial<ErrorDetailInit>): ErrorDetail;
120
+
121
+ asError(o?: Partial<ErrorDetailInit>): Error;
122
+
123
+ asError(message: string): Error;
124
+
125
+ throw(o?: Partial<ErrorDetailInit>): never;
126
+
127
+ require<T>(v: T | undefined, o?: Partial<ErrorDetailInit> | string): NonNullable<T>;
128
+
129
+ // 不支持 return value
130
+ // https://stackoverflow.com/a/73252858/1870054
131
+
132
+ check(condition: boolean, o?: Partial<ErrorDetailInit> | string): asserts condition;
133
+
134
+ check<T>(v: T | undefined | null, o?: Partial<ErrorDetailInit> | string): asserts v is NonNullable<T>;
135
+ }
136
+
137
+ export class Errors {
138
+ static BadRequest: ErrorDetail = this.with({ status: 400 });
139
+ static Unauthorized: ErrorDetail = this.with({ status: 403 });
140
+ static Forbidden: ErrorDetail = this.with({ status: 403 });
141
+ static NotFound: ErrorDetail = this.with({ status: 404 });
142
+ static InternalServerError: ErrorDetail = this.with({ status: 501 });
143
+ static NotImplemented: ErrorDetail = this.with({ status: 501 });
144
+ static ServiceUnavailable: ErrorDetail = this.with({ status: 503 });
145
+
146
+ static with(init: ErrorDetailInit): ErrorDetail {
147
+ return new DetailHolder(init);
148
+ }
149
+
150
+ static ok(res: Response, o?: Partial<ErrorDetailInit>) {
151
+ if (res.ok) {
152
+ return res;
153
+ }
154
+ throw this.with({
155
+ description: res.statusText,
156
+ status: res.status,
157
+ ...o,
158
+ metadata: {
159
+ ...o?.metadata,
160
+ response: res,
161
+ },
162
+ }).asError();
163
+ }
164
+
165
+ static resolve(e: any): ErrorDetail {
166
+ if (e instanceof DetailHolder) {
167
+ return e;
168
+ }
169
+
170
+ if (e instanceof DetailError) {
171
+ return e.detail;
172
+ }
173
+
174
+ if (e instanceof Error) {
175
+ const { message, code, status } = e as any;
176
+ // can get status from NestJS HttpException
177
+ return new DetailHolder({
178
+ message,
179
+ status: parseInt(status) || 500,
180
+ code,
181
+ cause: e,
182
+ });
183
+ }
184
+
185
+ return new DetailHolder({
186
+ message: e.message,
187
+ status: 500,
188
+ cause: e,
189
+ });
190
+ }
191
+ }
192
+
193
+ // interface ZodError {
194
+ // path: Array<string | number>;
195
+ // message: string;
196
+ // code: string;
197
+ // expected?: any;
198
+ // received?: any;
199
+ // }
@@ -10,9 +10,9 @@ export async function dumpResponse({
10
10
  log?: (s: string) => void;
11
11
  }) {
12
12
  let out = `<- ${res.status} ${res.statusText} ${req.method} ${url}
13
- ${Array.from(res.headers.entries())
14
- .map(([k, v]) => `${k}: ${v}`)
15
- .join('\n')}
13
+ ${Array.from(res.headers.entries())
14
+ .map(([k, v]) => `${k}: ${v}`)
15
+ .join('\n')}
16
16
  `;
17
17
  let contentType = res.headers.get('content-type');
18
18
  // TODO text/event-stream
@@ -0,0 +1,96 @@
1
+ // http://httpstat.us/
2
+ // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
3
+ const HttpStatus: Record<string, string> = {
4
+ 100: 'Continue',
5
+ 101: 'Switching Protocols',
6
+ 102: 'Processing',
7
+ 103: 'Early Hints',
8
+ 200: 'OK',
9
+ 201: 'Created',
10
+ 202: 'Accepted',
11
+ 203: 'Non-Authoritative Information',
12
+ 204: 'No Content',
13
+ 205: 'Reset Content',
14
+ 206: 'Partial Content',
15
+ 207: 'Multi-Status',
16
+ 208: 'Already Reported',
17
+ 226: 'IM Used',
18
+ 300: 'Multiple Choices',
19
+ 301: 'Moved Permanently',
20
+ 302: 'Found',
21
+ 303: 'See Other',
22
+ 304: 'Not Modified',
23
+ 305: 'Use Proxy',
24
+ 306: 'Unused',
25
+ 307: 'Temporary Redirect',
26
+ 308: 'Permanent Redirect',
27
+
28
+ 400: 'Bad Request',
29
+ 401: 'Unauthorized',
30
+ 402: 'Payment Required',
31
+ 403: 'Forbidden',
32
+ 404: 'Not Found',
33
+ 405: 'Method Not Allowed',
34
+ 406: 'Not Acceptable',
35
+ 407: 'Proxy Authentication Required',
36
+ 408: 'Request Timeout',
37
+ 409: 'Conflict',
38
+ 410: 'Gone',
39
+ 411: 'Length Required',
40
+ 412: 'Precondition Required',
41
+ 413: 'Request Entry Too Large',
42
+ 414: 'Request-URI Too Long',
43
+ 415: 'Unsupported Media Type',
44
+ 416: 'Requested Range Not Satisfiable',
45
+ 417: 'Expectation Failed',
46
+ 418: "I'm a teapot",
47
+ 421: 'Misdirected Request',
48
+ 422: 'Unprocessable Entity',
49
+ 423: 'Locked',
50
+ 424: 'Failed Dependency',
51
+ 425: 'Too Early',
52
+ 426: 'Upgrade Required',
53
+ 428: 'Precondition Required',
54
+ 429: 'Too Many Requests',
55
+ 431: 'Request Header Fields Too Large',
56
+ 451: 'Unavailable For Legal Reasons',
57
+ 500: 'Internal Server Error',
58
+ 501: 'Not Implemented',
59
+ 502: 'Bad Gateway',
60
+ 503: 'Service Unavailable',
61
+ 504: 'Gateway Timeout',
62
+ 505: 'HTTP Version Not Supported',
63
+ 506: 'Variant Also Negotiates',
64
+ 507: 'Insufficient Storage',
65
+ 508: 'Loop Detected',
66
+ 509: 'Bandwidth Limit Exceeded',
67
+ 510: 'Not Extended',
68
+ 511: 'Network Authentication Required',
69
+ };
70
+
71
+ export function getHttpStatusText(status: number | string): string | undefined {
72
+ return HttpStatus[status];
73
+ }
74
+
75
+ export function isRetryableHttpStatus(status: number) {
76
+ switch (status) {
77
+ /*
78
+ 408 Request Timeout
79
+ 425 Too Early
80
+ 429 Too Many Requests
81
+ 500 Internal Server Error
82
+ 502 Bad Gateway
83
+ 503 Service Unavailable
84
+ 504 Gateway Timeout
85
+ */
86
+ case 408:
87
+ case 425:
88
+ case 429:
89
+ case 502:
90
+ case 503:
91
+ case 504:
92
+ return true;
93
+ default:
94
+ return false;
95
+ }
96
+ }
package/src/index.ts CHANGED
@@ -18,8 +18,10 @@ export { merge, type MergeOptions } from './objects/merge';
18
18
  export { createLazyPromise, type LazyPromise } from './asyncs/createLazyPromise';
19
19
  export { setAsyncInterval, clearAsyncInterval } from './asyncs/AsyncInterval';
20
20
  export { type MaybePromise } from './asyncs/MaybePromise';
21
+ // async - iterator
21
22
  export { createAsyncIterator } from './asyncs/createAsyncIterator';
22
23
  export { firstOfAsyncIterator } from './asyncs/firstOfAsyncIterator';
24
+ export { nextOfAsyncIterator } from './asyncs/nextOfAsyncIterator';
23
25
  export { isIterator } from './asyncs/isIterator';
24
26
 
25
27
  export { sleep } from './asyncs/sleep';
@@ -84,6 +86,7 @@ export { structuredClone } from './isomorphics/structuredClone';
84
86
  export { randomUUID } from './crypto/randomUUID';
85
87
  export { getRandomValues } from './crypto/getRandomValues';
86
88
  export { sha1, sha256, sha384, sha512 } from './crypto/hashing';
89
+ export { md5 } from './crypto/md5';
87
90
  export { hex } from './crypto/base';
88
91
  export { isULID, createULID, ulid, parseULID } from './crypto/ulid';
89
92
  export { PEM } from './crypto/pem/pem';
@@ -96,4 +99,10 @@ export { type FetchLike, createFetchWith, createFetchWithLogging, dumpResponse,
96
99
 
97
100
  // bundled
98
101
  export { default as ms } from './libs/ms';
99
- export { nextOfAsyncIterator } from './asyncs/nextOfAsyncIterator';
102
+
103
+ // error
104
+ export { Errors, DetailError, type ErrorDetail, type ErrorDetailInit } from './errors/Errors';
105
+ // http
106
+ export { getHttpStatusText, isRetryableHttpStatus } from './http/HttpStatus';
107
+
108
+ export type * from './types';
@@ -1,5 +1,12 @@
1
1
  import type { LoggerWithChild, LogLevel } from './Logger';
2
2
 
3
+ export interface CreateLoggerOptions {
4
+ name?: string;
5
+ handler?: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void;
6
+ context?: Record<string, any>;
7
+ levels?: LogLevel[];
8
+ }
9
+
3
10
  export function createLogger(
4
11
  write: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void = ({
5
12
  level,
@@ -39,3 +46,5 @@ function merge(ctx: any, values: any[]) {
39
46
  }
40
47
  return { ...ctx, values };
41
48
  }
49
+
50
+ // https://github.com/nestjs/nest/blob/master/packages/common/services/console-logger.service.ts
package/src/server.ts CHANGED
@@ -1,7 +1,4 @@
1
1
  export { polyfillCrypto } from './servers/polyfill/polyfillCrypto';
2
- export { polyfillJsDom } from './servers/polyfill/polyfillJsDom';
3
- export { polyfillBrowser } from './servers/polyfill/polyfillBrowser';
4
- export { polyfillWebSocket } from './servers/polyfill/polyfillWebSocket';
5
2
  export { createFetchWithProxyByUndici } from './servers/fetch/createFetchWithProxyByUndici';
6
3
  export { createFetchWithProxy } from './servers/fetch/createFetchWithProxy';
7
4
  export { createFetchWithRetry, type FetchWithRetryOptions } from './servers/fetch/createFetchWithRetry';
@@ -0,0 +1 @@
1
+ export * from './polyfill/polyfillJsDom';
@@ -0,0 +1,2 @@
1
+ export * from './polyfill/polyfillFetch';
2
+ export * from './fetch/createFetchWithProxyByNodeFetch';
@@ -0,0 +1 @@
1
+ export * from './polyfill/polyfillWebSocket';
@@ -0,0 +1,11 @@
1
+ declare var __DEV__: boolean;
2
+
3
+ namespace NodeJS {
4
+ interface Process {
5
+ // webpack check
6
+ readonly browser?: boolean;
7
+ }
8
+ interface ProcessEnv {
9
+ readonly NODE_ENV: 'development' | 'production' | 'test';
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ export type AbstractConstructor<T = unknown> = abstract new (...args: any[]) => T;
2
+ export type Constructor<T = unknown> = new (...args: any[]) => T;
3
+ export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
4
+ export type PartialRequired<T, K extends keyof T> = Partial<Omit<T, K>> & Required<Pick<T, K>>;
5
+
6
+ /*
7
+ https://github.com/total-typescript/ts-reset/blob/main/src/entrypoints/filter-boolean.d.ts
8
+ */