@oyolincc/create 0.3.0 → 0.5.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/package.json +2 -2
  2. package/templates/hono-fullstack/.codegraph/.gitignore +5 -0
  3. package/templates/hono-fullstack/README.md +22 -1
  4. package/templates/hono-fullstack/_gitignore +1 -0
  5. package/templates/hono-fullstack/apps/server/package.json +7 -2
  6. package/templates/hono-fullstack/apps/server/src/adapters/cloudflare/entry.ts +4 -30
  7. package/templates/hono-fullstack/apps/server/src/adapters/nodejs/bootstrap.ts +20 -12
  8. package/templates/hono-fullstack/apps/server/src/adapters/nodejs/entry.ts +7 -57
  9. package/templates/hono-fullstack/apps/server/src/app.ts +37 -21
  10. package/templates/hono-fullstack/apps/server/src/config.ts +1 -1
  11. package/templates/hono-fullstack/apps/server/src/di-container.ts +51 -0
  12. package/templates/hono-fullstack/apps/server/src/infra/logger/getter.ts +1 -1
  13. package/templates/hono-fullstack/apps/server/src/infra/logger/pino.ts +21 -34
  14. package/templates/hono-fullstack/apps/server/src/infra/work-runner/errors.ts +22 -0
  15. package/templates/hono-fullstack/apps/server/src/infra/work-runner/pass-through/runner.ts +28 -22
  16. package/templates/hono-fullstack/apps/server/src/infra/work-runner/piscina/runner.ts +11 -34
  17. package/templates/hono-fullstack/apps/server/src/infra/work-runner/{example → piscina}/worker-entry.ts +6 -2
  18. package/templates/hono-fullstack/apps/server/src/infra/work-runner/types.ts +2 -16
  19. package/templates/hono-fullstack/apps/server/src/infra/work-runner/utils/business-error.ts +10 -5
  20. package/templates/hono-fullstack/apps/server/src/infra/work-runner/utils/message.ts +5 -17
  21. package/templates/hono-fullstack/apps/server/src/middlewares/cors.ts +16 -22
  22. package/templates/hono-fullstack/apps/server/src/middlewares/logger.ts +34 -0
  23. package/templates/hono-fullstack/apps/server/src/modules/example/module.ts +8 -0
  24. package/templates/hono-fullstack/apps/server/src/modules/example/queries.ts +8 -0
  25. package/templates/hono-fullstack/apps/server/src/modules/example/routes.ts +74 -68
  26. package/templates/hono-fullstack/apps/server/src/modules/example/service.test.ts +53 -0
  27. package/templates/hono-fullstack/apps/server/src/modules/example/service.ts +54 -0
  28. package/templates/hono-fullstack/apps/server/src/modules/example/types.ts +12 -0
  29. package/templates/hono-fullstack/apps/server/src/modules/example/work-task/tasks.test.ts +9 -35
  30. package/templates/hono-fullstack/apps/server/src/modules/example/work-task/tasks.ts +15 -46
  31. package/templates/hono-fullstack/apps/server/src/shared/errors/defs/index.ts +6 -1
  32. package/templates/hono-fullstack/apps/server/src/shared/errors/handler.ts +1 -1
  33. package/templates/hono-fullstack/apps/server/src/shared/network/openapi/index.ts +1 -1
  34. package/templates/hono-fullstack/apps/server/src/shared/types/app.ts +51 -0
  35. package/templates/hono-fullstack/apps/server/src/shared/types/db.ts +126 -0
  36. package/templates/hono-fullstack/apps/server/src/shared/utils/data-access/check.ts +19 -0
  37. package/templates/hono-fullstack/apps/server/src/shared/utils/data-access/model.ts +47 -0
  38. package/templates/hono-fullstack/apps/server/src/shared/utils/data-access/params.ts +105 -0
  39. package/templates/hono-fullstack/apps/server/src/shared/utils/data-access/query.test.ts +139 -0
  40. package/templates/hono-fullstack/apps/server/src/shared/utils/data-access/query.ts +236 -0
  41. package/templates/hono-fullstack/apps/server/vite.config.ts +2 -2
  42. package/templates/hono-fullstack/apps/server/wrangler.jsonc +1 -1
  43. package/templates/hono-fullstack/apps/stack/frontend/assets/styles.css +6 -0
  44. package/templates/hono-fullstack/apps/stack/frontend/components/general/ErrorMessage.tsx +3 -1
  45. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/AppLayout.tsx +2 -1
  46. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/Header.tsx +14 -2
  47. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/Page.tsx +2 -1
  48. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/PageContainer.tsx +4 -1
  49. package/templates/hono-fullstack/apps/stack/frontend/modules/example/api.ts +16 -9
  50. package/templates/hono-fullstack/apps/stack/frontend/modules/example/components/ExampleForm.tsx +25 -12
  51. package/templates/hono-fullstack/apps/stack/frontend/modules/example/components/ExampleList.tsx +13 -4
  52. package/templates/hono-fullstack/apps/stack/frontend/modules/example/hooks/api-hooks.ts +21 -8
  53. package/templates/hono-fullstack/apps/stack/frontend/routes/__root.tsx +1 -1
  54. package/templates/hono-fullstack/apps/stack/frontend/routes/index.tsx +35 -12
  55. package/templates/hono-fullstack/apps/stack/frontend/shared/network/query-hooks.ts +33 -0
  56. package/templates/hono-fullstack/apps/stack/package.json +9 -4
  57. package/templates/hono-fullstack/apps/stack/panda.config.ts +31 -0
  58. package/templates/hono-fullstack/apps/stack/tsconfig.json +1 -0
  59. package/templates/hono-fullstack/apps/stack/turbo.json +20 -0
  60. package/templates/hono-fullstack/apps/stack/vite.config.ts +48 -12
  61. package/templates/hono-fullstack/apps/stack/wrangler.jsonc +1 -1
  62. package/templates/hono-fullstack/envs/.env.example.sqlite-d1 +1 -0
  63. package/templates/hono-fullstack/libs/db/drizzle-kit/sqlite-d1.config.ts +29 -10
  64. package/templates/hono-fullstack/libs/db/package.json +1 -0
  65. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/columns.ts +1 -1
  66. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/modules/examples/examples.ts +6 -3
  67. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/vo.ts +7 -1
  68. package/templates/hono-fullstack/libs/definition/README.md +81 -0
  69. package/templates/hono-fullstack/libs/definition/package.json +3 -1
  70. package/templates/hono-fullstack/libs/definition/src/constants/index.ts +1 -0
  71. package/templates/hono-fullstack/libs/definition/src/constants/pagination.ts +3 -0
  72. package/templates/hono-fullstack/libs/definition/src/modules/common-contracts.ts +24 -0
  73. package/templates/hono-fullstack/libs/definition/src/modules/example/contracts.ts +34 -0
  74. package/templates/hono-fullstack/libs/definition/src/modules/example/index.ts +1 -16
  75. package/templates/hono-fullstack/libs/definition/src/modules/index.ts +2 -0
  76. package/templates/hono-fullstack/libs/definition/src/modules/vo-generated-types.ts +12 -0
  77. package/templates/hono-fullstack/libs/ui/.storybook/main.ts +32 -0
  78. package/templates/hono-fullstack/libs/ui/.storybook/panda.config.ts +22 -0
  79. package/templates/hono-fullstack/libs/ui/.storybook/preview.tsx +79 -0
  80. package/templates/hono-fullstack/libs/ui/.storybook/styles.css +1 -0
  81. package/templates/hono-fullstack/libs/ui/.storybook/vite.config.ts +37 -0
  82. package/templates/hono-fullstack/libs/ui/components.json +15 -0
  83. package/templates/hono-fullstack/libs/ui/package.json +114 -0
  84. package/templates/hono-fullstack/libs/ui/panda.config.ts +41 -0
  85. package/templates/hono-fullstack/libs/ui/src/Tooltip.tsx +47 -0
  86. package/templates/hono-fullstack/libs/ui/src/components/atoms/buttons/Button.tsx +80 -0
  87. package/templates/hono-fullstack/libs/ui/src/components/atoms/buttons/CloseButton.tsx +15 -0
  88. package/templates/hono-fullstack/libs/ui/src/components/atoms/buttons/IconButton.tsx +10 -0
  89. package/templates/hono-fullstack/libs/ui/src/components/atoms/collections/Combobox.tsx +91 -0
  90. package/templates/hono-fullstack/libs/ui/src/components/atoms/collections/Select.tsx +88 -0
  91. package/templates/hono-fullstack/libs/ui/src/components/atoms/collections/TreeView.tsx +142 -0
  92. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Avatar.tsx +64 -0
  93. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Badge.tsx +7 -0
  94. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Card.tsx +23 -0
  95. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Clipboard.tsx +77 -0
  96. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Icon.tsx +9 -0
  97. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Table.tsx +51 -0
  98. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Tag.tsx +23 -0
  99. package/templates/hono-fullstack/libs/ui/src/components/atoms/data-display/Timeline.tsx +33 -0
  100. package/templates/hono-fullstack/libs/ui/src/components/atoms/date-and-time/DatePicker.tsx +255 -0
  101. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Accordion.tsx +48 -0
  102. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Breadcrumb.tsx +50 -0
  103. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Collapsible.tsx +34 -0
  104. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Pagination.tsx +74 -0
  105. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Steps.tsx +91 -0
  106. package/templates/hono-fullstack/libs/ui/src/components/atoms/disclosure/Tabs.tsx +37 -0
  107. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/Alert.tsx +52 -0
  108. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/Progress.tsx +41 -0
  109. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/ProgressCircle.tsx +40 -0
  110. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/Skeleton.tsx +37 -0
  111. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/Spinner.tsx +7 -0
  112. package/templates/hono-fullstack/libs/ui/src/components/atoms/feedback/Toast.tsx +99 -0
  113. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Checkbox.tsx +95 -0
  114. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/ColorPicker.tsx +148 -0
  115. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Editable.tsx +44 -0
  116. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Field.tsx +36 -0
  117. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Fieldset.tsx +34 -0
  118. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/FileUpload.tsx +143 -0
  119. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Input.tsx +7 -0
  120. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/InputAddon.tsx +7 -0
  121. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/InputGroup.tsx +61 -0
  122. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/NativeSelect.tsx +81 -0
  123. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/NumberInput.tsx +63 -0
  124. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/PasswordInput.tsx +76 -0
  125. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/PinInput.tsx +36 -0
  126. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/RadioCard.tsx +96 -0
  127. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/RadioGroup.tsx +61 -0
  128. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/RatingGroup.tsx +106 -0
  129. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/SegmentGroup.tsx +68 -0
  130. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Slider.tsx +87 -0
  131. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Switch.tsx +74 -0
  132. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/TagsInput.tsx +77 -0
  133. package/templates/hono-fullstack/libs/ui/src/components/atoms/forms/Textarea.tsx +7 -0
  134. package/templates/hono-fullstack/libs/ui/src/components/atoms/index.ts +98 -0
  135. package/templates/hono-fullstack/libs/ui/src/components/atoms/internal/AbsoluteCenter.tsx +7 -0
  136. package/templates/hono-fullstack/libs/ui/src/components/atoms/internal/Loader.tsx +69 -0
  137. package/templates/hono-fullstack/libs/ui/src/components/atoms/internal/Span.tsx +5 -0
  138. package/templates/hono-fullstack/libs/ui/src/components/atoms/internal/create-layout.ts +18 -0
  139. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/Float.tsx +7 -0
  140. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/Grid.tsx +17 -0
  141. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/Group.tsx +7 -0
  142. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/ScrollArea.tsx +46 -0
  143. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/Separator.tsx +26 -0
  144. package/templates/hono-fullstack/libs/ui/src/components/atoms/layout/Stack.tsx +54 -0
  145. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/Dialog.tsx +69 -0
  146. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/Drawer.tsx +49 -0
  147. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/HoverCard.tsx +37 -0
  148. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/Menu.tsx +74 -0
  149. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/OverlayManager.test.ts +124 -0
  150. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/OverlayManager.tsx +189 -0
  151. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/Popover.tsx +57 -0
  152. package/templates/hono-fullstack/libs/ui/src/components/atoms/overlays/Tooltip.tsx +37 -0
  153. package/templates/hono-fullstack/libs/ui/src/components/atoms/typography/Heading.tsx +6 -0
  154. package/templates/hono-fullstack/libs/ui/src/components/atoms/typography/Link.tsx +7 -0
  155. package/templates/hono-fullstack/libs/ui/src/components/atoms/typography/LinkOverlay.tsx +21 -0
  156. package/templates/hono-fullstack/libs/ui/src/components/atoms/typography/Text.tsx +6 -0
  157. package/templates/hono-fullstack/libs/ui/src/components/atoms/utilities/VisuallyHidden.tsx +13 -0
  158. package/templates/hono-fullstack/libs/ui/src/hooks.ts +242 -0
  159. package/templates/hono-fullstack/libs/ui/src/index.ts +19 -0
  160. package/templates/hono-fullstack/libs/ui/src/theme/animation-styles.ts +50 -0
  161. package/templates/hono-fullstack/libs/ui/src/theme/breakpoints.ts +7 -0
  162. package/templates/hono-fullstack/libs/ui/src/theme/conditions.ts +12 -0
  163. package/templates/hono-fullstack/libs/ui/src/theme/containers.ts +16 -0
  164. package/templates/hono-fullstack/libs/ui/src/theme/global-css.ts +12 -0
  165. package/templates/hono-fullstack/libs/ui/src/theme/keyframes.ts +157 -0
  166. package/templates/hono-fullstack/libs/ui/src/theme/layer-styles.ts +11 -0
  167. package/templates/hono-fullstack/libs/ui/src/theme/patterns/grid.ts +51 -0
  168. package/templates/hono-fullstack/libs/ui/src/theme/patterns/index.ts +60 -0
  169. package/templates/hono-fullstack/libs/ui/src/theme/patterns/stack.ts +46 -0
  170. package/templates/hono-fullstack/libs/ui/src/theme/recipes/absolute-center.ts +38 -0
  171. package/templates/hono-fullstack/libs/ui/src/theme/recipes/accordion.ts +68 -0
  172. package/templates/hono-fullstack/libs/ui/src/theme/recipes/alert.ts +83 -0
  173. package/templates/hono-fullstack/libs/ui/src/theme/recipes/avatar.ts +155 -0
  174. package/templates/hono-fullstack/libs/ui/src/theme/recipes/badge.ts +67 -0
  175. package/templates/hono-fullstack/libs/ui/src/theme/recipes/breadcrumb.ts +69 -0
  176. package/templates/hono-fullstack/libs/ui/src/theme/recipes/button.ts +149 -0
  177. package/templates/hono-fullstack/libs/ui/src/theme/recipes/card.ts +36 -0
  178. package/templates/hono-fullstack/libs/ui/src/theme/recipes/checkbox.ts +120 -0
  179. package/templates/hono-fullstack/libs/ui/src/theme/recipes/clipboard.ts +22 -0
  180. package/templates/hono-fullstack/libs/ui/src/theme/recipes/collapsible.ts +26 -0
  181. package/templates/hono-fullstack/libs/ui/src/theme/recipes/color-picker.ts +299 -0
  182. package/templates/hono-fullstack/libs/ui/src/theme/recipes/combobox.ts +141 -0
  183. package/templates/hono-fullstack/libs/ui/src/theme/recipes/date-picker.ts +302 -0
  184. package/templates/hono-fullstack/libs/ui/src/theme/recipes/dialog.ts +191 -0
  185. package/templates/hono-fullstack/libs/ui/src/theme/recipes/drawer.ts +170 -0
  186. package/templates/hono-fullstack/libs/ui/src/theme/recipes/editable.ts +64 -0
  187. package/templates/hono-fullstack/libs/ui/src/theme/recipes/field.ts +41 -0
  188. package/templates/hono-fullstack/libs/ui/src/theme/recipes/fieldset.ts +47 -0
  189. package/templates/hono-fullstack/libs/ui/src/theme/recipes/file-upload.ts +86 -0
  190. package/templates/hono-fullstack/libs/ui/src/theme/recipes/group.ts +78 -0
  191. package/templates/hono-fullstack/libs/ui/src/theme/recipes/heading.ts +24 -0
  192. package/templates/hono-fullstack/libs/ui/src/theme/recipes/hover-card.ts +47 -0
  193. package/templates/hono-fullstack/libs/ui/src/theme/recipes/icon.ts +25 -0
  194. package/templates/hono-fullstack/libs/ui/src/theme/recipes/index.ts +120 -0
  195. package/templates/hono-fullstack/libs/ui/src/theme/recipes/input-addon.ts +51 -0
  196. package/templates/hono-fullstack/libs/ui/src/theme/recipes/input-group.ts +77 -0
  197. package/templates/hono-fullstack/libs/ui/src/theme/recipes/input.ts +99 -0
  198. package/templates/hono-fullstack/libs/ui/src/theme/recipes/link.ts +36 -0
  199. package/templates/hono-fullstack/libs/ui/src/theme/recipes/menu.ts +114 -0
  200. package/templates/hono-fullstack/libs/ui/src/theme/recipes/native-select.ts +92 -0
  201. package/templates/hono-fullstack/libs/ui/src/theme/recipes/number-input.ts +91 -0
  202. package/templates/hono-fullstack/libs/ui/src/theme/recipes/pagination.ts +9 -0
  203. package/templates/hono-fullstack/libs/ui/src/theme/recipes/pin-input.ts +33 -0
  204. package/templates/hono-fullstack/libs/ui/src/theme/recipes/popover.ts +78 -0
  205. package/templates/hono-fullstack/libs/ui/src/theme/recipes/progress-circle.ts +50 -0
  206. package/templates/hono-fullstack/libs/ui/src/theme/recipes/progress.ts +112 -0
  207. package/templates/hono-fullstack/libs/ui/src/theme/recipes/radio-card.ts +223 -0
  208. package/templates/hono-fullstack/libs/ui/src/theme/recipes/radio-group.ts +78 -0
  209. package/templates/hono-fullstack/libs/ui/src/theme/recipes/rating-group.ts +98 -0
  210. package/templates/hono-fullstack/libs/ui/src/theme/recipes/scroll-area.ts +119 -0
  211. package/templates/hono-fullstack/libs/ui/src/theme/recipes/segment-group.ts +162 -0
  212. package/templates/hono-fullstack/libs/ui/src/theme/recipes/select.ts +157 -0
  213. package/templates/hono-fullstack/libs/ui/src/theme/recipes/separator.ts +25 -0
  214. package/templates/hono-fullstack/libs/ui/src/theme/recipes/skeleton.ts +65 -0
  215. package/templates/hono-fullstack/libs/ui/src/theme/recipes/slider.ts +164 -0
  216. package/templates/hono-fullstack/libs/ui/src/theme/recipes/spinner.ts +34 -0
  217. package/templates/hono-fullstack/libs/ui/src/theme/recipes/steps.ts +162 -0
  218. package/templates/hono-fullstack/libs/ui/src/theme/recipes/switch.ts +150 -0
  219. package/templates/hono-fullstack/libs/ui/src/theme/recipes/table.ts +150 -0
  220. package/templates/hono-fullstack/libs/ui/src/theme/recipes/tabs.ts +128 -0
  221. package/templates/hono-fullstack/libs/ui/src/theme/recipes/tag.ts +114 -0
  222. package/templates/hono-fullstack/libs/ui/src/theme/recipes/tags-input.ts +201 -0
  223. package/templates/hono-fullstack/libs/ui/src/theme/recipes/text.ts +7 -0
  224. package/templates/hono-fullstack/libs/ui/src/theme/recipes/textarea.ts +90 -0
  225. package/templates/hono-fullstack/libs/ui/src/theme/recipes/timeline.ts +137 -0
  226. package/templates/hono-fullstack/libs/ui/src/theme/recipes/toast.ts +52 -0
  227. package/templates/hono-fullstack/libs/ui/src/theme/recipes/tooltip.ts +44 -0
  228. package/templates/hono-fullstack/libs/ui/src/theme/recipes/tree-view.ts +200 -0
  229. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/amber.ts +91 -0
  230. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/gray.ts +103 -0
  231. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/green.ts +88 -0
  232. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/index.ts +14 -0
  233. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/lime.ts +91 -0
  234. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/colors/red.ts +88 -0
  235. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/index.ts +8 -0
  236. package/templates/hono-fullstack/libs/ui/src/theme/semanticTokens/shadows.ts +46 -0
  237. package/templates/hono-fullstack/libs/ui/src/theme/text-styles.ts +82 -0
  238. package/templates/hono-fullstack/libs/ui/src/theme/tokens/animations.ts +8 -0
  239. package/templates/hono-fullstack/libs/ui/src/theme/tokens/aspect-ratio.ts +6 -0
  240. package/templates/hono-fullstack/libs/ui/src/theme/tokens/borders.ts +5 -0
  241. package/templates/hono-fullstack/libs/ui/src/theme/tokens/colors.ts +35 -0
  242. package/templates/hono-fullstack/libs/ui/src/theme/tokens/durations.ts +11 -0
  243. package/templates/hono-fullstack/libs/ui/src/theme/tokens/easings.ts +9 -0
  244. package/templates/hono-fullstack/libs/ui/src/theme/tokens/index.ts +42 -0
  245. package/templates/hono-fullstack/libs/ui/src/theme/tokens/radii.ts +13 -0
  246. package/templates/hono-fullstack/libs/ui/src/theme/tokens/sizes.ts +27 -0
  247. package/templates/hono-fullstack/libs/ui/src/theme/tokens/spacing.ts +41 -0
  248. package/templates/hono-fullstack/libs/ui/src/theme/tokens/typography.ts +86 -0
  249. package/templates/hono-fullstack/libs/ui/src/theme/tokens/z-index.ts +43 -0
  250. package/templates/hono-fullstack/libs/ui/stories/README.md +107 -0
  251. package/templates/hono-fullstack/libs/ui/stories/actions/Button.stories.tsx +260 -0
  252. package/templates/hono-fullstack/libs/ui/stories/actions/Clipboard.stories.tsx +87 -0
  253. package/templates/hono-fullstack/libs/ui/stories/actions/IconButton.stories.tsx +33 -0
  254. package/templates/hono-fullstack/libs/ui/stories/collections/Combobox.stories.tsx +334 -0
  255. package/templates/hono-fullstack/libs/ui/stories/collections/Select.stories.tsx +342 -0
  256. package/templates/hono-fullstack/libs/ui/stories/collections/TreeView.stories.tsx +252 -0
  257. package/templates/hono-fullstack/libs/ui/stories/color/ColorPicker.stories.tsx +217 -0
  258. package/templates/hono-fullstack/libs/ui/stories/date/DatePicker.stories.tsx +302 -0
  259. package/templates/hono-fullstack/libs/ui/stories/disclosure/Accordion.stories.tsx +105 -0
  260. package/templates/hono-fullstack/libs/ui/stories/disclosure/Collapsible.stories.tsx +55 -0
  261. package/templates/hono-fullstack/libs/ui/stories/disclosure/Steps.stories.tsx +208 -0
  262. package/templates/hono-fullstack/libs/ui/stories/disclosure/Tabs.stories.tsx +176 -0
  263. package/templates/hono-fullstack/libs/ui/stories/display/Avatar.stories.tsx +108 -0
  264. package/templates/hono-fullstack/libs/ui/stories/display/Badge.stories.tsx +90 -0
  265. package/templates/hono-fullstack/libs/ui/stories/display/Card.stories.tsx +121 -0
  266. package/templates/hono-fullstack/libs/ui/stories/display/Heading.stories.tsx +62 -0
  267. package/templates/hono-fullstack/libs/ui/stories/display/Icon.stories.tsx +51 -0
  268. package/templates/hono-fullstack/libs/ui/stories/display/Table.stories.tsx +222 -0
  269. package/templates/hono-fullstack/libs/ui/stories/display/Tag.stories.tsx +168 -0
  270. package/templates/hono-fullstack/libs/ui/stories/display/Text.stories.tsx +32 -0
  271. package/templates/hono-fullstack/libs/ui/stories/display/Timeline.stories.tsx +241 -0
  272. package/templates/hono-fullstack/libs/ui/stories/feedback/Alert.stories.tsx +122 -0
  273. package/templates/hono-fullstack/libs/ui/stories/feedback/Progress.stories.tsx +163 -0
  274. package/templates/hono-fullstack/libs/ui/stories/feedback/ProgressCircle.stories.tsx +176 -0
  275. package/templates/hono-fullstack/libs/ui/stories/feedback/Skeleton.stories.tsx +75 -0
  276. package/templates/hono-fullstack/libs/ui/stories/feedback/Spinner.stories.tsx +49 -0
  277. package/templates/hono-fullstack/libs/ui/stories/feedback/Toast.stories.tsx +145 -0
  278. package/templates/hono-fullstack/libs/ui/stories/forms/Checkbox.stories.tsx +281 -0
  279. package/templates/hono-fullstack/libs/ui/stories/forms/Editable.stories.tsx +94 -0
  280. package/templates/hono-fullstack/libs/ui/stories/forms/Field.stories.tsx +72 -0
  281. package/templates/hono-fullstack/libs/ui/stories/forms/Fieldset.stories.tsx +109 -0
  282. package/templates/hono-fullstack/libs/ui/stories/forms/FileUpload.stories.tsx +115 -0
  283. package/templates/hono-fullstack/libs/ui/stories/forms/Form.stories.tsx +120 -0
  284. package/templates/hono-fullstack/libs/ui/stories/forms/Input.stories.tsx +155 -0
  285. package/templates/hono-fullstack/libs/ui/stories/forms/InputGroup.stories.tsx +79 -0
  286. package/templates/hono-fullstack/libs/ui/stories/forms/NativeSelect.stories.tsx +160 -0
  287. package/templates/hono-fullstack/libs/ui/stories/forms/NumberInput.stories.tsx +149 -0
  288. package/templates/hono-fullstack/libs/ui/stories/forms/PasswordInput.stories.tsx +141 -0
  289. package/templates/hono-fullstack/libs/ui/stories/forms/PinInput.stories.tsx +155 -0
  290. package/templates/hono-fullstack/libs/ui/stories/forms/RadioCard.stories.tsx +265 -0
  291. package/templates/hono-fullstack/libs/ui/stories/forms/RadioGroup.stories.tsx +109 -0
  292. package/templates/hono-fullstack/libs/ui/stories/forms/RatingGroup.stories.tsx +123 -0
  293. package/templates/hono-fullstack/libs/ui/stories/forms/SegmentGroup.stories.tsx +130 -0
  294. package/templates/hono-fullstack/libs/ui/stories/forms/Slider.stories.tsx +190 -0
  295. package/templates/hono-fullstack/libs/ui/stories/forms/Switch.stories.tsx +124 -0
  296. package/templates/hono-fullstack/libs/ui/stories/forms/TagsInput.stories.tsx +154 -0
  297. package/templates/hono-fullstack/libs/ui/stories/forms/Textarea.stories.tsx +148 -0
  298. package/templates/hono-fullstack/libs/ui/stories/layout/Grid.stories.tsx +60 -0
  299. package/templates/hono-fullstack/libs/ui/stories/layout/Positioning.stories.tsx +90 -0
  300. package/templates/hono-fullstack/libs/ui/stories/layout/ScrollArea.stories.tsx +68 -0
  301. package/templates/hono-fullstack/libs/ui/stories/layout/Stack.stories.tsx +87 -0
  302. package/templates/hono-fullstack/libs/ui/stories/navigation/Breadcrumb.stories.tsx +104 -0
  303. package/templates/hono-fullstack/libs/ui/stories/navigation/Link.stories.tsx +62 -0
  304. package/templates/hono-fullstack/libs/ui/stories/navigation/LinkBox.stories.tsx +45 -0
  305. package/templates/hono-fullstack/libs/ui/stories/navigation/Pagination.stories.tsx +74 -0
  306. package/templates/hono-fullstack/libs/ui/stories/overlays/Dialog.stories.tsx +255 -0
  307. package/templates/hono-fullstack/libs/ui/stories/overlays/Drawer.stories.tsx +114 -0
  308. package/templates/hono-fullstack/libs/ui/stories/overlays/HoverCard.stories.tsx +47 -0
  309. package/templates/hono-fullstack/libs/ui/stories/overlays/Menu.stories.tsx +133 -0
  310. package/templates/hono-fullstack/libs/ui/stories/overlays/OverlayManager.stories.tsx +206 -0
  311. package/templates/hono-fullstack/libs/ui/stories/overlays/Popover.stories.tsx +73 -0
  312. package/templates/hono-fullstack/libs/ui/stories/overlays/Tooltip.stories.tsx +114 -0
  313. package/templates/hono-fullstack/libs/ui/stories/tsconfig.json +14 -0
  314. package/templates/hono-fullstack/libs/ui/tsconfig.build.json +5 -0
  315. package/templates/hono-fullstack/libs/ui/tsconfig.json +13 -0
  316. package/templates/hono-fullstack/libs/ui/turbo.json +28 -0
  317. package/templates/hono-fullstack/libs/ui/vite.config.ts +33 -0
  318. package/templates/hono-fullstack/oyo.config.json +31 -1
  319. package/templates/hono-fullstack/package.json +1 -0
  320. package/templates/hono-fullstack/pnpm-workspace.yaml +20 -10
  321. package/templates/hono-fullstack/turbo.json +10 -0
  322. package/templates/hono-server/.codegraph/.gitignore +5 -0
  323. package/templates/hono-server/README.md +9 -1
  324. package/templates/hono-server/_gitignore +1 -0
  325. package/templates/hono-server/apps/server/package.json +7 -2
  326. package/templates/hono-server/apps/server/src/adapters/cloudflare/entry.ts +4 -30
  327. package/templates/hono-server/apps/server/src/adapters/nodejs/bootstrap.ts +20 -12
  328. package/templates/hono-server/apps/server/src/adapters/nodejs/entry.ts +7 -57
  329. package/templates/hono-server/apps/server/src/app.ts +37 -21
  330. package/templates/hono-server/apps/server/src/config.ts +1 -1
  331. package/templates/hono-server/apps/server/src/di-container.ts +51 -0
  332. package/templates/hono-server/apps/server/src/infra/logger/getter.ts +1 -1
  333. package/templates/hono-server/apps/server/src/infra/logger/pino.ts +21 -34
  334. package/templates/hono-server/apps/server/src/infra/work-runner/errors.ts +22 -0
  335. package/templates/hono-server/apps/server/src/infra/work-runner/pass-through/runner.ts +28 -22
  336. package/templates/hono-server/apps/server/src/infra/work-runner/piscina/runner.ts +11 -34
  337. package/templates/hono-server/apps/server/src/infra/work-runner/{example → piscina}/worker-entry.ts +6 -2
  338. package/templates/hono-server/apps/server/src/infra/work-runner/types.ts +2 -16
  339. package/templates/hono-server/apps/server/src/infra/work-runner/utils/business-error.ts +10 -5
  340. package/templates/hono-server/apps/server/src/infra/work-runner/utils/message.ts +5 -17
  341. package/templates/hono-server/apps/server/src/middlewares/cors.ts +16 -22
  342. package/templates/hono-server/apps/server/src/middlewares/logger.ts +34 -0
  343. package/templates/hono-server/apps/server/src/modules/example/module.ts +8 -0
  344. package/templates/hono-server/apps/server/src/modules/example/queries.ts +8 -0
  345. package/templates/hono-server/apps/server/src/modules/example/routes.ts +74 -68
  346. package/templates/hono-server/apps/server/src/modules/example/service.test.ts +53 -0
  347. package/templates/hono-server/apps/server/src/modules/example/service.ts +54 -0
  348. package/templates/hono-server/apps/server/src/modules/example/types.ts +12 -0
  349. package/templates/hono-server/apps/server/src/modules/example/work-task/tasks.test.ts +9 -35
  350. package/templates/hono-server/apps/server/src/modules/example/work-task/tasks.ts +15 -46
  351. package/templates/hono-server/apps/server/src/shared/errors/defs/index.ts +6 -1
  352. package/templates/hono-server/apps/server/src/shared/errors/handler.ts +1 -1
  353. package/templates/hono-server/apps/server/src/shared/network/openapi/index.ts +1 -1
  354. package/templates/hono-server/apps/server/src/shared/types/app.ts +51 -0
  355. package/templates/hono-server/apps/server/src/shared/types/db.ts +126 -0
  356. package/templates/hono-server/apps/server/src/shared/utils/data-access/check.ts +19 -0
  357. package/templates/hono-server/apps/server/src/shared/utils/data-access/model.ts +47 -0
  358. package/templates/hono-server/apps/server/src/shared/utils/data-access/params.ts +105 -0
  359. package/templates/hono-server/apps/server/src/shared/utils/data-access/query.test.ts +139 -0
  360. package/templates/hono-server/apps/server/src/shared/utils/data-access/query.ts +236 -0
  361. package/templates/hono-server/apps/server/vite.config.ts +2 -2
  362. package/templates/hono-server/apps/server/wrangler.jsonc +1 -1
  363. package/templates/hono-server/docker/README.md +1 -1
  364. package/templates/hono-server/envs/.env.example.sqlite-d1 +1 -0
  365. package/templates/hono-server/libs/db/drizzle-kit/sqlite-d1.config.ts +29 -10
  366. package/templates/hono-server/libs/db/package.json +1 -0
  367. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/columns.ts +1 -1
  368. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/modules/examples/examples.ts +6 -3
  369. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/vo.ts +7 -1
  370. package/templates/hono-server/libs/definition/README.md +81 -0
  371. package/templates/hono-server/libs/definition/package.json +3 -1
  372. package/templates/hono-server/libs/definition/src/constants/index.ts +1 -0
  373. package/templates/hono-server/libs/definition/src/constants/pagination.ts +3 -0
  374. package/templates/hono-server/libs/definition/src/modules/common-contracts.ts +24 -0
  375. package/templates/hono-server/libs/definition/src/modules/example/contracts.ts +34 -0
  376. package/templates/hono-server/libs/definition/src/modules/example/index.ts +1 -16
  377. package/templates/hono-server/libs/definition/src/modules/index.ts +2 -0
  378. package/templates/hono-server/libs/definition/src/modules/vo-generated-types.ts +12 -0
  379. package/templates/hono-server/oyo.config.json +31 -1
  380. package/templates/hono-server/package.json +1 -0
  381. package/templates/hono-server/pnpm-workspace.yaml +9 -7
  382. package/templates/hono-server/turbo.json +10 -0
  383. package/templates/monorepo/.codegraph/.gitignore +5 -0
  384. package/templates/monorepo/_gitignore +1 -0
  385. package/templates/monorepo/oyo.config.json +7 -1
  386. package/templates/monorepo/pnpm-workspace.yaml +4 -4
  387. package/templates/monorepo/turbo.json +10 -0
  388. package/templates/hono-fullstack/apps/server/src/modules/example/contracts.ts +0 -9
  389. package/templates/hono-fullstack/apps/server/src/shared/app/types.ts +0 -44
  390. package/templates/hono-fullstack/apps/stack/frontend/styles.css +0 -23
  391. package/templates/hono-server/apps/server/src/modules/example/contracts.ts +0 -9
  392. package/templates/hono-server/apps/server/src/shared/app/types.ts +0 -44
