@planet-matrix/mobius-model 0.6.0 → 0.10.1

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 (258) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/oxlint.config.ts +1 -2
  3. package/package.json +29 -17
  4. package/scripts/build.ts +2 -52
  5. package/src/ai/README.md +1 -0
  6. package/src/ai/ai.ts +107 -0
  7. package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
  8. package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
  9. package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
  10. package/src/ai/chat-completion-ai/index.ts +7 -0
  11. package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
  12. package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
  13. package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
  14. package/src/ai/embedding-ai/embedding-ai.ts +63 -0
  15. package/src/ai/embedding-ai/embedding.ts +50 -0
  16. package/src/ai/embedding-ai/index.ts +4 -0
  17. package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
  18. package/src/ai/index.ts +4 -0
  19. package/src/aio/README.md +100 -0
  20. package/src/aio/content.ts +141 -0
  21. package/src/aio/index.ts +3 -0
  22. package/src/aio/json.ts +127 -0
  23. package/src/aio/prompt.ts +246 -0
  24. package/src/basic/README.md +20 -15
  25. package/src/basic/error.ts +19 -5
  26. package/src/basic/function.ts +2 -2
  27. package/src/basic/index.ts +1 -0
  28. package/src/basic/promise.ts +141 -71
  29. package/src/basic/schedule.ts +111 -0
  30. package/src/basic/stream.ts +135 -25
  31. package/src/credential/README.md +107 -0
  32. package/src/credential/api-key.ts +158 -0
  33. package/src/credential/bearer.ts +73 -0
  34. package/src/credential/index.ts +4 -0
  35. package/src/credential/json-web-token.ts +96 -0
  36. package/src/credential/password.ts +170 -0
  37. package/src/cron/README.md +86 -0
  38. package/src/cron/cron.ts +87 -0
  39. package/src/cron/index.ts +1 -0
  40. package/src/drizzle/README.md +1 -0
  41. package/src/drizzle/drizzle.ts +1 -0
  42. package/src/drizzle/helper.ts +47 -0
  43. package/src/drizzle/index.ts +5 -0
  44. package/src/drizzle/infer.ts +52 -0
  45. package/src/drizzle/kysely.ts +8 -0
  46. package/src/drizzle/pagination.ts +198 -0
  47. package/src/email/README.md +1 -0
  48. package/src/email/index.ts +1 -0
  49. package/src/email/resend.ts +25 -0
  50. package/src/event/class-event-proxy.ts +5 -6
  51. package/src/event/common.ts +13 -3
  52. package/src/event/event-manager.ts +3 -3
  53. package/src/event/instance-event-proxy.ts +5 -6
  54. package/src/event/internal.ts +4 -4
  55. package/src/exception/README.md +28 -19
  56. package/src/exception/error/error.ts +123 -0
  57. package/src/exception/error/index.ts +2 -0
  58. package/src/exception/error/match.ts +38 -0
  59. package/src/exception/error/must-fix.ts +17 -0
  60. package/src/exception/index.ts +2 -0
  61. package/src/file-system/find.ts +53 -0
  62. package/src/file-system/index.ts +2 -0
  63. package/src/file-system/path.ts +76 -0
  64. package/src/file-system/resolve.ts +22 -0
  65. package/src/form/README.md +25 -0
  66. package/src/form/index.ts +1 -0
  67. package/src/form/inputor-controller/base.ts +861 -0
  68. package/src/form/inputor-controller/boolean.ts +39 -0
  69. package/src/form/inputor-controller/file.ts +39 -0
  70. package/src/form/inputor-controller/form.ts +179 -0
  71. package/src/form/inputor-controller/helper.ts +117 -0
  72. package/src/form/inputor-controller/index.ts +17 -0
  73. package/src/form/inputor-controller/multi-select.ts +99 -0
  74. package/src/form/inputor-controller/number.ts +116 -0
  75. package/src/form/inputor-controller/select.ts +109 -0
  76. package/src/form/inputor-controller/text.ts +82 -0
  77. package/src/http/READMD.md +1 -0
  78. package/src/http/api/api-core.ts +84 -0
  79. package/src/http/api/api-handler.ts +79 -0
  80. package/src/http/api/api-host.ts +47 -0
  81. package/src/http/api/api-result.ts +56 -0
  82. package/src/http/api/api-schema.ts +154 -0
  83. package/src/http/api/api-server.ts +130 -0
  84. package/src/http/api/api-test.ts +142 -0
  85. package/src/http/api/api-type.ts +34 -0
  86. package/src/http/api/api.ts +81 -0
  87. package/src/http/api/index.ts +11 -0
  88. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  89. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  90. package/src/http/api-adapter/api-result-arktype.ts +294 -0
  91. package/src/http/api-adapter/api-result-zod.ts +286 -0
  92. package/src/http/api-adapter/index.ts +5 -0
  93. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  94. package/src/http/bin/gen-api-list/index.ts +1 -0
  95. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  96. package/src/http/bin/gen-api-test/index.ts +1 -0
  97. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  98. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  99. package/src/http/bin/gen-api-type/index.ts +2 -0
  100. package/src/http/bin/index.ts +2 -0
  101. package/src/http/index.ts +3 -0
  102. package/src/huawei/README.md +1 -0
  103. package/src/huawei/index.ts +2 -0
  104. package/src/huawei/moderation/index.ts +1 -0
  105. package/src/huawei/moderation/moderation.ts +355 -0
  106. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  107. package/src/huawei/obs/index.ts +1 -0
  108. package/src/huawei/obs/obs.ts +42 -0
  109. package/src/index.ts +21 -2
  110. package/src/json/README.md +92 -0
  111. package/src/json/index.ts +1 -0
  112. package/src/json/repair.ts +18 -0
  113. package/src/log/logger.ts +15 -4
  114. package/src/openai/README.md +1 -0
  115. package/src/openai/index.ts +1 -0
  116. package/src/openai/openai.ts +509 -0
  117. package/src/orchestration/README.md +9 -7
  118. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  119. package/src/orchestration/dispatching/index.ts +2 -0
  120. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  121. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  122. package/src/orchestration/dispatching/selector/index.ts +2 -0
  123. package/src/orchestration/index.ts +2 -0
  124. package/src/orchestration/scheduling/index.ts +2 -0
  125. package/src/orchestration/scheduling/scheduler.ts +103 -0
  126. package/src/orchestration/scheduling/task.ts +32 -0
  127. package/src/random/README.md +8 -7
  128. package/src/random/base.ts +66 -0
  129. package/src/random/index.ts +5 -1
  130. package/src/random/random-boolean.ts +40 -0
  131. package/src/random/random-integer.ts +60 -0
  132. package/src/random/random-number.ts +72 -0
  133. package/src/random/random-string.ts +66 -0
  134. package/src/request/README.md +108 -0
  135. package/src/request/fetch/base.ts +108 -0
  136. package/src/request/fetch/browser.ts +280 -0
  137. package/src/request/fetch/general.ts +20 -0
  138. package/src/request/fetch/index.ts +4 -0
  139. package/src/request/fetch/nodejs.ts +280 -0
  140. package/src/request/index.ts +2 -0
  141. package/src/request/request/base.ts +246 -0
  142. package/src/request/request/general.ts +63 -0
  143. package/src/request/request/index.ts +3 -0
  144. package/src/request/request/resource.ts +68 -0
  145. package/src/result/README.md +4 -0
  146. package/src/result/controller.ts +58 -0
  147. package/src/result/either.ts +363 -0
  148. package/src/result/generator.ts +168 -0
  149. package/src/result/index.ts +3 -0
  150. package/src/route/README.md +105 -0
  151. package/src/route/adapter/browser.ts +122 -0
  152. package/src/route/adapter/driver.ts +56 -0
  153. package/src/route/adapter/index.ts +2 -0
  154. package/src/route/index.ts +3 -0
  155. package/src/route/router/index.ts +2 -0
  156. package/src/route/router/route.ts +630 -0
  157. package/src/route/router/router.ts +1641 -0
  158. package/src/route/uri/hash.ts +307 -0
  159. package/src/route/uri/index.ts +7 -0
  160. package/src/route/uri/pathname.ts +376 -0
  161. package/src/route/uri/search.ts +412 -0
  162. package/src/service/README.md +1 -0
  163. package/src/service/index.ts +1 -0
  164. package/src/service/service.ts +110 -0
  165. package/src/socket/README.md +105 -0
  166. package/src/socket/client/index.ts +2 -0
  167. package/src/socket/client/socket-unit.ts +658 -0
  168. package/src/socket/client/socket.ts +203 -0
  169. package/src/socket/common/index.ts +2 -0
  170. package/src/socket/common/socket-unit-common.ts +23 -0
  171. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  172. package/src/socket/index.ts +3 -0
  173. package/src/socket/server/index.ts +3 -0
  174. package/src/socket/server/server.ts +183 -0
  175. package/src/socket/server/socket-unit.ts +448 -0
  176. package/src/socket/server/socket.ts +264 -0
  177. package/src/storage/table.ts +3 -3
  178. package/src/timer/expiration/expiration-manager.ts +3 -3
  179. package/src/timer/expiration/remaining-manager.ts +3 -3
  180. package/src/tube/README.md +99 -0
  181. package/src/tube/helper.ts +137 -0
  182. package/src/tube/index.ts +2 -0
  183. package/src/tube/tube.ts +880 -0
  184. package/src/weixin/README.md +1 -0
  185. package/src/weixin/index.ts +2 -0
  186. package/src/weixin/official-account/authorization.ts +157 -0
  187. package/src/weixin/official-account/index.ts +2 -0
  188. package/src/weixin/official-account/js-api.ts +132 -0
  189. package/src/weixin/open/index.ts +1 -0
  190. package/src/weixin/open/oauth2.ts +131 -0
  191. package/tests/unit/ai/ai.spec.ts +85 -0
  192. package/tests/unit/aio/content.spec.ts +105 -0
  193. package/tests/unit/aio/json.spec.ts +146 -0
  194. package/tests/unit/aio/prompt.spec.ts +111 -0
  195. package/tests/unit/basic/error.spec.ts +16 -4
  196. package/tests/unit/basic/promise.spec.ts +158 -50
  197. package/tests/unit/basic/schedule.spec.ts +74 -0
  198. package/tests/unit/basic/stream.spec.ts +90 -37
  199. package/tests/unit/credential/api-key.spec.ts +36 -0
  200. package/tests/unit/credential/bearer.spec.ts +23 -0
  201. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  202. package/tests/unit/credential/password.spec.ts +40 -0
  203. package/tests/unit/cron/cron.spec.ts +84 -0
  204. package/tests/unit/event/class-event-proxy.spec.ts +3 -3
  205. package/tests/unit/event/event-manager.spec.ts +3 -3
  206. package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
  207. package/tests/unit/exception/error/error.spec.ts +83 -0
  208. package/tests/unit/exception/error/match.spec.ts +81 -0
  209. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  210. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  211. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  212. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  213. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  214. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  215. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  216. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  217. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  218. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  219. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  220. package/tests/unit/http/api/api-server.spec.ts +363 -0
  221. package/tests/unit/http/api/api-test.spec.ts +117 -0
  222. package/tests/unit/http/api/api.spec.ts +121 -0
  223. package/tests/unit/http/api-adapter/node-http.spec.ts +187 -0
  224. package/tests/unit/identifier/uuid.spec.ts +0 -1
  225. package/tests/unit/json/repair.spec.ts +11 -0
  226. package/tests/unit/log/logger.spec.ts +19 -4
  227. package/tests/unit/openai/openai.spec.ts +64 -0
  228. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  229. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  230. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  231. package/tests/unit/random/base.spec.ts +58 -0
  232. package/tests/unit/random/random-boolean.spec.ts +25 -0
  233. package/tests/unit/random/random-integer.spec.ts +32 -0
  234. package/tests/unit/random/random-number.spec.ts +33 -0
  235. package/tests/unit/random/random-string.spec.ts +22 -0
  236. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  237. package/tests/unit/request/fetch/general.spec.ts +43 -0
  238. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  239. package/tests/unit/request/request/base.spec.ts +382 -0
  240. package/tests/unit/request/request/general.spec.ts +160 -0
  241. package/tests/unit/result/controller.spec.ts +82 -0
  242. package/tests/unit/result/either.spec.ts +377 -0
  243. package/tests/unit/result/generator.spec.ts +273 -0
  244. package/tests/unit/route/router/route.spec.ts +430 -0
  245. package/tests/unit/route/router/router.spec.ts +407 -0
  246. package/tests/unit/route/uri/hash.spec.ts +72 -0
  247. package/tests/unit/route/uri/pathname.spec.ts +146 -0
  248. package/tests/unit/route/uri/search.spec.ts +107 -0
  249. package/tests/unit/socket/client.spec.ts +208 -0
  250. package/tests/unit/socket/server.spec.ts +133 -0
  251. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  252. package/tests/unit/tube/helper.spec.ts +139 -0
  253. package/tests/unit/tube/tube.spec.ts +501 -0
  254. package/vite.config.ts +2 -1
  255. package/dist/index.js +0 -50
  256. package/dist/index.js.map +0 -209
  257. package/src/random/string.ts +0 -35
  258. package/tests/unit/random/string.spec.ts +0 -11
