weifuwu 0.87.0 → 0.89.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 (392) hide show
  1. package/README.md +111 -135
  2. package/dist/client/components/ActionSheet/ActionSheet.d.ts +1 -1
  3. package/dist/client/components/AiChat/AiChat.d.ts +3 -4
  4. package/dist/client/components/ChatInput/ChatInput.d.ts +5 -0
  5. package/dist/client/components/CitationCard/CitationCard.d.ts +1 -1
  6. package/dist/client/components/Command/Command.d.ts +1 -1
  7. package/dist/client/components/ContextMenu/ContextMenu.d.ts +1 -1
  8. package/dist/client/components/DatePicker/DatePicker.d.ts +1 -1
  9. package/dist/client/components/Dropdown/Dropdown.d.ts +1 -1
  10. package/dist/client/components/Editor/model/html.d.ts +10 -0
  11. package/dist/client/components/ImageCropper/ImageCropper.d.ts +6 -2
  12. package/dist/client/components/Menu/Menu.d.ts +1 -1
  13. package/dist/client/components/NavMenu/NavMenu.d.ts +1 -1
  14. package/dist/client/components/Popconfirm/Popconfirm.d.ts +1 -1
  15. package/dist/client/components/SlideCanvas/SlideCanvas.d.ts +1 -1
  16. package/dist/client/components/Tour/Tour.d.ts +1 -1
  17. package/dist/client/components/TreeSelect/TreeSelect.d.ts +1 -1
  18. package/dist/client/components/index.js +41 -41
  19. package/dist/client/components/style.css +298 -644
  20. package/dist/client/layout/weifuwu-layout.css +286 -640
  21. package/dist/client/vdom/browser/Browser.d.ts +2 -0
  22. package/dist/client/vdom/commands.d.ts +4 -1
  23. package/dist/client/vdom/context/UIContext.d.ts +8 -0
  24. package/dist/client/vdom/core/diff/attrs.d.ts +10 -2
  25. package/dist/client/vdom/core/field/attributes.d.ts +12 -0
  26. package/dist/client/vdom/core/field/events.d.ts +8 -0
  27. package/dist/client/vdom/core/field/input-sync.d.ts +14 -0
  28. package/dist/client/vdom/core/field/key.d.ts +3 -0
  29. package/dist/client/vdom/core/field/props.d.ts +13 -1
  30. package/dist/client/vdom/core/field/ref.d.ts +6 -0
  31. package/dist/client/vdom/core/field/style.d.ts +7 -1
  32. package/dist/client/vdom/core/node/component.d.ts +3 -4
  33. package/dist/client/vdom/core/node/native.d.ts +6 -1
  34. package/dist/client/vdom/core/patch/index.d.ts +24 -1
  35. package/dist/client/vdom/core/patch/processors.d.ts +8 -1
  36. package/dist/client/vdom/core/protocol.d.ts +45 -0
  37. package/dist/client/vdom/core/router.d.ts +7 -0
  38. package/dist/client/vdom/core/ssr/absorb.d.ts +31 -4
  39. package/dist/client/vdom/core/transform/index.d.ts +6 -6
  40. package/dist/client/vdom/core/v2/cycle.d.ts +54 -0
  41. package/dist/client/vdom/core/v2/diff.d.ts +80 -0
  42. package/dist/client/vdom/core/v2/integrate.d.ts +24 -0
  43. package/dist/client/vdom/core/v2/render.d.ts +28 -0
  44. package/dist/client/vdom/core/v2/schedule.d.ts +33 -0
  45. package/dist/client/vdom/core/v2/serve.d.ts +4 -0
  46. package/dist/client/vdom/core/v2/spy.d.ts +21 -0
  47. package/dist/client/vdom/core/v2/ssr.d.ts +14 -0
  48. package/dist/client/vdom/core/vnode.d.ts +9 -6
  49. package/dist/client/vdom/dev/error-counter.d.ts +27 -0
  50. package/dist/client/vdom/dev/render-health.d.ts +60 -0
  51. package/dist/client/vdom/hooks/chat.d.ts +32 -5
  52. package/dist/client/vdom/hooks/drag-media.d.ts +3 -1
  53. package/dist/client/vdom/hooks/env.d.ts +32 -0
  54. package/dist/client/vdom/hooks/popup-manager.d.ts +21 -0
  55. package/dist/client/vdom/hooks/popup.d.ts +4 -1
  56. package/dist/client/vdom/hooks/stable.d.ts +4 -0
  57. package/dist/client/vdom/hooks/use-observable.d.ts +13 -0
  58. package/dist/client/vdom/index.d.ts +14 -6
  59. package/dist/client/vdom/index.js +4 -7
  60. package/dist/client/vdom/jsx-runtime.js +1 -1
  61. package/dist/client/vdom/middlewares/api.d.ts +8 -0
  62. package/dist/client/vdom/middlewares/auth-i18n.d.ts +7 -0
  63. package/dist/client/vdom/middlewares/ws.d.ts +41 -1
  64. package/dist/client/vdom/observable/index.d.ts +13 -0
  65. package/dist/client/vdom/observable/observable.d.ts +26 -0
  66. package/dist/client/vdom/observable/operators.d.ts +76 -0
  67. package/dist/client/vdom/observable/sources.d.ts +54 -0
  68. package/dist/client/vdom/observable/types.d.ts +45 -0
  69. package/dist/client/vdom/store.d.ts +17 -2
  70. package/dist/client/vdom/testing.js +2 -2
  71. package/dist/server/ai/agent.d.ts +18 -0
  72. package/dist/server/ai/client.d.ts +14 -2
  73. package/dist/server/ai/contracts.d.ts +2 -2
  74. package/dist/server/ai/sse.d.ts +6 -0
  75. package/dist/server/core/collect.d.ts +31 -0
  76. package/dist/server/core/error-counter.d.ts +11 -0
  77. package/dist/server/core/hub.d.ts +2 -0
  78. package/dist/server/core/router.d.ts +12 -9
  79. package/dist/server/db/contracts.d.ts +24 -0
  80. package/dist/server/db/memory-redis.d.ts +3 -4
  81. package/dist/server/db/memory-sql.d.ts +20 -4
  82. package/dist/server/db/postgres-server.d.ts +2 -0
  83. package/dist/server/db/query.d.ts +21 -0
  84. package/dist/server/db/redis-server.d.ts +4 -2
  85. package/dist/server/db/sql-parser.d.ts +2 -1
  86. package/dist/server/email/index.d.ts +2 -0
  87. package/dist/server/index.d.ts +4 -1
  88. package/dist/server/index.js +3927 -1982
  89. package/dist/server/messager/index.d.ts +21 -2
  90. package/dist/server/middleware/compress.d.ts +25 -0
  91. package/dist/server/ui/index.d.ts +8 -1
  92. package/dist/server/user/index.d.ts +4 -0
  93. package/dist/shared/router/chain.d.ts +9 -0
  94. package/dist/shared/router/context.d.ts +35 -0
  95. package/dist/shared/router/ctx-fields.d.ts +20 -0
  96. package/dist/shared/router/pipeline.d.ts +70 -0
  97. package/dist/shared/router/trie.d.ts +11 -3
  98. package/dist/shared/router/types.d.ts +23 -0
  99. package/docs/style-guide.md +44 -41
  100. package/package.json +13 -10
  101. package/content/apps/admin.md +0 -55
  102. package/content/apps/agent-platform.md +0 -35
  103. package/content/apps/auth.md +0 -49
  104. package/content/apps/multi.md +0 -44
  105. package/content/apps/todo.md +0 -51
  106. package/content/backend/ai.md +0 -28
  107. package/content/backend/auth.md +0 -20
  108. package/content/backend/email.md +0 -23
  109. package/content/backend/graphql.md +0 -23
  110. package/content/backend/http.md +0 -23
  111. package/content/backend/limit.md +0 -23
  112. package/content/backend/middleware.md +0 -17
  113. package/content/backend/queue.md +0 -23
  114. package/content/backend/redis.md +0 -26
  115. package/content/backend/router.md +0 -23
  116. package/content/backend/schedule.md +0 -23
  117. package/content/backend/sql.md +0 -27
  118. package/content/backend/sse.md +0 -26
  119. package/content/backend/ws.md +0 -26
  120. package/content/capabilities/app-node.md +0 -21
  121. package/content/capabilities/data.md +0 -21
  122. package/content/capabilities/events.md +0 -21
  123. package/content/capabilities/hooks.md +0 -22
  124. package/content/capabilities/i18n.md +0 -21
  125. package/content/capabilities/popup.md +0 -21
  126. package/content/capabilities/render-only.md +0 -23
  127. package/content/capabilities/router.md +0 -22
  128. package/content/capabilities/self-id.md +0 -21
  129. package/content/capabilities/store.md +0 -21
  130. package/content/capabilities/theme.md +0 -21
  131. package/content/capabilities/two-phase.md +0 -21
  132. package/content/components/accordion.md +0 -50
  133. package/content/components/actionsheet.md +0 -46
  134. package/content/components/affix.md +0 -51
  135. package/content/components/aichat.md +0 -57
  136. package/content/components/alert.md +0 -52
  137. package/content/components/alertgroup.md +0 -45
  138. package/content/components/anchor.md +0 -52
  139. package/content/components/app.md +0 -37
  140. package/content/components/approvalcard.md +0 -56
  141. package/content/components/appshell.md +0 -50
  142. package/content/components/aspectratio.md +0 -47
  143. package/content/components/authpage.md +0 -61
  144. package/content/components/autocomplete-v2.md +0 -40
  145. package/content/components/autocomplete.md +0 -56
  146. package/content/components/avatar.md +0 -51
  147. package/content/components/avatargroup.md +0 -47
  148. package/content/components/backtop.md +0 -53
  149. package/content/components/badge.md +0 -55
  150. package/content/components/breadcrumb.md +0 -49
  151. package/content/components/button.md +0 -63
  152. package/content/components/calendar-v2.md +0 -40
  153. package/content/components/calendar.md +0 -50
  154. package/content/components/card.md +0 -58
  155. package/content/components/carousel.md +0 -52
  156. package/content/components/cascader-v2.md +0 -39
  157. package/content/components/cascader.md +0 -54
  158. package/content/components/chart.md +0 -53
  159. package/content/components/chatinput.md +0 -63
  160. package/content/components/checkbox.md +0 -51
  161. package/content/components/checkboxgroup.md +0 -52
  162. package/content/components/citationcard.md +0 -48
  163. package/content/components/codeblock.md +0 -48
  164. package/content/components/codeeditor.md +0 -47
  165. package/content/components/collapse.md +0 -49
  166. package/content/components/colorpicker.md +0 -50
  167. package/content/components/command.md +0 -50
  168. package/content/components/confirm.md +0 -57
  169. package/content/components/contextmenu.md +0 -48
  170. package/content/components/copybutton.md +0 -51
  171. package/content/components/datepicker.md +0 -52
  172. package/content/components/descriptions-v2.md +0 -39
  173. package/content/components/descriptions.md +0 -52
  174. package/content/components/diffview-v2.md +0 -39
  175. package/content/components/diffview.md +0 -50
  176. package/content/components/divider.md +0 -48
  177. package/content/components/drawer.md +0 -55
  178. package/content/components/dropdown.md +0 -53
  179. package/content/components/editor.md +0 -49
  180. package/content/components/emptystate.md +0 -51
  181. package/content/components/exportcsv.md +0 -38
  182. package/content/components/field.md +0 -54
  183. package/content/components/filepreview-office.md +0 -37
  184. package/content/components/filepreview.md +0 -49
  185. package/content/components/filetree.md +0 -56
  186. package/content/components/fileupload-v2.md +0 -39
  187. package/content/components/fileupload.md +0 -57
  188. package/content/components/floatbutton.md +0 -52
  189. package/content/components/form-v2.md +0 -41
  190. package/content/components/form.md +0 -60
  191. package/content/components/grid.md +0 -51
  192. package/content/components/highlight-v2.md +0 -39
  193. package/content/components/highlight.md +0 -46
  194. package/content/components/hovercard.md +0 -51
  195. package/content/components/icon.md +0 -50
  196. package/content/components/imagecropper.md +0 -45
  197. package/content/components/img.md +0 -56
  198. package/content/components/infinitescroll-v2.md +0 -40
  199. package/content/components/infinitescroll.md +0 -54
  200. package/content/components/input.md +0 -65
  201. package/content/components/inputnumber.md +0 -58
  202. package/content/components/inview.md +0 -56
  203. package/content/components/jsonschemaform.md +0 -53
  204. package/content/components/jsonviewer-v2.md +0 -39
  205. package/content/components/jsonviewer.md +0 -49
  206. package/content/components/kanban.md +0 -46
  207. package/content/components/label.md +0 -48
  208. package/content/components/layout.md +0 -54
  209. package/content/components/layoutcontent.md +0 -43
  210. package/content/components/layoutheader.md +0 -43
  211. package/content/components/layoutsider.md +0 -43
  212. package/content/components/link.md +0 -52
  213. package/content/components/list.md +0 -44
  214. package/content/components/loading.md +0 -45
  215. package/content/components/logviewer-v2.md +0 -39
  216. package/content/components/logviewer.md +0 -53
  217. package/content/components/markdown.md +0 -51
  218. package/content/components/markdowneditor.md +0 -47
  219. package/content/components/math.md +0 -42
  220. package/content/components/mentions-v2.md +0 -39
  221. package/content/components/mentions.md +0 -52
  222. package/content/components/menu.md +0 -56
  223. package/content/components/menubar.md +0 -44
  224. package/content/components/messagebubble.md +0 -50
  225. package/content/components/modal.md +0 -59
  226. package/content/components/navmenu.md +0 -47
  227. package/content/components/notification.md +0 -51
  228. package/content/components/pageheader.md +0 -53
  229. package/content/components/pagination.md +0 -49
  230. package/content/components/paragraph.md +0 -45
  231. package/content/components/passwordinput.md +0 -57
  232. package/content/components/pininput-v2.md +0 -39
  233. package/content/components/pininput.md +0 -50
  234. package/content/components/pipeline.md +0 -49
  235. package/content/components/popconfirm.md +0 -58
  236. package/content/components/popover.md +0 -61
  237. package/content/components/progressbar.md +0 -50
  238. package/content/components/prompttemplate.md +0 -49
  239. package/content/components/qrcode.md +0 -50
  240. package/content/components/radiogroup.md +0 -53
  241. package/content/components/rate.md +0 -53
  242. package/content/components/reasoningblock.md +0 -47
  243. package/content/components/relationgraph.md +0 -52
  244. package/content/components/resizable.md +0 -53
  245. package/content/components/result.md +0 -49
  246. package/content/components/scrollbar.md +0 -49
  247. package/content/components/searchinput.md +0 -51
  248. package/content/components/segmentedcontrol.md +0 -59
  249. package/content/components/select-searchable.md +0 -47
  250. package/content/components/select.md +0 -66
  251. package/content/components/sessionlist.md +0 -52
  252. package/content/components/sheetgrid.md +0 -44
  253. package/content/components/skeleton.md +0 -55
  254. package/content/components/slidecanvas.md +0 -44
  255. package/content/components/slider.md +0 -62
  256. package/content/components/sortablelist.md +0 -39
  257. package/content/components/space.md +0 -52
  258. package/content/components/sparkline.md +0 -52
  259. package/content/components/statcard-countdown.md +0 -39
  260. package/content/components/statcard.md +0 -56
  261. package/content/components/steps.md +0 -48
  262. package/content/components/switch.md +0 -50
  263. package/content/components/tabbar.md +0 -45
  264. package/content/components/table-v2.md +0 -40
  265. package/content/components/table.md +0 -66
  266. package/content/components/tabs.md +0 -56
  267. package/content/components/tag.md +0 -51
  268. package/content/components/tagsinput-v2.md +0 -39
  269. package/content/components/tagsinput.md +0 -54
  270. package/content/components/text.md +0 -45
  271. package/content/components/textarea.md +0 -57
  272. package/content/components/themeswitch.md +0 -69
  273. package/content/components/timeline.md +0 -50
  274. package/content/components/title.md +0 -45
  275. package/content/components/toast.md +0 -52
  276. package/content/components/toggle-togglegroup.md +0 -52
  277. package/content/components/togglegroup.md +0 -47
  278. package/content/components/toolcallcard.md +0 -51
  279. package/content/components/tooltip.md +0 -50
  280. package/content/components/tour.md +0 -50
  281. package/content/components/transfer.md +0 -52
  282. package/content/components/tree-v2.md +0 -39
  283. package/content/components/tree.md +0 -59
  284. package/content/components/treeselect.md +0 -54
  285. package/content/components/typography.md +0 -51
  286. package/content/components/videoplayer.md +0 -52
  287. package/content/components/virtuallist.md +0 -52
  288. package/content/components/virtualtable-v2.md +0 -39
  289. package/content/components/virtualtable.md +0 -55
  290. package/content/components/watermark.md +0 -53
  291. package/content/components/wave.md +0 -43
  292. package/content/guides/ai-chat-family.md +0 -24
  293. package/content/guides/choose.md +0 -67
  294. package/content/guides/component-model.md +0 -32
  295. package/content/guides/component-standards.md +0 -123
  296. package/content/guides/components-guide.md +0 -813
  297. package/content/guides/custom-component.md +0 -321
  298. package/content/guides/data-guide.md +0 -281
  299. package/content/guides/file-preview-family.md +0 -18
  300. package/content/guides/frontend.md +0 -968
  301. package/content/guides/layout-choice.md +0 -64
  302. package/content/guides/layout-guide.md +0 -241
  303. package/content/guides/middleware.md +0 -459
  304. package/content/guides/mobile-guide.md +0 -105
  305. package/content/guides/page-building.md +0 -98
  306. package/content/guides/production.md +0 -37
  307. package/content/guides/quality.md +0 -60
  308. package/content/guides/realtime-guide.md +0 -296
  309. package/content/guides/render-only.md +0 -44
  310. package/content/guides/saas-guide.md +0 -253
  311. package/content/guides/server-guide.md +0 -359
  312. package/content/guides/start.md +0 -41
  313. package/content/guides/styling.md +0 -154
  314. package/content/guides/ui-dom-guide.md +0 -157
  315. package/content/index.json +0 -4344
  316. package/content/index.md +0 -181
  317. package/content/layout/align.md +0 -20
  318. package/content/layout/anchor.md +0 -19
  319. package/content/layout/app-shell.md +0 -23
  320. package/content/layout/border.md +0 -20
  321. package/content/layout/center.md +0 -19
  322. package/content/layout/cluster.md +0 -19
  323. package/content/layout/container.md +0 -19
  324. package/content/layout/fill.md +0 -19
  325. package/content/layout/grid.md +0 -19
  326. package/content/layout/hidden.md +0 -22
  327. package/content/layout/layer.md +0 -19
  328. package/content/layout/position.md +0 -22
  329. package/content/layout/row.md +0 -23
  330. package/content/layout/safe-area.md +0 -20
  331. package/content/layout/scroll.md +0 -21
  332. package/content/layout/spacing.md +0 -22
  333. package/content/layout/split.md +0 -19
  334. package/content/layout/stack.md +0 -19
  335. package/content/layout/surface.md +0 -23
  336. package/content/layout/text.md +0 -22
  337. package/content/patterns/app-shell.md +0 -34
  338. package/content/patterns/dashboard.md +0 -36
  339. package/content/patterns/data-screen.md +0 -30
  340. package/content/patterns/detail-page.md +0 -31
  341. package/content/patterns/docs.md +0 -34
  342. package/content/patterns/focus-task.md +0 -34
  343. package/content/patterns/landing.md +0 -35
  344. package/content/patterns/list-page.md +0 -32
  345. package/content/patterns/mobile.md +0 -31
  346. package/content/patterns/settings-page.md +0 -33
  347. package/content/patterns/workspace.md +0 -32
  348. package/dist/cli/content-sync.test.d.ts +0 -1
  349. package/dist/cli/docs-cli.test.d.ts +0 -1
  350. package/dist/cli/docs.d.ts +0 -2
  351. package/dist/cli/docs.mjs +0 -10961
  352. package/dist/client/vdom/core/build.d.ts +0 -36
  353. package/dist/client/vdom/core/diff/children.d.ts +0 -29
  354. package/dist/client/vdom/core/diff/index.d.ts +0 -22
  355. package/dist/client/vdom/core/diff/output.d.ts +0 -30
  356. package/dist/client/vdom/core/diff/same.d.ts +0 -22
  357. package/dist/client/vdom/core/serve.d.ts +0 -75
  358. package/dist/client/vdom/core/ssr/index.d.ts +0 -25
  359. package/examples/apps/admin/README.md +0 -23
  360. package/examples/apps/admin/api.ts +0 -27
  361. package/examples/apps/admin/app.tsx +0 -144
  362. package/examples/apps/admin/main.tsx +0 -8
  363. package/examples/apps/admin/server.ts +0 -37
  364. package/examples/apps/auth/README.md +0 -23
  365. package/examples/apps/auth/api.ts +0 -49
  366. package/examples/apps/auth/app.tsx +0 -137
  367. package/examples/apps/auth/main.tsx +0 -8
  368. package/examples/apps/auth/server.ts +0 -37
  369. package/examples/apps/multi/README.md +0 -23
  370. package/examples/apps/multi/app.tsx +0 -83
  371. package/examples/apps/multi/main.tsx +0 -8
  372. package/examples/apps/multi/server.ts +0 -33
  373. package/examples/apps/todo/README.md +0 -23
  374. package/examples/apps/todo/api.ts +0 -26
  375. package/examples/apps/todo/app.tsx +0 -128
  376. package/examples/apps/todo/main.tsx +0 -9
  377. package/examples/apps/todo/server.ts +0 -39
  378. package/examples/hello-world/README.md +0 -9
  379. package/examples/hello-world/client.ts +0 -14
  380. package/examples/hello-world/routes.tsx +0 -26
  381. package/examples/hello-world/server.ts +0 -46
  382. package/examples/patterns/AppShell.tsx +0 -224
  383. package/examples/patterns/Dashboard.tsx +0 -153
  384. package/examples/patterns/DataScreen.tsx +0 -104
  385. package/examples/patterns/DetailPage.tsx +0 -79
  386. package/examples/patterns/Docs.tsx +0 -105
  387. package/examples/patterns/FocusTask.tsx +0 -67
  388. package/examples/patterns/Landing.tsx +0 -90
  389. package/examples/patterns/ListPage.tsx +0 -77
  390. package/examples/patterns/Mobile.tsx +0 -154
  391. package/examples/patterns/SettingsPage.tsx +0 -98
  392. package/examples/patterns/SplitWorkspace.tsx +0 -113
