@linyjs/plugin-docs 0.1.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 (252) hide show
  1. package/README.md +97 -0
  2. package/docs/api-reference/index.md +341 -0
  3. package/docs/best-practices/error-handling.md +462 -0
  4. package/docs/best-practices/naming-conventions.md +495 -0
  5. package/docs/best-practices/performance.md +532 -0
  6. package/docs/best-practices/security.md +620 -0
  7. package/docs/faq.md +323 -0
  8. package/docs/getting-started/first-plugin.md +358 -0
  9. package/docs/getting-started/installation.md +244 -0
  10. package/docs/getting-started/quick-start.md +174 -0
  11. package/docs/guides/client-module.md +598 -0
  12. package/docs/guides/data-persistence.md +536 -0
  13. package/docs/guides/permissions.md +440 -0
  14. package/docs/guides/server-module.md +371 -0
  15. package/docs/guides/ui-slots.md +475 -0
  16. package/docs/migration/v0-to-v1.md +354 -0
  17. package/examples/analytics-plugin/README.md +416 -0
  18. package/examples/analytics-plugin/dist/client/index.d.ts +36 -0
  19. package/examples/analytics-plugin/dist/client/index.js +173 -0
  20. package/examples/analytics-plugin/dist/index.d.ts +64 -0
  21. package/examples/analytics-plugin/dist/index.js +72 -0
  22. package/examples/analytics-plugin/dist/server/index.d.ts +119 -0
  23. package/examples/analytics-plugin/dist/server/index.js +313 -0
  24. package/examples/analytics-plugin/package.json +28 -0
  25. package/examples/analytics-plugin/src/client/index.tsx +410 -0
  26. package/examples/analytics-plugin/src/index.ts +71 -0
  27. package/examples/analytics-plugin/src/server/index.ts +348 -0
  28. package/examples/analytics-plugin/tsconfig.json +21 -0
  29. package/examples/blog-plugin/README.md +316 -0
  30. package/examples/blog-plugin/dist/client/index.d.ts +22 -0
  31. package/examples/blog-plugin/dist/client/index.js +197 -0
  32. package/examples/blog-plugin/dist/server/index.d.ts +5 -0
  33. package/examples/blog-plugin/dist/server/index.js +220 -0
  34. package/examples/blog-plugin/package.json +24 -0
  35. package/examples/blog-plugin/src/client/index.tsx +405 -0
  36. package/examples/blog-plugin/src/server/index.ts +240 -0
  37. package/examples/blog-plugin/tsconfig.json +16 -0
  38. package/examples/hello-world/README.md +101 -0
  39. package/examples/hello-world/dist/client/index.d.ts +5 -0
  40. package/examples/hello-world/dist/client/index.js +80 -0
  41. package/examples/hello-world/dist/server/index.d.ts +5 -0
  42. package/examples/hello-world/dist/server/index.js +38 -0
  43. package/examples/hello-world/node_modules/.package-lock.json +61 -0
  44. package/examples/hello-world/node_modules/@linyjs/client-module-interface/HOOKS_USAGE.md +281 -0
  45. package/examples/hello-world/node_modules/@linyjs/client-module-interface/IMPLEMENTATION_SUMMARY.md +166 -0
  46. package/examples/hello-world/node_modules/@linyjs/client-module-interface/QUICK_REFERENCE.md +130 -0
  47. package/examples/hello-world/node_modules/@linyjs/client-module-interface/README.md +214 -0
  48. package/examples/hello-world/node_modules/@linyjs/client-module-interface/package.json +26 -0
  49. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/application.ts +50 -0
  50. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/comparison-example.tsx +229 -0
  51. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/di.ts +127 -0
  52. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/domain.ts +52 -0
  53. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/hooks-example.tsx +275 -0
  54. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/hooks.ts +175 -0
  55. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/index.ts +87 -0
  56. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/interfaces.ts +117 -0
  57. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/router.ts +49 -0
  58. package/examples/hello-world/node_modules/@linyjs/client-module-interface/tsconfig.json +10 -0
  59. package/examples/hello-world/node_modules/@linyjs/server-module-interface/package.json +21 -0
  60. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/application.ts +21 -0
  61. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/di.ts +127 -0
  62. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/domain.ts +75 -0
  63. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/index.ts +55 -0
  64. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/interfaces.ts +58 -0
  65. package/examples/hello-world/node_modules/@linyjs/server-module-interface/tsconfig.json +8 -0
  66. package/examples/hello-world/node_modules/@types/react/LICENSE +21 -0
  67. package/examples/hello-world/node_modules/@types/react/README.md +15 -0
  68. package/examples/hello-world/node_modules/@types/react/canary.d.ts +129 -0
  69. package/examples/hello-world/node_modules/@types/react/compiler-runtime.d.ts +4 -0
  70. package/examples/hello-world/node_modules/@types/react/experimental.d.ts +184 -0
  71. package/examples/hello-world/node_modules/@types/react/global.d.ts +166 -0
  72. package/examples/hello-world/node_modules/@types/react/index.d.ts +4369 -0
  73. package/examples/hello-world/node_modules/@types/react/jsx-dev-runtime.d.ts +33 -0
  74. package/examples/hello-world/node_modules/@types/react/jsx-runtime.d.ts +24 -0
  75. package/examples/hello-world/node_modules/@types/react/package.json +210 -0
  76. package/examples/hello-world/node_modules/@types/react/ts5.0/canary.d.ts +129 -0
  77. package/examples/hello-world/node_modules/@types/react/ts5.0/experimental.d.ts +184 -0
  78. package/examples/hello-world/node_modules/@types/react/ts5.0/global.d.ts +166 -0
  79. package/examples/hello-world/node_modules/@types/react/ts5.0/index.d.ts +4356 -0
  80. package/examples/hello-world/node_modules/@types/react/ts5.0/jsx-dev-runtime.d.ts +33 -0
  81. package/examples/hello-world/node_modules/@types/react/ts5.0/jsx-runtime.d.ts +24 -0
  82. package/examples/hello-world/node_modules/csstype/LICENSE +19 -0
  83. package/examples/hello-world/node_modules/csstype/README.md +291 -0
  84. package/examples/hello-world/node_modules/csstype/index.d.ts +22569 -0
  85. package/examples/hello-world/node_modules/csstype/index.js.flow +6863 -0
  86. package/examples/hello-world/node_modules/csstype/package.json +70 -0
  87. package/examples/hello-world/node_modules/react/LICENSE +21 -0
  88. package/examples/hello-world/node_modules/react/README.md +37 -0
  89. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.development.js +24 -0
  90. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.production.js +16 -0
  91. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.profiling.js +16 -0
  92. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.development.js +338 -0
  93. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.production.js +14 -0
  94. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.profiling.js +14 -0
  95. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.react-server.development.js +370 -0
  96. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.react-server.production.js +40 -0
  97. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.development.js +352 -0
  98. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.production.js +34 -0
  99. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.profiling.js +34 -0
  100. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.react-server.development.js +370 -0
  101. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.react-server.production.js +40 -0
  102. package/examples/hello-world/node_modules/react/cjs/react.development.js +1284 -0
  103. package/examples/hello-world/node_modules/react/cjs/react.production.js +542 -0
  104. package/examples/hello-world/node_modules/react/cjs/react.react-server.development.js +848 -0
  105. package/examples/hello-world/node_modules/react/cjs/react.react-server.production.js +423 -0
  106. package/examples/hello-world/node_modules/react/compiler-runtime.js +14 -0
  107. package/examples/hello-world/node_modules/react/index.js +7 -0
  108. package/examples/hello-world/node_modules/react/jsx-dev-runtime.js +7 -0
  109. package/examples/hello-world/node_modules/react/jsx-dev-runtime.react-server.js +7 -0
  110. package/examples/hello-world/node_modules/react/jsx-runtime.js +7 -0
  111. package/examples/hello-world/node_modules/react/jsx-runtime.react-server.js +7 -0
  112. package/examples/hello-world/node_modules/react/package.json +51 -0
  113. package/examples/hello-world/node_modules/react/react.react-server.js +7 -0
  114. package/examples/hello-world/node_modules/typescript/LICENSE.txt +55 -0
  115. package/examples/hello-world/node_modules/typescript/README.md +50 -0
  116. package/examples/hello-world/node_modules/typescript/SECURITY.md +41 -0
  117. package/examples/hello-world/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  118. package/examples/hello-world/node_modules/typescript/bin/tsc +2 -0
  119. package/examples/hello-world/node_modules/typescript/bin/tsserver +2 -0
  120. package/examples/hello-world/node_modules/typescript/lib/_tsc.js +133818 -0
  121. package/examples/hello-world/node_modules/typescript/lib/_tsserver.js +659 -0
  122. package/examples/hello-world/node_modules/typescript/lib/_typingsInstaller.js +222 -0
  123. package/examples/hello-world/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
  124. package/examples/hello-world/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
  125. package/examples/hello-world/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
  126. package/examples/hello-world/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
  127. package/examples/hello-world/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
  128. package/examples/hello-world/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
  129. package/examples/hello-world/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
  130. package/examples/hello-world/node_modules/typescript/lib/lib.d.ts +22 -0
  131. package/examples/hello-world/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  132. package/examples/hello-world/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  133. package/examples/hello-world/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  134. package/examples/hello-world/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  135. package/examples/hello-world/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  136. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  137. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  138. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  139. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  140. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  141. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  142. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  143. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  144. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  145. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  146. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  147. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  148. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  149. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  150. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  151. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  152. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  153. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  154. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  155. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  156. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  157. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  158. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  159. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  160. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  161. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  162. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  163. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  164. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  165. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  166. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  167. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  168. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  169. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  170. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  171. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  172. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  173. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  174. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  175. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  176. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  177. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  178. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  179. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  180. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  181. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  182. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  183. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  184. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  185. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  186. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  187. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  188. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  189. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  190. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  191. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  192. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  193. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  194. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  195. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  196. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  197. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  198. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  199. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  200. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  201. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  202. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  203. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  204. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  205. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  206. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  207. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  208. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  209. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  210. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  211. package/examples/hello-world/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  212. package/examples/hello-world/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  213. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  214. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  215. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  216. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  217. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  218. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  219. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  220. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  221. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  222. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  223. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  224. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  225. package/examples/hello-world/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  226. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  227. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  228. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  229. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  230. package/examples/hello-world/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
  231. package/examples/hello-world/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
  232. package/examples/hello-world/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
  233. package/examples/hello-world/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
  234. package/examples/hello-world/node_modules/typescript/lib/tsc.js +8 -0
  235. package/examples/hello-world/node_modules/typescript/lib/tsserver.js +8 -0
  236. package/examples/hello-world/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
  237. package/examples/hello-world/node_modules/typescript/lib/tsserverlibrary.js +21 -0
  238. package/examples/hello-world/node_modules/typescript/lib/typesMap.json +497 -0
  239. package/examples/hello-world/node_modules/typescript/lib/typescript.d.ts +11437 -0
  240. package/examples/hello-world/node_modules/typescript/lib/typescript.js +200276 -0
  241. package/examples/hello-world/node_modules/typescript/lib/typingsInstaller.js +8 -0
  242. package/examples/hello-world/node_modules/typescript/lib/watchGuard.js +53 -0
  243. package/examples/hello-world/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
  244. package/examples/hello-world/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
  245. package/examples/hello-world/node_modules/typescript/package.json +120 -0
  246. package/examples/hello-world/package-lock.json +74 -0
  247. package/examples/hello-world/package.json +23 -0
  248. package/examples/hello-world/src/client/index.tsx +110 -0
  249. package/examples/hello-world/src/server/index.ts +42 -0
  250. package/examples/hello-world/tsconfig.json +16 -0
  251. package/package.json +42 -0
  252. package/src/cli.ts +321 -0
