@planet-matrix/mobius-model 0.6.0 → 0.9.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 (233) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/index.js +706 -36
  3. package/dist/index.js.map +855 -59
  4. package/package.json +28 -16
  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/schedule.ts +111 -0
  29. package/src/basic/stream.ts +135 -25
  30. package/src/credential/README.md +107 -0
  31. package/src/credential/api-key.ts +158 -0
  32. package/src/credential/bearer.ts +73 -0
  33. package/src/credential/index.ts +4 -0
  34. package/src/credential/json-web-token.ts +96 -0
  35. package/src/credential/password.ts +170 -0
  36. package/src/cron/README.md +86 -0
  37. package/src/cron/cron.ts +87 -0
  38. package/src/cron/index.ts +1 -0
  39. package/src/drizzle/README.md +1 -0
  40. package/src/drizzle/drizzle.ts +1 -0
  41. package/src/drizzle/helper.ts +47 -0
  42. package/src/drizzle/index.ts +5 -0
  43. package/src/drizzle/infer.ts +52 -0
  44. package/src/drizzle/kysely.ts +8 -0
  45. package/src/drizzle/pagination.ts +200 -0
  46. package/src/email/README.md +1 -0
  47. package/src/email/index.ts +1 -0
  48. package/src/email/resend.ts +25 -0
  49. package/src/event/class-event-proxy.ts +6 -5
  50. package/src/event/common.ts +13 -3
  51. package/src/event/event-manager.ts +3 -3
  52. package/src/event/instance-event-proxy.ts +6 -5
  53. package/src/event/internal.ts +4 -4
  54. package/src/form/README.md +25 -0
  55. package/src/form/index.ts +1 -0
  56. package/src/form/inputor-controller/base.ts +874 -0
  57. package/src/form/inputor-controller/boolean.ts +39 -0
  58. package/src/form/inputor-controller/file.ts +39 -0
  59. package/src/form/inputor-controller/form.ts +181 -0
  60. package/src/form/inputor-controller/helper.ts +117 -0
  61. package/src/form/inputor-controller/index.ts +17 -0
  62. package/src/form/inputor-controller/multi-select.ts +99 -0
  63. package/src/form/inputor-controller/number.ts +116 -0
  64. package/src/form/inputor-controller/select.ts +109 -0
  65. package/src/form/inputor-controller/text.ts +82 -0
  66. package/src/http/READMD.md +1 -0
  67. package/src/http/api/api-core.ts +84 -0
  68. package/src/http/api/api-handler.ts +79 -0
  69. package/src/http/api/api-host.ts +47 -0
  70. package/src/http/api/api-result.ts +56 -0
  71. package/src/http/api/api-schema.ts +154 -0
  72. package/src/http/api/api-server.ts +130 -0
  73. package/src/http/api/api-test.ts +142 -0
  74. package/src/http/api/api-type.ts +37 -0
  75. package/src/http/api/api.ts +81 -0
  76. package/src/http/api/index.ts +11 -0
  77. package/src/http/api-adapter/api-core-node-http.ts +260 -0
  78. package/src/http/api-adapter/api-host-node-http.ts +156 -0
  79. package/src/http/api-adapter/api-result-arktype.ts +297 -0
  80. package/src/http/api-adapter/api-result-zod.ts +286 -0
  81. package/src/http/api-adapter/index.ts +5 -0
  82. package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
  83. package/src/http/bin/gen-api-list/index.ts +1 -0
  84. package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
  85. package/src/http/bin/gen-api-test/index.ts +1 -0
  86. package/src/http/bin/gen-api-type/calc-code.ts +25 -0
  87. package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
  88. package/src/http/bin/gen-api-type/index.ts +2 -0
  89. package/src/http/bin/index.ts +2 -0
  90. package/src/http/index.ts +3 -0
  91. package/src/huawei/README.md +1 -0
  92. package/src/huawei/index.ts +2 -0
  93. package/src/huawei/moderation/index.ts +1 -0
  94. package/src/huawei/moderation/moderation.ts +355 -0
  95. package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
  96. package/src/huawei/obs/index.ts +1 -0
  97. package/src/huawei/obs/obs.ts +42 -0
  98. package/src/index.ts +19 -2
  99. package/src/json/README.md +92 -0
  100. package/src/json/index.ts +1 -0
  101. package/src/json/repair.ts +18 -0
  102. package/src/log/logger.ts +15 -4
  103. package/src/openai/README.md +1 -0
  104. package/src/openai/index.ts +1 -0
  105. package/src/openai/openai.ts +510 -0
  106. package/src/orchestration/README.md +9 -7
  107. package/src/orchestration/dispatching/dispatcher.ts +83 -0
  108. package/src/orchestration/dispatching/index.ts +2 -0
  109. package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
  110. package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
  111. package/src/orchestration/dispatching/selector/index.ts +2 -0
  112. package/src/orchestration/index.ts +2 -0
  113. package/src/orchestration/scheduling/index.ts +2 -0
  114. package/src/orchestration/scheduling/scheduler.ts +103 -0
  115. package/src/orchestration/scheduling/task.ts +32 -0
  116. package/src/random/README.md +8 -7
  117. package/src/random/base.ts +66 -0
  118. package/src/random/index.ts +5 -1
  119. package/src/random/random-boolean.ts +40 -0
  120. package/src/random/random-integer.ts +60 -0
  121. package/src/random/random-number.ts +72 -0
  122. package/src/random/random-string.ts +66 -0
  123. package/src/request/README.md +108 -0
  124. package/src/request/fetch/base.ts +108 -0
  125. package/src/request/fetch/browser.ts +285 -0
  126. package/src/request/fetch/general.ts +20 -0
  127. package/src/request/fetch/index.ts +4 -0
  128. package/src/request/fetch/nodejs.ts +285 -0
  129. package/src/request/index.ts +2 -0
  130. package/src/request/request/base.ts +250 -0
  131. package/src/request/request/general.ts +64 -0
  132. package/src/request/request/index.ts +3 -0
  133. package/src/request/request/resource.ts +68 -0
  134. package/src/result/README.md +4 -0
  135. package/src/result/controller.ts +54 -0
  136. package/src/result/either.ts +193 -0
  137. package/src/result/index.ts +2 -0
  138. package/src/route/README.md +105 -0
  139. package/src/route/adapter/browser.ts +122 -0
  140. package/src/route/adapter/driver.ts +56 -0
  141. package/src/route/adapter/index.ts +2 -0
  142. package/src/route/index.ts +3 -0
  143. package/src/route/router/index.ts +2 -0
  144. package/src/route/router/route.ts +630 -0
  145. package/src/route/router/router.ts +1642 -0
  146. package/src/route/uri/hash.ts +308 -0
  147. package/src/route/uri/index.ts +7 -0
  148. package/src/route/uri/pathname.ts +376 -0
  149. package/src/route/uri/search.ts +413 -0
  150. package/src/socket/README.md +105 -0
  151. package/src/socket/client/index.ts +2 -0
  152. package/src/socket/client/socket-unit.ts +660 -0
  153. package/src/socket/client/socket.ts +203 -0
  154. package/src/socket/common/index.ts +2 -0
  155. package/src/socket/common/socket-unit-common.ts +23 -0
  156. package/src/socket/common/socket-unit-heartbeat.ts +427 -0
  157. package/src/socket/index.ts +3 -0
  158. package/src/socket/server/index.ts +3 -0
  159. package/src/socket/server/server.ts +183 -0
  160. package/src/socket/server/socket-unit.ts +449 -0
  161. package/src/socket/server/socket.ts +264 -0
  162. package/src/storage/table.ts +3 -3
  163. package/src/timer/expiration/expiration-manager.ts +3 -3
  164. package/src/timer/expiration/remaining-manager.ts +3 -3
  165. package/src/tube/README.md +99 -0
  166. package/src/tube/helper.ts +138 -0
  167. package/src/tube/index.ts +2 -0
  168. package/src/tube/tube.ts +880 -0
  169. package/src/weixin/README.md +1 -0
  170. package/src/weixin/index.ts +2 -0
  171. package/src/weixin/official-account/authorization.ts +159 -0
  172. package/src/weixin/official-account/index.ts +2 -0
  173. package/src/weixin/official-account/js-api.ts +134 -0
  174. package/src/weixin/open/index.ts +1 -0
  175. package/src/weixin/open/oauth2.ts +133 -0
  176. package/tests/unit/ai/ai.spec.ts +85 -0
  177. package/tests/unit/aio/content.spec.ts +105 -0
  178. package/tests/unit/aio/json.spec.ts +147 -0
  179. package/tests/unit/aio/prompt.spec.ts +111 -0
  180. package/tests/unit/basic/error.spec.ts +16 -4
  181. package/tests/unit/basic/schedule.spec.ts +74 -0
  182. package/tests/unit/basic/stream.spec.ts +90 -37
  183. package/tests/unit/credential/api-key.spec.ts +37 -0
  184. package/tests/unit/credential/bearer.spec.ts +23 -0
  185. package/tests/unit/credential/json-web-token.spec.ts +23 -0
  186. package/tests/unit/credential/password.spec.ts +41 -0
  187. package/tests/unit/cron/cron.spec.ts +84 -0
  188. package/tests/unit/event/class-event-proxy.spec.ts +3 -3
  189. package/tests/unit/event/event-manager.spec.ts +3 -3
  190. package/tests/unit/event/instance-event-proxy.spec.ts +3 -3
  191. package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
  192. package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
  193. package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
  194. package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
  195. package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
  196. package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
  197. package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
  198. package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
  199. package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
  200. package/tests/unit/http/api/api-core-host.spec.ts +207 -0
  201. package/tests/unit/http/api/api-schema.spec.ts +120 -0
  202. package/tests/unit/http/api/api-server.spec.ts +363 -0
  203. package/tests/unit/http/api/api-test.spec.ts +117 -0
  204. package/tests/unit/http/api/api.spec.ts +121 -0
  205. package/tests/unit/http/api-adapter/node-http.spec.ts +191 -0
  206. package/tests/unit/json/repair.spec.ts +11 -0
  207. package/tests/unit/log/logger.spec.ts +19 -4
  208. package/tests/unit/openai/openai.spec.ts +64 -0
  209. package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
  210. package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
  211. package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
  212. package/tests/unit/random/base.spec.ts +58 -0
  213. package/tests/unit/random/random-boolean.spec.ts +25 -0
  214. package/tests/unit/random/random-integer.spec.ts +32 -0
  215. package/tests/unit/random/random-number.spec.ts +33 -0
  216. package/tests/unit/random/random-string.spec.ts +22 -0
  217. package/tests/unit/request/fetch/browser.spec.ts +222 -0
  218. package/tests/unit/request/fetch/general.spec.ts +43 -0
  219. package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
  220. package/tests/unit/request/request/base.spec.ts +385 -0
  221. package/tests/unit/request/request/general.spec.ts +161 -0
  222. package/tests/unit/route/router/route.spec.ts +431 -0
  223. package/tests/unit/route/router/router.spec.ts +407 -0
  224. package/tests/unit/route/uri/hash.spec.ts +72 -0
  225. package/tests/unit/route/uri/pathname.spec.ts +147 -0
  226. package/tests/unit/route/uri/search.spec.ts +107 -0
  227. package/tests/unit/socket/client.spec.ts +208 -0
  228. package/tests/unit/socket/server.spec.ts +135 -0
  229. package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
  230. package/tests/unit/tube/helper.spec.ts +139 -0
  231. package/tests/unit/tube/tube.spec.ts +501 -0
  232. package/src/random/string.ts +0 -35
  233. package/tests/unit/random/string.spec.ts +0 -11