@@ -1,36 +0,0 @@
1
- /**
2
- * vdom core — build 阶段(vnode → 全量命令事件流)
3
- *
4
- * 四阶段管线(route → build → diff → patch):build 是「新树渲染」——
5
- * vnode → 命令事件流(create/insert/close...——done.full 全量标记——
6
- * patch 据此清理旧树多余节点)。
7
- *
8
- * **共享渲染分发器**(createRenderDispatcher——build/diff 共用——单一
9
- * 规则源):kindOf 分类 → 各 node/ 文件渲染(text/hole/array/fragment/
10
- * element/component/invalid)——diff 的新侧渲染复用本分发器——
11
- * **消除重复**(diff 只做对照决策——新侧渲染走这里)。
12
- */
13
- import type { VNode, VNodeChild } from './vnode.ts';
14
- import { type ComponentRegistry } from './node/component.ts';
15
- import type { UIContext } from '../context/UIContext.ts';
16
- import type { Command } from './command/index.ts';
17
- /** 渲染 sink(子节点递归出口——build/diff 共用) */
18
- export type RenderSink = (v: VNodeChild, parent: string, index: number, ref: string | null) => Promise<void>;
19
- /**
20
- * 创建渲染分发器(**共享——build 首帧/diff 新侧渲染同一实现**):
21
- * emit(v, parent, index, ref)——kindOf 分类 → 各 node/ 文件渲染
22
- */
23
- /** 生成端 emit 状态机(**维度 6——2026-XX**):
24
- * 本流内 id 类型表(id → 节点形态)——验证:
25
- * ① create 类型冲突:同 id 先 el 后 text(或反)→ 违例(投影错位)
26
- * ② insert parent 容器性:parent 是已生成的锚/文本 → 违例(id 空间
27
- * 错位——组件 fuzz an:root.0(div) 类在生成时暴露——而非消费/终态)
28
- * 宽容项:parent 不在类型表(组件 compId——sink 特判子空间)→ 合法
29
- * (段回退由消费端处理);create 同 id 同类型重复(幂等复用)→ 合法
30
- * 报告:console.error(不中断生成——生成端产物仍由对账器裁决) */
31
- export declare function createRenderDispatcher(emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry): RenderSink;
32
- /**
33
- * vnode → 全量命令事件流(首帧/导航——done.full——patch 清理旧树多余)
34
- * ctx:组件共享上下文(serve 创建);registry:组件实例注册表
35
- */
36
- export declare function renderToStream(root: VNode, ctx?: UIContext, registry?: ComponentRegistry): ReadableStream<Command>;
@@ -1,29 +0,0 @@
1
- /**
2
- * vdom core/diff — children(children 对照 + keyed 列表策略——细节模块)
3
- *
4
- * 职责:children 列表对照——A 级检测(长度变化 + 无 key 组件 warn)、
5
- * 列表分类(all-keyed/含 keyed/unkeyed)、diffSlot 单槽对照(位置身份——
6
- * 含 null ↔ null 空洞保持)、diffKeyedChildren(相对顺序检测——顺移
7
- * noMove remap / 交换重建 / 实例复用)、emitWithKey(keyed 项渲染)。
8
- *
9
- * diff/same 只做中转——本文件为列表策略细节。
10
- */
11
- import type { VNode, VNodeChild } from '../vnode.ts';
12
- import { type ComponentRegistry } from '../node/component.ts';
13
- import type { Command } from '../command/index.ts';
14
- import type { RenderSink } from '../build.ts';
15
- import type { UIContext } from '../../context/UIContext.ts';
16
- /** children 对照(列表分类:全 unkeyed 位置身份 / 全 keyed 身份复用 / 混合) */
17
- export declare function diffChildren(oldV: VNode, newV: VNode, id: string, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry): Promise<void>;
18
- /** children 项对照(列表分类:全 unkeyed 位置身份 / 全 keyed 身份复用 / 混合——
19
- * 组件数组输出(隐式 Fragment)同用——旧项移除清理) */
20
- export declare function diffChildrenItems(oldCs: VNodeChild[], newCs: VNodeChild[], id: string, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry, shapeChanged?: boolean): Promise<void>;
21
- export declare function hasKeyed(items: VNodeChild[]): boolean;
22
- /** keyed 列表对照(身份映射——增删/重排状态跟随 key)
23
- * **move 版**(2026-12):复用项位置变化 → **move 命令**(DOM 不重建——
24
- * 节点移动 + 子树 id 重映射——焦点保持);位置不变 → 组件输出对照(精准);
25
- * 真移除 → unmount + remove;新增 → 新侧渲染 */
26
- export declare function diffKeyedChildren(oldCs: VNodeChild[], newCs: VNodeChild[], parent: string, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry): Promise<void>;
27
- /** keyed 项渲染(compId = 位置路径 + .k{key}——身份稳定——增删/重排复用)
28
- * 组件输出对照(lastOutput → diffSame 精准——move 后节点已在新位置) */
29
- export declare function emitWithKey(v: VNodeChild, parent: string, index: number, ref: string | null, key: string, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry): Promise<void>;
@@ -1,22 +0,0 @@
1
- /**
2
- * vdom core/diff — index(diff 阶段中转站)
3
- *
4
- * 职责:**中转站——自身不处理细节逻辑**——root 级对照决策
5
- * (transitionOf 查表——异态交 transform / 同态交 diffSame)——细节
6
- * 下沉独立模块:
7
- * - same.ts:同态对照决策(组件/元素分支——再中转)
8
- * - attrs.ts:属性值比较(精准命令)
9
- * - children.ts:children 对照 + keyed 列表策略
10
- * - output.ts:组件输出对照(null ↔ vnode/数组对照)
11
- * - cleanup.ts:旧输出递归清理
12
- * - transform/:类型转换状态机(异态执行)
13
- */
14
- import type { VNode } from '../vnode.ts';
15
- import type { ComponentRegistry } from '../node/component.ts';
16
- import type { UIContext } from '../../context/UIContext.ts';
17
- import type { Command } from '../command/index.ts';
18
- /**
19
- * diff:旧树 → 新树——精准增量命令事件流
20
- * ctx:组件共享上下文;registry:组件实例注册表(跨渲染保持)
21
- */
22
- export declare function diffStream(oldTree: VNode, newTree: VNode, ctx: UIContext, registry: ComponentRegistry): ReadableStream<Command>;
@@ -1,30 +0,0 @@
1
- /**
2
- * vdom core/diff — output(组件输出对照——细节模块)
3
- *
4
- * 职责:组件 renderFn 输出的对照决策——输出级空值转换(null ↔ vnode——
5
- * transform 状态机)、单节点对照(diffSame)、数组输出对照(逐项 diffSlot)、
6
- * 数组 ↔ 单节点(transform——旧展开区间递归清理)、类型切换(卸载重建)。
7
- *
8
- * diffSame 组件分支的 sink 在此实现——diff/same 只做中转。
9
- */
10
- import type { VNode, VNodeChild } from '../vnode.ts';
11
- import type { Command } from '../command/index.ts';
12
- import type { RenderSink } from '../build.ts';
13
- import type { ComponentRegistry, CompOutput } from '../node/component.ts';
14
- import type { UIContext } from '../../context/UIContext.ts';
15
- /** 组件输出对照(组件分支 sink——细节集中在此)
16
- * **方案 3——判别联合穷尽**:oldOut 为 CompOutput(null 结构性消除)——
17
- * switch(kind) 编译器强制——hole(空洞锚)与真实输出同等处理——
18
- * undefined = 未渲染(首帧——全量渲染) */
19
- export declare function diffComponentOutput(oldOut: CompOutput | undefined, out: VNodeChild, p: string, i: number, r: string | null, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry, diffSame: (oldV: VNode, newV: VNode, parent: string, index: number, ref: string | null, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry) => Promise<void>,
20
- /** 组件实例 compId(**证明审计——输出形态 id 空间**):组件输出单元素
21
- * 挂槽位(锚点法——id = compId);空洞/数组/组件输出挂 compId 子空间
22
- * (compId.0 起)——转换的 oldId 必须按**旧输出形态**计算(p/i 是
23
- * 新输出的 sink 参数——数组/空洞输出时 p=compId、i=0——outId 对新
24
- * 输出正确对旧输出错位——可变输出 div→数组/收缩/展开实证——旧 div
25
- * 保留 + 锚插入 + 实例残留)
26
- * @param slotId 组件槽位(单元素/文本输出挂载点——= pathId(渲染父,
27
- * 渲染索引)——keyed 组件 compId ≠ 槽位——必须由调用点提供)
28
- * @param keyedOut keyed 组件输出回调(对照分支——keyed 输出组件的
29
- * rec 在 keyedId(p, key)——diffSame 按槽位查落空——递归 emitWithKey) */
30
- compId: string, slotId: string, keyedOut?: (out: VNodeChild, p: string, i: number, r: string | null, key: string) => Promise<void>): Promise<void>;
@@ -1,22 +0,0 @@
1
- /**
2
- * vdom core/diff — same(同态对照决策——中转)
3
- *
4
- * 职责:同位置同类型的对照决策——组件分支(类型比较/复用——输出对照
5
- * 细节在 output.ts)、元素分支(diffAttrs + diffChildren——细节在
6
- * attrs.ts/children.ts)。
7
- *
8
- * 本文件是「对照决策的中转站」——具体命令生成下沉 attrs/children/output/
9
- * cleanup——自身不处理细节逻辑。
10
- */
11
- import type { VNode } from '../vnode.ts';
12
- import { type ComponentRegistry } from '../node/component.ts';
13
- import type { Command } from '../command/index.ts';
14
- import type { RenderSink } from '../build.ts';
15
- import type { UIContext } from '../../context/UIContext.ts';
16
- /**
17
- * 同态对照(同位置同类型——**精准命令生成**):
18
- * 组件 → renderComponent 复用(工厂不重跑——lastOutput 对照递归);
19
- * 元素 → 属性值比较(只发变化)+ 函数面引用比较 + children 递归(列表分类)
20
- */
21
- export declare function diffSame(oldV: VNode, newV: VNode, parent: string, index: number, ref: string | null, emit: RenderSink, emitCommand: (cmd: Command) => void, ctx: UIContext, registry: ComponentRegistry): Promise<void>;
22
- /** 属性精准 diff(值比较——只发变化的键;函数面引用比较——prev 传递) */
@@ -1,75 +0,0 @@
1
- /**
2
- * vdom core — uiServe(渲染落地——公共面——双端一体)
3
- *
4
- * 设计(design/vdom-plan.md §3/§4):
5
- * - UIRouter 唯一应用入口——uiServe(router, { root }) 收养渲染(真实浏览器全局
6
- * document/window——2026-12 删除 browser 注入——测试与生产同环境)
7
- * - 渲染循环:初始 URL resolve → Response(command 事件流)→ patch
8
- * - **ctx.render() = 重新渲染**(事件触发/fetch 结束/定时器回调的唯一入口):
9
- * 重新 resolve(handler 重跑——registry 复用——组件工厂不重跑——
10
- * renderFn 重调读最新状态)→ **新的 Response command 事件流** → 消费
11
- * (patch 对照现有 DOM 节点——幂等——就地更新)
12
- * - 函数面传输:同进程共享函数表——编码时函数 → {$fn: n} 标记——
13
- * 解码时查表还原(事件绑定跨 Response 保持)
14
- *
15
- * 服务端面(SSR——同一 handler 同一 Response——body 经 commandToHtml()
16
- * TransformStream 流式吐 HTML)后续实现。
17
- */
18
- import { UIRouter } from './router.ts';
19
- import type { VNode } from './vnode.ts';
20
- import type { UIContext } from '../context/UIContext.ts';
21
- import type { Command } from './command/index.ts';
22
- /** 函数表还原($fn 标记 → 函数——编码/解码同进程共享) */
23
- export declare function reviveFn(fnTable: Map<number, unknown>): (k: string, v: unknown) => unknown;
24
- /** NDJSON 命令流解析(行缓冲——命令可能跨 chunk——函数表还原——
25
- * 导出(测试——跨 chunk 边界/畸形行合规断言)) */
26
- export declare function commandReader(reader: ReadableStreamDefaultReader<Uint8Array>, fnTable: Map<number, unknown>): AsyncGenerator<Command>;
27
- /** 命令流编码(函数面 → {$fn: n}——函数表——同进程共享) */
28
- export declare function encodeCommands(stream: ReadableStream<Command>, fnTable: Map<number, unknown>): ReadableStream<Uint8Array>;
29
- /** 函数表(serve 级共享——编码/解码同进程) */
30
- export declare function createFnTable(): Map<number, unknown>;
31
- export interface UiServeOptions {
32
- /** 根容器(选择器或元素——'#root') */
33
- root: string | HTMLElement;
34
- /** 中间件注入面(ctx.api/auth/ws/i18n——组件/页面可用——可选) */
35
- api?: import('../middlewares/api.ts').ApiClient;
36
- auth?: import('../middlewares/auth-i18n.ts').AuthClient;
37
- ws?: import('../middlewares/ws.ts').WsClient;
38
- i18n?: import('../middlewares/auth-i18n.ts').I18nState;
39
- /** 命令式轻提示(ctx.toast——应用装配) */
40
- toast?: (message: string, type?: 'success' | 'error' | 'info' | 'warning', duration?: number) => void;
41
- /** 命令式确认(ctx.confirm——应用装配——返回 Promise<boolean>) */
42
- confirm?: (message: string, options?: Record<string, unknown>) => Promise<boolean>;
43
- /** 命令式通知(ctx.notification——应用装配) */
44
- notification?: unknown;
45
- /**
46
- * 渲染错误回退 UI(R1 熔断——连续渲染错误达阈值后显示——应用可配置——
47
- * 缺省内置:错误文案 + 重试按钮(独立于应用路由——不依赖 router.resolve))
48
- */
49
- errorFallback?: (error: Error, ctx: UIContext) => VNode;
50
- }
51
- export interface UiServeHandle {
52
- /** 首帧渲染完成 Promise(await 精确等待) */
53
- ready: Promise<void>;
54
- /** 编程式导航(URL 变化 → 重新 resolve → 新命令事件流 → 消费——
55
- * root 异类型 = 整树替换;同类型 = diff 精准) */
56
- navigate(path: string): Promise<void>;
57
- /** 卸载(清理 DOM/监听) */
58
- unmount(): void;
59
- }
60
- /** serve 生命周期状态机(**全部状态机化——2026-XX**):
61
- * active → unmounted(unmount 消费——迁移后 render/navigate 违例报错) */
62
- export type ServePhase = 'active' | 'unmounted';
63
- /** 渲染队列状态机(**替代裸 rendering boolean**):
64
- * idle → rendering(render 启动)→ idle(runRender 完成/错误/队列空)
65
- * - rendering 中 render() → 入队(合法——FIFO 确定性——非违例)
66
- * - unmounted 中 render()/navigate() → 违例报错(DOM 已清——静默渲染
67
- * 是隐藏错误——审计 2026-XX) */
68
- export type RenderPhase = 'idle' | 'rendering';
69
- /** 页面作者渲染入口(ctx 面——vnode → Response command 事件流——
70
- * 公共面仍只有 h/jsx/uiServe/UIRouter——本入口经 ctx 提供) */
71
- export interface RenderCtx extends UIContext {
72
- /** vnode → Response(command 事件流——函数表编码——事件绑定跨流保持) */
73
- stream(vnode: VNode, init?: ResponseInit): Response;
74
- }
75
- export declare function uiServe(router: UIRouter, opts: UiServeOptions): UiServeHandle;
@@ -1,25 +0,0 @@
1
- /**
2
- * vdom core/ssr — index(SSR 中转站——自身不处理细节逻辑)
3
- *
4
- * 职责:服务端渲染入口(uiSsr——同一 UIRouter 同一 handler)——
5
- * 具体功能交由独立文件:
6
- * - html.ts(commandToHtml 流式序列化 + htmlDocument 文档包装)
7
- * - absorb.ts(客户端结构吸收状态机——首帧复用 SSR DOM)
8
- *
9
- * 与客户端同构:同一命令流——客户端 apply DOM / 服务端吐 HTML——
10
- * 首帧吸收(结构对齐)——接管原子性(mismatch → 回退清空重建)。
11
- */
12
- export { escapeHtml, attrsToHtml, htmlDocument, commandToHtml, VOID_ELEMENTS, kebab } from './html.ts';
13
- export { AbsorbState } from './absorb.ts';
14
- import { UIRouter } from '../router.ts';
15
- /** 服务端渲染选项 */
16
- export interface SsrOptions {
17
- title?: string;
18
- /** __DATA__ 种子(ctx.data 预取结果——序列化进文档) */
19
- data?: Record<string, unknown>;
20
- }
21
- /** 服务端渲染(SSR——同一 router 同一 handler——命令流 → HTML 文档)
22
- * **无 hydration**(客户端接管结构吸收——SSR = 首屏/SEO + 吸收种子);
23
- * 函数面(事件)经空函数表编码为 $fn 标记——解码 undefined——
24
- * commandToHtml 的 setProp no-op——HTML 无运行时面 */
25
- export declare function uiSsr(router: UIRouter, url: string, opts?: SsrOptions): Promise<string>;
@@ -1,23 +0,0 @@
1
- # admin 应用模板(复制即用)
2
-
3
- ```bash
4
- # 1. 安装依赖(weifuwu 包——含 content/ 离线文档 + examples/ 模板源码)
5
- npm i weifuwu
6
-
7
- # 2. 复制本目录到你的项目(或直接在 examples/apps/admin 内开发)
8
- # 3. 启动
9
- node server.ts # → http://localhost:admin/3300 3301 3302 3303
10
- ```
11
-
12
- ## 改造指南
13
-
14
- 见 `node_modules/weifuwu/content/apps/admin.md`(目录结构 + 逐步改造步骤)。
15
-
16
- ## 结构
17
-
18
- | 文件 | 职责 |
19
- |------|------|
20
- | app.tsx | 前端:路由表 + 页面组件 + 状态 |
21
- | api.ts | 后端:API 注册函数(独立/嵌入共享) |
22
- | server.ts | 独立入口(MemorySql——生产换 postgres() 一行) |
23
- | main.tsx | 独立前端入口 |
@@ -1,27 +0,0 @@
1
- /**
2
- * admin 后端 API——订单表(注册函数:独立 server 与 showcase 嵌入共享)
3
- */
4
- import type { Router } from 'weifuwu'
5
-
6
- export function registerAdminApi(app: Router, sql: any): void {
7
- app.get('/api/admin/orders', async () => {
8
- const rows = await sql`SELECT * FROM admin_orders ORDER BY id DESC LIMIT 50`
9
- return Response.json({ rows })
10
- })
11
- }
12
-
13
- /** 建表 + 种子数据(独立/嵌入共用) */
14
- export async function ensureAdminTables(sql: any): Promise<void> {
15
- await sql.unsafe('CREATE TABLE IF NOT EXISTS admin_orders (id serial PRIMARY KEY, customer text, amount numeric, status text, date text)')
16
- const rows = await sql`SELECT COUNT(*) AS n FROM admin_orders`
17
- if (Number(rows[0]?.n) > 0) return
18
- const seed = [
19
- ['张伟', 1280, 'paid', '2026-08-10'], ['李娜', 560, 'pending', '2026-08-11'],
20
- ['王强', 3200, 'shipped', '2026-08-12'], ['赵敏', 890, 'paid', '2026-08-13'],
21
- ['陈杰', 2100, 'pending', '2026-08-14'], ['刘洋', 450, 'paid', '2026-08-15'],
22
- ['孙丽', 1750, 'shipped', '2026-08-16'], ['周涛', 980, 'paid', '2026-08-17'],
23
- ]
24
- for (const [customer, amount, status, date] of seed) {
25
- await sql`INSERT INTO admin_orders (customer, amount, status, date) VALUES (${customer}, ${amount}, ${status}, ${date})`
26
- }
27
- }
@@ -1,144 +0,0 @@
1
- /**
2
- * admin 应用模板——管理后台(AppShell + 多页 + 表格,完整全栈复制即用)
3
- *
4
- * 演示能力:
5
- * - Layout 组件骨架(Sider 折叠 + Header + Content)+ 路由 layout 包裹复用
6
- * - Table 排序 + StatCard KPI + 菜单导航(源于 agent-platform 架构提炼)
7
- * - 后端:MemorySql 订单表(api.ts 注册函数——独立/嵌入共享)
8
- */
9
- import { UIRouter, uiServe, h, createStore, createClientBrowser } from 'weifuwu/vdom'
10
- import type { Component } from 'weifuwu/vdom'
11
- import { Layout, LayoutHeader, LayoutSider, LayoutContent, Menu, StatCard, Table, Badge, Tag, ThemeSwitch, PageHeader, EmptyState } from 'weifuwu/components'
12
-
13
- export interface Order { id: string; customer: string; amount: number; status: 'pending' | 'paid' | 'shipped'; date: string }
14
-
15
- export const adminStore = createStore<{ orders: Order[]; loading: boolean }>({ orders: [], loading: true })
16
-
17
- export async function loadOrders(): Promise<void> {
18
- const res = await fetch('/api/admin/orders')
19
- const data = await res.json()
20
- adminStore.update((s) => { s.orders = data.rows; s.loading = false })
21
- }
22
-
23
- const statusTag = (s: Order['status']) =>
24
- s === 'paid' ? <Tag variant="success">已支付</Tag> : s === 'shipped' ? <Tag variant="primary">已发货</Tag> : <Tag>待支付</Tag>
25
-
26
- /** 仪表盘页 */
27
- export const DashboardPage: Component = async (_init: any, ctx: any) => {
28
- void loadOrders()
29
- const state = ctx.ui.useExternal(adminStore)
30
- const paid = state.orders.filter((o: Order) => o.status === 'paid' || o.status === 'shipped')
31
- const total = state.orders.reduce((a: number, o: Order) => a + o.amount, 0)
32
- return async (_p: any) => (
33
- <div class="wf-stack wf-gap-md">
34
- <PageHeader title="仪表盘" sub="KPI + 订单概览(数据来自 MemorySql)" />
35
- <div class="wf-grid" style="--wf-cols:repeat(auto-fit,minmax(180px,1fr));--wf-gap:12px">
36
- <StatCard label="订单总数" value={state.orders.length} />
37
- <StatCard label="已支付/发货" value={paid.length} />
38
- <StatCard label="销售总额" value={`¥${total.toLocaleString()}`} />
39
- <StatCard label="待处理" value={state.orders.filter((o: Order) => o.status === 'pending').length} />
40
- </div>
41
- {state.loading ? <div class="wf-text-secondary">加载中…</div> : (
42
- <Table
43
- columns={[
44
- { key: 'id', label: '订单号' },
45
- { key: 'customer', label: '客户' },
46
- { key: 'amount', label: '金额', sortable: true, render: (v: any) => `¥${Number(v).toLocaleString()}` },
47
- { key: 'date', label: '日期' },
48
- { key: 'status', label: '状态', render: (v: any) => statusTag(v) },
49
- ]}
50
- data={state.orders}
51
-
52
- />
53
- )}
54
- </div>
55
- )
56
- }
57
-
58
- /** 订单页(全量表格 + 筛选) */
59
- export const OrdersPage: Component = async (_init: any, ctx: any) => {
60
- void loadOrders()
61
- const state = ctx.ui.useExternal(adminStore)
62
- let q = ''
63
- return async (_p: any) => {
64
- const list = state.orders.filter((o: Order) => !q || o.customer.toLowerCase().includes(q.toLowerCase()) || o.id.includes(q))
65
- return (
66
- <div class="wf-stack wf-gap-md">
67
- <PageHeader title="订单管理" sub={`共 ${list.length} 条`}>
68
- <input class="wf-input" style="max-width:200px" placeholder="搜索客户/订单号…" value={q}
69
- onInput={(e: any) => { q = (e.target as HTMLInputElement).value; ctx.render() }} />
70
- </PageHeader>
71
- {list.length === 0 && !state.loading ? <EmptyState text="无匹配订单" /> : (
72
- <Table
73
- columns={[
74
- { key: 'id', label: '订单号' },
75
- { key: 'customer', label: '客户', sortable: true },
76
- { key: 'amount', label: '金额', sortable: true, render: (v: any) => `¥${Number(v).toLocaleString()}` },
77
- { key: 'date', label: '日期' },
78
- { key: 'status', label: '状态', render: (v: any) => statusTag(v) },
79
- ]}
80
- data={list}
81
-
82
- />
83
- )}
84
- </div>
85
- )
86
- }
87
- }
88
-
89
- // ── 路由(layout 包裹 = AppShell 复用——跨页保持侧栏/折叠状态) ──
90
- export const adminRoutes = [
91
- { path: '/', render: () => h(DashboardPage, {}) },
92
- { path: '/orders', render: () => h(OrdersPage, {}) },
93
- ]
94
-
95
- const AppShell: Component = async (_init: any, ctx: any) => {
96
- let collapsed = false
97
- const current = () => location.hash.replace('#/', '') || '/'
98
- return async (props: any) => (
99
- <Layout style="min-height:420px;border:1px solid var(--wf-color-border);border-radius:8px;overflow:hidden">
100
- <LayoutSider collapsed={collapsed} collapsible onCollapse={(c) => { collapsed = c; ctx.render() }} width={200}>
101
- <div style={{ background: "var(--wf-color-bg-secondary)", height: "100%" }}>
102
- <div class="wf-p-sm wf-text-bold" style="color:var(--wf-color-text)">⚙️ 管理后台</div>
103
- <Menu
104
- items={[
105
- { key: '/', label: '仪表盘' },
106
- { key: '/orders', label: '订单管理' },
107
- ]}
108
- activeKey={current()}
109
- collapsible
110
- collapsed={collapsed}
111
- onCollapseChange={(c) => { collapsed = c; ctx.render() }}
112
- onSelect={(k: string) => { location.hash = `#/${k === '/' ? '' : k}` }}
113
- />
114
- </div>
115
- </LayoutSider>
116
- <Layout>
117
- <LayoutHeader style="display:flex;align-items:center;justify-content:flex-end;gap:8px">
118
- <Badge variant="success">admin 模板</Badge>
119
- <ThemeSwitch />
120
- </LayoutHeader>
121
- <LayoutContent style="padding:16px">{props.page}</LayoutContent>
122
- </Layout>
123
- </Layout>
124
- )
125
- }
126
-
127
- export const adminAppShell = AppShell
128
-
129
- export function createAdminApp(root: HTMLElement, options?: { history?: boolean }): ReturnType<typeof uiServe> {
130
- // vdom 规范面:UIRouter(Trie 匹配)+ uiServe(渲染落地)——布局共享
131
- // (root 稳定——AppShell 包裹——精准路由切换)
132
- const router = new UIRouter()
133
- for (const r of adminRoutes) {
134
- router.get(r.path, (req: Request, ctx: any) =>
135
- (ctx as { stream: (v: unknown) => Response }).stream(h(AppShell, { page: r.render() })))
136
- }
137
- return uiServe(router, {
138
- root,
139
- browser: createClientBrowser()!,
140
- ...(options?.history === false ? {} : {}),
141
- })
142
- }
143
-
144
- export const pathFromHash = (): string => location.hash.replace(/^#/, '') || '/'
@@ -1,8 +0,0 @@
1
- /**
2
- * admin 独立入口——复制本目录即可运行:
3
- * cd examples/apps/admin && node server.ts → http://localhost:3302
4
- */
5
- import { createAdminApp, pathFromHash } from './app.tsx'
6
-
7
- const sub = createAdminApp(document.querySelector('#root') as HTMLElement)
8
- window.addEventListener('hashchange', () => sub.navigate(pathFromHash()))
@@ -1,37 +0,0 @@
1
- /**
2
- * admin 独立 server——MemorySql 订单表(生产换 postgres())
3
- * cd examples/apps/admin && node server.ts → http://localhost:3302
4
- */
5
- import { serve, Router, ui, createMemorySql } from 'weifuwu'
6
- import { resolve, dirname } from 'node:path'
7
- import { fileURLToPath } from 'node:url'
8
- import { registerAdminApi, ensureAdminTables } from './api.ts'
9
-
10
- const __dirname = dirname(fileURLToPath(import.meta.url))
11
- const sql = createMemorySql()
12
- await ensureAdminTables(sql)
13
-
14
- const app = new Router()
15
- app.use(ui())
16
- app.get('/app.js', (req, ctx) => ctx.ui.js(resolve(__dirname, 'main.tsx')))
17
- registerAdminApi(app, sql)
18
-
19
- app.get('/*', async (req, ctx) => ctx.ui.html`
20
- <!DOCTYPE html>
21
- <html lang="zh-CN">
22
- <head>
23
- <meta charset="UTF-8">
24
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
25
- <link rel="stylesheet" href="/components.css">
26
- <title>admin 应用模板</title>
27
- </head>
28
- <body>
29
- <div id="root"></div>
30
- <script src="/app.js"></script>
31
- </body>
32
- </html>
33
- `)
34
- app.get('/components.css', (req, ctx) => ctx.ui.css('weifuwu/components/style.css'))
35
-
36
- serve(app, { port: 3302 })
37
- console.log('admin 模板 → http://localhost:3302')
@@ -1,23 +0,0 @@
1
- # auth 应用模板(复制即用)
2
-
3
- ```bash
4
- # 1. 安装依赖(weifuwu 包——含 content/ 离线文档 + examples/ 模板源码)
5
- npm i weifuwu
6
-
7
- # 2. 复制本目录到你的项目(或直接在 examples/apps/auth 内开发)
8
- # 3. 启动
9
- node server.ts # → http://localhost:auth/3300 3301 3302 3303
10
- ```
11
-
12
- ## 改造指南
13
-
14
- 见 `node_modules/weifuwu/content/apps/auth.md`(目录结构 + 逐步改造步骤)。
15
-
16
- ## 结构
17
-
18
- | 文件 | 职责 |
19
- |------|------|
20
- | app.tsx | 前端:路由表 + 页面组件 + 状态 |
21
- | api.ts | 后端:API 注册函数(独立/嵌入共享) |
22
- | server.ts | 独立入口(MemorySql——生产换 postgres() 一行) |
23
- | main.tsx | 独立前端入口 |
@@ -1,49 +0,0 @@
1
- /**
2
- * auth 后端 API——内存用户表 + 会话(注册函数:独立 server 与 showcase 嵌入共享)
3
- */
4
- import type { Router } from 'weifuwu'
5
- import { createMemorySql } from 'weifuwu'
6
-
7
- export interface AuthUser { id: string; email: string; name: string }
8
-
9
- export function registerAuthApi(app: Router, sql: any): void {
10
- // 内存会话表(token → userId)——演示用;生产换 ctx.auth/userSystem
11
- const sessions = new Map<string, string>()
12
- let seq = 0
13
-
14
- app.post('/api/auth/register', async (req: Request) => {
15
- const { email, password, name } = await req.json()
16
- if (!String(email ?? '').includes('@')) return Response.json({ ok: false, error: '邮箱格式无效' })
17
- if (String(password ?? '').length < 6) return Response.json({ ok: false, error: '密码至少 6 位' })
18
- const rows = await sql`INSERT INTO auth_users (email, password, name) VALUES (${String(email)}, ${String(password)}, ${String(name ?? email.split('@')[0])}) RETURNING id, email, name`
19
- const user = rows[0]
20
- const token = `tok_${++seq}_${user.id}`
21
- sessions.set(token, String(user.id))
22
- return Response.json({ ok: true, user, token }, { status: 201 })
23
- })
24
-
25
- app.post('/api/auth/login', async (req: Request) => {
26
- const { email, password } = await req.json()
27
- const rows = await sql`SELECT * FROM auth_users WHERE email = ${String(email)} AND password = ${String(password)}`
28
- if (!rows.length) return Response.json({ ok: false, error: '邮箱或密码错误' }, { status: 401 })
29
- const user = rows[0]
30
- const token = `tok_${++seq}_${user.id}`
31
- sessions.set(token, String(user.id))
32
- return Response.json({ ok: true, user, token })
33
- })
34
-
35
- app.get('/api/auth/me', async (req: Request) => {
36
- const auth = req.headers.get('authorization') ?? ''
37
- const token = auth.replace('Bearer ', '')
38
- const userId = sessions.get(token)
39
- if (!userId) return Response.json({ ok: false }, { status: 401 })
40
- const rows = await sql`SELECT id, email, name FROM auth_users WHERE id = ${userId}`
41
- if (!rows.length) return Response.json({ ok: false }, { status: 401 })
42
- return Response.json({ ok: true, user: rows[0] })
43
- })
44
- }
45
-
46
- /** 建表(独立/嵌入共用) */
47
- export async function ensureAuthTables(sql: any): Promise<void> {
48
- await sql.unsafe('CREATE TABLE IF NOT EXISTS auth_users (id serial PRIMARY KEY, email text UNIQUE, password text, name text)')
49
- }