@@ -8,18 +8,19 @@ import type {
8
8
  WorkerMessage,
9
9
  } from '../types'
10
10
  import { WorkerErrorCode, WorkSubject } from '../constants'
11
- import { isWorkerTaskError, WorkerTaskError } from '../errors'
11
+ import { serializeWorkerTaskError, WorkerTaskError } from '../errors'
12
12
  import Piscina from 'piscina'
13
13
  import path from 'node:path'
14
14
  import { MessageChannel, type MessagePort } from 'node:worker_threads'
15
15
  import workersDir from 'virtual:workers'
16
16
  import { getLogger } from '@/infra/logger/getter'
17
- import type * as ExampleWorker from '../example/worker-entry'
17
+ import type * as PiscinaWorker from './worker-entry'
18
18
  import { handleWorkerMessage } from '../utils/message'
19
+ import { extractTransferables } from '../utils/transfer'
19
20
 
20
21
  const taskNameMap = {
21
22
  [WorkSubject.PROCESS_EXAMPLE]: 'executeExampleTask',
22
- } satisfies Partial<Record<WorkSubject, keyof typeof ExampleWorker>>
23
+ } satisfies Partial<Record<WorkSubject, keyof typeof PiscinaWorker>>
23
24
 
24
25
  export class PiscinaWorkRunner implements AppWorkRunner {
25
26
  static #instance: PiscinaWorkRunner | null = null
@@ -31,7 +32,7 @@ export class PiscinaWorkRunner implements AppWorkRunner {
31
32
  throw new Error('[PiscinaWorkRunner] config is required')
32
33
  }
33
34
  this.#pool = new Piscina({
34
- filename: path.join(workersDir, 'example-worker.mjs'),
35
+ filename: path.join(workersDir, 'piscina-worker.mjs'),
35
36
  minThreads: config.minThreads,
36
37
  maxThreads: config.maxThreads,
37
38
  concurrentTasksPerWorker: config.concurrentTasksPerWorker,
@@ -61,15 +62,14 @@ export class PiscinaWorkRunner implements AppWorkRunner {
61
62
  let result: RunnerTaskRunResult<TSubject>
62
63
  let workerMessagePort: MessagePort | undefined
63
64
 
64
- const { signal: optSignal, transferList } = options || {}
65
- const logger = getLogger()
65
+ const { signal: optSignal } = options || {}
66
66
  // pool当前状态
67
67
  const poolStats = {
68
68
  idleThreads: this.#pool.idleThreads,
69
69
  threads: this.#pool.threads.length,
70
70
  queueSize: this.#pool.queueSize,
71
71
  }
72
- logger.assign({
72
+ const logger = getLogger().child({
73
73
  pool: poolStats,
74
74
  subject: taskParams.subject,
75
75
  })
@@ -123,45 +123,22 @@ export class PiscinaWorkRunner implements AppWorkRunner {
123
123
  }
124
124
 
125
125
  // 开始调用
126
+ const { input, transferList } = extractTransferables(taskParams.input)
126
127
  const invocation: RunnerTaskInvocation<(typeof taskParams)['input']> = {
127
- input: taskParams.input,
128
+ input,
128
129
  messagePort: workerMessagePort,
129
130
  }
130
131
  const taskPromise = this.#pool.run(invocation, {
131
132
  name: targetName,
132
133
  signal: taskSignal,
133
- transferList: [...(transferList || []), workerMessagePort],
134
+ transferList: [...transferList, workerMessagePort],
134
135
  }) as Promise<RunnerTaskRunResult<TSubject>>
135
136
 
136
137
  result = timeoutPromise
137
138
  ? await Promise.race([taskPromise, timeoutPromise])
138
139
  : await taskPromise
139
140
  } catch (error) {
140
- if (isWorkerTaskError(error)) {
141
- result = {
142
- ok: false,
143
- error: error.serialize(),
144
- }
145
- } else if (error instanceof Error && error.name === 'AbortError') {
146
- result = {
147
- ok: false,
148
- error: new WorkerTaskError(
149
- WorkerErrorCode.TASK_ABORTED,
150
- error.message,
151
- undefined,
152
- ).serialize(),
153
- }
154
- } else {
155
- result = {
156
- ok: false,
157
- error: new WorkerTaskError(
158
- WorkerErrorCode.UNKNOWN,
159
- 'Worker task failed unexpectedly',
160
- undefined,
161
- error,
162
- ).serialize(),
163
- }
164
- }
141
+ result = { ok: false, error: serializeWorkerTaskError(error) }
165
142
  } finally {
166
143
  if (timeoutTimer) clearTimeout(timeoutTimer)
167
144
  try {
@@ -5,9 +5,13 @@ import {
5
5
  type ExampleRunnerTaskModel,
6
6
  } from '@/modules/example/work-task/tasks'
7
7
 
8
- export function executeExampleTask({
8
+ export async function executeExampleTask({
9
9
  input,
10
10
  messagePort,
11
11
  }: RunnerTaskInvocation<ExampleRunnerTaskModel['input']>): ReturnType<typeof runExampleTask> {
12
- return runExampleTask(input, messagePort).finally(() => messagePort.close())
12
+ try {
13
+ return await runExampleTask(input)
14
+ } finally {
15
+ messagePort.close()
16
+ }
13
17
  }
@@ -1,5 +1,5 @@
1
1
  import type { ExampleRunnerTaskModel } from '@/modules/example/work-task/tasks'
2
- import type { Transferable } from 'node:worker_threads'
2
+ import type { MessagePort } from 'node:worker_threads'
3
3
  import type { WorkerErrorCode, WorkSubject } from './constants'
4
4
 
5
5
  // export const WorkerInvocationType = Object.freeze({
@@ -43,7 +43,7 @@ export type RunnerTaskErrorCode<TSubject extends WorkSubject> =
43
43
 
44
44
  export type RunnerTaskInvocation<TInput> = {
45
45
  input: TInput
46
- messagePort: WorkerMessagePort
46
+ messagePort: MessagePort
47
47
  }
48
48
 
49
49
  export type RunnerTaskJsonValue =
@@ -69,19 +69,6 @@ export type WorkerMessage =
69
69
  value: number
70
70
  message?: string
71
71
  }
72
- | {
73
- type: 'result'
74
- data: RunnerTaskJsonValue
75
- }
76
- | {
77
- type: 'error'
78
- error: RunnerTaskError
79
- }
80
-
81
- export interface WorkerMessagePort {
82
- postMessage(message: WorkerMessage): void
83
- close(): void
84
- }
85
72
 
86
73
  export type RunnerTaskError<TCode extends string = string> = {
87
74
  code: TCode
@@ -102,7 +89,6 @@ export type RunnerTaskRunResult<TSubject extends WorkSubject> = RunnerTaskResult
102
89
 
103
90
  export type RunnerTaskRunOptions = {
104
91
  signal?: AbortSignal
105
- transferList?: Transferable[]
106
92
  }
107
93
 
108
94
  export interface AppWorkRunner {
@@ -2,18 +2,23 @@ import { hasProp } from '@/shared/utils'
2
2
  import type { RunnerTaskErrorDetails } from '../types'
3
3
 
4
4
  export class WorkerTaskBusinessError extends Error {
5
- readonly details?: RunnerTaskErrorDetails
5
+ declare readonly cause: {
6
+ type: 'WorkerTaskBusinessError'
7
+ details?: RunnerTaskErrorDetails
8
+ cause?: unknown
9
+ }
6
10
 
7
11
  constructor(message: string, details?: RunnerTaskErrorDetails, cause?: unknown) {
8
- super(message, { cause })
12
+ super(message, { cause: { type: 'WorkerTaskBusinessError', details, cause } })
9
13
  this.name = 'WorkerTaskBusinessError'
10
- this.details = details
11
14
  }
12
15
  }
13
16
 
14
17
  export function isWorkerTaskBusinessError(error: unknown): error is WorkerTaskBusinessError {
15
18
  return (
16
- error instanceof WorkerTaskBusinessError ||
17
- (error instanceof Error && hasProp(error, 'name') && error.name === 'WorkerTaskBusinessError')
19
+ error instanceof Error &&
20
+ !!error.cause &&
21
+ hasProp(error.cause, 'type') &&
22
+ error.cause.type === 'WorkerTaskBusinessError'
18
23
  )
19
24
  }
@@ -1,9 +1,10 @@
1
- import type { AppLogger } from '@/shared/app/types'
2
- import type { RunnerTaskErrorDetails, WorkerMessage, WorkerMessagePort } from '../types'
1
+ import type { AppLogger } from '@/shared/types/app'
2
+ import type { RunnerTaskErrorDetails, WorkerMessage } from '../types'
3
+ import type { MessagePort } from 'node:worker_threads'
3
4
  import type { WorkSubject } from '../constants'
4
5
 
5
6
  export function workerLog(
6
- messagePort: WorkerMessagePort,
7
+ messagePort: MessagePort,
7
8
  level: Extract<WorkerMessage, { type: 'log' }>['level'],
8
9
  message: string,
9
10
  data?: RunnerTaskErrorDetails,
@@ -11,11 +12,7 @@ export function workerLog(
11
12
  messagePort.postMessage({ type: 'log', level, message, data } satisfies WorkerMessage)
12
13
  }
13
14
 
14
- export function workerProgress(
15
- messagePort: WorkerMessagePort,
16
- value: number,
17
- message?: string,
18
- ): void {
15
+ export function workerProgress(messagePort: MessagePort, value: number, message?: string): void {
19
16
  messagePort.postMessage({ type: 'progress', value, message } satisfies WorkerMessage)
20
17
  }
21
18
 
@@ -36,14 +33,5 @@ export function handleWorkerMessage(
36
33
  message.message || 'Worker progress',
37
34
  )
38
35
  break
39
- case 'result':
40
- logger.debug({ subject: context.subject }, 'Worker result delivered')
41
- break
42
- case 'error':
43
- logger.warn(
44
- { subject: context.subject, workerError: message.error },
45
- 'Worker error delivered',
46
- )
47
- break
48
36
  }
49
37
  }
@@ -1,26 +1,20 @@
1
- import type { AppEnv } from '@/shared/app/types'
1
+ import type { CORSConfig } from '@repo/definition/backend'
2
2
  import { cors } from 'hono/cors'
3
- import { createMiddleware } from 'hono/factory'
4
3
 
5
- export const corsMiddleware = () => {
6
- return createMiddleware<AppEnv>(async (c, next) => {
7
- const corsConfig = c.get('appConfig')
8
- const domains = corsConfig.middleware.cors.domains
9
- const middleware = cors({
10
- origin: (origin) => {
11
- const isAllowedDomain = domains.some((domain) => {
12
- try {
13
- return domain === '*' || new URL(origin).host === domain
14
- } catch {
15
- return false
16
- }
17
- })
18
- return isAllowedDomain ? origin : null
19
- },
20
- allowHeaders: ['Content-Type'],
21
- allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
22
- credentials: true,
23
- })
24
- return middleware(c, next)
4
+ export const corsMiddleware = ({ domains }: CORSConfig) => {
5
+ return cors({
6
+ origin: (origin) => {
7
+ const isAllowedDomain = domains.some((domain) => {
8
+ try {
9
+ return domain === '*' || new URL(origin).host === domain
10
+ } catch {
11
+ return false
12
+ }
13
+ })
14
+ return isAllowedDomain ? origin : null
15
+ },
16
+ allowHeaders: ['Content-Type'],
17
+ allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
18
+ credentials: true,
25
19
  })
26
20
  }
@@ -0,0 +1,34 @@
1
+ import type { AppEnv } from '@/shared/types/app'
2
+ import { structuredLogger } from '@hono/structured-logger'
3
+ import type { Logger } from 'pino'
4
+
5
+ export const loggerMiddleware = (rootLogger: Logger) => {
6
+ const logResponse = (logger: Logger, response: Response, responseTime: number) => {
7
+ // access log 只记请求完成;错误细节由 onError 走 serializers.err。
8
+ // 错误请求仍记 info 级别的完成日志,避免与 globalErrorHandler 重复记录 error。
9
+ logger.info(
10
+ {
11
+ res: {
12
+ status: response.status,
13
+ headers: Object.fromEntries(response.headers),
14
+ },
15
+ responseTime: Math.round(responseTime),
16
+ },
17
+ 'Request completed',
18
+ )
19
+ }
20
+
21
+ return structuredLogger<AppEnv, Logger>({
22
+ createLogger: (c) =>
23
+ rootLogger.child({
24
+ req: {
25
+ url: c.req.path,
26
+ method: c.req.method,
27
+ headers: c.req.header(),
28
+ },
29
+ reqId: c.get('requestId'),
30
+ }),
31
+ onResponse: (logger, c, responseTime) => logResponse(logger, c.res, responseTime),
32
+ onError: (logger, _error, c, responseTime) => logResponse(logger, c.res, responseTime),
33
+ })
34
+ }
@@ -0,0 +1,8 @@
1
+ import type { Module, SpecMap } from '@inferdi/inferdi'
2
+ import type { Database } from '@/shared/types/db'
3
+ import { ExampleService } from './service'
4
+
5
+ export const exampleModule: Module<
6
+ SpecMap<{ database: Database }>,
7
+ SpecMap<{ exampleService: ExampleService }>
8
+ > = (container) => container.registerClass('exampleService', ExampleService, ['database'])
@@ -0,0 +1,8 @@
1
+ import { examples, vcExamples } from '@repo/db/sqlite/schema'
2
+ import { Model } from '@/shared/utils/data-access/model'
3
+ import { createQueries } from '@/shared/utils/data-access/query'
4
+
5
+ const model = new Model(examples, vcExamples)
6
+ const queries = createQueries(model, { orderBy: { id: 'asc' } })
7
+
8
+ export const { query, findOne, findPage, insert, update, deleteRecords } = queries
@@ -1,73 +1,79 @@
1
- import { type Context, Hono } from 'hono'
2
- import { describeRoute } from 'hono-openapi'
3
- import * as v from 'valibot'
4
- import { examples, vcExamples, type SqliteDBType } from '@repo/db/sqlite/schema'
5
- import type { AppEnv } from '@/shared/app/types'
1
+ import { Hono } from 'hono'
6
2
  import { WorkSubject } from '@/infra/work-runner/constants'
7
3
  import { E } from '@/shared/errors/defs'
8
- import { jsonResponse, OpenApiTags } from '@/shared/network/openapi'
9
- import { successJson } from '@/shared/network/utils'
4
+ import type { AppEnv } from '@/shared/types/app'
5
+
6
+ import * as v from 'valibot'
7
+ import {
8
+ Example$CreateOne,
9
+ Example$UpdateOne,
10
+ Example$FindOne,
11
+ Example$FindMany,
12
+ Example$Process,
13
+ } from '@repo/definition/backend'
10
14
  import { generalValidator } from '@/shared/network/validator'
11
- import { createExampleInputSchema, processExampleInputSchema } from './contracts'
15
+ import { successJson } from '@/shared/network/utils'
16
+
17
+ export const routes = new Hono<AppEnv>()
18
+
19
+ routes.post('/', generalValidator('json', Example$CreateOne), async (c) => {
20
+ const body = c.req.valid('json')
21
+ const exampleService = c.var.di.get('exampleService')
22
+ return successJson(c, await exampleService.createOne(body))
23
+ })
24
+
25
+ routes.get('/', generalValidator('query', Example$FindMany), async (c) => {
26
+ const query = c.req.valid('query')
27
+ const exampleService = c.var.di.get('exampleService')
28
+ return successJson(c, await exampleService.findMany(query))
29
+ })
30
+
31
+ routes.get(
32
+ '/:id',
33
+ generalValidator('param', v.required(v.pick(Example$FindOne, ['id']))),
34
+ generalValidator('query', Example$FindOne),
35
+ async (c) => {
36
+ const { id } = c.req.valid('param')
37
+ const query = c.req.valid('query')
38
+ const exampleService = c.var.di.get('exampleService')
39
+ return successJson(c, await exampleService.findOne({ ...query, id }))
40
+ },
41
+ )
12
42
 
13
- const getDb = (context: Context<AppEnv>) => context.get('db') as SqliteDBType
43
+ routes.patch(
44
+ '/:id',
45
+ generalValidator('param', v.required(v.pick(Example$FindOne, ['id']))),
46
+ generalValidator('json', Example$UpdateOne),
47
+ async (c) => {
48
+ const { id } = c.req.valid('param')
49
+ const body = c.req.valid('json')
50
+ const exampleService = c.var.di.get('exampleService')
51
+ return successJson(c, await exampleService.updateOneById(id, body))
52
+ },
53
+ )
54
+ routes.delete(
55
+ '/',
56
+ generalValidator(
57
+ 'json',
58
+ v.object({ ids: v.array(v.required(v.pick(Example$FindOne, ['id'])).entries.id) }),
59
+ ),
60
+ async (c) => {
61
+ const { ids } = c.req.valid('json')
62
+ const exampleService = c.var.di.get('exampleService')
63
+ return successJson(c, await exampleService.deleteRecords(ids))
64
+ },
65
+ )
14
66
 
15
- export const exampleRoutes = new Hono<AppEnv>()
16
- .get(
17
- '/health',
18
- describeRoute({
19
- operationId: 'getHealth',
20
- tags: [OpenApiTags.System],
21
- summary: 'Health check',
22
- responses: { 200: jsonResponse(v.object({ data: v.object({ status: v.string() }) })) },
23
- }),
24
- (c) => successJson(c, { status: 'ok' }),
25
- )
26
- .get(
27
- '/examples',
28
- describeRoute({
29
- operationId: 'listExamples',
30
- tags: [OpenApiTags.Example],
31
- summary: 'List example rows',
32
- responses: { 200: { description: 'Example rows' } },
33
- }),
34
- async (c) => successJson(c, await getDb(c).select(vcExamples.default).from(examples)),
35
- )
36
- .post(
37
- '/examples',
38
- describeRoute({
39
- operationId: 'createExample',
40
- tags: [OpenApiTags.Example],
41
- summary: 'Create an example row',
42
- responses: { 200: { description: 'Created example row' } },
43
- }),
44
- generalValidator('json', createExampleInputSchema),
45
- async (c) => {
46
- const input = c.req.valid('json')
47
- const [row] = await getDb(c).insert(examples).values(input).returning(vcExamples.default)
48
- return successJson(c, row)
49
- },
50
- )
51
- .post(
52
- '/examples/process',
53
- describeRoute({
54
- operationId: 'processExample',
55
- tags: [OpenApiTags.Example],
56
- summary: 'Process an example message in the worker pool',
57
- responses: { 200: jsonResponse(v.object({ data: v.object({ normalized: v.string() }) })) },
58
- }),
59
- generalValidator('json', processExampleInputSchema),
60
- async (c) => {
61
- const result = await c.get('workRunner').run({
62
- subject: WorkSubject.PROCESS_EXAMPLE,
63
- input: c.req.valid('json'),
64
- })
65
- if (!result.ok) {
66
- throw E.NORMAL.INTERNAL.create({
67
- cause: result.error,
68
- extensions: { workerCode: result.error.code },
69
- })
70
- }
71
- return successJson(c, result.data)
72
- },
73
- )
67
+ routes.post('/process', generalValidator('json', Example$Process), async (c) => {
68
+ const result = await c.var.di.get('workRunner').run({
69
+ subject: WorkSubject.PROCESS_EXAMPLE,
70
+ input: c.req.valid('json'),
71
+ })
72
+ if (!result.ok) {
73
+ throw E.NORMAL.INTERNAL.create({
74
+ cause: result.error,
75
+ extensions: { workerCode: result.error.code },
76
+ })
77
+ }
78
+ return successJson(c, result.data)
79
+ })
@@ -0,0 +1,53 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vite-plus/test'
2
+ import { Container } from '@inferdi/inferdi'
3
+ import { createSqliteClient } from '@repo/db/sqlite/sqlite'
4
+ import { sql } from 'drizzle-orm'
5
+ import { exampleModule } from './module'
6
+ import { ExampleService } from './service'
7
+
8
+ describe('ExampleService', () => {
9
+ let client: ReturnType<typeof createSqliteClient>
10
+ let service: ExampleService
11
+
12
+ beforeEach(() => {
13
+ client = createSqliteClient(':memory:')
14
+ client.db.run(sql`
15
+ CREATE TABLE examples (
16
+ id INTEGER PRIMARY KEY,
17
+ message TEXT NOT NULL,
18
+ created_at INTEGER NOT NULL DEFAULT 0,
19
+ updated_at INTEGER NOT NULL DEFAULT 0
20
+ )
21
+ `)
22
+ service = new Container()
23
+ .registerValue('database', { db: client.db })
24
+ .use(exampleModule)
25
+ .get('exampleService')
26
+ })
27
+
28
+ afterEach(() => {
29
+ client?.close()
30
+ })
31
+
32
+ it('分页返回总数,不存在的示例返回 null', async () => {
33
+ await service.createOne({ message: 'A' })
34
+ await service.createOne({ message: 'B' })
35
+ const page = await service.findMany({ page: 2, limit: 1 })
36
+ expect(page.results.map((example) => example.message)).toEqual(['B'])
37
+ expect(page.meta).toMatchObject({ total: 2, offset: 1, limit: 1 })
38
+ const filtered = await service.findMany({ page: 1, limit: 10, message: 'B' })
39
+ expect(filtered.results.map((example) => example.message)).toEqual(['B'])
40
+ expect(filtered.meta.total).toBe(1)
41
+ expect(await service.findOne({ message: 'missing' })).toBeNull()
42
+ })
43
+
44
+ it('更新不存在的记录或提交空更新均抛错', async () => {
45
+ await expect(service.updateOneById('999', { message: 'missing' })).rejects.toMatchObject({
46
+ problemDetails: { type: 'EXAMPLES.NOT_FOUND' },
47
+ })
48
+ const {
49
+ result: [example],
50
+ } = await service.createOne({ message: 'Example' })
51
+ await expect(service.updateOneById(example!.id, {})).rejects.toThrow('no update fields')
52
+ })
53
+ })
@@ -0,0 +1,54 @@
1
+ import type { IExamplesIdVO } from '@repo/definition/backend'
2
+ import { E } from '@/shared/errors/defs'
3
+ import type { Database } from '@/shared/types/db'
4
+ import * as exampleQueries from './queries'
5
+ import type {
6
+ CreateOneExampleDto,
7
+ FindManyExamplesDto,
8
+ FindOneExampleDto,
9
+ UpdateOneExampleDto,
10
+ } from './types'
11
+
12
+ export class ExampleService {
13
+ private readonly db: Database['db']
14
+
15
+ constructor(database: Database) {
16
+ this.db = database.db
17
+ }
18
+
19
+ async createOne(params: CreateOneExampleDto) {
20
+ return exampleQueries.insert(this.db, {
21
+ values: { message: params.message },
22
+ voType: 'id',
23
+ })
24
+ }
25
+
26
+ async findMany({ page, limit, ...whereParams }: FindManyExamplesDto) {
27
+ return exampleQueries.findPage(this.db, {
28
+ page,
29
+ limit,
30
+ where: whereParams,
31
+ voType: 'list',
32
+ })
33
+ }
34
+
35
+ async findOne(whereParams: FindOneExampleDto) {
36
+ return exampleQueries.findOne(this.db, { where: whereParams, voType: 'list' })
37
+ }
38
+
39
+ async updateOneById(id: IExamplesIdVO['id'], params: UpdateOneExampleDto) {
40
+ const current = await exampleQueries.findOne(this.db, { where: { id }, voType: 'id' })
41
+ if (!current) throw E.EXAMPLES.NOT_FOUND.create()
42
+ const result = await exampleQueries.update(this.db, {
43
+ where: { id },
44
+ value: { message: params.message },
45
+ })
46
+ if (!result.updated) throw E.EXAMPLES.NOT_FOUND.create()
47
+ return result
48
+ }
49
+
50
+ async deleteRecords(ids: IExamplesIdVO['id'][]) {
51
+ if (!ids.length) return { deleted: 0 }
52
+ return exampleQueries.deleteRecords(this.db, { where: { id: { in: ids } } })
53
+ }
54
+ }
@@ -0,0 +1,12 @@
1
+ import type * as v from 'valibot'
2
+ import type {
3
+ Example$CreateOne,
4
+ Example$UpdateOne,
5
+ Example$FindOne,
6
+ Example$FindMany,
7
+ } from '@repo/definition/backend'
8
+
9
+ export type CreateOneExampleDto = v.InferOutput<typeof Example$CreateOne>
10
+ export type UpdateOneExampleDto = v.InferOutput<typeof Example$UpdateOne>
11
+ export type FindOneExampleDto = v.InferOutput<typeof Example$FindOne>
12
+ export type FindManyExamplesDto = v.InferOutput<typeof Example$FindMany>
@@ -1,49 +1,23 @@
1
- import { MessageChannel } from 'node:worker_threads'
2
1
  import { describe, expect, it } from 'vite-plus/test'
3
2
  import { executeExampleTask } from './tasks'
4
3
 
5
4
  describe('Example worker task', () => {
6
- it('normalizes a message and reports progress', async () => {
7
- const { port1, port2 } = new MessageChannel()
8
- const messages: unknown[] = []
9
- port1.on('message', (message) => messages.push(message))
10
- const result = await executeExampleTask({ message: ' hello worker ' }, port2)
11
- await new Promise<void>((resolve) => setImmediate(resolve))
12
-
5
+ it('normalizes a message', async () => {
6
+ const result = await executeExampleTask({ message: ' hello worker ' })
13
7
  expect(result).toEqual({
14
8
  ok: true,
15
9
  data: { original: ' hello worker ', normalized: 'hello worker', length: 12 },
16
10
  })
17
- expect(messages).toEqual(
18
- expect.arrayContaining([
19
- expect.objectContaining({ type: 'log' }),
20
- expect.objectContaining({ type: 'progress', value: 100 }),
21
- expect.objectContaining({ type: 'result' }),
22
- ]),
23
- )
24
- port1.close()
25
- port2.close()
26
11
  })
27
12
 
28
- it('serializes a business exception and reports it', async () => {
29
- const { port1, port2 } = new MessageChannel()
30
- const messages: unknown[] = []
31
- port1.on('message', (message) => messages.push(message))
32
- const result = await executeExampleTask({ message: ' ' }, port2)
33
- await new Promise<void>((resolve) => setImmediate(resolve))
34
-
35
- expect(result).toEqual({
36
- ok: false,
37
- error: {
38
- code: 'EXAMPLE_PROCESS_FAILED',
39
- message: 'Message must not be empty',
40
- details: { field: 'message' },
13
+ it('wraps a business exception for the runner to serialize', async () => {
14
+ await expect(executeExampleTask({ message: ' ' })).rejects.toMatchObject({
15
+ name: 'WorkerTaskBusinessError',
16
+ message: 'Message must not be empty',
17
+ cause: {
18
+ type: 'WorkerTaskBusinessError',
19
+ details: { code: 'EXAMPLE_PROCESS_FAILED', field: 'message' },
41
20
  },
42
21
  })
43
- expect(messages).toEqual(
44
- expect.arrayContaining([expect.objectContaining({ type: 'error' })]),
45
- )
46
- port1.close()
47
- port2.close()
48
22
  })
49
23
  })