@@ -0,0 +1,111 @@
1
+ export type SyncTask = () => void
2
+ export type AsyncTask = () => Promise<void>
3
+ export type Task = SyncTask | AsyncTask
4
+ /**
5
+ * 表示接收一个任务并负责安排其执行时机的调度器。
6
+ */
7
+ export type Scheduler = (task: Task) => void
8
+
9
+ /**
10
+ * 在微任务队列中安排一个同步任务。
11
+ *
12
+ * @example
13
+ * ```
14
+ * const values: string[] = []
15
+ * scheduleMicroTaskSimple(() => {
16
+ * values.push("micro")
17
+ * })
18
+ * // Expect: ["micro"]
19
+ * const example1 = await Promise.resolve().then(() => Promise.resolve(values))
20
+ * ```
21
+ */
22
+ export const scheduleMicroTaskSimple = (task: Task): void => {
23
+ queueMicrotask(() => {
24
+ void task()
25
+ })
26
+ }
27
+
28
+ /**
29
+ * 在宏任务队列中安排一个任务。
30
+ *
31
+ * @example
32
+ * ```
33
+ * const values: string[] = []
34
+ * await new Promise<void>((resolve) => {
35
+ * scheduleMacroTaskSimple(() => {
36
+ * values.push("macro")
37
+ * resolve()
38
+ * })
39
+ * })
40
+ * // Expect: ["macro"]
41
+ * const example1 = values
42
+ * ```
43
+ */
44
+ export const scheduleMacroTaskSimple = (task: Task): void => {
45
+ setTimeout(() => {
46
+ void task()
47
+ }, 0)
48
+ }
49
+
50
+ /**
51
+ * `scheduleMicroTask` 的配置项。
52
+ */
53
+ export interface ScheduleMicroTaskOptions {
54
+ task: Task
55
+ }
56
+
57
+ /**
58
+ * 在微任务队列中安排一个任务。
59
+ *
60
+ * @example
61
+ * ```
62
+ * const values: string[] = []
63
+ * scheduleMicroTask({
64
+ * task: async () => {
65
+ * values.push("micro")
66
+ * },
67
+ * })
68
+ * // Expect: ["micro"]
69
+ * const example1 = await Promise.resolve().then(() => Promise.resolve(values))
70
+ * ```
71
+ */
72
+ export const scheduleMicroTask = (options: ScheduleMicroTaskOptions): void => {
73
+ const { task } = options
74
+ queueMicrotask(() => {
75
+ void task()
76
+ })
77
+ }
78
+
79
+ /**
80
+ * `scheduleMacroTask` 的配置项。
81
+ */
82
+ export interface ScheduleMacroTaskOptions {
83
+ task: Task
84
+ timeout?: number
85
+ }
86
+
87
+ /**
88
+ * 在宏任务队列中安排一个任务。
89
+ *
90
+ * @example
91
+ * ```
92
+ * const values: string[] = []
93
+ * await new Promise<void>((resolve) => {
94
+ * scheduleMacroTask({
95
+ * timeout: 0,
96
+ * task: async () => {
97
+ * values.push("macro")
98
+ * resolve()
99
+ * },
100
+ * })
101
+ * })
102
+ * // Expect: ["macro"]
103
+ * const example1 = values
104
+ * ```
105
+ */
106
+ export const scheduleMacroTask = (options: ScheduleMacroTaskOptions): void => {
107
+ const { task, timeout = 0 } = options
108
+ setTimeout(() => {
109
+ void task()
110
+ }, timeout)
111
+ }
@@ -1,11 +1,24 @@
1
- import type { ReadableStreamController, ReadableStreamReadResult } from "node:stream/web"
1
+ import type {
2
+ ReadableStreamController,
3
+ ReadableStreamDefaultController,
4
+ ReadableStreamDefaultReader,
5
+ ReadableStreamReadResult,
6
+ } from "node:stream/web"
2
7
 