@@ -0,0 +1 @@
1
+ # Drizzle
@@ -0,0 +1 @@
1
+ export * as d from "drizzle-orm"
@@ -0,0 +1,47 @@
1
+ import type { ExtractTablesWithRelations } from "drizzle-orm"
2
+ import { PgDatabase, PgTransaction } from "drizzle-orm/pg-core"
3
+ import type {
4
+ PostgresJsDatabase as RawPostgresJsDatabase,
5
+ PostgresJsTransaction as RawPostgresJsTransaction,
6
+ } from "drizzle-orm/postgres-js"
7
+
8
+ export type PostgresJsNormalDatabase<Schema extends Record<string, unknown> = Record<string, never>>
9
+ = RawPostgresJsDatabase<Schema>
10
+ export type PostgresJsTransactionDatabase<Schema extends Record<string, unknown> = Record<string, never>>
11
+ = RawPostgresJsTransaction<Schema, ExtractTablesWithRelations<Schema>>
12
+ export type PostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>>
13
+ = PostgresJsNormalDatabase<Schema> | PostgresJsTransactionDatabase<Schema>
14
+ export interface WithPostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>> {
15
+ database: PostgresJsDatabase<Schema>
16
+ }
17
+ export interface WithOptionalPostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>> {
18
+ database?: PostgresJsDatabase<Schema> | undefined
19
+ }
20
+ export type WithoutPostgresJsDatabase<T> = Omit<T, "database">
21
+
22
+ export const isPostgresJsNormalDatabase = <Schema extends Record<string, unknown> = Record<string, never>>(
23
+ database: PostgresJsDatabase<Schema>,
24
+ ): database is PostgresJsNormalDatabase<Schema> => {
25
+ return database instanceof PgDatabase
26
+ }
27
+ export const isPostgresJsTransactionDatabase = <Schema extends Record<string, unknown> = Record<string, never>>(
28
+ database: PostgresJsDatabase<Schema>,
29
+ ): database is PostgresJsTransactionDatabase<Schema> => {
30
+ return database instanceof PgTransaction
31
+ }
32
+ export const autoPostgresJsDatabaseTransaction = async <Result, Schema extends Record<string, unknown> = Record<string, never>>(
33
+ database: PostgresJsDatabase<Schema>,
34
+ run: (database: PostgresJsTransactionDatabase<Schema>) => Promise<Result>,
35
+ ): Promise<Result> => {
36
+ // detect transaction database first, then normal database
37
+ // because transaction database is a subclass of normal database
38
+ if (isPostgresJsTransactionDatabase(database)) {
39
+ return await run(database)
40
+ }
41
+ if (isPostgresJsNormalDatabase(database)) {
42
+ return await database.transaction(async (database) => {
43
+ return await run(database)
44
+ })
45
+ }
46
+ throw new Error("Invalid database instance")
47
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./drizzle.ts"
2
+ export type * from "./infer.ts"
3
+ export type * from "./kysely.ts"
4
+ export * from "./pagination.ts"
5
+ export * from "./helper.ts"
@@ -0,0 +1,52 @@
1
+ import type { DrizzleTypeError, InferEnum, InferInsertModel, InferSelectModel } from "drizzle-orm"
2
+ import type { PgEnum, PgTableWithColumns } from "drizzle-orm/pg-core"
3
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"
4
+
5
+ type RemoveNeverValue<T> = {
6
+ [K in keyof T as T[K] extends never ? never : K]: T[K]
7
+ }
8
+
9
+ type PreInferModel<T extends Record<string, unknown> = Record<string, never>> = {
10
+ [K in keyof T]: T[K] extends PgTableWithColumns<infer _>
11
+ ? InferSelectModel<T[K]>
12
+ : (
13
+ T[K] extends PgEnum<infer __>
14
+ ? InferEnum<T[K]>
15
+ : never
16
+ )
17
+ }
18
+ export type InferModel<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferModel<T>>
19
+
20
+ type PreInferInsert<T extends Record<string, unknown> = Record<string, never>> = {
21
+ [K in keyof T]: T[K] extends PgTableWithColumns<infer _>
22
+ ? InferInsertModel<T[K]>
23
+ : never
24
+ }
25
+ export type InferInsert<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferInsert<T>>
26
+
27
+ type PreInferUpdate<T extends Record<string, unknown> = Record<string, never>> = {
28
+ [K in keyof T]: T[K] extends PgTableWithColumns<infer _>
29
+ ? Partial<InferSelectModel<T[K]>>
30
+ : (
31
+ T[K] extends PgEnum<infer __>
32
+ ? InferEnum<T[K]>
33
+ : never
34
+ )
35
+ }
36
+ export type InferUpdate<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferUpdate<T>>
37
+
38
+ type GetValidQuery<T extends Record<string, unknown> = Record<string, never>> = Exclude<
39
+ PostgresJsDatabase<T>["query"],
40
+ DrizzleTypeError<string>
41
+ >
42
+ type PreInferWith<T extends Record<string, unknown> = Record<string, never>> = {
43
+ [K in keyof GetValidQuery<T>]: NonNullable<NonNullable<Parameters<GetValidQuery<T>[K]["findMany"]>[0]>["with"]>
44
+ }
45
+ export type InferWith<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferWith<T>>
46
+
47
+ // oxlint-disable-next-line typescript/no-explicit-any
48
+ export type AnyPgTableWithColumns = PgTableWithColumns<any>
49
+ type PreInferModelFromPgTableWithColumns<T extends AnyPgTableWithColumns> = {
50
+ [K in keyof InferSelectModel<T>]: InferSelectModel<T>[K]
51
+ }
52
+ export type InferModelFromPgTableWithColumns<T extends AnyPgTableWithColumns> = RemoveNeverValue<PreInferModelFromPgTableWithColumns<T>>
@@ -0,0 +1,8 @@
1
+ import type { Table } from "drizzle-orm"
2
+ import type { Kyselify } from "drizzle-orm/kysely"
3
+ import type { AnyPgTable } from "drizzle-orm/pg-core"
4
+
5
+ export type KyselifyTable<T extends Table> = Kyselify<T>
6
+ export type KyselifyDatabase<T extends Record<string, unknown> = Record<string, never>> = {
7
+ [K in keyof T as T[K] extends AnyPgTable ? T[K]["_"]["name"] : never]: T[K] extends AnyPgTable ? Kyselify<T[K]> : never
8
+ }
@@ -0,0 +1,200 @@
1
+ import { d } from "./drizzle.ts"
2
+ import type { AnyPgTableWithColumns, InferModelFromPgTableWithColumns } from "./infer.ts"
3
+
4
+ export type Cursor = string | null
5
+ export interface WithCursorBasedPaginationOptions {
6
+ limit: number
7
+ cursor: Cursor
8
+ }
9
+ export interface WithCursorBasedPaginationResult {
10
+ nextCursor: Cursor
11
+ totalCount: number
12
+ }
13
+
14
+ interface OrderByItem<Key> {
15
+ key: Key
16
+ order: "asc" | "desc"
17
+ }
18
+ export interface EncodeCursorOptions<Model> {
19
+ model: Model
20
+ orderBy: Array<OrderByItem<keyof Model>>
21
+ }
22
+ export type EncodeCursorResult = string
23
+ export const encodeCursor = <Model>(
24
+ options: EncodeCursorOptions<Model>,
25
+ ): EncodeCursorResult => {
26
+ const { model, orderBy } = options
27
+ const encoded = orderBy
28
+ .map((item) => {
29
+ const { key } = item
30
+ if (model[key] === undefined) {
31
+ throw new Error(`model[${String(key)}] is undefined`)
32
+ }
33
+ return model[key]
34
+ })
35
+ .map((value) => {
36
+ if (value instanceof Date) {
37
+ return `Date(${value.getTime()})`
38
+ }
39
+ return String(value)
40
+ })
41
+ .join(":")
42
+ return btoa(encoded)
43
+ }
44
+
45
+ export interface DecodeCursorOptions<Model, Key extends keyof Model = keyof Model> {
46
+ modelForType: Model
47
+ cursor: Cursor
48
+ orderBy: Array<OrderByItem<Key>>
49
+ }
50
+ export type DecodedCursor<Model, Key extends keyof Model = keyof Model> = {
51
+ [K in Key]: Model[K] extends Date ? Date : Model[K]
52
+ }
53
+ export type DecodeCursorResult<Model, Key extends keyof Model = keyof Model> = DecodedCursor<Model, Key> | null
54
+ export const decodeCursor = <Model, Key extends keyof Model = keyof Model>(
55
+ options: DecodeCursorOptions<Model, Key>,
56
+ ): DecodeCursorResult<Model, Key> => {
57
+ const { cursor, orderBy } = options
58
+ if (cursor === null) {
59
+ return null
60
+ }
61
+ const decoded = atob(cursor)
62
+ .split(":")
63
+ .map((value) => {
64
+ if (value.startsWith("Date(")) {
65
+ return new Date(Number.parseInt(value.slice(5, -1), 10))
66
+ }
67
+ return value
68
+ })
69
+ .reduce((acc, value, index) => {
70
+ const key = orderBy[index]!.key
71
+ return { ...acc, [key]: value }
72
+ }, {})
73
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
74
+ return decoded as DecodedCursor<Model, Key>
75
+ }
76
+
77
+ export interface GetNextCursorOptions<Model> {
78
+ list: Model[]
79
+ limit: number
80
+ encodeOptions: Omit<EncodeCursorOptions<Model>, "model">
81
+ }
82
+ export const getNextCursor = <Model>(options: GetNextCursorOptions<Model>): Cursor => {
83
+ const { list, limit, encodeOptions } = options
84
+ if (list.length === 0) {
85
+ return null
86
+ }
87
+ if (list.length < limit) {
88
+ return null
89
+ }
90
+ const lastModel = list.at(-1)!
91
+ const cursor = encodeCursor({
92
+ model: lastModel,
93
+ ...encodeOptions,
94
+ })
95
+ return cursor
96
+ }
97
+
98
+ export interface BuildWhereSqlOptions<Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>> {
99
+ table: Table
100
+ orderBy: Array<OrderByItem<Key>>
101
+ decodeCursorResult: DecodeCursorResult<InferModelFromPgTableWithColumns<Table>, Key>
102
+ }
103
+ export const buildWhereSql = <Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>>(
104
+ options: BuildWhereSqlOptions<Table, Key>,
105
+ ): d.SQL | undefined => {
106
+ const { table, decodeCursorResult, orderBy } = options
107
+ if (decodeCursorResult === null) {
108
+ return undefined
109
+ }
110
+ if (orderBy.length === 0) {
111
+ return undefined
112
+ }
113
+ const conditionSqlList = orderBy.map((item) => {
114
+ const { key, order } = item
115
+ if (order === "asc") {
116
+ return d.gt(table[key], decodeCursorResult[key])
117
+ }
118
+ if (order === "desc") {
119
+ return d.lt(table[key], decodeCursorResult[key])
120
+ }
121
+ throw new Error(`Invalid order: ${String(order)}`)
122
+ })
123
+ return d.and(...conditionSqlList)
124
+ }
125
+
126
+ export interface BuildOrderBySql<Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>> {
127
+ table: Table
128
+ orderBy: Array<OrderByItem<Key>>
129
+ }
130
+ export const buildOrderBySql = <Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>>(
131
+ options: BuildOrderBySql<Table, Key>,
132
+ ): d.SQL[] => {
133
+ const { table, orderBy } = options
134
+ const sqlList = orderBy.map((item) => {
135
+ const { key, order } = item
136
+ if (order === "asc") {
137
+ return d.asc(table[key])
138
+ }
139
+ if (order === "desc") {
140
+ return d.desc(table[key])
141
+ }
142
+ throw new Error(`Invalid order: ${String(order)}`)
143
+ })
144
+ return sqlList
145
+ }
146
+
147
+ export interface BuildCursorBasedPaginationOptions<Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>> {
148
+ table: Table
149
+ orderBy: Array<OrderByItem<Key>>
150
+ cursor: Cursor
151
+ limit: number
152
+ }
153
+ export interface BuildCursorBasedPaginationResult<Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>> {
154
+ decodeCursorResult: DecodeCursorResult<InferModelFromPgTableWithColumns<Table>, Key>
155
+ whereSql: d.SQL | undefined
156
+ orderBySql: d.SQL[]
157
+ getNextCursor: (list: Array<InferModelFromPgTableWithColumns<Table>>) => Cursor
158
+ }
159
+ export const buildCursorBasedPagination = <Table extends AnyPgTableWithColumns, Key extends keyof InferModelFromPgTableWithColumns<Table>>(
160
+ options: BuildCursorBasedPaginationOptions<Table, Key>,
161
+ ): BuildCursorBasedPaginationResult<Table, Key> => {
162
+ const { table, orderBy, limit, cursor } = options
163
+
164
+ type Model = InferModelFromPgTableWithColumns<Table>
165
+
166
+ const decodeCursorResult = decodeCursor({
167
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
168
+ modelForType: {} as Model,
169
+ cursor,
170
+ orderBy,
171
+ })
172
+
173
+ const whereSql = buildWhereSql({
174
+ table,
175
+ decodeCursorResult,
176
+ orderBy,
177
+ })
178
+
179
+ const orderBySql = buildOrderBySql({
180
+ table,
181
+ orderBy,
182
+ })
183
+
184
+ const _getNextCursor = (list: Model[]): Cursor => {
185
+ return getNextCursor({
186
+ list,
187
+ limit,
188
+ encodeOptions: {
189
+ orderBy,
190
+ },
191
+ })
192
+ }
193
+
194
+ return {
195
+ decodeCursorResult,
196
+ whereSql,
197
+ orderBySql,
198
+ getNextCursor: _getNextCursor,
199
+ }
200
+ }
@@ -0,0 +1 @@
1
+ # Email
@@ -0,0 +1 @@
1
+ export * from "./resend.ts"
@@ -0,0 +1,25 @@
1
+ import { Resend } from "resend"
2
+
3
+ export interface SendEmailOptions {
4
+ from: string
5
+ to: string
6
+ subject: string
7
+ html: string
8
+ }
9
+ export type SendEmailResult = ReturnType<typeof Resend.prototype.emails.send>
10
+
11
+ export interface EmailOptions {
12
+ key: string
13
+ }
14
+ export class Email {
15
+ private sendClient: Resend
16
+
17
+ constructor(options: EmailOptions) {
18
+ const { key } = options
19
+ this.sendClient = new Resend(key)
20
+ }
21
+
22
+ async sendEmail(options: SendEmailOptions): Promise<SendEmailResult> {
23
+ return await this.sendClient.emails.send({ ...options })
24
+ }
25
+ }
@@ -1,13 +1,13 @@
1
1
  import type { InternalProxySubscriberEntryMap } from "./internal.ts"
2
2
  import type {
3
- BaseEvents,
3
+ EventsConstraint,
4
4
  SubscriberEntry,
5
5
  } from "./common.ts"
6
6
 
7
7
  /**
8
8
  * 表示 ClassEventProxy 用于接入目标实例及其事件系统的适配器。
9
9
  */
10
- export interface ClassEventProxyTargetAdapter<Target, Events extends BaseEvents> {
10
+ export interface ClassEventProxyTargetAdapter<Target, Events extends EventsConstraint<Events>> {
11
11
  emit<K extends keyof Events>(target: Target, event: K, ...args: Parameters<Events[K]>): boolean
12
12
  subscribe<K extends keyof Events>(target: Target, event: K, subscriber: Events[K]): void
13
13
  unsubscribe<K extends keyof Events>(target: Target, event: K, subscriber: Events[K]): void
@@ -16,7 +16,7 @@ export interface ClassEventProxyTargetAdapter<Target, Events extends BaseEvents>
16
16
  /**
17
17
  * 表示 ClassEventProxy 的构造选项。
18
18
  */
19
- export interface ClassEventProxyOptions<Target, Events extends BaseEvents> {
19
+ export interface ClassEventProxyOptions<Target, Events extends EventsConstraint<Events>> {
20
20
  targetAdapter: ClassEventProxyTargetAdapter<Target, Events>
21
21
  /**
22
22
  * 在代理管理的订阅者执行出错时接收错误与对应订阅项。
@@ -27,7 +27,7 @@ export interface ClassEventProxyOptions<Target, Events extends BaseEvents> {
27
27
  /**
28
28
  * 将一组目标实例的事件系统适配为统一的代理订阅模型。
29
29
  */
30
- export class ClassEventProxy<Target, Events extends BaseEvents> {
30
+ export class ClassEventProxy<Target, Events extends EventsConstraint<Events>> {
31
31
  protected options: ClassEventProxyOptions<Target, Events>
32
32
  protected subscribers: Map<Target, InternalProxySubscriberEntryMap<Events>>
33
33
 
@@ -196,7 +196,8 @@ export class ClassEventProxy<Target, Events extends BaseEvents> {
196
196
 
197
197
  const events = Object.keys(proxySubscriberEntryMap)
198
198
  for (const event of events) {
199
- this.removeSubscribersOfEvent(target, event)
199
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
200
+ this.removeSubscribersOfEvent(target, event as keyof Events)
200
201
  }
201
202
  this.subscribers.delete(target)
202
203
 
@@ -4,14 +4,24 @@
4
4
  // oxlint-disable-next-line no-explicit-any
5
5
  export type BaseSubscriber = (...args: any[]) => void
6
6
  /**
7
- * 表示由事件名到订阅者函数类型构成的事件表。
7
+ * 表示事件表中允许的事件-订阅者关系的约束类型。
8
+ * 该类型要求事件表的每个事件都必须对应一个 BaseSubscriber 类型的订阅者函数。
9
+ * 通过该约束类型,EventManager 和相关组件能够在编译时确保事件表的正确性。
8
10
  */
9
- export type BaseEvents = Record<string, BaseSubscriber>
11
+ export type EventsConstraint<Events extends EventsConstraint<Events>> = {
12
+ [K in keyof Events]: BaseSubscriber
13
+ }
14
+ export type BuildEvents<Events extends EventsConstraint<Events>> = {
15
+ [K in keyof Events]: Events[K]
16
+ }
17
+ export interface AnyEvents {
18
+ [event: string]: BaseSubscriber
19
+ }
10
20
 
11
21
  /**
12
22
  * 表示一次订阅关系的标准化描述。
13
23
  */
14
- export interface SubscriberEntry<Events extends BaseEvents, K extends keyof Events> {
24
+ export interface SubscriberEntry<Events extends EventsConstraint<Events>, K extends keyof Events> {
15
25
  event: K
16
26
  once: boolean
17
27
  subscriber: Events[K]
@@ -1,10 +1,10 @@
1
1
  import type { InternalSubscriberEntryMap } from "./internal.ts"
2
- import type { BaseEvents, SubscriberEntry } from "./common.ts"
2
+ import type { EventsConstraint, SubscriberEntry } from "./common.ts"
3
3
 
4
4
  /**
5
5
  * 表示 EventManager 的构造选项。
6
6
  */
7
- export interface EventManagerOptions<Events extends BaseEvents> {
7
+ export interface EventManagerOptions<Events extends EventsConstraint<Events>> {
8
8
  /**
9
9
  * 在订阅者执行出错时接收错误与对应订阅项。
10
10
  */
@@ -14,7 +14,7 @@ export interface EventManagerOptions<Events extends BaseEvents> {
14
14
  /**
15
15
  * 管理同一事件表下的订阅、取消订阅与事件派发。
16
16
  */
17
- export class EventManager<Events extends BaseEvents> {
17
+ export class EventManager<Events extends EventsConstraint<Events>> {
18
18
  protected options: EventManagerOptions<Events>
19
19
  /**
20
20
  * 每一类事件对应一个内部订阅映射,映射中的 key 是订阅者函数,value 是 SubscriberEntry 对象。
@@ -1,13 +1,13 @@
1
1
  import type { InternalProxySubscriberEntryMap } from "./internal.ts"
2
2
  import type {
3
- BaseEvents,
3
+ EventsConstraint,
4
4
  SubscriberEntry,
5
5
  } from "./common.ts"
6
6
 
7
7
  /**
8
8
  * 表示 InstanceEventProxy 用于接入底层事件目标的适配器。
9
9
  */
10
- export interface InstanceEventProxyTargetAdapter<Events extends BaseEvents> {
10
+ export interface InstanceEventProxyTargetAdapter<Events extends EventsConstraint<Events>> {
11
11
  emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): boolean
12
12
  subscribe<K extends keyof Events>(event: K, subscriber: Events[K]): void
13
13
  unsubscribe<K extends keyof Events>(event: K, subscriber: Events[K]): void
@@ -16,7 +16,7 @@ export interface InstanceEventProxyTargetAdapter<Events extends BaseEvents> {
16
16
  /**
17
17
  * 表示 InstanceEventProxy 的构造选项。
18
18
  */
19
- export interface InstanceEventProxyOptions<Events extends BaseEvents> {
19
+ export interface InstanceEventProxyOptions<Events extends EventsConstraint<Events>> {
20
20
  targetAdapter: InstanceEventProxyTargetAdapter<Events>
21
21
  /**
22
22
  * 在代理管理的订阅者执行出错时接收错误与对应订阅项。
@@ -27,7 +27,7 @@ export interface InstanceEventProxyOptions<Events extends BaseEvents> {
27
27
  /**
28
28
  * 将单个事件目标适配为可管理下游订阅关系的代理。
29
29
  */
30
- export class InstanceEventProxy<Events extends BaseEvents> {
30
+ export class InstanceEventProxy<Events extends EventsConstraint<Events>> {
31
31
  protected options: InstanceEventProxyOptions<Events>
32
32
  protected subscribers: InternalProxySubscriberEntryMap<Events>
33
33
 
@@ -168,7 +168,8 @@ export class InstanceEventProxy<Events extends BaseEvents> {
168
168
  const events = Object.keys(this.subscribers)
169
169
 
170
170
  for (const event of events) {
171
- this.removeSubscribersOfEvent(event)
171
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
172
+ this.removeSubscribersOfEvent(event as keyof Events)
172
173
  }
173
174
  this.subscribers = {}
174
175
 
@@ -1,9 +1,9 @@
1
- import type { BaseEvents, SubscriberEntry } from "./common.ts"
1
+ import type { EventsConstraint, SubscriberEntry } from "./common.ts"
2
2
 
3
3
  /**
4
4
  * 表示某一事件名下由订阅者函数到订阅项的内部映射。
5
5
  */
6
- export type InternalSubscriberEntryMap<Events extends BaseEvents, K extends keyof Events> = Map<
6
+ export type InternalSubscriberEntryMap<Events extends EventsConstraint<Events>, K extends keyof Events> = Map<
7
7
  Events[K],
8
8
  SubscriberEntry<Events, K>
9
9
  >
@@ -11,7 +11,7 @@ export type InternalSubscriberEntryMap<Events extends BaseEvents, K extends keyo
11
11
  /**
12
12
  * 表示代理订阅项及其所管理的下游订阅集合的内部结构。
13
13
  */
14
- export interface InternalProxySubscriberEntry<Events extends BaseEvents, K extends keyof Events> {
14
+ export interface InternalProxySubscriberEntry<Events extends EventsConstraint<Events>, K extends keyof Events> {
15
15
  managedSubscribers: InternalSubscriberEntryMap<Events, K>
16
16
  proxySubscriber: Events[K]
17
17
  }
@@ -19,6 +19,6 @@ export interface InternalProxySubscriberEntry<Events extends BaseEvents, K exten
19
19
  /**
20
20
  * 使用对象而非 Map 来保存事件到代理订阅项的内部映射。
21
21
  */
22
- export type InternalProxySubscriberEntryMap<Events extends BaseEvents> = {
22
+ export type InternalProxySubscriberEntryMap<Events extends EventsConstraint<Events>> = {
23
23
  [K in keyof Events]?: InternalProxySubscriberEntry<Events, K> | undefined
24
24
  }
@@ -0,0 +1,25 @@
1
+ # Form
2
+
3
+ ## Description
4
+
5
+ Form 模块提供围绕类表单输入项(form-like input)及其组合关系的通用建模能力,用于表达输入状态、值转换与聚合边界。
6
+
7
+ 它关注的不是某个组件库的渲染细节,也不是某个框架各自的表单接入方式,而是“一个输入项应如何被视为可独立管理的输入原子、多个输入项如何组合成更高层的类表单数据管理器、以及输入值与聚合值如何保持清楚且可维护的对应关系”这一类基础问题。它之所以被命名为 Form,不是因为它只服务于页面表单,而是因为表单场景最自然、最直观地体现了这类模型的价值。
8
+
9
+ ## For Understanding
10
+
11
+ 理解 Form 模块时,首先应把它看成“类表单数据管理模型”,而不是“页面表单组件集合”或“校验规则工具箱”。它要解决的问题,不是把某个现成表单 API 重新包装一遍,而是为输入项本身建立稳定语义:一个输入项有哪些核心状态,输入过程与最终值如何区分,多个输入项如何组合,以及组合之后的整体值应如何被表达。
12
+
13
+ 这个模块更适合放在以下边界中:
14
+
15
+ - 你希望把输入逻辑从具体接入层中抽离出来,让输入状态、值更新和聚合关系可以在不同 UI、服务端流程或其它非界面场景之间复用。
16
+ - 你需要先把输入项视为一组可独立管理的输入原子,再把它们组合成更高层的类表单数据管理器,而不是一开始就把所有逻辑揉成单个大对象。
17
+ - 你需要明确区分“输入过程中的值”和“对外稳定表达的值”,并希望这种区分能够成为长期可维护的公共语义。
18
+
19
+ 理解这个模块时,还应守住几条边界原则:
20
+
21
+ - Form 模块表达的是输入项状态、输入项组合与值映射语义,不负责页面布局、样式、校验文案或具体提交流程。
22
+ - 它可以服务于具体输入组件,但不应因为适配某个框架或某种表单交互习惯,而把这些宿主细节直接上升为模块公共语义。
23
+ - 它关注的是“输入项如何被建模、如何更新、如何聚合”,而不是所有表单相关问题的总容器;像复杂校验编排、错误展示策略、网络提交流程或业务字段规范,通常应由更上层模块承担。
24
+
25
+ 因此,更合适的理解方式是:Form 模块提供的是一套围绕输入原子与类表单聚合的数据管理基础模型能力。表单只是它最典型的落点之一,而不是它的唯一归宿。只有当某个能力确实在澄清这条边界时,它才适合作为该模块的组成部分;如果某个能力只是某类页面表单的临时便利封装,那么它通常不应直接进入这个模块。
@@ -0,0 +1 @@
1
+ export * from "./inputor-controller/index.ts"