@@ -0,0 +1,348 @@
1
+ import type { IModule } from '@linyjs/server-module-interface';
2
+
3
+ /**
4
+ * 分析数据服务 - 收集和聚合应用使用数据
5
+ */
6
+ class AnalyticsService {
7
+ private metrics: Map<string, any[]> = new Map();
8
+ private users: Map<string, any> = new Map();
9
+
10
+ /**
11
+ * 记录用户行为事件
12
+ */
13
+ async trackEvent(eventName: string, userId: string, data: any) {
14
+ const event = {
15
+ id: Date.now(),
16
+ eventName,
17
+ userId,
18
+ timestamp: new Date().toISOString(),
19
+ data
20
+ };
21
+
22
+ if (!this.metrics.has(eventName)) {
23
+ this.metrics.set(eventName, []);
24
+ }
25
+
26
+ this.metrics.get(eventName)!.push(event);
27
+
28
+ return { success: true, eventId: event.id };
29
+ }
30
+
31
+ /**
32
+ * 获取指定时间范围内的统计汇总
33
+ */
34
+ async getAnalytics(startDate: string, endDate: string) {
35
+ const start = new Date(startDate);
36
+ const end = new Date(endDate);
37
+
38
+ const result: any = {
39
+ totalEvents: 0,
40
+ eventsByDay: {},
41
+ eventTypes: {},
42
+ activeUsers: 0,
43
+ topEvents: []
44
+ };
45
+
46
+ // 统计各类事件
47
+ for (const [eventName, events] of this.metrics.entries()) {
48
+ const filtered = events.filter(event => {
49
+ const eventDate = new Date(event.timestamp);
50
+ return eventDate >= start && eventDate <= end;
51
+ });
52
+
53
+ if (filtered.length > 0) {
54
+ result.eventTypes[eventName] = filtered.length;
55
+ result.totalEvents += filtered.length;
56
+
57
+ // 统计每日事件
58
+ filtered.forEach(event => {
59
+ const day = event.timestamp.split('T')[0];
60
+ result.eventsByDay[day] = (result.eventsByDay[day] || 0) + 1;
61
+ });
62
+
63
+ // 记录活跃用户
64
+ const uniqueUsers = new Set(filtered.map(e => e.userId));
65
+ result.activeUsers = Math.max(result.activeUsers, uniqueUsers.size);
66
+ }
67
+ }
68
+
69
+ // 计算热门事件
70
+ result.topEvents = Object.entries(result.eventTypes)
71
+ .sort(([,a], [,b]) => (b as number) - (a as number))
72
+ .slice(0, 10)
73
+ .map(([name, count]) => ({ name, count }));
74
+
75
+ return result;
76
+ }
77
+
78
+ /**
79
+ * 获取实时在线用户数(模拟)
80
+ */
81
+ async getRealTimeStats() {
82
+ // 模拟实时数据
83
+ const onlineUsers = Math.floor(Math.random() * 100) + 50;
84
+ const currentEvents = Math.floor(Math.random() * 20) + 5;
85
+
86
+ return {
87
+ onlineUsers,
88
+ currentEvents,
89
+ serverTime: new Date().toISOString()
90
+ };
91
+ }
92
+
93
+ /**
94
+ * 定时聚合任务 - 每小时运行一次
95
+ */
96
+ async runHourlyAggregation() {
97
+ const now = new Date();
98
+ const hourStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours());
99
+ const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);
100
+
101
+ const hourData = await this.getAnalytics(hourStart.toISOString(), hourEnd.toISOString());
102
+
103
+ // 这里可以将聚合数据保存到数据库,现在只返回
104
+ return {
105
+ period: `${hourStart.toISOString()} to ${hourEnd.toISOString()}`,
106
+ summary: hourData
107
+ };
108
+ }
109
+
110
+ /**
111
+ * 用户留存率分析
112
+ */
113
+ async getUserRetention(days: number = 7) {
114
+ const now = new Date();
115
+ const retentionData: any = {
116
+ dayIntervals: [],
117
+ newUsers: [],
118
+ returningUsers: []
119
+ };
120
+
121
+ // 模拟留存率数据
122
+ for (let i = 0; i < days; i++) {
123
+ const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
124
+ const dayKey = date.toISOString().split('T')[0];
125
+
126
+ retentionData.dayIntervals.push(dayKey);
127
+ retentionData.newUsers.push(Math.floor(Math.random() * 50) + 10);
128
+ retentionData.returningUsers.push(Math.floor(Math.random() * 30) + 5);
129
+ }
130
+
131
+ // 计算留存率
132
+ retentionData.retentionRates = retentionData.returningUsers.map((returning: number, index: number) => {
133
+ const newUsers = retentionData.newUsers[index] || 1;
134
+ return ((returning / newUsers) * 100).toFixed(1);
135
+ });
136
+
137
+ return retentionData;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * 分析控制器 - 提供API接口
143
+ */
144
+ class AnalyticsController {
145
+ private analyticsService: AnalyticsService;
146
+
147
+ constructor() {
148
+ this.analyticsService = new AnalyticsService();
149
+ }
150
+
151
+ getRoutes() {
152
+ return [
153
+ // POST /api/analytics/track - 记录事件
154
+ {
155
+ method: 'POST' as const,
156
+ path: '/api/analytics/track',
157
+ middlewares: [],
158
+ responseType: 'json' as const,
159
+ handler: async (params: any, ctx: any) => {
160
+ try {
161
+ const { eventName, userId, data } = params.body;
162
+
163
+ if (!eventName || !userId) {
164
+ return {
165
+ status: 400,
166
+ data: { error: 'eventName and userId are required' }
167
+ };
168
+ }
169
+
170
+ const result = await this.analyticsService.trackEvent(eventName, userId, data);
171
+ return { success: true, data: result };
172
+ } catch (error: any) {
173
+ return {
174
+ status: 500,
175
+ data: { error: error.message }
176
+ };
177
+ }
178
+ }
179
+ },
180
+
181
+ // GET /api/analytics/summary - 获取分析摘要
182
+ {
183
+ method: 'GET' as const,
184
+ path: '/api/analytics/summary',
185
+ middlewares: [],
186
+ responseType: 'json' as const,
187
+ handler: async (params: any, ctx: any) => {
188
+ try {
189
+ const startDate = params.query?.start || new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
190
+ const endDate = params.query?.end || new Date().toISOString();
191
+
192
+ const result = await this.analyticsService.getAnalytics(startDate, endDate);
193
+ return result;
194
+ } catch (error: any) {
195
+ return {
196
+ status: 500,
197
+ data: { error: error.message }
198
+ };
199
+ }
200
+ }
201
+ },
202
+
203
+ // GET /api/analytics/realtime - 获取实时统计
204
+ {
205
+ method: 'GET' as const,
206
+ path: '/api/analytics/realtime',
207
+ middlewares: [],
208
+ responseType: 'json' as const,
209
+ handler: async (params: any, ctx: any) => {
210
+ try {
211
+ const result = await this.analyticsService.getRealTimeStats();
212
+ return result;
213
+ } catch (error: any) {
214
+ return {
215
+ status: 500,
216
+ data: { error: error.message }
217
+ };
218
+ }
219
+ }
220
+ },
221
+
222
+ // GET /api/analytics/retention - 用户留存分析
223
+ {
224
+ method: 'GET' as const,
225
+ path: '/api/analytics/retention',
226
+ middlewares: [],
227
+ responseType: 'json' as const,
228
+ handler: async (params: any, ctx: any) => {
229
+ try {
230
+ const days = parseInt(params.query?.days || '7');
231
+ const result = await this.analyticsService.getUserRetention(days);
232
+ return result;
233
+ } catch (error: any) {
234
+ return {
235
+ status: 500,
236
+ data: { error: error.message }
237
+ };
238
+ }
239
+ }
240
+ },
241
+
242
+ // POST /api/analytics/aggregate - 手动触发聚合 (管理员用)
243
+ {
244
+ method: 'POST' as const,
245
+ path: '/api/analytics/aggregate',
246
+ middlewares: [],
247
+ responseType: 'json' as const,
248
+ handler: async (params: any, ctx: any) => {
249
+ try {
250
+ const result = await this.analyticsService.runHourlyAggregation();
251
+ return { success: true, data: result };
252
+ } catch (error: any) {
253
+ return {
254
+ status: 500,
255
+ data: { error: error.message }
256
+ };
257
+ }
258
+ }
259
+ }
260
+ ];
261
+ }
262
+ }
263
+
264
+ /**
265
+ * 定时任务服务
266
+ */
267
+ class AnalyticsCronService {
268
+ private analyticsService: AnalyticsService;
269
+ private intervalId: NodeJS.Timeout | null = null;
270
+
271
+ constructor() {
272
+ this.analyticsService = new AnalyticsService();
273
+ }
274
+
275
+ /**
276
+ * 启动定时聚合任务
277
+ */
278
+ startHourlyAggregation() {
279
+ // 每小时执行一次聚合
280
+ this.intervalId = setInterval(async () => {
281
+ try {
282
+ const result = await this.analyticsService.runHourlyAggregation();
283
+ console.log('Analytics aggregation completed:', result.period);
284
+ } catch (error) {
285
+ console.error('Analytics aggregation failed:', error);
286
+ }
287
+ }, 60 * 60 * 1000); // 1小时
288
+
289
+ console.log('Started analytics hourly aggregation');
290
+ }
291
+
292
+ /**
293
+ * 停止定时聚合任务
294
+ */
295
+ stopHourlyAggregation() {
296
+ if (this.intervalId) {
297
+ clearInterval(this.intervalId);
298
+ this.intervalId = null;
299
+ console.log('Stopped analytics hourly aggregation');
300
+ }
301
+ }
302
+
303
+ /**
304
+ * 插件启动时调用
305
+ */
306
+ onModuleInit() {
307
+ this.startHourlyAggregation();
308
+ }
309
+
310
+ /**
311
+ * 插件销毁时调用
312
+ */
313
+ onModuleDestroy() {
314
+ this.stopHourlyAggregation();
315
+ }
316
+ }
317
+
318
+ /**
319
+ * 服务端模块
320
+ */
321
+ export const analyticsServerModule: IModule = {
322
+ name: 'analyticsServer',
323
+ serviceDefs: [
324
+ {
325
+ serviceTag: 'analyticsController',
326
+ serviceImpl: AnalyticsController,
327
+ meta: { usageType: 'controller' }
328
+ },
329
+ {
330
+ serviceTag: 'analyticsCron',
331
+ serviceImpl: AnalyticsCronService,
332
+ meta: {
333
+ usageType: 'service',
334
+ lifecycle: {
335
+ init: 'onModuleInit',
336
+ destroy: 'onModuleDestroy'
337
+ }
338
+ }
339
+ }
340
+ ]
341
+ };
342
+
343
+ // 导出服务类供其他插件使用
344
+ export {
345
+ AnalyticsService,
346
+ AnalyticsController,
347
+ AnalyticsCronService
348
+ };
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "module": "NodeNext",
5
+ "lib": ["ES2017", "DOM"],
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "moduleResolution": "NodeNext",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "declaration": true,
16
+ "outDir": "dist",
17
+ "rootDir": "src"
18
+ },
19
+ "include": ["src/**/*"],
20
+ "exclude": ["node_modules"]
21
+ }
@@ -0,0 +1,316 @@
1
+ # Blog Plugin Example
2
+
3
+ 这是一个完整的博客插件示例,展示了 linyjs 插件开发的核心功能。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 文章发布和管理
8
+ - ✅ 文章列表和详情页面
9
+ - ✅ 用户权限控制
10
+ - ✅ MongoDB 数据持久化
11
+ - ✅ RESTful API 设计
12
+ - ✅ 响应式前端界面
13
+
14
+ ## 快速开始
15
+
16
+ ### 前置要求
17
+
18
+ - Node.js >= 18.0
19
+ - MongoDB >= 5.0
20
+ - npm 或 yarn
21
+
22
+ ### 安装和运行
23
+
24
+ ```bash
25
+ # 1. 安装依赖
26
+ cd blog-plugin
27
+ npm install
28
+
29
+ # 2. 配置 MongoDB 连接
30
+ export MONGODB_URI="mongodb://localhost:27017/linyjs-blog"
31
+
32
+ # 3. 构建插件
33
+ npm run build
34
+
35
+ # 4. 启动开发服务器
36
+ npm run dev
37
+ ```
38
+
39
+ ## 项目结构
40
+
41
+ ```
42
+ blog-plugin/
43
+ ├── src/
44
+ │ ├── server/
45
+ │ │ ├── controllers/
46
+ │ │ │ └── article-controller.ts # 文章 CRUD 控制器
47
+ │ │ ├── services/
48
+ │ │ │ └── article-service.ts # 业务逻辑层
49
+ │ │ └── index.ts # 服务端入口
50
+ │ ├── client/
51
+ │ │ ├── components/
52
+ │ │ │ ├── ArticleList.tsx # 文章列表组件
53
+ │ │ │ ├── ArticleDetail.tsx # 文章详情组件
54
+ │ │ │ └── ArticleForm.tsx # 文章表单组件
55
+ │ │ ├── pages/
56
+ │ │ │ ├── ArticleListPage.tsx # 文章列表页面
57
+ │ │ │ ├── ArticleDetailPage.tsx # 文章详情页面
58
+ │ │ │ └── ArticleEditPage.tsx # 文章编辑页面
59
+ │ │ └── index.tsx # 客户端入口
60
+ │ └── shared/
61
+ │ ├── types.ts # 共享类型定义
62
+ │ └── constants.ts # 共享常量
63
+ ├── package.json
64
+ ├── tsconfig.json
65
+ └── README.md
66
+ ```
67
+
68
+ ## API 文档
69
+
70
+ ### 获取文章列表
71
+
72
+ ```http
73
+ GET /api/articles
74
+ ```
75
+
76
+ **查询参数:**
77
+ - `page` - 页码 (默认: 1)
78
+ - `limit` - 每页数量 (默认: 10)
79
+ - `status` - 状态过滤: `published` | `draft` | `all` (默认: `published`)
80
+
81
+ **响应示例:**
82
+ ```json
83
+ {
84
+ "data": [
85
+ {
86
+ "id": "60b8f7d5f1b2c3d4e5f6a7b8",
87
+ "title": "我的第一篇文章",
88
+ "excerpt": "文章摘要内容...",
89
+ "author": "作者名",
90
+ "status": "published",
91
+ "createdAt": "2023-01-01T00:00:00.000Z",
92
+ "updatedAt": "2023-01-01T00:00:00.000Z"
93
+ }
94
+ ],
95
+ "total": 25,
96
+ "page": 1,
97
+ "limit": 10,
98
+ "totalPages": 3
99
+ }
100
+ ```
101
+
102
+ ### 创建文章
103
+
104
+ ```http
105
+ POST /api/articles
106
+ Authorization: Bearer <token>
107
+ Content-Type: application/json
108
+ ```
109
+
110
+ **请求体:**
111
+ ```json
112
+ {
113
+ "title": "文章标题",
114
+ "content": "文章内容...",
115
+ "excerpt": "文章摘要",
116
+ "status": "draft" | "published"
117
+ }
118
+ ```
119
+
120
+ ### 获取文章详情
121
+
122
+ ```http
123
+ GET /api/articles/{id}
124
+ ```
125
+
126
+ ### 更新文章
127
+
128
+ ```http
129
+ PUT /api/articles/{id}
130
+ Authorization: Bearer <token>
131
+ ```
132
+
133
+ ### 删除文章
134
+
135
+ ```http
136
+ DELETE /api/articles/{id}
137
+ Authorization: Bearer <token>
138
+ ```
139
+
140
+ ## 权限控制
141
+
142
+ - **游客**: 只能查看已发布的文章
143
+ - **作者**: 可以创建、编辑、删除自己的文章
144
+ - **管理员**: 可以管理所有文章
145
+
146
+ ## 开发说明
147
+
148
+ ### 服务端模块
149
+
150
+ 服务端模块注册了文章控制器和服务:
151
+
152
+ ```typescript
153
+ // src/server/index.ts
154
+ export const blogServerModule: IModule = {
155
+ name: 'blogServer',
156
+ moduleDependencies: ['mongodb', 'auth'],
157
+ serviceDefs: [
158
+ articleControllerDef,
159
+ articleServiceDef
160
+ ]
161
+ };
162
+ ```
163
+
164
+ ### 客户端模块
165
+
166
+ 客户端模块提供了文章相关的页面和组件:
167
+
168
+ ```typescript
169
+ // src/client/index.tsx
170
+ export const blogClientModule: IModule = {
171
+ name: 'blogClient',
172
+ serviceDefs: [
173
+ articleListRoute,
174
+ articleDetailRoute,
175
+ articleEditRoute,
176
+ articleListComponent,
177
+ articleDetailComponent,
178
+ articleFormComponent
179
+ ]
180
+ };
181
+ ```
182
+
183
+ ## 代码示例
184
+
185
+ ### 文章服务 - 数据操作
186
+
187
+ ```typescript
188
+ // src/server/services/article-service.ts
189
+ class ArticleService {
190
+ constructor(
191
+ private mongodb: IMongoDBService,
192
+ private auth: IAuthService
193
+ ) {}
194
+
195
+ async createArticle(data: CreateArticleDto, userId: string) {
196
+ const db = this.mongodb.getDb();
197
+ const collection = db.collection('articles');
198
+
199
+ const article = {
200
+ ...data,
201
+ authorId: userId,
202
+ createdAt: new Date(),
203
+ updatedAt: new Date()
204
+ };
205
+
206
+ const result = await collection.insertOne(article);
207
+ return {
208
+ id: result.insertedId,
209
+ ...article
210
+ };
211
+ }
212
+
213
+ async getArticles(filters: ArticleFilters = {}) {
214
+ const db = this.mongodb.getDb();
215
+ const collection = db.collection('articles');
216
+
217
+ const query: any = {};
218
+
219
+ // 状态过滤
220
+ if (filters.status && filters.status !== 'all') {
221
+ query.status = filters.status;
222
+ } else if (!filters.status) {
223
+ query.status = 'published'; // 默认只显示已发布
224
+ }
225
+
226
+ const page = filters.page || 1;
227
+ const limit = Math.min(filters.limit || 10, 100);
228
+ const skip = (page - 1) * limit;
229
+
230
+ const [total, articles] = await Promise.all([
231
+ collection.countDocuments(query),
232
+ collection.find(query)
233
+ .sort({ createdAt: -1 })
234
+ .skip(skip)
235
+ .limit(limit)
236
+ .project({
237
+ content: 0 // 不返回完整内容
238
+ })
239
+ .toArray()
240
+ ]);
241
+
242
+ return {
243
+ data: articles,
244
+ total,
245
+ page,
246
+ limit,
247
+ totalPages: Math.ceil(total / limit)
248
+ };
249
+ }
250
+ }
251
+ ```
252
+
253
+ ### 文章列表组件
254
+
255
+ ```typescript
256
+ // src/client/components/ArticleList.tsx
257
+ function ArticleList() {
258
+ const [articles, setArticles] = useState<Article[]>([]);
259
+ const [loading, setLoading] = useState(true);
260
+ const [error, setError] = useState<string | null>(null);
261
+
262
+ useEffect(() => {
263
+ loadArticles();
264
+ }, []);
265
+
266
+ const loadArticles = async () => {
267
+ try {
268
+ setLoading(true);
269
+ const response = await fetch('/api/articles');
270
+ const result = await response.json();
271
+ setArticles(result.data);
272
+ } catch (err) {
273
+ setError('加载文章失败');
274
+ } finally {
275
+ setLoading(false);
276
+ }
277
+ };
278
+
279
+ if (loading) return <div>加载中...</div>;
280
+ if (error) return <div>错误: {error}</div>;
281
+
282
+ return (
283
+ <div className="article-list">
284
+ {articles.map(article => (
285
+ <ArticleCard key={article.id} article={article} />
286
+ ))}
287
+ </div>
288
+ );
289
+ }
290
+ ```
291
+
292
+ ## 测试
293
+
294
+ ```bash
295
+ # 构建测试
296
+ npm run build
297
+
298
+ # 包格式验证
299
+ npx @linyjs/cli pack
300
+ npx @linyjs/cli validate *.mpk
301
+ ```
302
+
303
+ ## 相关链接
304
+
305
+ - 📖 [插件开发指南](../../docs/getting-started/quick-start.md)
306
+ - 🔧 [API 参考](../../docs/api-reference/server-interface.md)
307
+ - 📚 [服务端模块指南](../../docs/guides/server-module.md)
308
+ - 🎨 [客户端模块指南](../../docs/guides/client-module.md)
309
+
310
+ ## 许可证
311
+
312
+ MIT License
313
+
314
+ ---
315
+
316
+ 这是一个完整的博客插件示例,可以作为开发类似插件的参考。查看完整实现代码了解更多细节。
@@ -0,0 +1,22 @@
1
+ import type { IModule } from '@linyjs/client-module-interface';
2
+ /**
3
+ * 文章列表组件
4
+ */
5
+ declare function ArticleList(): import("react/jsx-runtime").JSX.Element;
6
+ /**
7
+ * 文章详情组件
8
+ */
9
+ declare function ArticleDetail(): import("react/jsx-runtime").JSX.Element;
10
+ /**
11
+ * 文章编辑表单组件
12
+ */
13
+ declare function ArticleForm(): import("react/jsx-runtime").JSX.Element;
14
+ /**
15
+ * 博客主页组件
16
+ */
17
+ declare function BlogHome(): import("react/jsx-runtime").JSX.Element;
18
+ /**
19
+ * 客户端模块定义
20
+ */
21
+ export declare const blogClientModule: IModule;
22
+ export { BlogHome, ArticleList, ArticleDetail, ArticleForm };