3
8
  import { ReadableStream } from "node:stream/web"
4
9
 
5
10
  /**
6
- * 从数组创建一个 ReadableStream
11
+ * 从数组创建一个立即推送全部值的 `ReadableStream`。
12
+ *
13
+ * @example
14
+ * ```
15
+ * // Expect: [1, 2, 3]
16
+ * const example1 = await Array.fromAsync(streamFromArrayEager([1, 2, 3]))
17
+ * // Expect: []
18
+ * const example2 = await Array.fromAsync(streamFromArrayEager([]))
19
+ * ```
7
20
  */
8
- export const streamFromArray = <T>(values: T[]): ReadableStream<T> => {
21
+ export const streamFromArrayEager = <T>(values: T[]): ReadableStream<T> => {
9
22
  const stream = new ReadableStream<T>({
10
23
  start(controller): void {
11
24
  for (const value of values) {
@@ -17,43 +30,118 @@ export const streamFromArray = <T>(values: T[]): ReadableStream<T> => {
17
30
  return stream
18
31
  }
19
32
 
20
- export interface StreamConsumeInSyncMacroTaskOptions<T> {
33
+ /**
34
+ * 从数组创建一个按需逐项提供值的 `ReadableStream`。
35
+ *
36
+ * @example
37
+ * ```
38
+ * // Expect: [1, 2, 3]
39
+ * const example1 = await Array.fromAsync(streamFromArrayLazy([1, 2, 3]))
40
+ * // Expect: []
41
+ * const example2 = await Array.fromAsync(streamFromArrayLazy([]))
42
+ * ```
43
+ */
44
+ export const streamFromArrayLazy = <T>(values: T[]): ReadableStream<T> => {
45
+ let i = 0
46
+ const stream = new ReadableStream<T>({
47
+ pull(controller): void {
48
+ if (i < values.length) {
49
+ controller.enqueue(values[i])
50
+ i = i + 1
51
+ }
52
+ else {
53
+ controller.close()
54
+ }
55
+ }
56
+ })
57
+ return stream
58
+ }
59
+
60
+ /**
61
+ * `streamConsumeInMicroTask` 的配置项。
62
+ */
63
+ export interface StreamConsumeInMicroTaskOptions<T> {
21
64
  readableStream: ReadableStream<T>
22
65
  onValue?: ((chunk: T) => (void | Promise<void>)) | undefined
23
66
  onDone?: (() => (void | Promise<void>)) | undefined
24
67
  onError?: ((error: Error) => (void | Promise<void>)) | undefined
25
68
  }
69
+
26
70
  /**
27
- * 在同步宏任务中完成 ReadableStream 的消费。
71
+ * 在微任务队列中消费 `ReadableStream`。
72
+ *
73
+ * @example
74
+ * ```
75
+ * const values: number[] = []
76
+ * streamConsumeInMicroTask({
77
+ * readableStream: streamFromArrayEager([1, 2]),
78
+ * onValue: (value) => {
79
+ * values.push(value)
80
+ * },
81
+ * })
82
+ * // Expect: [1, 2]
83
+ * const example1 = await Promise.resolve().then(() => Promise.resolve(values))
84
+ * ```
28
85
  */
29
- export const streamConsumeInSyncMacroTask = async <T>(
30
- options: StreamConsumeInSyncMacroTaskOptions<T>,
31
- ): Promise<void> => {
86
+ export const streamConsumeInMicroTask = <T>(
87
+ options: StreamConsumeInMicroTaskOptions<T>,
88
+ ): void => {
32
89
  const { readableStream, onValue, onDone, onError } = options
33
90
 
34
- try {
35
- for await (const chunk of readableStream) {
36
- await onValue?.(chunk)
37
- }
38
- await onDone?.()
39
- }
40
- catch (exception) {
41
- console.error(`Error reading stream: ${String(exception)}`)
42
- await onError?.(new Error(`Error reading stream: ${String(exception)}`))
91
+ const reader = readableStream.getReader()
92
+
93
+ const read = (): void => {
94
+ queueMicrotask(() => {
95
+ void reader.read()
96
+ .then(async ({ done, value }) => {
97
+ if (done) {
98
+ await onDone?.()
99
+ return
100
+ }
101
+ await onValue?.(value)
102
+ read()
103
+ })
104
+ .catch(async (reason: unknown) => {
105
+ console.error(`Error reading stream: ${String(reason)}`)
106
+ await onError?.(new Error(String(reason)))
107
+ })
108
+ })
43
109
  }
110
+
111
+ read()
44
112
  }
45
113
 
46
- export interface StreamConsumeInAsyncMacroTaskOptions<T> {
114
+ /**
115
+ * `streamConsumeInMacroTask` 的配置项。
116
+ */
117
+ export interface StreamConsumeInMacroTaskOptions<T> {
47
118
  readableStream: ReadableStream<T>
48
119
  onValue?: ((chunk: T) => (void | Promise<void>)) | undefined
49
120
  onDone?: (() => (void | Promise<void>)) | undefined
50
121
  onError?: ((error: Error) => (void | Promise<void>)) | undefined
51
122
  }
123
+
52
124
  /**
53
- * 在异步宏任务中完成 ReadableStream 的消费。
125
+ * 在宏任务队列中消费 `ReadableStream`。
126
+ *
127
+ * @example
128
+ * ```
129
+ * const values: number[] = []
130
+ * await new Promise<void>((resolve) => {
131
+ * streamConsumeInMacroTask({
132
+ * readableStream: streamFromArrayEager([1, 2]),
133
+ * onValue: (value) => {
134
+ * values.push(value)
135
+ * },
136
+ * onDone: resolve,
137
+ * })
138
+ * })
139
+ * // Expect: [1, 2]
140
+ * const example1 = values
141
+ * ```
54
142
  */
55
- export const streamConsumeInAsyncMacroTask = <T>(
56
- options: StreamConsumeInAsyncMacroTaskOptions<T>,
143
+ export const streamConsumeInMacroTask = <T>(
144
+ options: StreamConsumeInMacroTaskOptions<T>,
57
145
  ): void => {
58
146
  const { readableStream, onValue, onDone, onError } = options
59
147
 
@@ -71,6 +159,7 @@ export const streamConsumeInAsyncMacroTask = <T>(
71
159
  read()
72
160
  })
73
161
  .catch(async (reason: unknown) => {
162
+ console.error(`Error reading stream: ${String(reason)}`)
74
163
  await onError?.(new Error(String(reason)))
75
164
  })
76
165
  }, 0)
@@ -78,17 +167,38 @@ export const streamConsumeInAsyncMacroTask = <T>(
78
167
  read()
79
168
  }
80
169
 
81
- export interface StreamTransformInAsyncMacroTaskOptions<T, U> {
170
+ /**
171
+ * `streamTransformInMacroTask` 的配置项。
172
+ */
173
+ export interface StreamTransformInMacroTaskOptions<T, U> {
82
174
  readableStream?: ReadableStream<T> | undefined
83
175
  reader?: ReadableStreamDefaultReader<T> | undefined
84
176
  onChunk?: ((chunk: ReadableStreamReadResult<T>, controller: ReadableStreamDefaultController<U>) => (void | Promise<void>)) | undefined
85
177
  onError?: ((error: Error) => (void | Error | Promise<void | Error>)) | undefined
86
178
  }
179
+
87
180
  /**
88
- * 在宏任务队列中完成 ReadableStream 到另一个 ReadableStream 的转换。
181
+ * 在宏任务队列中把一个 `ReadableStream` 转换为另一个 `ReadableStream`。
182
+ *
183
+ * @example
184
+ * ```
185
+ * const source = streamFromArrayEager([1, 2, 3])
186
+ * const transformed = streamTransformInMacroTask({
187
+ * readableStream: source,
188
+ * onChunk: (chunk, controller) => {
189
+ * if (chunk.done === true) {
190
+ * controller.close()
191
+ * return
192
+ * }
193
+ * controller.enqueue(chunk.value * 10)
194
+ * },
195
+ * })
196
+ * // Expect: [10, 20, 30]
197
+ * const example1 = await Array.fromAsync(transformed)
198
+ * ```
89
199
  */
90
- export const streamTransformInAsyncMacroTask = <T, U>(
91
- options: StreamTransformInAsyncMacroTaskOptions<T, U>,
200
+ export const streamTransformInMacroTask = <T, U>(
201
+ options: StreamTransformInMacroTaskOptions<T, U>,
92
202
  ): ReadableStream<U> => {
93
203
  const { readableStream, reader, onChunk, onError } = options
94
204
 
@@ -0,0 +1,107 @@
1
+ # Credential
2
+
3
+ ## Description
4
+
5
+ Credential 模块用于提供围绕凭据(credential)进行生成、签发、解析、校验、脱敏与比较的基础建模能力,用于把 API key、JSON Web Token(JWT)与密码散列这类可被系统接受为验证依据的材料组织成稳定公共边界。
6
+
7
+ 它关注的是“系统凭什么接受一个调用方”,而不是“一个对象是谁”,也不是完整登录流程、权限判定或传输协议接入本身。
8
+
9
+ ## For Understanding
10
+
11
+ 理解 Credential 模块时,应先把它与 Identifier、Random 和 Request 区分开。
12
+
13
+ - 与 Identifier 的区别在于:Identifier 关注的是身份或标识如何被稳定表达;Credential 关注的是调用方凭什么被信任、被验证或被放行。
14
+ - 与 Random 的区别在于:Credential 中虽然可能会使用随机源,但这里的重点不是通用随机文本生成,而是带有安全前提与凭据语义的结果格式。
15
+ - 与 Request 的区别在于:Credential 负责凭据本身的建模,不负责把凭据如何塞进 HTTP header、cookie 或具体请求链路中。
16
+
17
+ 当前这个模块适合承载以下几类稳定语义:
18
+
19
+ - 不透明凭据的生成与格式约束,例如 API key。
20
+ - 凭据载体字符串的格式化与提取,例如 Bearer credential。
21
+ - 可签发、可验证的令牌凭据,例如 JWT。
22
+ - 可生成、可比较的密码散列材料,例如带盐密码散列。
23
+
24
+ 同时也要守住几个边界:
25
+
26
+ - 这里不负责完整认证流程,例如登录、刷新流程编排或会话管理。
27
+ - 这里不负责授权(authorization)与权限决策,例如角色、权限、策略判断。
28
+ - 这里不负责完整密码学工具箱;只有当某个密码学能力直接服务于凭据建模时,才适合作为内部实现或局部公共能力存在。
29
+
30
+ ## For Using
31
+
32
+ 当你需要在系统边界生成、签发、验证或展示凭据,而又希望这些能力以稳定、可复用的公共 API 形式存在时,可以使用这个模块。
33
+
34
+ 从使用角度看,当前公共能力大致可以分为四类:
35
+
36
+ - API key 能力:用于生成默认或自定义格式的 key,并在日志或界面中按同一份格式约束做安全遮罩。
37
+ - Bearer 能力:用于把非空原始 token 表达为 Bearer 凭据字符串,或从 Bearer 凭据字符串中提取原始 token。
38
+ - JWT 能力:用于基于共享密钥签发与解析原始 token,并从 token 中恢复稳定业务载荷。
39
+ - 密码能力:用于生成盐值、产出带盐散列,以及比较用户输入与既有散列。
40
+
41
+ 更合理的接入方式通常是:在靠近应用边界的位置生成或验证这些凭据,再把结果作为普通输入传入更内层的业务模型。这样做可以避免让内层逻辑直接依赖随机源、签名库或散列细节。
42
+
43
+ 其中 API key 能力允许调用方覆写前缀、字符集与主体长度;一旦使用了自定义格式,后续做脱敏展示时也应继续沿用同一份格式约束,否则“这个字符串是否是合法 API key”就会在生成与遮罩两个动作之间出现分叉。
44
+
45
+ 其中 Bearer 能力只负责凭据字符串本身的格式化与提取,不负责与请求对象、header 容器或具体框架适配层直接耦合。格式化时应把“可被发送的 Bearer 凭据字符串”视为目标,因此空白输入应被视为无效 token,而不是被格式化成一个外形接近但语义上无效的结果。若你的需求已经开始偏向协议接入,例如把 Bearer 写入某个具体请求对象、处理 cookie 写入、OAuth 回调或会话刷新编排,那么更合适的做法通常是在更外层再建立专门模块,而不是直接扩张 Credential 顶层边界。
46
+
47
+ ## For Contributing
48
+
49
+ 贡献 Credential 模块时,应优先判断新增内容表达的是“凭据本身的稳定语义”,还是“某个接入场景下的临时便利代码”。只有前者才适合进入这个模块。
50
+
51
+ 在扩展时,应优先遵守以下边界:
52
+
53
+ - 公共能力应围绕凭据的生成、签发、解析、校验、脱敏、比较、格式化与失效语义展开。
54
+ - 不要把 HTTP、cookie、框架中间件或数据库存储策略直接提升为顶层公共 API。
55
+ - 不要把角色、权限、授权规则或完整会话编排混入这里。
56
+ - 如果某项能力的重点已经变成通用密码学原语,而不是凭据模型,应考虑在更明确的问题域中单独建模。
57
+
58
+ ### JSDoc 注释格式要求
59
+
60
+ - 每个公开导出的目标(类型、函数、变量、类等)都应包含 JSDoc 注释,让人在不跳转实现的情况下就能理解用途。
61
+ - JSDoc 注释第一行应为清晰且简洁的描述,该描述优先使用中文(英文也可以)。
62
+ - 如果描述后还有其他内容,应在描述后加一个空行。
63
+ - 如果有示例,应使用 `@example` 标签,后接三重反引号代码块(不带语言标识)。
64
+ - 如果有示例,应包含多个场景,展示不同用法,尤其要覆盖常见组合方式或边界输入。
65
+ - 如果有示例,应使用注释格式说明每个场景:`// Expect: <result>`。
66
+ - 如果有示例,应将结果赋值给 `example1`、`example2` 之类的变量,以保持示例易读。
67
+ - 如果有示例,`// Expect: <result>` 应该位于 `example1`、`example2` 之前,以保持示例的逻辑清晰。
68
+ - 如果有示例,应优先使用确定性示例;避免断言精确的随机输出。
69
+ - 如果函数返回结构化字符串,应展示其预期格式特征。
70
+ - 如果有参考资料,应将 `@see` 放在 `@example` 代码块之后,并用一个空行分隔。
71
+
72
+ ### 实现规范要求
73
+
74
+ - 不同程序元素之间使用一个空行分隔,保持结构清楚。这里的程序元素,通常指函数、类型、常量,以及直接服务于它们的辅助元素。
75
+ - 某程序元素独占的辅助元素与该程序元素本身视为一个整体,不要在它们之间添加空行。
76
+ - 程序元素的辅助元素应该放置在该程序元素的上方,以保持阅读时的逻辑顺序。
77
+ - 若辅助元素被多个程序元素共享,则应将其视为独立的程序元素,放在这些程序元素中第一个相关目标的上方,并与后续程序元素之间保留一个空行。
78
+ - 辅助元素也应该像其它程序元素一样,保持清晰的命名和适当的注释,以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
79
+ - 辅助元素的命名必须以前缀 `internal` 开头(或 `Internal`,大小写不敏感)。
80
+ - 辅助元素永远不要公开导出。
81
+ - 被模块内多个不同文件中的程序元素共享的辅助元素,应该放在一个单独的文件中,例如 `./src/credential/internal.ts`。
82
+ - 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时,才应将其视为子模块。
83
+ - 子模块包含多个文件时,应该为其单独创建子文件夹,并为其创建单独的 Barrel 文件;父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
84
+ - 子模块不需要有自己的 `README.md`。
85
+ - 子模块可以有自己的 `internal.ts` 文件,多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中,单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
86
+ - 对模块依赖关系的要求(通常是不循环依赖或不反向依赖)与对 DRY 的要求可能产生冲突。此时,若复用的代码数量不大,可以适当牺牲 DRY,复制粘贴并保留必要的注释说明;若复用的代码数量较大,则可以将其抽象到新的文件或子模块中,如 `common.ts`,并在需要的地方导入使用。
87
+ - 与凭据相关的实现应优先围绕格式约束、签发语义、校验语义、脱敏语义与比较语义组织,避免把协议接入或业务流程细节直接提升为公共 API。
88
+
89
+ ### 导出策略要求
90
+
91
+ - 保持内部辅助项和内部符号为私有,不要让外部接入依赖临时性的内部结构。
92
+ - 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
93
+ - Barrel 文件应命名为 `index.ts`,放在模块目录根部,并且所有公共 API 都应从该文件导出。
94
+ - 新增公共能力时,应优先检查它是否表达稳定、清楚且值得长期维护的凭据语义,而不是某段实现细节的便捷暴露;仅在确认需要长期对外承诺时再加入 Barrel 导出。
95
+
96
+ ### 测试要求
97
+
98
+ - 若程序元素是函数,则只为该函数编写一个测试,如果该函数需要测试多个用例,应放在同一个测试中。
99
+ - 若程序元素是类,则至少要为该类的每一个方法编写一个测试,如果该方法需要测试多个用例,应放在同一个测试中。
100
+ - 若程序元素是类,除了为该类的每一个方法编写至少一个测试之外,还可以为该类编写任意多个测试,以覆盖该类的不同使用场景或边界情况。
101
+ - 若编写测试时需要用到辅助元素(Mock 或 Spy 等),可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单,则可以直接放在每一个测试内部,优先保证每个测试的独立性,而不是追求极致 DRY;若辅助元素较为复杂或需要在多个测试中复用,则可以放在测试文件顶部,供该测试文件中的所有测试使用。
102
+ - 测试顺序应与源文件中被测试目标的原始顺序保持一致。
103
+ - 若该模块不需要测试,必须在说明文件中明确说明该模块不需要测试,并说明理由。一般来说,只有在该模块没有可执行的公共函数、只承载类型层表达,或其语义已被上层模块的测试完整覆盖且重复测试几乎不再带来额外价值时,才适合这样处理。
104
+ - 模块的单元测试文件目录是 `./tests/unit/credential`,若模块包含子模块,则子模块的单元测试文件目录为 `./tests/unit/credential/<sub-module-name>`。
105
+ - 对这个模块来说,测试应优先覆盖 API key 的格式与遮罩、Bearer 凭据的格式化与提取、JWT 的签发与解析、密码盐值的结果特征、带盐散列的一致性,以及密码比较在匹配与不匹配场景下的稳定行为。
106
+ - 若 API key 支持可配置格式,测试应同时覆盖默认格式与至少一种自定义格式,并验证生成、校验与遮罩对“合法 key”的理解保持一致。
107
+ - Bearer 能力的测试除正常格式化与提取外,还应覆盖空白输入被拒绝的情况,避免格式化函数产出一个校验函数本身都不会接受的结果。
@@ -0,0 +1,158 @@
1
+ const internalApiKeyAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
2
+ const internalApiKeyPrefix = "sk-"
3
+ const internalApiKeyBodyLength = 48
4
+
5
+ interface InternalApiKeyFormat {
6
+ prefix: string
7
+ alphabet: string
8
+ bodyLength: number
9
+ }
10
+
11
+ // API key 的生成依赖安全随机源。
12
+ // 这个辅助函数同时负责长度校验和随机字节填充,使 API key 生成逻辑可以直接建立在“安全随机字节”之上。
13
+ const internalGetApiKeyRandomValues = (length: number): Uint8Array => {
14
+ if (Number.isInteger(length) === false || length <= 0) {
15
+ throw new RangeError(`Expected length to be a positive integer, got: ${length}`)
16
+ }
17
+
18
+ if (globalThis.crypto === undefined || typeof globalThis.crypto.getRandomValues !== "function") {
19
+ throw new Error("Credential utilities require crypto.getRandomValues")
20
+ }
21
+
22
+ const buffer = new Uint8Array(length)
23
+ globalThis.crypto.getRandomValues(buffer)
24
+ return buffer
25
+ }
26
+
27
+ // API key 的生成与校验必须共享同一份格式定义。
28
+ // 这个辅助函数负责补齐默认值并统一校验前缀、字符集和主体长度,避免生成与遮罩对“合法 key”的理解出现分叉。
29
+ const internalResolveApiKeyFormat = (options: GenerateApiKeyOptions | undefined): InternalApiKeyFormat => {
30
+ const prefix = options?.prefix ?? internalApiKeyPrefix
31
+ const alphabet = options?.alphabet ?? internalApiKeyAlphabet
32
+ const bodyLength = options?.bodyLength ?? internalApiKeyBodyLength
33
+
34
+ if (prefix.length === 0) {
35
+ throw new RangeError("Expected prefix to contain at least one character")
36
+ }
37
+
38
+ if (alphabet.length === 0) {
39
+ throw new RangeError("Expected alphabet to contain at least one character")
40
+ }
41
+
42
+ if (Number.isInteger(bodyLength) === false || bodyLength <= 0) {
43
+ throw new RangeError(`Expected bodyLength to be a positive integer, got: ${bodyLength}`)
44
+ }
45
+
46
+ return {
47
+ prefix,
48
+ alphabet,
49
+ bodyLength,
50
+ }
51
+ }
52
+
53
+ // Step 1: 校验输入值是否满足 API key 格式约定。
54
+ //
55
+ // 遮罩 API key 时需要按固定位置保留前缀和尾部字符,因此必须先确认输入值符合预期长度和前缀规则。
56
+ const internalAssertApiKey = (apiKey: string, format: InternalApiKeyFormat): void => {
57
+ const expectedLength = format.prefix.length + format.bodyLength
58
+
59
+ if (
60
+ apiKey.startsWith(format.prefix) === false
61
+ || apiKey.length !== expectedLength
62
+ ) {
63
+ throw new Error("Invalid API key format")
64
+ }
65
+
66
+ const body = apiKey.slice(format.prefix.length)
67
+
68
+ for (const character of body) {
69
+ if (format.alphabet.includes(character) === false) {
70
+ throw new Error("Invalid API key format")
71
+ }
72
+ }
73
+ }
74
+
75
+ // Step 2: 生成 API key 的随机主体。
76
+ //
77
+ // 该实现直接把安全随机字节映射为 API key 字符,避免把凭据格式语义拆散到通用随机能力之外。
78
+ // 读者只需要理解一个规则:每个随机字节都会被转换成允许字符集中的一个字符。
79
+ const internalGenerateApiKeyBody = (alphabet: string, bodyLength: number): string => {
80
+ const randomValues = internalGetApiKeyRandomValues(bodyLength)
81
+ let result = ""
82
+
83
+ for (const value of randomValues) {
84
+ result = result + alphabet[value % alphabet.length]!
85
+ }
86
+
87
+ return result
88
+ }
89
+
90
+ /**
91
+ * API key 生成选项。
92
+ *
93
+ * `prefix` 用于指定凭据前缀,`alphabet` 用于指定主体字符集,`bodyLength` 用于指定主体长度。
94
+ * 未提供的字段会分别回退到默认前缀、默认字符集和默认主体长度。
95
+ */
96
+ export interface GenerateApiKeyOptions {
97
+ prefix?: string | undefined
98
+ alphabet?: string | undefined
99
+ bodyLength?: number | undefined
100
+ }
101
+
102
+ /**
103
+ * 生成 API key 字符串,并允许调用方覆写前缀、字符集和主体长度。
104
+ *
105
+ * 该函数使用运行时提供的安全随机源生成固定长度的凭据文本,适合在需要不透明访问凭据的边界层生成新 key。
106
+ *
107
+ * @example
108
+ * ```
109
+ * const apiKey = generateApiKey({})
110
+ * // Expect: true
111
+ * const example1 = apiKey.startsWith("sk-")
112
+ * // Expect: 51
113
+ * const example2 = apiKey.length
114
+ * const customApiKey = generateApiKey({ prefix: "pk_", alphabet: "ABC123", bodyLength: 8 })
115
+ * // Expect: true
116
+ * const example3 = customApiKey.startsWith("pk_")
117
+ * // Expect: 11
118
+ * const example4 = customApiKey.length
119
+ * ```
120
+ */
121
+ export const generateApiKey = (options: GenerateApiKeyOptions): string => {
122
+ const { prefix, alphabet, bodyLength } = internalResolveApiKeyFormat(options)
123
+
124
+ return `${prefix}${internalGenerateApiKeyBody(alphabet, bodyLength)}`
125
+ }
126
+
127
+ /**
128
+ * 遮罩 API key 的中间部分,保留前缀与末尾少量可见字符。
129
+ *
130
+ * 当输入值不满足当前 API key 格式约定时,该函数会抛出 Error。
131
+ * 若 API key 使用了非默认前缀、字符集或主体长度,应传入同一份格式选项以保持生成与遮罩语义一致。
132
+ *
133
+ * @example
134
+ * ```
135
+ * // Expect: "sk-ab********************************************yz"
136
+ * const example1 = maskApiKey("sk-ab0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklyz")
137
+ * const customOptions = { prefix: "pk_", alphabet: "ABC123", bodyLength: 6 }
138
+ * // Expect: "pk_AB**23"
139
+ * const example2 = maskApiKey("pk_ABC123", customOptions)
140
+ * // Expect: throws Error
141
+ * const example3 = () => maskApiKey("not-an-api-key")
142
+ * ```
143
+ */
144
+ export const maskApiKey = (apiKey: string, options?: GenerateApiKeyOptions): string => {
145
+ const format = internalResolveApiKeyFormat(options)
146
+
147
+ internalAssertApiKey(apiKey, format)
148
+
149
+ // 保留前缀可以帮助识别凭据类型,保留末尾少量字符可以帮助区分不同的 key。
150
+ // 遮罩中间主体可以降低 API key 在日志、报错信息或界面中被完整泄露的风险。
151
+ const visibleBodyStartLength = Math.min(2, format.bodyLength)
152
+ const visibleBodyEndLength = Math.min(2, Math.max(0, format.bodyLength - visibleBodyStartLength))
153
+ const visibleStart = apiKey.slice(0, format.prefix.length + visibleBodyStartLength)
154
+ const visibleEnd = visibleBodyEndLength === 0 ? "" : apiKey.slice(-visibleBodyEndLength)
155
+ const maskedPart = "*".repeat(Math.max(0, format.bodyLength - visibleBodyStartLength - visibleBodyEndLength))
156
+
157
+ return `${visibleStart}${maskedPart}${visibleEnd}`
158
+ }
@@ -0,0 +1,73 @@
1
+ const internalCredentialBearerRegexp = /^Bearer\s+(.+)$/i
2
+
3
+ // Bearer credential 的标准文本形态是 "Bearer <token>"。
4
+ // 这个辅助函数统一去掉多余空白和 Bearer 前缀,使判断、格式化和解析共享同一条规范化规则。
5
+ const internalNormalizeBearerToken = (token: string): string => {
6
+ return token.trim().replace(/^Bearer\s+/i, "")
7
+ }
8
+
9
+ /**
10
+ * 判断输入值是否为 Bearer 凭据字符串。
11
+ *
12
+ * @example
13
+ * ```
14
+ * // Expect: true
15
+ * const example1 = isBearerCredential("Bearer token-value")
16
+ * // Expect: false
17
+ * const example2 = isBearerCredential("Basic token-value")
18
+ * ```
19
+ */
20
+ export const isBearerCredential = (input: string): boolean => {
21
+ return internalCredentialBearerRegexp.test(input.trim())
22
+ }
23
+
24
+ /**
25
+ * 把原始 token 格式化为 Bearer 凭据字符串。
26
+ *
27
+ * 当输入值只包含空白字符时,该函数会抛出 RangeError,避免产出一个连 Bearer 校验器都不会接受的无效凭据字符串。
28
+ *
29
+ * @example
30
+ * ```
31
+ * // Expect: "Bearer token-value"
32
+ * const example1 = formatBearerCredential("token-value")
33
+ * // Expect: "Bearer token-value"
34
+ * const example2 = formatBearerCredential(" token-value ")
35
+ * // Expect: throws RangeError
36
+ * const example3 = () => formatBearerCredential(" ")
37
+ * ```
38
+ */
39
+ export const formatBearerCredential = (token: string): string => {
40
+ const normalizedToken = internalNormalizeBearerToken(token)
41
+
42
+ if (normalizedToken.length === 0) {
43
+ throw new RangeError("Expected token to contain at least one non-whitespace character")
44
+ }
45
+
46
+ return `Bearer ${normalizedToken}`
47
+ }
48
+
49
+ /**
50
+ * 从 Bearer 凭据字符串中提取原始 token。
51
+ *
52
+ * 当输入值不是 Bearer 格式时,该函数返回 `undefined`。
53
+ *
54
+ * @example
55
+ * ```
56
+ * // Expect: "token-value"
57
+ * const example1 = parseBearerCredential("Bearer token-value")
58
+ * // Expect: undefined
59
+ * const example2 = parseBearerCredential("Basic token-value")
60
+ * ```
61
+ */
62
+ export const parseBearerCredential = (input: string | undefined): string | undefined => {
63
+ if (input === undefined) {
64
+ return undefined
65
+ }
66
+
67
+ if (isBearerCredential(input) === false) {
68
+ return undefined
69
+ }
70
+
71
+ const normalizedToken = internalNormalizeBearerToken(input)
72
+ return normalizedToken.length === 0 ? undefined : normalizedToken
73
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./api-key.ts"
2
+ export * from "./password.ts"
3
+ export * from "./json-web-token.ts"
4
+ export * from "./bearer.ts"