sa2kit 1.6.30 → 1.6.32

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 (251) hide show
  1. package/dist/AliyunOSSProvider-4W47OFEK.mjs +6 -0
  2. package/dist/{AliyunOSSProvider-KJYRIZES.mjs.map → AliyunOSSProvider-4W47OFEK.mjs.map} +1 -1
  3. package/dist/AliyunOSSProvider-HCNGDJL7.js +15 -0
  4. package/dist/{AliyunOSSProvider-FWAKUB2T.js.map → AliyunOSSProvider-HCNGDJL7.js.map} +1 -1
  5. package/dist/ConfigService-3DIC6C3Q.js +21 -0
  6. package/dist/{ConfigService-7MEZXKJ5.js.map → ConfigService-3DIC6C3Q.js.map} +1 -1
  7. package/dist/ConfigService-V6ZK273Z.mjs +4 -0
  8. package/dist/{ConfigService-BV57YYFW.mjs.map → ConfigService-V6ZK273Z.mjs.map} +1 -1
  9. package/dist/LocalStorageProvider-3RVPCQB3.mjs +6 -0
  10. package/dist/{LocalStorageProvider-RTPMUOZ2.mjs.map → LocalStorageProvider-3RVPCQB3.mjs.map} +1 -1
  11. package/dist/LocalStorageProvider-PP7MA5OT.js +15 -0
  12. package/dist/{LocalStorageProvider-XSRCUXOU.js.map → LocalStorageProvider-PP7MA5OT.js.map} +1 -1
  13. package/dist/PMXParser-2VTA737I.js +13 -0
  14. package/dist/{PMXParser-YBS3B6HM.js.map → PMXParser-2VTA737I.js.map} +1 -1
  15. package/dist/PMXParser-RNVQL76A.mjs +4 -0
  16. package/dist/{PMXParser-L6IWHL4I.mjs.map → PMXParser-RNVQL76A.mjs.map} +1 -1
  17. package/dist/analytics/index.js +46 -45
  18. package/dist/analytics/index.js.map +1 -1
  19. package/dist/analytics/index.mjs +45 -44
  20. package/dist/analytics/index.mjs.map +1 -1
  21. package/dist/analytics/server/index.js +4 -4
  22. package/dist/analytics/server/index.js.map +1 -1
  23. package/dist/analytics/server/index.mjs +4 -4
  24. package/dist/analytics/server/index.mjs.map +1 -1
  25. package/dist/api/index.js +5 -5
  26. package/dist/api/index.js.map +1 -1
  27. package/dist/api/index.mjs +5 -5
  28. package/dist/api/index.mjs.map +1 -1
  29. package/dist/audioDetection/index.js +17 -16
  30. package/dist/audioDetection/index.js.map +1 -1
  31. package/dist/audioDetection/index.mjs +17 -16
  32. package/dist/audioDetection/index.mjs.map +1 -1
  33. package/dist/auth/client/index.js +4 -4
  34. package/dist/auth/client/index.mjs +1 -1
  35. package/dist/auth/components/index.js +3 -3
  36. package/dist/auth/components/index.js.map +1 -1
  37. package/dist/auth/components/index.mjs +3 -3
  38. package/dist/auth/components/index.mjs.map +1 -1
  39. package/dist/auth/index.js +29 -29
  40. package/dist/auth/index.mjs +5 -5
  41. package/dist/auth/middleware/index.js +3 -3
  42. package/dist/auth/middleware/index.mjs +2 -2
  43. package/dist/auth/routes/index.js +14 -14
  44. package/dist/auth/routes/index.mjs +2 -2
  45. package/dist/auth/services/index.js +7 -7
  46. package/dist/auth/services/index.mjs +1 -1
  47. package/dist/calendar/index.js +146 -182
  48. package/dist/calendar/index.js.map +1 -1
  49. package/dist/calendar/index.mjs +139 -175
  50. package/dist/calendar/index.mjs.map +1 -1
  51. package/dist/calendar/routes/index.js +1 -1
  52. package/dist/calendar/routes/index.js.map +1 -1
  53. package/dist/calendar/routes/index.mjs +1 -1
  54. package/dist/calendar/routes/index.mjs.map +1 -1
  55. package/dist/{chunk-5YQ5B7IZ.js → chunk-24HGREE6.js} +5 -5
  56. package/dist/{chunk-5YQ5B7IZ.js.map → chunk-24HGREE6.js.map} +1 -1
  57. package/dist/{chunk-6PRFP5EG.js → chunk-25OFOKNF.js} +6 -6
  58. package/dist/chunk-25OFOKNF.js.map +1 -0
  59. package/dist/{chunk-KQGP6BTS.mjs → chunk-3DXPQ4YV.mjs} +6 -6
  60. package/dist/chunk-3DXPQ4YV.mjs.map +1 -0
  61. package/dist/{chunk-3BGPZN4X.mjs → chunk-3NHAT7D4.mjs} +12 -12
  62. package/dist/chunk-3NHAT7D4.mjs.map +1 -0
  63. package/dist/{chunk-MW4BCIZC.mjs → chunk-4HC6M7FK.mjs} +3 -3
  64. package/dist/chunk-4HC6M7FK.mjs.map +1 -0
  65. package/dist/{chunk-ESRCX5TQ.mjs → chunk-52TN2QSS.mjs} +3 -3
  66. package/dist/{chunk-ESRCX5TQ.mjs.map → chunk-52TN2QSS.mjs.map} +1 -1
  67. package/dist/{chunk-CNTILN5J.mjs → chunk-5YQ62BKX.mjs} +20 -19
  68. package/dist/chunk-5YQ62BKX.mjs.map +1 -0
  69. package/dist/{chunk-6W5BMXJG.js → chunk-6OWNMJKG.js} +4 -4
  70. package/dist/{chunk-6W5BMXJG.js.map → chunk-6OWNMJKG.js.map} +1 -1
  71. package/dist/{chunk-DUHZ7VZP.js → chunk-7VRT55ZD.js} +3 -3
  72. package/dist/chunk-7VRT55ZD.js.map +1 -0
  73. package/dist/{chunk-3WOAPLEG.mjs → chunk-EB4NR623.mjs} +27 -26
  74. package/dist/chunk-EB4NR623.mjs.map +1 -0
  75. package/dist/chunk-EI27JKND.mjs +1988 -0
  76. package/dist/chunk-EI27JKND.mjs.map +1 -0
  77. package/dist/{chunk-CD77U7LZ.js → chunk-GBPLX42J.js} +9 -9
  78. package/dist/chunk-GBPLX42J.js.map +1 -0
  79. package/dist/{chunk-TFQF2HDO.mjs → chunk-HDEOCX2L.mjs} +12 -12
  80. package/dist/chunk-HDEOCX2L.mjs.map +1 -0
  81. package/dist/{chunk-TV3VKRJK.mjs → chunk-HDMIOOZY.mjs} +38 -68
  82. package/dist/chunk-HDMIOOZY.mjs.map +1 -0
  83. package/dist/{chunk-OPPF3326.js → chunk-HJ6MH7J7.js} +39 -69
  84. package/dist/chunk-HJ6MH7J7.js.map +1 -0
  85. package/dist/chunk-KO73EBUT.js +80 -0
  86. package/dist/chunk-KO73EBUT.js.map +1 -0
  87. package/dist/{chunk-6YKMCPQI.mjs → chunk-KZKIH4AS.mjs} +4 -4
  88. package/dist/chunk-KZKIH4AS.mjs.map +1 -0
  89. package/dist/{chunk-LX4XX6W7.js → chunk-L47ZOYHL.js} +15 -89
  90. package/dist/chunk-L47ZOYHL.js.map +1 -0
  91. package/dist/{chunk-6MQUBPKB.mjs → chunk-LJ4CCSSY.mjs} +3 -3
  92. package/dist/{chunk-6MQUBPKB.mjs.map → chunk-LJ4CCSSY.mjs.map} +1 -1
  93. package/dist/{chunk-TOC5FSHP.js → chunk-NJ2SNXBJ.js} +12 -12
  94. package/dist/chunk-NJ2SNXBJ.js.map +1 -0
  95. package/dist/{chunk-OCR5DS4C.mjs → chunk-PE5EAHZK.mjs} +3 -3
  96. package/dist/chunk-PE5EAHZK.mjs.map +1 -0
  97. package/dist/{chunk-LZHMNOED.js → chunk-Q5EDCKQA.js} +26 -26
  98. package/dist/chunk-Q5EDCKQA.js.map +1 -0
  99. package/dist/{chunk-CLKKZSPZ.js → chunk-RBKGYWME.js} +20 -19
  100. package/dist/chunk-RBKGYWME.js.map +1 -0
  101. package/dist/{chunk-VRTRSEEH.mjs → chunk-RSJSZ7QH.mjs} +11 -11
  102. package/dist/chunk-RSJSZ7QH.mjs.map +1 -0
  103. package/dist/{chunk-E7RGBAYJ.js → chunk-TDCDEBGP.js} +30 -29
  104. package/dist/chunk-TDCDEBGP.js.map +1 -0
  105. package/dist/{chunk-JZXJQMVE.js → chunk-UIFFDRTE.js} +11 -11
  106. package/dist/chunk-UIFFDRTE.js.map +1 -0
  107. package/dist/{chunk-T5OZHYVM.mjs → chunk-UKT3PLON.mjs} +13 -85
  108. package/dist/chunk-UKT3PLON.mjs.map +1 -0
  109. package/dist/{chunk-UOFTHYIH.js → chunk-UL6XJGUZ.js} +4 -4
  110. package/dist/chunk-UL6XJGUZ.js.map +1 -0
  111. package/dist/chunk-VVWQTO4Y.mjs +77 -0
  112. package/dist/chunk-VVWQTO4Y.mjs.map +1 -0
  113. package/dist/{chunk-A3UP56MS.js → chunk-WA67GZSZ.js} +3 -3
  114. package/dist/chunk-WA67GZSZ.js.map +1 -0
  115. package/dist/{chunk-OLHGZXN3.mjs → chunk-WEEXCPSE.mjs} +5 -5
  116. package/dist/chunk-WEEXCPSE.mjs.map +1 -0
  117. package/dist/chunk-XGBE4SUV.js +2093 -0
  118. package/dist/chunk-XGBE4SUV.js.map +1 -0
  119. package/dist/{chunk-QU5OT4DF.js → chunk-XJ7ZAGC5.js} +5 -5
  120. package/dist/chunk-XJ7ZAGC5.js.map +1 -0
  121. package/dist/{chunk-ZI25QCHD.mjs → chunk-YOTQG4NP.mjs} +25 -25
  122. package/dist/chunk-YOTQG4NP.mjs.map +1 -0
  123. package/dist/{chunk-QAT2RWAO.mjs → chunk-Z36R3P62.mjs} +7 -7
  124. package/dist/chunk-Z36R3P62.mjs.map +1 -0
  125. package/dist/{chunk-7Z5LLJ3A.js → chunk-ZWQJSZEY.js} +13 -13
  126. package/dist/chunk-ZWQJSZEY.js.map +1 -0
  127. package/dist/config/index.js +6 -6
  128. package/dist/config/index.js.map +1 -1
  129. package/dist/config/index.mjs +6 -6
  130. package/dist/config/index.mjs.map +1 -1
  131. package/dist/config/server/index.js +37 -37
  132. package/dist/config/server/index.js.map +1 -1
  133. package/dist/config/server/index.mjs +37 -37
  134. package/dist/config/server/index.mjs.map +1 -1
  135. package/dist/i18n/index.d.mts +2 -2
  136. package/dist/i18n/index.d.ts +2 -2
  137. package/dist/i18n/index.js +16 -17
  138. package/dist/i18n/index.js.map +1 -1
  139. package/dist/i18n/index.mjs +16 -17
  140. package/dist/i18n/index.mjs.map +1 -1
  141. package/dist/imageCrop/index.js +11 -10
  142. package/dist/imageCrop/index.js.map +1 -1
  143. package/dist/imageCrop/index.mjs +11 -10
  144. package/dist/imageCrop/index.mjs.map +1 -1
  145. package/dist/index.d.mts +185 -100
  146. package/dist/index.d.ts +185 -100
  147. package/dist/index.js +225 -249
  148. package/dist/index.js.map +1 -1
  149. package/dist/index.mjs +80 -104
  150. package/dist/index.mjs.map +1 -1
  151. package/dist/logger/index.js +6 -6
  152. package/dist/logger/index.mjs +1 -1
  153. package/dist/mikuFusionGame/index.d.mts +112 -0
  154. package/dist/mikuFusionGame/index.d.ts +112 -0
  155. package/dist/mikuFusionGame/index.js +680 -0
  156. package/dist/mikuFusionGame/index.js.map +1 -0
  157. package/dist/mikuFusionGame/index.mjs +667 -0
  158. package/dist/mikuFusionGame/index.mjs.map +1 -0
  159. package/dist/mmd/admin/index.js +11 -10
  160. package/dist/mmd/admin/index.js.map +1 -1
  161. package/dist/mmd/admin/index.mjs +11 -10
  162. package/dist/mmd/admin/index.mjs.map +1 -1
  163. package/dist/mmd/index.js +223 -241
  164. package/dist/mmd/index.js.map +1 -1
  165. package/dist/mmd/index.mjs +220 -238
  166. package/dist/mmd/index.mjs.map +1 -1
  167. package/dist/mmd/server/index.js +6 -6
  168. package/dist/mmd/server/index.js.map +1 -1
  169. package/dist/mmd/server/index.mjs +6 -6
  170. package/dist/mmd/server/index.mjs.map +1 -1
  171. package/dist/music/index.js +16 -16
  172. package/dist/music/index.mjs +2 -2
  173. package/dist/music/server/index.js +8 -8
  174. package/dist/music/server/index.mjs +1 -1
  175. package/dist/request/index.js +2 -2
  176. package/dist/request/index.js.map +1 -1
  177. package/dist/request/index.mjs +2 -2
  178. package/dist/request/index.mjs.map +1 -1
  179. package/dist/storage/index.js +15 -14
  180. package/dist/storage/index.mjs +3 -2
  181. package/dist/testYourself/admin/index.js +3 -3
  182. package/dist/testYourself/admin/index.mjs +1 -1
  183. package/dist/testYourself/index.js +22 -22
  184. package/dist/testYourself/index.js.map +1 -1
  185. package/dist/testYourself/index.mjs +14 -14
  186. package/dist/testYourself/index.mjs.map +1 -1
  187. package/dist/testYourself/server/index.js +4 -4
  188. package/dist/testYourself/server/index.mjs +1 -1
  189. package/dist/universalExport/index.d.mts +3 -3
  190. package/dist/universalExport/index.d.ts +3 -3
  191. package/dist/universalExport/index.js +48 -47
  192. package/dist/universalExport/index.js.map +1 -1
  193. package/dist/universalExport/index.mjs +48 -47
  194. package/dist/universalExport/index.mjs.map +1 -1
  195. package/dist/universalExport/server/index.js +29 -29
  196. package/dist/universalExport/server/index.js.map +1 -1
  197. package/dist/universalExport/server/index.mjs +28 -28
  198. package/dist/universalExport/server/index.mjs.map +1 -1
  199. package/dist/universalFile/index.d.mts +3 -3
  200. package/dist/universalFile/index.d.ts +3 -3
  201. package/dist/universalFile/index.js +73 -72
  202. package/dist/universalFile/index.js.map +1 -1
  203. package/dist/universalFile/index.mjs +73 -72
  204. package/dist/universalFile/index.mjs.map +1 -1
  205. package/dist/universalFile/server/index.js +258 -260
  206. package/dist/universalFile/server/index.js.map +1 -1
  207. package/dist/universalFile/server/index.mjs +244 -246
  208. package/dist/universalFile/server/index.mjs.map +1 -1
  209. package/dist/utils/index.js +11 -11
  210. package/dist/utils/index.mjs +2 -2
  211. package/package.json +25 -31
  212. package/dist/AliyunOSSProvider-FWAKUB2T.js +0 -15
  213. package/dist/AliyunOSSProvider-KJYRIZES.mjs +0 -6
  214. package/dist/ConfigService-7MEZXKJ5.js +0 -21
  215. package/dist/ConfigService-BV57YYFW.mjs +0 -4
  216. package/dist/LocalStorageProvider-RTPMUOZ2.mjs +0 -6
  217. package/dist/LocalStorageProvider-XSRCUXOU.js +0 -15
  218. package/dist/PMXParser-L6IWHL4I.mjs +0 -4
  219. package/dist/PMXParser-YBS3B6HM.js +0 -13
  220. package/dist/chunk-3BGPZN4X.mjs.map +0 -1
  221. package/dist/chunk-3WOAPLEG.mjs.map +0 -1
  222. package/dist/chunk-6PRFP5EG.js.map +0 -1
  223. package/dist/chunk-6YKMCPQI.mjs.map +0 -1
  224. package/dist/chunk-7Z5LLJ3A.js.map +0 -1
  225. package/dist/chunk-A3UP56MS.js.map +0 -1
  226. package/dist/chunk-CD77U7LZ.js.map +0 -1
  227. package/dist/chunk-CLKKZSPZ.js.map +0 -1
  228. package/dist/chunk-CNTILN5J.mjs.map +0 -1
  229. package/dist/chunk-DUHZ7VZP.js.map +0 -1
  230. package/dist/chunk-DW2ZTOCV.js +0 -1727
  231. package/dist/chunk-DW2ZTOCV.js.map +0 -1
  232. package/dist/chunk-E7RGBAYJ.js.map +0 -1
  233. package/dist/chunk-JZXJQMVE.js.map +0 -1
  234. package/dist/chunk-KQGP6BTS.mjs.map +0 -1
  235. package/dist/chunk-LFG6FPM5.mjs +0 -1597
  236. package/dist/chunk-LFG6FPM5.mjs.map +0 -1
  237. package/dist/chunk-LX4XX6W7.js.map +0 -1
  238. package/dist/chunk-LZHMNOED.js.map +0 -1
  239. package/dist/chunk-MW4BCIZC.mjs.map +0 -1
  240. package/dist/chunk-OCR5DS4C.mjs.map +0 -1
  241. package/dist/chunk-OLHGZXN3.mjs.map +0 -1
  242. package/dist/chunk-OPPF3326.js.map +0 -1
  243. package/dist/chunk-QAT2RWAO.mjs.map +0 -1
  244. package/dist/chunk-QU5OT4DF.js.map +0 -1
  245. package/dist/chunk-T5OZHYVM.mjs.map +0 -1
  246. package/dist/chunk-TFQF2HDO.mjs.map +0 -1
  247. package/dist/chunk-TOC5FSHP.js.map +0 -1
  248. package/dist/chunk-TV3VKRJK.mjs.map +0 -1
  249. package/dist/chunk-UOFTHYIH.js.map +0 -1
  250. package/dist/chunk-VRTRSEEH.mjs.map +0 -1
  251. package/dist/chunk-ZI25QCHD.mjs.map +0 -1
@@ -45,8 +45,8 @@ var analyticsEvents = pgCore.pgTable(
45
45
  ]
46
46
  );
47
47
  var defaultLogger = {
48
- info: (message, data) => console.log(`[Analytics] ${message}`, data || ""),
49
- error: (message, error) => console.error(`[Analytics] ${message}`, error)
48
+ info: (message, data) => console.log("[Analytics] " + message, data || ""),
49
+ error: (message, error) => console.error("[Analytics] " + message, error)
50
50
  };
51
51
  function createAnalyticsService(db, analyticsEventsTable, logger = defaultLogger) {
52
52
  const analyticsEvents2 = analyticsEventsTable;
@@ -113,8 +113,8 @@ function createAnalyticsService(db, analyticsEventsTable, logger = defaultLogger
113
113
  const events = await db.select().from(analyticsEvents2).where(whereClause).orderBy(orderFn(orderByField)).limit(params.limit || 100).offset(params.offset || 0);
114
114
  const formattedEvents = events.map((event) => ({
115
115
  ...event,
116
- timestamp: event.timestamp.endsWith("Z") ? event.timestamp : `${event.timestamp}Z`,
117
- createdAt: event.createdAt.endsWith("Z") ? event.createdAt : `${event.createdAt}Z`
116
+ timestamp: event.timestamp.endsWith("Z") ? event.timestamp : event.timestamp + "Z",
117
+ createdAt: event.createdAt.endsWith("Z") ? event.createdAt : event.createdAt + "Z"
118
118
  }));
119
119
  return {
120
120
  events: formattedEvents,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/analytics/server/schema.ts","../../../src/analytics/server/service.ts","../../../src/analytics/server/handlers.ts"],"names":["pgTable","text","timestamp","integer","jsonb","sql","index","analyticsEvents","gte","lte","eq","inArray","and","count","asc","desc"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 埋点系统数据库 Schema\n * Analytics Database Schema\n *\n * 使用方式:\n * 在 backend/drizzle/migrations/schema.ts 中导入并导出:\n * export { analyticsEvents } from '@lyricnote/shared/analytics/server/schema'\n */\n\nimport { pgTable, text, timestamp, integer, jsonb, index } from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\n\n/**\n * 埋点事件表\n */\nexport const analyticsEvents = pgTable(\n 'analytics_events',\n {\n id: text().primaryKey().notNull(),\n eventType: text('event_type').notNull(),\n eventName: text('event_name').notNull(),\n timestamp: timestamp({ precision: 3, mode: 'string' }).notNull(),\n priority: integer().notNull(),\n\n userId: text('user_id'),\n sessionId: text('session_id').notNull(),\n deviceId: text('device_id').notNull(),\n\n pageUrl: text('page_url'),\n pageTitle: text('page_title'),\n referrer: text(),\n\n properties: jsonb(),\n\n platform: text().notNull(),\n appVersion: text('app_version').notNull(),\n sdkVersion: text('sdk_version').notNull(),\n\n createdAt: timestamp({ precision: 3, mode: 'string' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull(),\n },\n (table) => [\n index('analytics_events_user_id_idx').using(\n 'btree',\n table.userId.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_event_type_idx').using(\n 'btree',\n table.eventType.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_platform_idx').using(\n 'btree',\n table.platform.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_timestamp_idx').using('btree', table.timestamp.desc().nullsLast()),\n index('analytics_events_session_id_idx').using(\n 'btree',\n table.sessionId.asc().nullsLast().op('text_ops')\n ),\n ]\n);\n\n/**\n * 创建外键关系(需要在使用时手动添加)\n *\n * 在你的 schema.ts 中添加:\n *\n * foreignKey({\n * columns: [analyticsEvents.userId],\n * foreignColumns: [user.id],\n * name: \"analytics_events_userId_fkey\"\n * }).onUpdate(\"cascade\").onDelete(\"set null\")\n */\n","/**\n * 埋点分析服务\n * Analytics Service\n *\n * 使用方式:\n * import { createAnalyticsService } from '@lyricnote/shared/analytics/server'\n * const service = createAnalyticsService(db, analyticsEvents, logger)\n */\n\nimport { eq, and, gte, lte, sql, desc, asc, count, inArray } from 'drizzle-orm';\n\n// 导出类型\nexport * from './types';\nimport type {\n AnalyticsEvent,\n AnalyticsQueryParams,\n AnalyticsStats,\n UserBehavior,\n SessionAnalytics,\n DatabaseInstance,\n} from './types';\n\n// Logger 接口\ninterface Logger {\n info: (message: string, data?: any) => void;\n error: (message: string, error: Error) => void;\n}\n\n// 默认 logger(如果未提供)\nconst defaultLogger: Logger = {\n info: (message, data) => console.log(`[Analytics] ${message}`, data || ''),\n error: (message, error) => console.error(`[Analytics] ${message}`, error),\n};\n\n/**\n * 创建埋点服务实例\n * @param db - Drizzle 数据库实例\n * @param analyticsEventsTable - analytics_events 表定义\n * @param logger - 日志实例(可选)\n */\nexport function createAnalyticsService(\n db: DatabaseInstance,\n analyticsEventsTable: any,\n logger: Logger = defaultLogger\n) {\n const analyticsEvents = analyticsEventsTable;\n\n return {\n /**\n * 批量插入埋点事件\n */\n async insertAnalyticsEvents(events: AnalyticsEvent[]): Promise<void> {\n try {\n if (events.length === 0) return;\n\n // 使用 onConflictDoNothing 来忽略重复的事件 ID\n // 这样可以避免前端重试或离线队列导致的重复插入\n await db.insert(analyticsEvents).values(events).onConflictDoNothing();\n\n logger.info('Analytics events inserted', { count: events.length });\n } catch (error) {\n logger.error('Failed to insert analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 查询埋点事件\n */\n async queryAnalyticsEvents(\n params: AnalyticsQueryParams\n ): Promise<{ events: AnalyticsEvent[]; total: number }> {\n try {\n const conditions: any[] = [];\n\n // 时间范围过滤\n if (params.startDate) {\n conditions.push(gte(analyticsEvents.timestamp, params.startDate));\n }\n if (params.endDate) {\n conditions.push(lte(analyticsEvents.timestamp, params.endDate));\n }\n\n // 事件类型过滤\n if (params.eventType) {\n conditions.push(eq(analyticsEvents.eventType, params.eventType));\n }\n if (params.eventTypes && params.eventTypes.length > 0) {\n conditions.push(inArray(analyticsEvents.eventType, params.eventTypes));\n }\n\n // 用户过滤\n if (params.userId) {\n conditions.push(eq(analyticsEvents.userId, params.userId));\n }\n\n // 平台过滤\n if (params.platform) {\n conditions.push(eq(analyticsEvents.platform, params.platform));\n }\n if (params.platforms && params.platforms.length > 0) {\n conditions.push(inArray(analyticsEvents.platform, params.platforms));\n }\n\n // 会话过滤\n if (params.sessionId) {\n conditions.push(eq(analyticsEvents.sessionId, params.sessionId));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 排序\n const orderByColumn = params.orderBy || 'timestamp';\n const orderDirection = params.orderDirection || 'desc';\n const orderFn = orderDirection === 'asc' ? asc : desc;\n\n let orderByField;\n switch (orderByColumn) {\n case 'eventType':\n orderByField = analyticsEvents.eventType;\n break;\n case 'platform':\n orderByField = analyticsEvents.platform;\n break;\n default:\n orderByField = analyticsEvents.timestamp;\n }\n\n // 查询数据\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(whereClause)\n .orderBy(orderFn(orderByField))\n .limit(params.limit || 100)\n .offset(params.offset || 0);\n\n // 修复时间戳格式:添加 'Z' 后缀表示 UTC 时间\n const formattedEvents = events.map((event: any) => ({\n ...event,\n timestamp: event.timestamp.endsWith('Z') ? event.timestamp : `${event.timestamp}Z`,\n createdAt: event.createdAt.endsWith('Z') ? event.createdAt : `${event.createdAt}Z`,\n }));\n\n return {\n events: formattedEvents as AnalyticsEvent[],\n total: Number(total),\n };\n } catch (error) {\n logger.error('Failed to query analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取统计数据\n */\n async getAnalyticsStats(\n startDate?: string,\n endDate?: string,\n platform?: string\n ): Promise<AnalyticsStats> {\n try {\n const conditions: any[] = [];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n if (platform) {\n conditions.push(eq(analyticsEvents.platform, platform));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 总事件数\n const [{ totalEvents }] = await db\n .select({ totalEvents: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一用户数\n const [{ uniqueUsers }] = await db\n .select({ uniqueUsers: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一会话数\n const [{ uniqueSessions }] = await db\n .select({ uniqueSessions: sql<number>`COUNT(DISTINCT ${analyticsEvents.sessionId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一设备数\n const [{ uniqueDevices }] = await db\n .select({ uniqueDevices: sql<number>`COUNT(DISTINCT ${analyticsEvents.deviceId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 按事件类型统计\n const eventsByType = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(10);\n\n // 按平台统计\n const eventsByPlatform = await db\n .select({\n platform: analyticsEvents.platform,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform)\n .orderBy(desc(count()));\n\n // 热门页面\n const topPages = await db\n .select({\n pageUrl: analyticsEvents.pageUrl,\n count: count(),\n })\n .from(analyticsEvents)\n .where(and(whereClause, sql`${analyticsEvents.pageUrl} IS NOT NULL`))\n .groupBy(analyticsEvents.pageUrl)\n .orderBy(desc(count()))\n .limit(10);\n\n return {\n totalEvents: Number(totalEvents),\n uniqueUsers: Number(uniqueUsers),\n uniqueSessions: Number(uniqueSessions),\n uniqueDevices: Number(uniqueDevices),\n eventsByType: eventsByType.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n eventsByPlatform: eventsByPlatform.map((e: any) => ({\n platform: e.platform,\n count: Number(e.count),\n })),\n topPages: topPages\n .filter((p: any) => p.pageUrl)\n .map((p: any) => ({\n pageUrl: p.pageUrl!,\n count: Number(p.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get analytics stats', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取用户行为分析\n */\n async getUserBehavior(\n userId: string,\n startDate?: string,\n endDate?: string\n ): Promise<UserBehavior | null> {\n try {\n const conditions: any[] = [eq(analyticsEvents.userId, userId)];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n // 事件总数\n const [{ eventCount }] = await db\n .select({ eventCount: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n if (eventCount === 0) return null;\n\n // 最后活跃时间\n const [{ lastActive }] = await db\n .select({ lastActive: sql<string>`MAX(${analyticsEvents.timestamp})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 使用的平台\n const platformsResult = await db\n .select({ platform: analyticsEvents.platform })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform);\n\n // 热门事件\n const topEvents = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(5);\n\n return {\n userId,\n eventCount: Number(eventCount),\n lastActive,\n platforms: platformsResult.map((p: any) => p.platform),\n topEvents: topEvents.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get user behavior', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取会话分析\n */\n async getSessionAnalytics(sessionId: string): Promise<SessionAnalytics | null> {\n try {\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(eq(analyticsEvents.sessionId, sessionId))\n .orderBy(asc(analyticsEvents.timestamp));\n\n if (events.length === 0) return null;\n\n const firstEvent = events[0];\n const lastEvent = events[events.length - 1];\n\n const startTime = new Date(firstEvent.timestamp).getTime();\n const endTime = new Date(lastEvent.timestamp).getTime();\n const duration = endTime - startTime;\n\n return {\n sessionId,\n userId: firstEvent.userId || undefined,\n deviceId: firstEvent.deviceId,\n platform: firstEvent.platform,\n startTime: firstEvent.timestamp,\n endTime: lastEvent.timestamp,\n duration,\n eventCount: events.length,\n events: events as AnalyticsEvent[],\n };\n } catch (error) {\n logger.error('Failed to get session analytics', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取漏斗分析\n */\n async getFunnelAnalysis(\n steps: string[],\n startDate?: string,\n endDate?: string\n ): Promise<{ step: string; count: number; conversionRate: number }[]> {\n try {\n const results = [];\n let previousCount = 0;\n\n for (let i = 0; i < steps.length; i++) {\n const conditions: any[] = [eq(analyticsEvents.eventType, steps[i])];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n const [{ count: stepCount }] = await db\n .select({ count: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n const conversionRate = i === 0 ? 100 : (Number(stepCount) / previousCount) * 100;\n\n results.push({\n step: steps[i] || 'unknown',\n count: Number(stepCount),\n conversionRate: Math.round(conversionRate * 100) / 100,\n });\n\n previousCount = Number(stepCount);\n }\n\n return results;\n } catch (error) {\n logger.error('Failed to get funnel analysis', error as Error);\n throw error;\n }\n },\n\n /**\n * 删除旧数据(数据清理)\n */\n async cleanOldAnalyticsEvents(daysToKeep: number = 90): Promise<number> {\n try {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n await db\n .delete(analyticsEvents)\n .where(lte(analyticsEvents.timestamp, cutoffDate.toISOString()));\n\n logger.info('Old analytics events cleaned', { daysToKeep });\n\n return 0; // Drizzle doesn't return affected rows count in delete\n } catch (error) {\n logger.error('Failed to clean old analytics events', error as Error);\n throw error;\n }\n },\n };\n}\n","/**\n * 埋点 API 路由处理器\n * Analytics API Route Handlers\n *\n * 使用方式(Next.js):\n * import { createAnalyticsHandlers } from '@lyricnote/shared/analytics/server'\n * const handlers = createAnalyticsHandlers(analyticsService)\n * export const POST = handlers.handleEventsPost\n */\n\nimport type { AnalyticsEvent, AnalyticsQueryParams } from './types';\n\n// 服务接口类型\ninterface AnalyticsService {\n insertAnalyticsEvents: (events: AnalyticsEvent[]) => Promise<void>;\n queryAnalyticsEvents: (\n params: AnalyticsQueryParams\n ) => Promise<{ events: AnalyticsEvent[]; total: number }>;\n getAnalyticsStats: (startDate?: string, endDate?: string, platform?: string) => Promise<any>;\n getUserBehavior: (userId: string, startDate?: string, endDate?: string) => Promise<any>;\n getSessionAnalytics: (sessionId: string) => Promise<any>;\n getFunnelAnalysis: (steps: string[], startDate?: string, endDate?: string) => Promise<any>;\n}\n\n// Request/Response 接口(兼容多种框架)\ninterface Request {\n json: () => Promise<any>;\n url?: string;\n nextUrl?: { searchParams: URLSearchParams };\n}\n\ninterface ResponseInit {\n status?: number;\n headers?: Record<string, string>;\n}\n\n/**\n * 创建埋点 API 处理器\n */\nexport function createAnalyticsHandlers(\n service: AnalyticsService,\n ResponseClass?: any // Next.js NextResponse 或其他响应类\n) {\n // 默认使用标准响应格式\n const createResponse = ResponseClass\n ? (data: any, init?: ResponseInit) => ResponseClass.json(data, init)\n : (data: any, init?: ResponseInit) => ({ body: data, status: init?.status || 200 });\n\n return {\n /**\n * POST /api/analytics/events\n * 处理事件上报\n */\n async handleEventsPost(request: Request) {\n try {\n const body = await request.json();\n const { events } = body;\n\n // 验证数据\n if (!Array.isArray(events)) {\n return createResponse(\n { success: false, message: 'Invalid events format' },\n { status: 400 }\n );\n }\n\n if (events.length === 0) {\n return createResponse(\n { success: true, message: 'No events to process' },\n { status: 200 }\n );\n }\n\n // 验证每个事件的必填字段\n for (const event of events) {\n if (!event.event_id || !event.event_type || !event.event_name) {\n return createResponse(\n { success: false, message: 'Missing required event fields' },\n { status: 400 }\n );\n }\n }\n\n // 转换字段名(前端使用 snake_case,数据库使用 camelCase)\n const formattedEvents = events.map((event) => ({\n id: event.event_id,\n eventType: event.event_type,\n eventName: event.event_name,\n timestamp: new Date(event.timestamp).toISOString(),\n priority: event.priority,\n userId: event.user_id || null,\n sessionId: event.session_id,\n deviceId: event.device_id,\n pageUrl: event.page_url || null,\n pageTitle: event.page_title || null,\n referrer: event.referrer || null,\n properties: event.properties || {},\n platform: event.platform,\n appVersion: event.app_version,\n sdkVersion: event.sdk_version,\n }));\n\n // 插入数据库\n await service.insertAnalyticsEvents(formattedEvents);\n\n return createResponse({\n success: true,\n message: 'Events received successfully',\n count: events.length,\n });\n } catch (error) {\n console.error('Failed to process analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/query\n * 查询埋点事件\n */\n async handleQueryGet(request: Request) {\n try {\n // 解析查询参数\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const params: AnalyticsQueryParams = {\n startDate: searchParams.get('startDate') || undefined,\n endDate: searchParams.get('endDate') || undefined,\n eventType: searchParams.get('eventType') || undefined,\n eventTypes: searchParams.get('eventTypes')?.split(',') || undefined,\n userId: searchParams.get('userId') || undefined,\n platform: searchParams.get('platform') || undefined,\n platforms: searchParams.get('platforms')?.split(',') || undefined,\n sessionId: searchParams.get('sessionId') || undefined,\n limit: parseInt(searchParams.get('limit') || '100'),\n offset: parseInt(searchParams.get('offset') || '0'),\n orderBy: (searchParams.get('orderBy') || 'timestamp') as any,\n orderDirection: (searchParams.get('orderDirection') || 'desc') as any,\n };\n\n // 查询数据\n const result = await service.queryAnalyticsEvents(params);\n\n return createResponse({\n success: true,\n data: result.events,\n total: result.total,\n limit: params.limit,\n offset: params.offset,\n });\n } catch (error) {\n console.error('Failed to query analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/stats\n * 获取统计数据\n */\n async handleStatsGet(request: Request) {\n try {\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n const platform = searchParams.get('platform') || undefined;\n\n // 获取统计数据\n const stats = await service.getAnalyticsStats(startDate, endDate, platform);\n\n return createResponse({\n success: true,\n data: stats,\n });\n } catch (error) {\n console.error('Failed to get analytics stats', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/user/[userId]\n * 获取用户行为分析\n */\n async handleUserBehaviorGet(request: Request, params: { userId: string }) {\n try {\n const { userId } = params;\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n\n // 获取用户行为数据\n const behavior = await service.getUserBehavior(userId, startDate, endDate);\n\n if (!behavior) {\n return createResponse(\n { success: false, message: 'No data found for this user' },\n { status: 404 }\n );\n }\n\n return createResponse({\n success: true,\n data: behavior,\n });\n } catch (error) {\n console.error('Failed to get user behavior', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/session/[sessionId]\n * 获取会话分析\n */\n async handleSessionAnalyticsGet(_request: Request, params: { sessionId: string }) {\n try {\n const { sessionId } = params;\n\n // 获取会话分析数据\n const session = await service.getSessionAnalytics(sessionId);\n\n if (!session) {\n return createResponse({ success: false, message: 'Session not found' }, { status: 404 });\n }\n\n return createResponse({\n success: true,\n data: session,\n });\n } catch (error) {\n console.error('Failed to get session analytics', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * POST /api/analytics/funnel\n * 漏斗分析\n */\n async handleFunnelPost(request: Request) {\n try {\n const body = await request.json();\n const { steps, startDate, endDate } = body;\n\n // 验证数据\n if (!Array.isArray(steps) || steps.length === 0) {\n return createResponse(\n { success: false, message: 'Invalid steps format' },\n { status: 400 }\n );\n }\n\n // 获取漏斗分析数据\n const funnel = await service.getFunnelAnalysis(steps, startDate, endDate);\n\n return createResponse({\n success: true,\n data: funnel,\n });\n } catch (error) {\n console.error('Failed to get funnel analysis', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../../src/analytics/server/schema.ts","../../../src/analytics/server/service.ts","../../../src/analytics/server/handlers.ts"],"names":["pgTable","text","timestamp","integer","jsonb","sql","index","analyticsEvents","gte","lte","eq","inArray","and","count","asc","desc"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 埋点系统数据库 Schema\n * Analytics Database Schema\n *\n * 使用方式:\n * 在 backend/drizzle/migrations/schema.ts 中导入并导出:\n * export { analyticsEvents } from '@lyricnote/shared/analytics/server/schema'\n */\n\nimport { pgTable, text, timestamp, integer, jsonb, index } from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\n\n/**\n * 埋点事件表\n */\nexport const analyticsEvents = pgTable(\n 'analytics_events',\n {\n id: text().primaryKey().notNull(),\n eventType: text('event_type').notNull(),\n eventName: text('event_name').notNull(),\n timestamp: timestamp({ precision: 3, mode: 'string' }).notNull(),\n priority: integer().notNull(),\n\n userId: text('user_id'),\n sessionId: text('session_id').notNull(),\n deviceId: text('device_id').notNull(),\n\n pageUrl: text('page_url'),\n pageTitle: text('page_title'),\n referrer: text(),\n\n properties: jsonb(),\n\n platform: text().notNull(),\n appVersion: text('app_version').notNull(),\n sdkVersion: text('sdk_version').notNull(),\n\n createdAt: timestamp({ precision: 3, mode: 'string' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull(),\n },\n (table) => [\n index('analytics_events_user_id_idx').using(\n 'btree',\n table.userId.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_event_type_idx').using(\n 'btree',\n table.eventType.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_platform_idx').using(\n 'btree',\n table.platform.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_timestamp_idx').using('btree', table.timestamp.desc().nullsLast()),\n index('analytics_events_session_id_idx').using(\n 'btree',\n table.sessionId.asc().nullsLast().op('text_ops')\n ),\n ]\n);\n\n/**\n * 创建外键关系(需要在使用时手动添加)\n *\n * 在你的 schema.ts 中添加:\n *\n * foreignKey({\n * columns: [analyticsEvents.userId],\n * foreignColumns: [user.id],\n * name: \"analytics_events_userId_fkey\"\n * }).onUpdate(\"cascade\").onDelete(\"set null\")\n */\n","/**\n * 埋点分析服务\n * Analytics Service\n *\n * 使用方式:\n * import { createAnalyticsService } from '@lyricnote/shared/analytics/server'\n * const service = createAnalyticsService(db, analyticsEvents, logger)\n */\n\nimport { eq, and, gte, lte, sql, desc, asc, count, inArray } from 'drizzle-orm';\n\n// 导出类型\nexport * from './types';\nimport type {\n AnalyticsEvent,\n AnalyticsQueryParams,\n AnalyticsStats,\n UserBehavior,\n SessionAnalytics,\n DatabaseInstance,\n} from './types';\n\n// Logger 接口\ninterface Logger {\n info: (message: string, data?: any) => void;\n error: (message: string, error: Error) => void;\n}\n\n// 默认 logger(如果未提供)\nconst defaultLogger: Logger = {\n info: (message, data) => console.log('[Analytics] ' + (message), data || ''),\n error: (message, error) => console.error('[Analytics] ' + (message), error),\n};\n\n/**\n * 创建埋点服务实例\n * @param db - Drizzle 数据库实例\n * @param analyticsEventsTable - analytics_events 表定义\n * @param logger - 日志实例(可选)\n */\nexport function createAnalyticsService(\n db: DatabaseInstance,\n analyticsEventsTable: any,\n logger: Logger = defaultLogger\n) {\n const analyticsEvents = analyticsEventsTable;\n\n return {\n /**\n * 批量插入埋点事件\n */\n async insertAnalyticsEvents(events: AnalyticsEvent[]): Promise<void> {\n try {\n if (events.length === 0) return;\n\n // 使用 onConflictDoNothing 来忽略重复的事件 ID\n // 这样可以避免前端重试或离线队列导致的重复插入\n await db.insert(analyticsEvents).values(events).onConflictDoNothing();\n\n logger.info('Analytics events inserted', { count: events.length });\n } catch (error) {\n logger.error('Failed to insert analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 查询埋点事件\n */\n async queryAnalyticsEvents(\n params: AnalyticsQueryParams\n ): Promise<{ events: AnalyticsEvent[]; total: number }> {\n try {\n const conditions: any[] = [];\n\n // 时间范围过滤\n if (params.startDate) {\n conditions.push(gte(analyticsEvents.timestamp, params.startDate));\n }\n if (params.endDate) {\n conditions.push(lte(analyticsEvents.timestamp, params.endDate));\n }\n\n // 事件类型过滤\n if (params.eventType) {\n conditions.push(eq(analyticsEvents.eventType, params.eventType));\n }\n if (params.eventTypes && params.eventTypes.length > 0) {\n conditions.push(inArray(analyticsEvents.eventType, params.eventTypes));\n }\n\n // 用户过滤\n if (params.userId) {\n conditions.push(eq(analyticsEvents.userId, params.userId));\n }\n\n // 平台过滤\n if (params.platform) {\n conditions.push(eq(analyticsEvents.platform, params.platform));\n }\n if (params.platforms && params.platforms.length > 0) {\n conditions.push(inArray(analyticsEvents.platform, params.platforms));\n }\n\n // 会话过滤\n if (params.sessionId) {\n conditions.push(eq(analyticsEvents.sessionId, params.sessionId));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 排序\n const orderByColumn = params.orderBy || 'timestamp';\n const orderDirection = params.orderDirection || 'desc';\n const orderFn = orderDirection === 'asc' ? asc : desc;\n\n let orderByField;\n switch (orderByColumn) {\n case 'eventType':\n orderByField = analyticsEvents.eventType;\n break;\n case 'platform':\n orderByField = analyticsEvents.platform;\n break;\n default:\n orderByField = analyticsEvents.timestamp;\n }\n\n // 查询数据\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(whereClause)\n .orderBy(orderFn(orderByField))\n .limit(params.limit || 100)\n .offset(params.offset || 0);\n\n // 修复时间戳格式:添加 'Z' 后缀表示 UTC 时间\n const formattedEvents = events.map((event: any) => ({\n ...event,\n timestamp: event.timestamp.endsWith('Z') ? event.timestamp : (event.timestamp) + 'Z',\n createdAt: event.createdAt.endsWith('Z') ? event.createdAt : (event.createdAt) + 'Z',\n }));\n\n return {\n events: formattedEvents as AnalyticsEvent[],\n total: Number(total),\n };\n } catch (error) {\n logger.error('Failed to query analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取统计数据\n */\n async getAnalyticsStats(\n startDate?: string,\n endDate?: string,\n platform?: string\n ): Promise<AnalyticsStats> {\n try {\n const conditions: any[] = [];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n if (platform) {\n conditions.push(eq(analyticsEvents.platform, platform));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 总事件数\n const [{ totalEvents }] = await db\n .select({ totalEvents: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一用户数\n const [{ uniqueUsers }] = await db\n .select({ uniqueUsers: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一会话数\n const [{ uniqueSessions }] = await db\n .select({ uniqueSessions: sql<number>`COUNT(DISTINCT ${analyticsEvents.sessionId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一设备数\n const [{ uniqueDevices }] = await db\n .select({ uniqueDevices: sql<number>`COUNT(DISTINCT ${analyticsEvents.deviceId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 按事件类型统计\n const eventsByType = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(10);\n\n // 按平台统计\n const eventsByPlatform = await db\n .select({\n platform: analyticsEvents.platform,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform)\n .orderBy(desc(count()));\n\n // 热门页面\n const topPages = await db\n .select({\n pageUrl: analyticsEvents.pageUrl,\n count: count(),\n })\n .from(analyticsEvents)\n .where(and(whereClause, sql`${analyticsEvents.pageUrl} IS NOT NULL`))\n .groupBy(analyticsEvents.pageUrl)\n .orderBy(desc(count()))\n .limit(10);\n\n return {\n totalEvents: Number(totalEvents),\n uniqueUsers: Number(uniqueUsers),\n uniqueSessions: Number(uniqueSessions),\n uniqueDevices: Number(uniqueDevices),\n eventsByType: eventsByType.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n eventsByPlatform: eventsByPlatform.map((e: any) => ({\n platform: e.platform,\n count: Number(e.count),\n })),\n topPages: topPages\n .filter((p: any) => p.pageUrl)\n .map((p: any) => ({\n pageUrl: p.pageUrl!,\n count: Number(p.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get analytics stats', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取用户行为分析\n */\n async getUserBehavior(\n userId: string,\n startDate?: string,\n endDate?: string\n ): Promise<UserBehavior | null> {\n try {\n const conditions: any[] = [eq(analyticsEvents.userId, userId)];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n // 事件总数\n const [{ eventCount }] = await db\n .select({ eventCount: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n if (eventCount === 0) return null;\n\n // 最后活跃时间\n const [{ lastActive }] = await db\n .select({ lastActive: sql<string>`MAX(${analyticsEvents.timestamp})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 使用的平台\n const platformsResult = await db\n .select({ platform: analyticsEvents.platform })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform);\n\n // 热门事件\n const topEvents = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(5);\n\n return {\n userId,\n eventCount: Number(eventCount),\n lastActive,\n platforms: platformsResult.map((p: any) => p.platform),\n topEvents: topEvents.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get user behavior', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取会话分析\n */\n async getSessionAnalytics(sessionId: string): Promise<SessionAnalytics | null> {\n try {\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(eq(analyticsEvents.sessionId, sessionId))\n .orderBy(asc(analyticsEvents.timestamp));\n\n if (events.length === 0) return null;\n\n const firstEvent = events[0];\n const lastEvent = events[events.length - 1];\n\n const startTime = new Date(firstEvent.timestamp).getTime();\n const endTime = new Date(lastEvent.timestamp).getTime();\n const duration = endTime - startTime;\n\n return {\n sessionId,\n userId: firstEvent.userId || undefined,\n deviceId: firstEvent.deviceId,\n platform: firstEvent.platform,\n startTime: firstEvent.timestamp,\n endTime: lastEvent.timestamp,\n duration,\n eventCount: events.length,\n events: events as AnalyticsEvent[],\n };\n } catch (error) {\n logger.error('Failed to get session analytics', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取漏斗分析\n */\n async getFunnelAnalysis(\n steps: string[],\n startDate?: string,\n endDate?: string\n ): Promise<{ step: string; count: number; conversionRate: number }[]> {\n try {\n const results = [];\n let previousCount = 0;\n\n for (let i = 0; i < steps.length; i++) {\n const conditions: any[] = [eq(analyticsEvents.eventType, steps[i])];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n const [{ count: stepCount }] = await db\n .select({ count: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n const conversionRate = i === 0 ? 100 : (Number(stepCount) / previousCount) * 100;\n\n results.push({\n step: steps[i] || 'unknown',\n count: Number(stepCount),\n conversionRate: Math.round(conversionRate * 100) / 100,\n });\n\n previousCount = Number(stepCount);\n }\n\n return results;\n } catch (error) {\n logger.error('Failed to get funnel analysis', error as Error);\n throw error;\n }\n },\n\n /**\n * 删除旧数据(数据清理)\n */\n async cleanOldAnalyticsEvents(daysToKeep: number = 90): Promise<number> {\n try {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n await db\n .delete(analyticsEvents)\n .where(lte(analyticsEvents.timestamp, cutoffDate.toISOString()));\n\n logger.info('Old analytics events cleaned', { daysToKeep });\n\n return 0; // Drizzle doesn't return affected rows count in delete\n } catch (error) {\n logger.error('Failed to clean old analytics events', error as Error);\n throw error;\n }\n },\n };\n}\n","/**\n * 埋点 API 路由处理器\n * Analytics API Route Handlers\n *\n * 使用方式(Next.js):\n * import { createAnalyticsHandlers } from '@lyricnote/shared/analytics/server'\n * const handlers = createAnalyticsHandlers(analyticsService)\n * export const POST = handlers.handleEventsPost\n */\n\nimport type { AnalyticsEvent, AnalyticsQueryParams } from './types';\n\n// 服务接口类型\ninterface AnalyticsService {\n insertAnalyticsEvents: (events: AnalyticsEvent[]) => Promise<void>;\n queryAnalyticsEvents: (\n params: AnalyticsQueryParams\n ) => Promise<{ events: AnalyticsEvent[]; total: number }>;\n getAnalyticsStats: (startDate?: string, endDate?: string, platform?: string) => Promise<any>;\n getUserBehavior: (userId: string, startDate?: string, endDate?: string) => Promise<any>;\n getSessionAnalytics: (sessionId: string) => Promise<any>;\n getFunnelAnalysis: (steps: string[], startDate?: string, endDate?: string) => Promise<any>;\n}\n\n// Request/Response 接口(兼容多种框架)\ninterface Request {\n json: () => Promise<any>;\n url?: string;\n nextUrl?: { searchParams: URLSearchParams };\n}\n\ninterface ResponseInit {\n status?: number;\n headers?: Record<string, string>;\n}\n\n/**\n * 创建埋点 API 处理器\n */\nexport function createAnalyticsHandlers(\n service: AnalyticsService,\n ResponseClass?: any // Next.js NextResponse 或其他响应类\n) {\n // 默认使用标准响应格式\n const createResponse = ResponseClass\n ? (data: any, init?: ResponseInit) => ResponseClass.json(data, init)\n : (data: any, init?: ResponseInit) => ({ body: data, status: init?.status || 200 });\n\n return {\n /**\n * POST /api/analytics/events\n * 处理事件上报\n */\n async handleEventsPost(request: Request) {\n try {\n const body = await request.json();\n const { events } = body;\n\n // 验证数据\n if (!Array.isArray(events)) {\n return createResponse(\n { success: false, message: 'Invalid events format' },\n { status: 400 }\n );\n }\n\n if (events.length === 0) {\n return createResponse(\n { success: true, message: 'No events to process' },\n { status: 200 }\n );\n }\n\n // 验证每个事件的必填字段\n for (const event of events) {\n if (!event.event_id || !event.event_type || !event.event_name) {\n return createResponse(\n { success: false, message: 'Missing required event fields' },\n { status: 400 }\n );\n }\n }\n\n // 转换字段名(前端使用 snake_case,数据库使用 camelCase)\n const formattedEvents = events.map((event) => ({\n id: event.event_id,\n eventType: event.event_type,\n eventName: event.event_name,\n timestamp: new Date(event.timestamp).toISOString(),\n priority: event.priority,\n userId: event.user_id || null,\n sessionId: event.session_id,\n deviceId: event.device_id,\n pageUrl: event.page_url || null,\n pageTitle: event.page_title || null,\n referrer: event.referrer || null,\n properties: event.properties || {},\n platform: event.platform,\n appVersion: event.app_version,\n sdkVersion: event.sdk_version,\n }));\n\n // 插入数据库\n await service.insertAnalyticsEvents(formattedEvents);\n\n return createResponse({\n success: true,\n message: 'Events received successfully',\n count: events.length,\n });\n } catch (error) {\n console.error('Failed to process analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/query\n * 查询埋点事件\n */\n async handleQueryGet(request: Request) {\n try {\n // 解析查询参数\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const params: AnalyticsQueryParams = {\n startDate: searchParams.get('startDate') || undefined,\n endDate: searchParams.get('endDate') || undefined,\n eventType: searchParams.get('eventType') || undefined,\n eventTypes: searchParams.get('eventTypes')?.split(',') || undefined,\n userId: searchParams.get('userId') || undefined,\n platform: searchParams.get('platform') || undefined,\n platforms: searchParams.get('platforms')?.split(',') || undefined,\n sessionId: searchParams.get('sessionId') || undefined,\n limit: parseInt(searchParams.get('limit') || '100'),\n offset: parseInt(searchParams.get('offset') || '0'),\n orderBy: (searchParams.get('orderBy') || 'timestamp') as any,\n orderDirection: (searchParams.get('orderDirection') || 'desc') as any,\n };\n\n // 查询数据\n const result = await service.queryAnalyticsEvents(params);\n\n return createResponse({\n success: true,\n data: result.events,\n total: result.total,\n limit: params.limit,\n offset: params.offset,\n });\n } catch (error) {\n console.error('Failed to query analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/stats\n * 获取统计数据\n */\n async handleStatsGet(request: Request) {\n try {\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n const platform = searchParams.get('platform') || undefined;\n\n // 获取统计数据\n const stats = await service.getAnalyticsStats(startDate, endDate, platform);\n\n return createResponse({\n success: true,\n data: stats,\n });\n } catch (error) {\n console.error('Failed to get analytics stats', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/user/[userId]\n * 获取用户行为分析\n */\n async handleUserBehaviorGet(request: Request, params: { userId: string }) {\n try {\n const { userId } = params;\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n\n // 获取用户行为数据\n const behavior = await service.getUserBehavior(userId, startDate, endDate);\n\n if (!behavior) {\n return createResponse(\n { success: false, message: 'No data found for this user' },\n { status: 404 }\n );\n }\n\n return createResponse({\n success: true,\n data: behavior,\n });\n } catch (error) {\n console.error('Failed to get user behavior', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/session/[sessionId]\n * 获取会话分析\n */\n async handleSessionAnalyticsGet(_request: Request, params: { sessionId: string }) {\n try {\n const { sessionId } = params;\n\n // 获取会话分析数据\n const session = await service.getSessionAnalytics(sessionId);\n\n if (!session) {\n return createResponse({ success: false, message: 'Session not found' }, { status: 404 });\n }\n\n return createResponse({\n success: true,\n data: session,\n });\n } catch (error) {\n console.error('Failed to get session analytics', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * POST /api/analytics/funnel\n * 漏斗分析\n */\n async handleFunnelPost(request: Request) {\n try {\n const body = await request.json();\n const { steps, startDate, endDate } = body;\n\n // 验证数据\n if (!Array.isArray(steps) || steps.length === 0) {\n return createResponse(\n { success: false, message: 'Invalid steps format' },\n { status: 400 }\n );\n }\n\n // 获取漏斗分析数据\n const funnel = await service.getFunnelAnalysis(steps, startDate, endDate);\n\n return createResponse({\n success: true,\n data: funnel,\n });\n } catch (error) {\n console.error('Failed to get funnel analysis', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n };\n}\n"]}
@@ -43,8 +43,8 @@ var analyticsEvents = pgTable(
43
43
  ]
44
44
  );
45
45
  var defaultLogger = {
46
- info: (message, data) => console.log(`[Analytics] ${message}`, data || ""),
47
- error: (message, error) => console.error(`[Analytics] ${message}`, error)
46
+ info: (message, data) => console.log("[Analytics] " + message, data || ""),
47
+ error: (message, error) => console.error("[Analytics] " + message, error)
48
48
  };
49
49
  function createAnalyticsService(db, analyticsEventsTable, logger = defaultLogger) {
50
50
  const analyticsEvents2 = analyticsEventsTable;
@@ -111,8 +111,8 @@ function createAnalyticsService(db, analyticsEventsTable, logger = defaultLogger
111
111
  const events = await db.select().from(analyticsEvents2).where(whereClause).orderBy(orderFn(orderByField)).limit(params.limit || 100).offset(params.offset || 0);
112
112
  const formattedEvents = events.map((event) => ({
113
113
  ...event,
114
- timestamp: event.timestamp.endsWith("Z") ? event.timestamp : `${event.timestamp}Z`,
115
- createdAt: event.createdAt.endsWith("Z") ? event.createdAt : `${event.createdAt}Z`
114
+ timestamp: event.timestamp.endsWith("Z") ? event.timestamp : event.timestamp + "Z",
115
+ createdAt: event.createdAt.endsWith("Z") ? event.createdAt : event.createdAt + "Z"
116
116
  }));
117
117
  return {
118
118
  events: formattedEvents,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/analytics/server/schema.ts","../../../src/analytics/server/service.ts","../../../src/analytics/server/handlers.ts"],"names":["analyticsEvents","sql"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * 埋点系统数据库 Schema\n * Analytics Database Schema\n *\n * 使用方式:\n * 在 backend/drizzle/migrations/schema.ts 中导入并导出:\n * export { analyticsEvents } from '@lyricnote/shared/analytics/server/schema'\n */\n\nimport { pgTable, text, timestamp, integer, jsonb, index } from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\n\n/**\n * 埋点事件表\n */\nexport const analyticsEvents = pgTable(\n 'analytics_events',\n {\n id: text().primaryKey().notNull(),\n eventType: text('event_type').notNull(),\n eventName: text('event_name').notNull(),\n timestamp: timestamp({ precision: 3, mode: 'string' }).notNull(),\n priority: integer().notNull(),\n\n userId: text('user_id'),\n sessionId: text('session_id').notNull(),\n deviceId: text('device_id').notNull(),\n\n pageUrl: text('page_url'),\n pageTitle: text('page_title'),\n referrer: text(),\n\n properties: jsonb(),\n\n platform: text().notNull(),\n appVersion: text('app_version').notNull(),\n sdkVersion: text('sdk_version').notNull(),\n\n createdAt: timestamp({ precision: 3, mode: 'string' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull(),\n },\n (table) => [\n index('analytics_events_user_id_idx').using(\n 'btree',\n table.userId.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_event_type_idx').using(\n 'btree',\n table.eventType.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_platform_idx').using(\n 'btree',\n table.platform.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_timestamp_idx').using('btree', table.timestamp.desc().nullsLast()),\n index('analytics_events_session_id_idx').using(\n 'btree',\n table.sessionId.asc().nullsLast().op('text_ops')\n ),\n ]\n);\n\n/**\n * 创建外键关系(需要在使用时手动添加)\n *\n * 在你的 schema.ts 中添加:\n *\n * foreignKey({\n * columns: [analyticsEvents.userId],\n * foreignColumns: [user.id],\n * name: \"analytics_events_userId_fkey\"\n * }).onUpdate(\"cascade\").onDelete(\"set null\")\n */\n","/**\n * 埋点分析服务\n * Analytics Service\n *\n * 使用方式:\n * import { createAnalyticsService } from '@lyricnote/shared/analytics/server'\n * const service = createAnalyticsService(db, analyticsEvents, logger)\n */\n\nimport { eq, and, gte, lte, sql, desc, asc, count, inArray } from 'drizzle-orm';\n\n// 导出类型\nexport * from './types';\nimport type {\n AnalyticsEvent,\n AnalyticsQueryParams,\n AnalyticsStats,\n UserBehavior,\n SessionAnalytics,\n DatabaseInstance,\n} from './types';\n\n// Logger 接口\ninterface Logger {\n info: (message: string, data?: any) => void;\n error: (message: string, error: Error) => void;\n}\n\n// 默认 logger(如果未提供)\nconst defaultLogger: Logger = {\n info: (message, data) => console.log(`[Analytics] ${message}`, data || ''),\n error: (message, error) => console.error(`[Analytics] ${message}`, error),\n};\n\n/**\n * 创建埋点服务实例\n * @param db - Drizzle 数据库实例\n * @param analyticsEventsTable - analytics_events 表定义\n * @param logger - 日志实例(可选)\n */\nexport function createAnalyticsService(\n db: DatabaseInstance,\n analyticsEventsTable: any,\n logger: Logger = defaultLogger\n) {\n const analyticsEvents = analyticsEventsTable;\n\n return {\n /**\n * 批量插入埋点事件\n */\n async insertAnalyticsEvents(events: AnalyticsEvent[]): Promise<void> {\n try {\n if (events.length === 0) return;\n\n // 使用 onConflictDoNothing 来忽略重复的事件 ID\n // 这样可以避免前端重试或离线队列导致的重复插入\n await db.insert(analyticsEvents).values(events).onConflictDoNothing();\n\n logger.info('Analytics events inserted', { count: events.length });\n } catch (error) {\n logger.error('Failed to insert analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 查询埋点事件\n */\n async queryAnalyticsEvents(\n params: AnalyticsQueryParams\n ): Promise<{ events: AnalyticsEvent[]; total: number }> {\n try {\n const conditions: any[] = [];\n\n // 时间范围过滤\n if (params.startDate) {\n conditions.push(gte(analyticsEvents.timestamp, params.startDate));\n }\n if (params.endDate) {\n conditions.push(lte(analyticsEvents.timestamp, params.endDate));\n }\n\n // 事件类型过滤\n if (params.eventType) {\n conditions.push(eq(analyticsEvents.eventType, params.eventType));\n }\n if (params.eventTypes && params.eventTypes.length > 0) {\n conditions.push(inArray(analyticsEvents.eventType, params.eventTypes));\n }\n\n // 用户过滤\n if (params.userId) {\n conditions.push(eq(analyticsEvents.userId, params.userId));\n }\n\n // 平台过滤\n if (params.platform) {\n conditions.push(eq(analyticsEvents.platform, params.platform));\n }\n if (params.platforms && params.platforms.length > 0) {\n conditions.push(inArray(analyticsEvents.platform, params.platforms));\n }\n\n // 会话过滤\n if (params.sessionId) {\n conditions.push(eq(analyticsEvents.sessionId, params.sessionId));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 排序\n const orderByColumn = params.orderBy || 'timestamp';\n const orderDirection = params.orderDirection || 'desc';\n const orderFn = orderDirection === 'asc' ? asc : desc;\n\n let orderByField;\n switch (orderByColumn) {\n case 'eventType':\n orderByField = analyticsEvents.eventType;\n break;\n case 'platform':\n orderByField = analyticsEvents.platform;\n break;\n default:\n orderByField = analyticsEvents.timestamp;\n }\n\n // 查询数据\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(whereClause)\n .orderBy(orderFn(orderByField))\n .limit(params.limit || 100)\n .offset(params.offset || 0);\n\n // 修复时间戳格式:添加 'Z' 后缀表示 UTC 时间\n const formattedEvents = events.map((event: any) => ({\n ...event,\n timestamp: event.timestamp.endsWith('Z') ? event.timestamp : `${event.timestamp}Z`,\n createdAt: event.createdAt.endsWith('Z') ? event.createdAt : `${event.createdAt}Z`,\n }));\n\n return {\n events: formattedEvents as AnalyticsEvent[],\n total: Number(total),\n };\n } catch (error) {\n logger.error('Failed to query analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取统计数据\n */\n async getAnalyticsStats(\n startDate?: string,\n endDate?: string,\n platform?: string\n ): Promise<AnalyticsStats> {\n try {\n const conditions: any[] = [];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n if (platform) {\n conditions.push(eq(analyticsEvents.platform, platform));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 总事件数\n const [{ totalEvents }] = await db\n .select({ totalEvents: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一用户数\n const [{ uniqueUsers }] = await db\n .select({ uniqueUsers: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一会话数\n const [{ uniqueSessions }] = await db\n .select({ uniqueSessions: sql<number>`COUNT(DISTINCT ${analyticsEvents.sessionId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一设备数\n const [{ uniqueDevices }] = await db\n .select({ uniqueDevices: sql<number>`COUNT(DISTINCT ${analyticsEvents.deviceId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 按事件类型统计\n const eventsByType = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(10);\n\n // 按平台统计\n const eventsByPlatform = await db\n .select({\n platform: analyticsEvents.platform,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform)\n .orderBy(desc(count()));\n\n // 热门页面\n const topPages = await db\n .select({\n pageUrl: analyticsEvents.pageUrl,\n count: count(),\n })\n .from(analyticsEvents)\n .where(and(whereClause, sql`${analyticsEvents.pageUrl} IS NOT NULL`))\n .groupBy(analyticsEvents.pageUrl)\n .orderBy(desc(count()))\n .limit(10);\n\n return {\n totalEvents: Number(totalEvents),\n uniqueUsers: Number(uniqueUsers),\n uniqueSessions: Number(uniqueSessions),\n uniqueDevices: Number(uniqueDevices),\n eventsByType: eventsByType.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n eventsByPlatform: eventsByPlatform.map((e: any) => ({\n platform: e.platform,\n count: Number(e.count),\n })),\n topPages: topPages\n .filter((p: any) => p.pageUrl)\n .map((p: any) => ({\n pageUrl: p.pageUrl!,\n count: Number(p.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get analytics stats', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取用户行为分析\n */\n async getUserBehavior(\n userId: string,\n startDate?: string,\n endDate?: string\n ): Promise<UserBehavior | null> {\n try {\n const conditions: any[] = [eq(analyticsEvents.userId, userId)];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n // 事件总数\n const [{ eventCount }] = await db\n .select({ eventCount: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n if (eventCount === 0) return null;\n\n // 最后活跃时间\n const [{ lastActive }] = await db\n .select({ lastActive: sql<string>`MAX(${analyticsEvents.timestamp})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 使用的平台\n const platformsResult = await db\n .select({ platform: analyticsEvents.platform })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform);\n\n // 热门事件\n const topEvents = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(5);\n\n return {\n userId,\n eventCount: Number(eventCount),\n lastActive,\n platforms: platformsResult.map((p: any) => p.platform),\n topEvents: topEvents.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get user behavior', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取会话分析\n */\n async getSessionAnalytics(sessionId: string): Promise<SessionAnalytics | null> {\n try {\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(eq(analyticsEvents.sessionId, sessionId))\n .orderBy(asc(analyticsEvents.timestamp));\n\n if (events.length === 0) return null;\n\n const firstEvent = events[0];\n const lastEvent = events[events.length - 1];\n\n const startTime = new Date(firstEvent.timestamp).getTime();\n const endTime = new Date(lastEvent.timestamp).getTime();\n const duration = endTime - startTime;\n\n return {\n sessionId,\n userId: firstEvent.userId || undefined,\n deviceId: firstEvent.deviceId,\n platform: firstEvent.platform,\n startTime: firstEvent.timestamp,\n endTime: lastEvent.timestamp,\n duration,\n eventCount: events.length,\n events: events as AnalyticsEvent[],\n };\n } catch (error) {\n logger.error('Failed to get session analytics', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取漏斗分析\n */\n async getFunnelAnalysis(\n steps: string[],\n startDate?: string,\n endDate?: string\n ): Promise<{ step: string; count: number; conversionRate: number }[]> {\n try {\n const results = [];\n let previousCount = 0;\n\n for (let i = 0; i < steps.length; i++) {\n const conditions: any[] = [eq(analyticsEvents.eventType, steps[i])];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n const [{ count: stepCount }] = await db\n .select({ count: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n const conversionRate = i === 0 ? 100 : (Number(stepCount) / previousCount) * 100;\n\n results.push({\n step: steps[i] || 'unknown',\n count: Number(stepCount),\n conversionRate: Math.round(conversionRate * 100) / 100,\n });\n\n previousCount = Number(stepCount);\n }\n\n return results;\n } catch (error) {\n logger.error('Failed to get funnel analysis', error as Error);\n throw error;\n }\n },\n\n /**\n * 删除旧数据(数据清理)\n */\n async cleanOldAnalyticsEvents(daysToKeep: number = 90): Promise<number> {\n try {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n await db\n .delete(analyticsEvents)\n .where(lte(analyticsEvents.timestamp, cutoffDate.toISOString()));\n\n logger.info('Old analytics events cleaned', { daysToKeep });\n\n return 0; // Drizzle doesn't return affected rows count in delete\n } catch (error) {\n logger.error('Failed to clean old analytics events', error as Error);\n throw error;\n }\n },\n };\n}\n","/**\n * 埋点 API 路由处理器\n * Analytics API Route Handlers\n *\n * 使用方式(Next.js):\n * import { createAnalyticsHandlers } from '@lyricnote/shared/analytics/server'\n * const handlers = createAnalyticsHandlers(analyticsService)\n * export const POST = handlers.handleEventsPost\n */\n\nimport type { AnalyticsEvent, AnalyticsQueryParams } from './types';\n\n// 服务接口类型\ninterface AnalyticsService {\n insertAnalyticsEvents: (events: AnalyticsEvent[]) => Promise<void>;\n queryAnalyticsEvents: (\n params: AnalyticsQueryParams\n ) => Promise<{ events: AnalyticsEvent[]; total: number }>;\n getAnalyticsStats: (startDate?: string, endDate?: string, platform?: string) => Promise<any>;\n getUserBehavior: (userId: string, startDate?: string, endDate?: string) => Promise<any>;\n getSessionAnalytics: (sessionId: string) => Promise<any>;\n getFunnelAnalysis: (steps: string[], startDate?: string, endDate?: string) => Promise<any>;\n}\n\n// Request/Response 接口(兼容多种框架)\ninterface Request {\n json: () => Promise<any>;\n url?: string;\n nextUrl?: { searchParams: URLSearchParams };\n}\n\ninterface ResponseInit {\n status?: number;\n headers?: Record<string, string>;\n}\n\n/**\n * 创建埋点 API 处理器\n */\nexport function createAnalyticsHandlers(\n service: AnalyticsService,\n ResponseClass?: any // Next.js NextResponse 或其他响应类\n) {\n // 默认使用标准响应格式\n const createResponse = ResponseClass\n ? (data: any, init?: ResponseInit) => ResponseClass.json(data, init)\n : (data: any, init?: ResponseInit) => ({ body: data, status: init?.status || 200 });\n\n return {\n /**\n * POST /api/analytics/events\n * 处理事件上报\n */\n async handleEventsPost(request: Request) {\n try {\n const body = await request.json();\n const { events } = body;\n\n // 验证数据\n if (!Array.isArray(events)) {\n return createResponse(\n { success: false, message: 'Invalid events format' },\n { status: 400 }\n );\n }\n\n if (events.length === 0) {\n return createResponse(\n { success: true, message: 'No events to process' },\n { status: 200 }\n );\n }\n\n // 验证每个事件的必填字段\n for (const event of events) {\n if (!event.event_id || !event.event_type || !event.event_name) {\n return createResponse(\n { success: false, message: 'Missing required event fields' },\n { status: 400 }\n );\n }\n }\n\n // 转换字段名(前端使用 snake_case,数据库使用 camelCase)\n const formattedEvents = events.map((event) => ({\n id: event.event_id,\n eventType: event.event_type,\n eventName: event.event_name,\n timestamp: new Date(event.timestamp).toISOString(),\n priority: event.priority,\n userId: event.user_id || null,\n sessionId: event.session_id,\n deviceId: event.device_id,\n pageUrl: event.page_url || null,\n pageTitle: event.page_title || null,\n referrer: event.referrer || null,\n properties: event.properties || {},\n platform: event.platform,\n appVersion: event.app_version,\n sdkVersion: event.sdk_version,\n }));\n\n // 插入数据库\n await service.insertAnalyticsEvents(formattedEvents);\n\n return createResponse({\n success: true,\n message: 'Events received successfully',\n count: events.length,\n });\n } catch (error) {\n console.error('Failed to process analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/query\n * 查询埋点事件\n */\n async handleQueryGet(request: Request) {\n try {\n // 解析查询参数\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const params: AnalyticsQueryParams = {\n startDate: searchParams.get('startDate') || undefined,\n endDate: searchParams.get('endDate') || undefined,\n eventType: searchParams.get('eventType') || undefined,\n eventTypes: searchParams.get('eventTypes')?.split(',') || undefined,\n userId: searchParams.get('userId') || undefined,\n platform: searchParams.get('platform') || undefined,\n platforms: searchParams.get('platforms')?.split(',') || undefined,\n sessionId: searchParams.get('sessionId') || undefined,\n limit: parseInt(searchParams.get('limit') || '100'),\n offset: parseInt(searchParams.get('offset') || '0'),\n orderBy: (searchParams.get('orderBy') || 'timestamp') as any,\n orderDirection: (searchParams.get('orderDirection') || 'desc') as any,\n };\n\n // 查询数据\n const result = await service.queryAnalyticsEvents(params);\n\n return createResponse({\n success: true,\n data: result.events,\n total: result.total,\n limit: params.limit,\n offset: params.offset,\n });\n } catch (error) {\n console.error('Failed to query analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/stats\n * 获取统计数据\n */\n async handleStatsGet(request: Request) {\n try {\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n const platform = searchParams.get('platform') || undefined;\n\n // 获取统计数据\n const stats = await service.getAnalyticsStats(startDate, endDate, platform);\n\n return createResponse({\n success: true,\n data: stats,\n });\n } catch (error) {\n console.error('Failed to get analytics stats', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/user/[userId]\n * 获取用户行为分析\n */\n async handleUserBehaviorGet(request: Request, params: { userId: string }) {\n try {\n const { userId } = params;\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n\n // 获取用户行为数据\n const behavior = await service.getUserBehavior(userId, startDate, endDate);\n\n if (!behavior) {\n return createResponse(\n { success: false, message: 'No data found for this user' },\n { status: 404 }\n );\n }\n\n return createResponse({\n success: true,\n data: behavior,\n });\n } catch (error) {\n console.error('Failed to get user behavior', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/session/[sessionId]\n * 获取会话分析\n */\n async handleSessionAnalyticsGet(_request: Request, params: { sessionId: string }) {\n try {\n const { sessionId } = params;\n\n // 获取会话分析数据\n const session = await service.getSessionAnalytics(sessionId);\n\n if (!session) {\n return createResponse({ success: false, message: 'Session not found' }, { status: 404 });\n }\n\n return createResponse({\n success: true,\n data: session,\n });\n } catch (error) {\n console.error('Failed to get session analytics', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * POST /api/analytics/funnel\n * 漏斗分析\n */\n async handleFunnelPost(request: Request) {\n try {\n const body = await request.json();\n const { steps, startDate, endDate } = body;\n\n // 验证数据\n if (!Array.isArray(steps) || steps.length === 0) {\n return createResponse(\n { success: false, message: 'Invalid steps format' },\n { status: 400 }\n );\n }\n\n // 获取漏斗分析数据\n const funnel = await service.getFunnelAnalysis(steps, startDate, endDate);\n\n return createResponse({\n success: true,\n data: funnel,\n });\n } catch (error) {\n console.error('Failed to get funnel analysis', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../../src/analytics/server/schema.ts","../../../src/analytics/server/service.ts","../../../src/analytics/server/handlers.ts"],"names":["analyticsEvents","sql"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * 埋点系统数据库 Schema\n * Analytics Database Schema\n *\n * 使用方式:\n * 在 backend/drizzle/migrations/schema.ts 中导入并导出:\n * export { analyticsEvents } from '@lyricnote/shared/analytics/server/schema'\n */\n\nimport { pgTable, text, timestamp, integer, jsonb, index } from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\n\n/**\n * 埋点事件表\n */\nexport const analyticsEvents = pgTable(\n 'analytics_events',\n {\n id: text().primaryKey().notNull(),\n eventType: text('event_type').notNull(),\n eventName: text('event_name').notNull(),\n timestamp: timestamp({ precision: 3, mode: 'string' }).notNull(),\n priority: integer().notNull(),\n\n userId: text('user_id'),\n sessionId: text('session_id').notNull(),\n deviceId: text('device_id').notNull(),\n\n pageUrl: text('page_url'),\n pageTitle: text('page_title'),\n referrer: text(),\n\n properties: jsonb(),\n\n platform: text().notNull(),\n appVersion: text('app_version').notNull(),\n sdkVersion: text('sdk_version').notNull(),\n\n createdAt: timestamp({ precision: 3, mode: 'string' })\n .default(sql`CURRENT_TIMESTAMP`)\n .notNull(),\n },\n (table) => [\n index('analytics_events_user_id_idx').using(\n 'btree',\n table.userId.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_event_type_idx').using(\n 'btree',\n table.eventType.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_platform_idx').using(\n 'btree',\n table.platform.asc().nullsLast().op('text_ops')\n ),\n index('analytics_events_timestamp_idx').using('btree', table.timestamp.desc().nullsLast()),\n index('analytics_events_session_id_idx').using(\n 'btree',\n table.sessionId.asc().nullsLast().op('text_ops')\n ),\n ]\n);\n\n/**\n * 创建外键关系(需要在使用时手动添加)\n *\n * 在你的 schema.ts 中添加:\n *\n * foreignKey({\n * columns: [analyticsEvents.userId],\n * foreignColumns: [user.id],\n * name: \"analytics_events_userId_fkey\"\n * }).onUpdate(\"cascade\").onDelete(\"set null\")\n */\n","/**\n * 埋点分析服务\n * Analytics Service\n *\n * 使用方式:\n * import { createAnalyticsService } from '@lyricnote/shared/analytics/server'\n * const service = createAnalyticsService(db, analyticsEvents, logger)\n */\n\nimport { eq, and, gte, lte, sql, desc, asc, count, inArray } from 'drizzle-orm';\n\n// 导出类型\nexport * from './types';\nimport type {\n AnalyticsEvent,\n AnalyticsQueryParams,\n AnalyticsStats,\n UserBehavior,\n SessionAnalytics,\n DatabaseInstance,\n} from './types';\n\n// Logger 接口\ninterface Logger {\n info: (message: string, data?: any) => void;\n error: (message: string, error: Error) => void;\n}\n\n// 默认 logger(如果未提供)\nconst defaultLogger: Logger = {\n info: (message, data) => console.log('[Analytics] ' + (message), data || ''),\n error: (message, error) => console.error('[Analytics] ' + (message), error),\n};\n\n/**\n * 创建埋点服务实例\n * @param db - Drizzle 数据库实例\n * @param analyticsEventsTable - analytics_events 表定义\n * @param logger - 日志实例(可选)\n */\nexport function createAnalyticsService(\n db: DatabaseInstance,\n analyticsEventsTable: any,\n logger: Logger = defaultLogger\n) {\n const analyticsEvents = analyticsEventsTable;\n\n return {\n /**\n * 批量插入埋点事件\n */\n async insertAnalyticsEvents(events: AnalyticsEvent[]): Promise<void> {\n try {\n if (events.length === 0) return;\n\n // 使用 onConflictDoNothing 来忽略重复的事件 ID\n // 这样可以避免前端重试或离线队列导致的重复插入\n await db.insert(analyticsEvents).values(events).onConflictDoNothing();\n\n logger.info('Analytics events inserted', { count: events.length });\n } catch (error) {\n logger.error('Failed to insert analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 查询埋点事件\n */\n async queryAnalyticsEvents(\n params: AnalyticsQueryParams\n ): Promise<{ events: AnalyticsEvent[]; total: number }> {\n try {\n const conditions: any[] = [];\n\n // 时间范围过滤\n if (params.startDate) {\n conditions.push(gte(analyticsEvents.timestamp, params.startDate));\n }\n if (params.endDate) {\n conditions.push(lte(analyticsEvents.timestamp, params.endDate));\n }\n\n // 事件类型过滤\n if (params.eventType) {\n conditions.push(eq(analyticsEvents.eventType, params.eventType));\n }\n if (params.eventTypes && params.eventTypes.length > 0) {\n conditions.push(inArray(analyticsEvents.eventType, params.eventTypes));\n }\n\n // 用户过滤\n if (params.userId) {\n conditions.push(eq(analyticsEvents.userId, params.userId));\n }\n\n // 平台过滤\n if (params.platform) {\n conditions.push(eq(analyticsEvents.platform, params.platform));\n }\n if (params.platforms && params.platforms.length > 0) {\n conditions.push(inArray(analyticsEvents.platform, params.platforms));\n }\n\n // 会话过滤\n if (params.sessionId) {\n conditions.push(eq(analyticsEvents.sessionId, params.sessionId));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 查询总数\n const [{ total }] = await db\n .select({ total: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 排序\n const orderByColumn = params.orderBy || 'timestamp';\n const orderDirection = params.orderDirection || 'desc';\n const orderFn = orderDirection === 'asc' ? asc : desc;\n\n let orderByField;\n switch (orderByColumn) {\n case 'eventType':\n orderByField = analyticsEvents.eventType;\n break;\n case 'platform':\n orderByField = analyticsEvents.platform;\n break;\n default:\n orderByField = analyticsEvents.timestamp;\n }\n\n // 查询数据\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(whereClause)\n .orderBy(orderFn(orderByField))\n .limit(params.limit || 100)\n .offset(params.offset || 0);\n\n // 修复时间戳格式:添加 'Z' 后缀表示 UTC 时间\n const formattedEvents = events.map((event: any) => ({\n ...event,\n timestamp: event.timestamp.endsWith('Z') ? event.timestamp : (event.timestamp) + 'Z',\n createdAt: event.createdAt.endsWith('Z') ? event.createdAt : (event.createdAt) + 'Z',\n }));\n\n return {\n events: formattedEvents as AnalyticsEvent[],\n total: Number(total),\n };\n } catch (error) {\n logger.error('Failed to query analytics events', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取统计数据\n */\n async getAnalyticsStats(\n startDate?: string,\n endDate?: string,\n platform?: string\n ): Promise<AnalyticsStats> {\n try {\n const conditions: any[] = [];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n if (platform) {\n conditions.push(eq(analyticsEvents.platform, platform));\n }\n\n const whereClause = conditions.length > 0 ? and(...conditions) : undefined;\n\n // 总事件数\n const [{ totalEvents }] = await db\n .select({ totalEvents: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一用户数\n const [{ uniqueUsers }] = await db\n .select({ uniqueUsers: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一会话数\n const [{ uniqueSessions }] = await db\n .select({ uniqueSessions: sql<number>`COUNT(DISTINCT ${analyticsEvents.sessionId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 唯一设备数\n const [{ uniqueDevices }] = await db\n .select({ uniqueDevices: sql<number>`COUNT(DISTINCT ${analyticsEvents.deviceId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 按事件类型统计\n const eventsByType = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(10);\n\n // 按平台统计\n const eventsByPlatform = await db\n .select({\n platform: analyticsEvents.platform,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform)\n .orderBy(desc(count()));\n\n // 热门页面\n const topPages = await db\n .select({\n pageUrl: analyticsEvents.pageUrl,\n count: count(),\n })\n .from(analyticsEvents)\n .where(and(whereClause, sql`${analyticsEvents.pageUrl} IS NOT NULL`))\n .groupBy(analyticsEvents.pageUrl)\n .orderBy(desc(count()))\n .limit(10);\n\n return {\n totalEvents: Number(totalEvents),\n uniqueUsers: Number(uniqueUsers),\n uniqueSessions: Number(uniqueSessions),\n uniqueDevices: Number(uniqueDevices),\n eventsByType: eventsByType.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n eventsByPlatform: eventsByPlatform.map((e: any) => ({\n platform: e.platform,\n count: Number(e.count),\n })),\n topPages: topPages\n .filter((p: any) => p.pageUrl)\n .map((p: any) => ({\n pageUrl: p.pageUrl!,\n count: Number(p.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get analytics stats', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取用户行为分析\n */\n async getUserBehavior(\n userId: string,\n startDate?: string,\n endDate?: string\n ): Promise<UserBehavior | null> {\n try {\n const conditions: any[] = [eq(analyticsEvents.userId, userId)];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n // 事件总数\n const [{ eventCount }] = await db\n .select({ eventCount: count() })\n .from(analyticsEvents)\n .where(whereClause);\n\n if (eventCount === 0) return null;\n\n // 最后活跃时间\n const [{ lastActive }] = await db\n .select({ lastActive: sql<string>`MAX(${analyticsEvents.timestamp})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n // 使用的平台\n const platformsResult = await db\n .select({ platform: analyticsEvents.platform })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.platform);\n\n // 热门事件\n const topEvents = await db\n .select({\n eventType: analyticsEvents.eventType,\n count: count(),\n })\n .from(analyticsEvents)\n .where(whereClause)\n .groupBy(analyticsEvents.eventType)\n .orderBy(desc(count()))\n .limit(5);\n\n return {\n userId,\n eventCount: Number(eventCount),\n lastActive,\n platforms: platformsResult.map((p: any) => p.platform),\n topEvents: topEvents.map((e: any) => ({\n eventType: e.eventType,\n count: Number(e.count),\n })),\n };\n } catch (error) {\n logger.error('Failed to get user behavior', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取会话分析\n */\n async getSessionAnalytics(sessionId: string): Promise<SessionAnalytics | null> {\n try {\n const events = await db\n .select()\n .from(analyticsEvents)\n .where(eq(analyticsEvents.sessionId, sessionId))\n .orderBy(asc(analyticsEvents.timestamp));\n\n if (events.length === 0) return null;\n\n const firstEvent = events[0];\n const lastEvent = events[events.length - 1];\n\n const startTime = new Date(firstEvent.timestamp).getTime();\n const endTime = new Date(lastEvent.timestamp).getTime();\n const duration = endTime - startTime;\n\n return {\n sessionId,\n userId: firstEvent.userId || undefined,\n deviceId: firstEvent.deviceId,\n platform: firstEvent.platform,\n startTime: firstEvent.timestamp,\n endTime: lastEvent.timestamp,\n duration,\n eventCount: events.length,\n events: events as AnalyticsEvent[],\n };\n } catch (error) {\n logger.error('Failed to get session analytics', error as Error);\n throw error;\n }\n },\n\n /**\n * 获取漏斗分析\n */\n async getFunnelAnalysis(\n steps: string[],\n startDate?: string,\n endDate?: string\n ): Promise<{ step: string; count: number; conversionRate: number }[]> {\n try {\n const results = [];\n let previousCount = 0;\n\n for (let i = 0; i < steps.length; i++) {\n const conditions: any[] = [eq(analyticsEvents.eventType, steps[i])];\n\n if (startDate) {\n conditions.push(gte(analyticsEvents.timestamp, startDate));\n }\n if (endDate) {\n conditions.push(lte(analyticsEvents.timestamp, endDate));\n }\n\n const whereClause = and(...conditions);\n\n const [{ count: stepCount }] = await db\n .select({ count: sql<number>`COUNT(DISTINCT ${analyticsEvents.userId})` })\n .from(analyticsEvents)\n .where(whereClause);\n\n const conversionRate = i === 0 ? 100 : (Number(stepCount) / previousCount) * 100;\n\n results.push({\n step: steps[i] || 'unknown',\n count: Number(stepCount),\n conversionRate: Math.round(conversionRate * 100) / 100,\n });\n\n previousCount = Number(stepCount);\n }\n\n return results;\n } catch (error) {\n logger.error('Failed to get funnel analysis', error as Error);\n throw error;\n }\n },\n\n /**\n * 删除旧数据(数据清理)\n */\n async cleanOldAnalyticsEvents(daysToKeep: number = 90): Promise<number> {\n try {\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);\n\n await db\n .delete(analyticsEvents)\n .where(lte(analyticsEvents.timestamp, cutoffDate.toISOString()));\n\n logger.info('Old analytics events cleaned', { daysToKeep });\n\n return 0; // Drizzle doesn't return affected rows count in delete\n } catch (error) {\n logger.error('Failed to clean old analytics events', error as Error);\n throw error;\n }\n },\n };\n}\n","/**\n * 埋点 API 路由处理器\n * Analytics API Route Handlers\n *\n * 使用方式(Next.js):\n * import { createAnalyticsHandlers } from '@lyricnote/shared/analytics/server'\n * const handlers = createAnalyticsHandlers(analyticsService)\n * export const POST = handlers.handleEventsPost\n */\n\nimport type { AnalyticsEvent, AnalyticsQueryParams } from './types';\n\n// 服务接口类型\ninterface AnalyticsService {\n insertAnalyticsEvents: (events: AnalyticsEvent[]) => Promise<void>;\n queryAnalyticsEvents: (\n params: AnalyticsQueryParams\n ) => Promise<{ events: AnalyticsEvent[]; total: number }>;\n getAnalyticsStats: (startDate?: string, endDate?: string, platform?: string) => Promise<any>;\n getUserBehavior: (userId: string, startDate?: string, endDate?: string) => Promise<any>;\n getSessionAnalytics: (sessionId: string) => Promise<any>;\n getFunnelAnalysis: (steps: string[], startDate?: string, endDate?: string) => Promise<any>;\n}\n\n// Request/Response 接口(兼容多种框架)\ninterface Request {\n json: () => Promise<any>;\n url?: string;\n nextUrl?: { searchParams: URLSearchParams };\n}\n\ninterface ResponseInit {\n status?: number;\n headers?: Record<string, string>;\n}\n\n/**\n * 创建埋点 API 处理器\n */\nexport function createAnalyticsHandlers(\n service: AnalyticsService,\n ResponseClass?: any // Next.js NextResponse 或其他响应类\n) {\n // 默认使用标准响应格式\n const createResponse = ResponseClass\n ? (data: any, init?: ResponseInit) => ResponseClass.json(data, init)\n : (data: any, init?: ResponseInit) => ({ body: data, status: init?.status || 200 });\n\n return {\n /**\n * POST /api/analytics/events\n * 处理事件上报\n */\n async handleEventsPost(request: Request) {\n try {\n const body = await request.json();\n const { events } = body;\n\n // 验证数据\n if (!Array.isArray(events)) {\n return createResponse(\n { success: false, message: 'Invalid events format' },\n { status: 400 }\n );\n }\n\n if (events.length === 0) {\n return createResponse(\n { success: true, message: 'No events to process' },\n { status: 200 }\n );\n }\n\n // 验证每个事件的必填字段\n for (const event of events) {\n if (!event.event_id || !event.event_type || !event.event_name) {\n return createResponse(\n { success: false, message: 'Missing required event fields' },\n { status: 400 }\n );\n }\n }\n\n // 转换字段名(前端使用 snake_case,数据库使用 camelCase)\n const formattedEvents = events.map((event) => ({\n id: event.event_id,\n eventType: event.event_type,\n eventName: event.event_name,\n timestamp: new Date(event.timestamp).toISOString(),\n priority: event.priority,\n userId: event.user_id || null,\n sessionId: event.session_id,\n deviceId: event.device_id,\n pageUrl: event.page_url || null,\n pageTitle: event.page_title || null,\n referrer: event.referrer || null,\n properties: event.properties || {},\n platform: event.platform,\n appVersion: event.app_version,\n sdkVersion: event.sdk_version,\n }));\n\n // 插入数据库\n await service.insertAnalyticsEvents(formattedEvents);\n\n return createResponse({\n success: true,\n message: 'Events received successfully',\n count: events.length,\n });\n } catch (error) {\n console.error('Failed to process analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/query\n * 查询埋点事件\n */\n async handleQueryGet(request: Request) {\n try {\n // 解析查询参数\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const params: AnalyticsQueryParams = {\n startDate: searchParams.get('startDate') || undefined,\n endDate: searchParams.get('endDate') || undefined,\n eventType: searchParams.get('eventType') || undefined,\n eventTypes: searchParams.get('eventTypes')?.split(',') || undefined,\n userId: searchParams.get('userId') || undefined,\n platform: searchParams.get('platform') || undefined,\n platforms: searchParams.get('platforms')?.split(',') || undefined,\n sessionId: searchParams.get('sessionId') || undefined,\n limit: parseInt(searchParams.get('limit') || '100'),\n offset: parseInt(searchParams.get('offset') || '0'),\n orderBy: (searchParams.get('orderBy') || 'timestamp') as any,\n orderDirection: (searchParams.get('orderDirection') || 'desc') as any,\n };\n\n // 查询数据\n const result = await service.queryAnalyticsEvents(params);\n\n return createResponse({\n success: true,\n data: result.events,\n total: result.total,\n limit: params.limit,\n offset: params.offset,\n });\n } catch (error) {\n console.error('Failed to query analytics events', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/stats\n * 获取统计数据\n */\n async handleStatsGet(request: Request) {\n try {\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n const platform = searchParams.get('platform') || undefined;\n\n // 获取统计数据\n const stats = await service.getAnalyticsStats(startDate, endDate, platform);\n\n return createResponse({\n success: true,\n data: stats,\n });\n } catch (error) {\n console.error('Failed to get analytics stats', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/user/[userId]\n * 获取用户行为分析\n */\n async handleUserBehaviorGet(request: Request, params: { userId: string }) {\n try {\n const { userId } = params;\n const searchParams =\n request.nextUrl?.searchParams || new URLSearchParams(request.url?.split('?')[1]);\n\n const startDate = searchParams.get('startDate') || undefined;\n const endDate = searchParams.get('endDate') || undefined;\n\n // 获取用户行为数据\n const behavior = await service.getUserBehavior(userId, startDate, endDate);\n\n if (!behavior) {\n return createResponse(\n { success: false, message: 'No data found for this user' },\n { status: 404 }\n );\n }\n\n return createResponse({\n success: true,\n data: behavior,\n });\n } catch (error) {\n console.error('Failed to get user behavior', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * GET /api/analytics/session/[sessionId]\n * 获取会话分析\n */\n async handleSessionAnalyticsGet(_request: Request, params: { sessionId: string }) {\n try {\n const { sessionId } = params;\n\n // 获取会话分析数据\n const session = await service.getSessionAnalytics(sessionId);\n\n if (!session) {\n return createResponse({ success: false, message: 'Session not found' }, { status: 404 });\n }\n\n return createResponse({\n success: true,\n data: session,\n });\n } catch (error) {\n console.error('Failed to get session analytics', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n\n /**\n * POST /api/analytics/funnel\n * 漏斗分析\n */\n async handleFunnelPost(request: Request) {\n try {\n const body = await request.json();\n const { steps, startDate, endDate } = body;\n\n // 验证数据\n if (!Array.isArray(steps) || steps.length === 0) {\n return createResponse(\n { success: false, message: 'Invalid steps format' },\n { status: 400 }\n );\n }\n\n // 获取漏斗分析数据\n const funnel = await service.getFunnelAnalysis(steps, startDate, endDate);\n\n return createResponse({\n success: true,\n data: funnel,\n });\n } catch (error) {\n console.error('Failed to get funnel analysis', error);\n\n return createResponse(\n {\n success: false,\n message: 'Internal server error',\n error: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,\n },\n { status: 500 }\n );\n }\n },\n };\n}\n"]}
package/dist/api/index.js CHANGED
@@ -17,9 +17,9 @@ var DEFAULT_API_ROUTES = {
17
17
  },
18
18
  users: {
19
19
  list: "/users",
20
- detail: (id) => `/users/${id}`,
21
- update: (id) => `/users/${id}`,
22
- delete: (id) => `/users/${id}`
20
+ detail: (id) => "/users/" + id,
21
+ update: (id) => "/users/" + id,
22
+ delete: (id) => "/users/" + id
23
23
  }
24
24
  };
25
25
 
@@ -124,11 +124,11 @@ var BaseApiClient = class {
124
124
  ...config.headers || {}
125
125
  };
126
126
  if (this.token) {
127
- headers["Authorization"] = `Bearer ${this.token}`;
127
+ headers["Authorization"] = "Bearer " + this.token;
128
128
  }
129
129
  const response = await this.request.request({
130
130
  ...config,
131
- url: `${this.baseUrl}${config.url}`,
131
+ url: this.baseUrl + config.url,
132
132
  headers
133
133
  });
134
134
  return response;