@goscribe/server 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/dist/context.d.ts +14 -1
  2. package/dist/context.js +23 -2
  3. package/dist/generated/prisma/client.d.ts +224 -0
  4. package/dist/generated/prisma/client.js +34 -0
  5. package/dist/generated/prisma/commonInputTypes.d.ts +941 -0
  6. package/dist/generated/prisma/commonInputTypes.js +10 -0
  7. package/dist/generated/prisma/enums.d.ts +67 -0
  8. package/dist/generated/prisma/enums.js +66 -0
  9. package/dist/generated/prisma/internal/class.d.ts +539 -0
  10. package/dist/generated/prisma/internal/class.js +49 -0
  11. package/dist/generated/prisma/internal/prismaNamespace.d.ts +3924 -0
  12. package/dist/generated/prisma/internal/prismaNamespace.js +557 -0
  13. package/dist/generated/prisma/models/ActivityLog.d.ts +1847 -0
  14. package/dist/generated/prisma/models/ActivityLog.js +1 -0
  15. package/dist/generated/prisma/models/Artifact.d.ts +2345 -0
  16. package/dist/generated/prisma/models/Artifact.js +1 -0
  17. package/dist/generated/prisma/models/ArtifactVersion.d.ts +1550 -0
  18. package/dist/generated/prisma/models/ArtifactVersion.js +1 -0
  19. package/dist/generated/prisma/models/Channel.d.ts +1257 -0
  20. package/dist/generated/prisma/models/Channel.js +1 -0
  21. package/dist/generated/prisma/models/Chat.d.ts +1339 -0
  22. package/dist/generated/prisma/models/Chat.js +1 -0
  23. package/dist/generated/prisma/models/CopilotConversation.d.ts +1450 -0
  24. package/dist/generated/prisma/models/CopilotConversation.js +1 -0
  25. package/dist/generated/prisma/models/CopilotMessage.d.ts +1179 -0
  26. package/dist/generated/prisma/models/CopilotMessage.js +1 -0
  27. package/dist/generated/prisma/models/FileAsset.d.ts +1832 -0
  28. package/dist/generated/prisma/models/FileAsset.js +1 -0
  29. package/dist/generated/prisma/models/Flashcard.d.ts +1460 -0
  30. package/dist/generated/prisma/models/Flashcard.js +1 -0
  31. package/dist/generated/prisma/models/FlashcardProgress.d.ts +1782 -0
  32. package/dist/generated/prisma/models/FlashcardProgress.js +1 -0
  33. package/dist/generated/prisma/models/Folder.d.ts +1685 -0
  34. package/dist/generated/prisma/models/Folder.js +1 -0
  35. package/dist/generated/prisma/models/IdempotencyRecord.d.ts +1319 -0
  36. package/dist/generated/prisma/models/IdempotencyRecord.js +1 -0
  37. package/dist/generated/prisma/models/Invoice.d.ts +1586 -0
  38. package/dist/generated/prisma/models/Invoice.js +1 -0
  39. package/dist/generated/prisma/models/KnowledgeBase.d.ts +1721 -0
  40. package/dist/generated/prisma/models/KnowledgeBase.js +1 -0
  41. package/dist/generated/prisma/models/KnowledgeBaseChunk.d.ts +1333 -0
  42. package/dist/generated/prisma/models/KnowledgeBaseChunk.js +1 -0
  43. package/dist/generated/prisma/models/KnowledgeBaseDocument.d.ts +1695 -0
  44. package/dist/generated/prisma/models/KnowledgeBaseDocument.js +1 -0
  45. package/dist/generated/prisma/models/Notification.d.ts +1992 -0
  46. package/dist/generated/prisma/models/Notification.js +1 -0
  47. package/dist/generated/prisma/models/PasswordResetToken.d.ts +1210 -0
  48. package/dist/generated/prisma/models/PasswordResetToken.js +1 -0
  49. package/dist/generated/prisma/models/Plan.d.ts +1431 -0
  50. package/dist/generated/prisma/models/Plan.js +1 -0
  51. package/dist/generated/prisma/models/PlanLimit.d.ts +1328 -0
  52. package/dist/generated/prisma/models/PlanLimit.js +1 -0
  53. package/dist/generated/prisma/models/PodcastSegment.d.ts +1564 -0
  54. package/dist/generated/prisma/models/PodcastSegment.js +1 -0
  55. package/dist/generated/prisma/models/ResourcePrice.d.ts +1008 -0
  56. package/dist/generated/prisma/models/ResourcePrice.js +1 -0
  57. package/dist/generated/prisma/models/Role.d.ts +1065 -0
  58. package/dist/generated/prisma/models/Role.js +1 -0
  59. package/dist/generated/prisma/models/Session.d.ts +1105 -0
  60. package/dist/generated/prisma/models/Session.js +1 -0
  61. package/dist/generated/prisma/models/StripeEvent.d.ts +1081 -0
  62. package/dist/generated/prisma/models/StripeEvent.js +1 -0
  63. package/dist/generated/prisma/models/StudyGuideComment.d.ts +1321 -0
  64. package/dist/generated/prisma/models/StudyGuideComment.js +1 -0
  65. package/dist/generated/prisma/models/StudyGuideHighlight.d.ts +1629 -0
  66. package/dist/generated/prisma/models/StudyGuideHighlight.js +1 -0
  67. package/dist/generated/prisma/models/Subscription.d.ts +1677 -0
  68. package/dist/generated/prisma/models/Subscription.js +1 -0
  69. package/dist/generated/prisma/models/User.d.ts +7559 -0
  70. package/dist/generated/prisma/models/User.js +1 -0
  71. package/dist/generated/prisma/models/UserCredit.d.ts +1249 -0
  72. package/dist/generated/prisma/models/UserCredit.js +1 -0
  73. package/dist/generated/prisma/models/VerificationToken.d.ts +946 -0
  74. package/dist/generated/prisma/models/VerificationToken.js +1 -0
  75. package/dist/generated/prisma/models/WorksheetPreset.d.ts +1433 -0
  76. package/dist/generated/prisma/models/WorksheetPreset.js +1 -0
  77. package/dist/generated/prisma/models/WorksheetQuestion.d.ts +1491 -0
  78. package/dist/generated/prisma/models/WorksheetQuestion.js +1 -0
  79. package/dist/generated/prisma/models/WorksheetQuestionProgress.d.ts +1620 -0
  80. package/dist/generated/prisma/models/WorksheetQuestionProgress.js +1 -0
  81. package/dist/generated/prisma/models/Workspace.d.ts +3620 -0
  82. package/dist/generated/prisma/models/Workspace.js +1 -0
  83. package/dist/generated/prisma/models/WorkspaceInvitation.d.ts +1490 -0
  84. package/dist/generated/prisma/models/WorkspaceInvitation.js +1 -0
  85. package/dist/generated/prisma/models/WorkspaceKnowledgeBase.d.ts +1410 -0
  86. package/dist/generated/prisma/models/WorkspaceKnowledgeBase.js +1 -0
  87. package/dist/generated/prisma/models/WorkspaceMember.d.ts +1326 -0
  88. package/dist/generated/prisma/models/WorkspaceMember.js +1 -0
  89. package/dist/generated/prisma/models.d.ts +39 -0
  90. package/dist/generated/prisma/models.js +1 -0
  91. package/dist/lib/ai/index.d.ts +3 -2
  92. package/dist/lib/ai/index.js +3 -2
  93. package/dist/lib/ai/llm-client.d.ts +1 -0
  94. package/dist/lib/ai/llm-client.js +17 -0
  95. package/dist/routers/_app.d.ts +40 -80
  96. package/dist/routers/auth.js +1 -1
  97. package/dist/routers/flashcards.d.ts +12 -1
  98. package/dist/routers/payment.d.ts +1 -12
  99. package/dist/routers/workspace.d.ts +27 -67
  100. package/dist/routers/workspace.js +1 -0
  101. package/dist/services/billing/payment.service.d.ts +1 -12
  102. package/dist/services/billing/payment.service.js +3 -6
  103. package/dist/services/billing/usage.service.d.ts +30 -10
  104. package/dist/services/billing/usage.service.js +87 -15
  105. package/dist/services/content/copilot.service.js +15 -29
  106. package/dist/services/content/flashcard-progress.service.js +9 -9
  107. package/dist/services/content/flashcard.service.d.ts +45 -1
  108. package/dist/services/content/flashcard.service.js +81 -68
  109. package/dist/services/content/media-analysis.service.js +27 -27
  110. package/dist/services/content/worksheet-generation.service.test.js +2 -2
  111. package/dist/services/workspace/workspace.service.d.ts +23 -67
  112. package/dist/services/workspace/workspace.service.js +69 -62
  113. package/dist/src/context.d.ts +27 -0
  114. package/dist/src/context.js +33 -0
  115. package/dist/src/index.d.ts +3 -0
  116. package/dist/src/index.js +1 -0
  117. package/dist/src/lib/ai/config.d.ts +20 -0
  118. package/dist/src/lib/ai/config.js +31 -0
  119. package/dist/src/lib/ai/embedding-client.d.ts +8 -0
  120. package/dist/src/lib/ai/embedding-client.js +30 -0
  121. package/dist/src/lib/ai/index.d.ts +48 -0
  122. package/dist/src/lib/ai/index.js +29 -0
  123. package/dist/src/lib/ai/inference-backend/client.d.ts +28 -0
  124. package/dist/src/lib/ai/inference-backend/client.js +301 -0
  125. package/dist/src/lib/ai/inference-backend/mocks.d.ts +12 -0
  126. package/dist/src/lib/ai/inference-backend/mocks.js +133 -0
  127. package/dist/src/lib/ai/inference-backend/types.d.ts +44 -0
  128. package/dist/src/lib/ai/inference-backend/types.js +1 -0
  129. package/dist/src/lib/ai/json-parse.d.ts +2 -0
  130. package/dist/src/lib/ai/json-parse.js +34 -0
  131. package/dist/src/lib/ai/llm-client.d.ts +7 -0
  132. package/dist/src/lib/ai/llm-client.js +36 -0
  133. package/dist/src/lib/ai/mock.d.ts +2 -0
  134. package/dist/src/lib/ai/mock.js +10 -0
  135. package/dist/src/lib/ai/types.d.ts +9 -0
  136. package/dist/src/lib/ai/types.js +1 -0
  137. package/dist/src/lib/auth.d.ts +36 -0
  138. package/dist/src/lib/auth.js +117 -0
  139. package/dist/src/lib/chunking.d.ts +19 -0
  140. package/dist/src/lib/chunking.js +47 -0
  141. package/dist/src/lib/constants.d.ts +13 -0
  142. package/dist/src/lib/constants.js +12 -0
  143. package/dist/src/lib/curated-kb-seed.d.ts +12 -0
  144. package/dist/src/lib/curated-kb-seed.js +155 -0
  145. package/dist/src/lib/email.d.ts +11 -0
  146. package/dist/src/lib/email.js +152 -0
  147. package/dist/src/lib/embeddings.d.ts +2 -0
  148. package/dist/src/lib/embeddings.js +1 -0
  149. package/dist/src/lib/ensure-curated-kb-catalog.d.ts +6 -0
  150. package/dist/src/lib/ensure-curated-kb-catalog.js +53 -0
  151. package/dist/src/lib/env.d.ts +41 -0
  152. package/dist/src/lib/env.js +57 -0
  153. package/dist/src/lib/errors.d.ts +33 -0
  154. package/dist/src/lib/errors.js +78 -0
  155. package/dist/src/lib/file.d.ts +0 -0
  156. package/dist/src/lib/file.js +1 -0
  157. package/dist/src/lib/inference.d.ts +1 -0
  158. package/dist/src/lib/inference.js +1 -0
  159. package/dist/src/lib/kb-meta.d.ts +8 -0
  160. package/dist/src/lib/kb-meta.js +77 -0
  161. package/dist/src/lib/logger.d.ts +62 -0
  162. package/dist/src/lib/logger.js +364 -0
  163. package/dist/src/lib/pdf.d.ts +11 -0
  164. package/dist/src/lib/pdf.js +11 -0
  165. package/dist/src/lib/prisma.d.ts +3 -0
  166. package/dist/src/lib/prisma.js +15 -0
  167. package/dist/src/lib/pusher.d.ts +38 -0
  168. package/dist/src/lib/pusher.js +170 -0
  169. package/dist/src/lib/retry.d.ts +15 -0
  170. package/dist/src/lib/retry.js +37 -0
  171. package/dist/src/lib/storage.d.ts +11 -0
  172. package/dist/src/lib/storage.js +71 -0
  173. package/dist/src/lib/stripe.d.ts +10 -0
  174. package/dist/src/lib/stripe.js +36 -0
  175. package/dist/src/lib/validation.d.ts +51 -0
  176. package/dist/src/lib/validation.js +64 -0
  177. package/dist/src/lib/workspace-kb.d.ts +5 -0
  178. package/dist/src/lib/workspace-kb.js +7 -0
  179. package/dist/src/repositories/artifact.repository.d.ts +64 -0
  180. package/dist/src/repositories/artifact.repository.js +40 -0
  181. package/dist/src/repositories/base.repository.d.ts +14 -0
  182. package/dist/src/repositories/base.repository.js +14 -0
  183. package/dist/src/repositories/invitation.repository.d.ts +104 -0
  184. package/dist/src/repositories/invitation.repository.js +44 -0
  185. package/dist/src/repositories/notification.repository.d.ts +76 -0
  186. package/dist/src/repositories/notification.repository.js +44 -0
  187. package/dist/src/repositories/user.repository.d.ts +84 -0
  188. package/dist/src/repositories/user.repository.js +37 -0
  189. package/dist/src/repositories/workspace-member.repository.d.ts +35 -0
  190. package/dist/src/repositories/workspace-member.repository.js +31 -0
  191. package/dist/src/repositories/workspace.repository.d.ts +101 -0
  192. package/dist/src/repositories/workspace.repository.js +79 -0
  193. package/dist/src/routers/_app.d.ts +3464 -0
  194. package/dist/src/routers/_app.js +36 -0
  195. package/dist/src/routers/admin.d.ts +358 -0
  196. package/dist/src/routers/admin.js +105 -0
  197. package/dist/src/routers/annotations.d.ts +219 -0
  198. package/dist/src/routers/annotations.js +29 -0
  199. package/dist/src/routers/artifactVersions.d.ts +65 -0
  200. package/dist/src/routers/artifactVersions.js +14 -0
  201. package/dist/src/routers/auth.d.ts +161 -0
  202. package/dist/src/routers/auth.js +97 -0
  203. package/dist/src/routers/chat.d.ts +170 -0
  204. package/dist/src/routers/chat.js +32 -0
  205. package/dist/src/routers/copilot.d.ts +200 -0
  206. package/dist/src/routers/copilot.js +52 -0
  207. package/dist/src/routers/flashcards.d.ts +336 -0
  208. package/dist/src/routers/flashcards.js +93 -0
  209. package/dist/src/routers/knowledgeBase.d.ts +421 -0
  210. package/dist/src/routers/knowledgeBase.js +118 -0
  211. package/dist/src/routers/members.d.ts +169 -0
  212. package/dist/src/routers/members.js +47 -0
  213. package/dist/src/routers/notifications.d.ts +99 -0
  214. package/dist/src/routers/notifications.js +25 -0
  215. package/dist/src/routers/payment.d.ts +80 -0
  216. package/dist/src/routers/payment.js +21 -0
  217. package/dist/src/routers/podcast.d.ts +287 -0
  218. package/dist/src/routers/podcast.js +34 -0
  219. package/dist/src/routers/studyguide.d.ts +36 -0
  220. package/dist/src/routers/studyguide.js +8 -0
  221. package/dist/src/routers/worksheets.d.ts +429 -0
  222. package/dist/src/routers/worksheets.js +139 -0
  223. package/dist/src/routers/workspace.d.ts +563 -0
  224. package/dist/src/routers/workspace.js +104 -0
  225. package/dist/src/scripts/purge-deleted-users.d.ts +1 -0
  226. package/dist/src/scripts/purge-deleted-users.js +148 -0
  227. package/dist/src/server.d.ts +1 -0
  228. package/dist/src/server.js +190 -0
  229. package/dist/src/services/activity/activity-human-description.service.d.ts +13 -0
  230. package/dist/src/services/activity/activity-human-description.service.js +221 -0
  231. package/dist/src/services/activity/activity-human-description.service.test.d.ts +1 -0
  232. package/dist/src/services/activity/activity-human-description.service.test.js +16 -0
  233. package/dist/src/services/activity/activity-log.service.d.ts +87 -0
  234. package/dist/src/services/activity/activity-log.service.js +276 -0
  235. package/dist/src/services/activity/activity-log.service.test.d.ts +1 -0
  236. package/dist/src/services/activity/activity-log.service.test.js +27 -0
  237. package/dist/src/services/admin/admin.service.d.ts +270 -0
  238. package/dist/src/services/admin/admin.service.js +476 -0
  239. package/dist/src/services/ai/ai-session.service.d.ts +5 -0
  240. package/dist/src/services/ai/ai-session.service.js +4 -0
  241. package/dist/src/services/artifacts/annotation.service.d.ts +177 -0
  242. package/dist/src/services/artifacts/annotation.service.js +154 -0
  243. package/dist/src/services/artifacts/artifact-version.service.d.ts +38 -0
  244. package/dist/src/services/artifacts/artifact-version.service.js +129 -0
  245. package/dist/src/services/artifacts/chat.service.d.ts +127 -0
  246. package/dist/src/services/artifacts/chat.service.js +182 -0
  247. package/dist/src/services/artifacts/study-guide.service.d.ts +18 -0
  248. package/dist/src/services/artifacts/study-guide.service.js +65 -0
  249. package/dist/src/services/auth/auth.service.d.ts +94 -0
  250. package/dist/src/services/auth/auth.service.js +368 -0
  251. package/dist/src/services/base.service.d.ts +14 -0
  252. package/dist/src/services/base.service.js +14 -0
  253. package/dist/src/services/billing/payment.service.d.ts +44 -0
  254. package/dist/src/services/billing/payment.service.js +365 -0
  255. package/dist/src/services/billing/subscription.service.d.ts +37 -0
  256. package/dist/src/services/billing/subscription.service.js +654 -0
  257. package/dist/src/services/billing/usage.service.d.ts +47 -0
  258. package/dist/src/services/billing/usage.service.js +149 -0
  259. package/dist/src/services/content/copilot.service.d.ts +113 -0
  260. package/dist/src/services/content/copilot.service.js +439 -0
  261. package/dist/src/services/content/flashcard-progress.service.d.ts +159 -0
  262. package/dist/src/services/content/flashcard-progress.service.js +432 -0
  263. package/dist/src/services/content/flashcard.service.d.ts +184 -0
  264. package/dist/src/services/content/flashcard.service.js +339 -0
  265. package/dist/src/services/content/media-analysis.service.d.ts +23 -0
  266. package/dist/src/services/content/media-analysis.service.js +404 -0
  267. package/dist/src/services/content/podcast.service.d.ts +267 -0
  268. package/dist/src/services/content/podcast.service.js +653 -0
  269. package/dist/src/services/content/worksheet-content.service.d.ts +37 -0
  270. package/dist/src/services/content/worksheet-content.service.js +84 -0
  271. package/dist/src/services/content/worksheet-content.service.test.d.ts +1 -0
  272. package/dist/src/services/content/worksheet-content.service.test.js +69 -0
  273. package/dist/src/services/content/worksheet-generation.service.d.ts +91 -0
  274. package/dist/src/services/content/worksheet-generation.service.js +95 -0
  275. package/dist/src/services/content/worksheet-generation.service.test.d.ts +1 -0
  276. package/dist/src/services/content/worksheet-generation.service.test.js +20 -0
  277. package/dist/src/services/content/worksheet.service.d.ts +347 -0
  278. package/dist/src/services/content/worksheet.service.js +599 -0
  279. package/dist/src/services/knowledge/knowledge-base.service.d.ts +316 -0
  280. package/dist/src/services/knowledge/knowledge-base.service.js +544 -0
  281. package/dist/src/services/members/invitation.service.d.ts +66 -0
  282. package/dist/src/services/members/invitation.service.js +348 -0
  283. package/dist/src/services/members/member.service.d.ts +36 -0
  284. package/dist/src/services/members/member.service.js +193 -0
  285. package/dist/src/services/notifications/notification.service.d.ts +214 -0
  286. package/dist/src/services/notifications/notification.service.js +550 -0
  287. package/dist/src/services/notifications/notification.service.test.d.ts +1 -0
  288. package/dist/src/services/notifications/notification.service.test.js +87 -0
  289. package/dist/src/services/workspace/workspace-analytics.service.d.ts +24 -0
  290. package/dist/src/services/workspace/workspace-analytics.service.js +95 -0
  291. package/dist/src/services/workspace/workspace-kb.service.d.ts +40 -0
  292. package/dist/src/services/workspace/workspace-kb.service.js +184 -0
  293. package/dist/src/services/workspace/workspace.service.d.ts +263 -0
  294. package/dist/src/services/workspace/workspace.service.js +401 -0
  295. package/dist/src/trpc.d.ts +60 -0
  296. package/dist/src/trpc.js +217 -0
  297. package/dist/src/types/index.d.ts +126 -0
  298. package/dist/src/types/index.js +1 -0
  299. package/dist/trpc.d.ts +12 -4
  300. package/dist/trpc.js +5 -11
  301. package/package.json +8 -9
  302. package/prisma/schema.prisma +3 -4
  303. package/prisma/seed.mjs +5 -2
  304. package/prisma.config.ts +16 -0
  305. package/src/context.ts +33 -3
  306. package/src/lib/ai/index.ts +3 -0
  307. package/src/lib/ai/llm-client.ts +23 -0
  308. package/src/lib/prisma.ts +18 -9
  309. package/src/routers/auth.ts +1 -1
  310. package/src/routers/workspace.ts +4 -0
  311. package/src/scripts/purge-deleted-users.ts +1 -3
  312. package/src/services/billing/payment.service.ts +3 -6
  313. package/src/services/billing/usage.service.ts +190 -77
  314. package/src/services/content/copilot.service.ts +23 -32
  315. package/src/services/content/flashcard-progress.service.ts +12 -9
  316. package/src/services/content/flashcard.service.ts +89 -66
  317. package/src/services/content/media-analysis.service.ts +34 -29
  318. package/src/services/content/worksheet-generation.service.test.ts +2 -2
  319. package/src/services/workspace/workspace.service.ts +73 -66
  320. package/src/trpc.ts +5 -13
  321. package/tsconfig.json +3 -0
@@ -7,6 +7,7 @@ import { ai } from '../../lib/ai/index.js';
7
7
  import { workspaceKbService } from '../workspace/workspace-kb.service.js';
8
8
  import { getUserUsage, getUserPlanLimits } from '../billing/usage.service.js';
9
9
  import { notifyArtifactFailed, notifyArtifactReady } from '../notifications/notification.service.js';
10
+ import { FlashcardService } from './flashcard.service.js';
10
11
  const PIPELINE_STEPS = ['fileUpload', 'fileAnalysis', 'studyGuide', 'flashcards'];
11
12
  const PROGRESS_FILENAME_MAX_CHARS = 20;
12
13
  function truncateProgressFilename(value, maxChars = PROGRESS_FILENAME_MAX_CHARS) {
@@ -312,16 +313,27 @@ export class MediaAnalysisService extends BaseService {
312
313
  }));
313
314
  const flashcardRag = await workspaceKbService.retrieveContext(input.workspaceId, 'flashcard key concepts facts definitions questions', 8);
314
315
  const content = await ai.backend.generateFlashcardQuestions(input.workspaceId, userId, 10, 'medium', undefined, { ragContext: flashcardRag });
315
- const artifact = await this.db.artifact.create({
316
- data: {
317
- workspaceId: input.workspaceId,
318
- type: ArtifactType.FLASHCARD_SET,
319
- title: files.length === 1
320
- ? `Flashcards - ${primaryFile.name}`
321
- : `Flashcards - ${files.length} files`,
322
- createdById: userId,
323
- },
316
+ const flashcardService = new FlashcardService(this.db);
317
+ const primarySet = await flashcardService.ensurePrimarySet(userId, input.workspaceId);
318
+ const orderOffset = primarySet.flashcards.reduce((max, card) => Math.max(max, card.order), -1);
319
+ const flashcardTitle = files.length === 1
320
+ ? `Flashcards - ${primaryFile.name}`
321
+ : `Flashcards - ${files.length} files`;
322
+ await this.db.artifact.update({
323
+ where: { id: primarySet.id },
324
+ data: { title: flashcardTitle },
324
325
  });
326
+ const appendCard = async (front, back, index) => {
327
+ await this.db.flashcard.create({
328
+ data: {
329
+ artifactId: primarySet.id,
330
+ front,
331
+ back,
332
+ order: orderOffset + 1 + index,
333
+ tags: ['ai-generated', 'medium'],
334
+ },
335
+ });
336
+ };
325
337
  try {
326
338
  const parsed = typeof content === 'string' ? JSON.parse(content) : content;
327
339
  const flashcardData = Array.isArray(parsed) ? parsed : (parsed.flashcards || []);
@@ -329,15 +341,7 @@ export class MediaAnalysisService extends BaseService {
329
341
  const card = flashcardData[i];
330
342
  const front = card.term || card.front || card.question || card.prompt || `Question ${i + 1}`;
331
343
  const back = card.definition || card.back || card.answer || card.solution || `Answer ${i + 1}`;
332
- await this.db.flashcard.create({
333
- data: {
334
- artifactId: artifact.id,
335
- front: front,
336
- back: back,
337
- order: i,
338
- tags: ['ai-generated', 'medium'],
339
- },
340
- });
344
+ await appendCard(front, back, i);
341
345
  }
342
346
  }
343
347
  catch (parseError) {
@@ -347,18 +351,14 @@ export class MediaAnalysisService extends BaseService {
347
351
  const line = lines[i];
348
352
  if (line.includes(' - ')) {
349
353
  const [front, back] = line.split(' - ');
350
- await this.db.flashcard.create({
351
- data: {
352
- artifactId: artifact.id,
353
- front: front.trim(),
354
- back: back.trim(),
355
- order: i,
356
- tags: ['ai-generated', 'medium'],
357
- },
358
- });
354
+ await appendCard(front.trim(), back.trim(), i);
359
355
  }
360
356
  }
361
357
  }
358
+ const artifact = await this.db.artifact.findUniqueOrThrow({
359
+ where: { id: primarySet.id },
360
+ include: { flashcards: true },
361
+ });
362
362
  results.artifacts.flashcards = artifact;
363
363
  await PusherService.emitFlashcardComplete(input.workspaceId, artifact);
364
364
  await notifyArtifactReady(this.db, {
@@ -4,8 +4,8 @@ import { mergeWorksheetGenerationConfig, normalizeWorksheetProblemForDb } from '
4
4
  test('mergeWorksheetGenerationConfig: override beats preset and legacy', () => {
5
5
  const r = mergeWorksheetGenerationConfig({ mode: 'practice', numQuestions: 5, difficulty: 'easy' }, { mode: 'quiz', numQuestions: 10, difficulty: 'medium' }, { numQuestions: 3, difficulty: 'hard' });
6
6
  assert.equal(r.mode, 'quiz');
7
- assert.equal(r.numQuestions, 10);
8
- assert.equal(r.difficulty, 'medium');
7
+ assert.equal(r.numQuestions, 3);
8
+ assert.equal(r.difficulty, 'hard');
9
9
  });
10
10
  test('normalizeWorksheetProblemForDb coerces MCQ answer to option index', () => {
11
11
  const row = normalizeWorksheetProblemForDb({
@@ -33,35 +33,26 @@ export declare class WorkspaceService extends BaseService {
33
33
  folders: {
34
34
  name: string;
35
35
  id: string;
36
- createdAt: Date;
37
36
  updatedAt: Date;
38
- ownerId: string;
39
37
  parentId: string | null;
40
38
  color: string;
41
39
  markerColor: string | null;
42
40
  }[];
43
- workspaces: ({
44
- uploads: {
45
- name: string;
46
- id: string;
47
- createdAt: Date;
48
- mimeType: string;
49
- }[];
50
- } & {
41
+ workspaces: {
51
42
  id: string;
52
- createdAt: Date;
53
43
  updatedAt: Date;
54
44
  title: string;
55
- description: string | null;
56
- ownerId: string;
57
45
  color: string;
58
46
  markerColor: string | null;
59
47
  icon: string;
60
48
  folderId: string | null;
61
- fileBeingAnalyzed: boolean;
62
- analysisProgress: import("@prisma/client/runtime/library").JsonValue | null;
63
- needsAnalysis: boolean;
64
- })[];
49
+ uploads: {
50
+ name: string;
51
+ id: string;
52
+ createdAt: Date;
53
+ mimeType: string;
54
+ }[];
55
+ }[];
65
56
  }>;
66
57
  create(userId: string, input: {
67
58
  name: string;
@@ -122,70 +113,35 @@ export declare class WorkspaceService extends BaseService {
122
113
  markerColor: string | null;
123
114
  }>;
124
115
  get(userId: string, id: string): Promise<{
116
+ id: string;
117
+ createdAt: Date;
118
+ updatedAt: Date;
119
+ title: string;
120
+ description: string | null;
125
121
  folder: {
126
122
  name: string;
127
123
  id: string;
128
- createdAt: Date;
129
- updatedAt: Date;
130
- ownerId: string;
131
- parentId: string | null;
132
124
  color: string;
133
- markerColor: string | null;
134
125
  } | null;
135
- artifacts: {
136
- id: string;
137
- createdAt: Date;
138
- updatedAt: Date;
139
- workspaceId: string;
140
- type: import("@prisma/client").$Enums.ArtifactType;
141
- title: string;
142
- isArchived: boolean;
143
- difficulty: import("@prisma/client").$Enums.Difficulty | null;
144
- estimatedTime: string | null;
145
- createdById: string | null;
146
- description: string | null;
147
- generating: boolean;
148
- generatingMetadata: import("@prisma/client/runtime/library").JsonValue | null;
149
- worksheetConfig: import("@prisma/client/runtime/library").JsonValue | null;
150
- imageObjectKey: string | null;
151
- }[];
126
+ ownerId: string;
127
+ color: string;
128
+ markerColor: string | null;
129
+ icon: string;
130
+ folderId: string | null;
131
+ fileBeingAnalyzed: boolean;
132
+ analysisProgress: import("@prisma/client/runtime/library").JsonValue;
133
+ needsAnalysis: boolean;
152
134
  uploads: {
153
- meta: import("@prisma/client/runtime/library").JsonValue | null;
154
135
  name: string;
155
136
  id: string;
156
137
  createdAt: Date;
157
- workspaceId: string | null;
158
- userId: string | null;
159
138
  mimeType: string;
160
139
  size: number;
161
- bucket: string | null;
162
140
  objectKey: string | null;
163
- url: string | null;
164
- checksum: string | null;
165
- aiTranscription: import("@prisma/client/runtime/library").JsonValue | null;
166
141
  }[];
167
- } & {
168
- id: string;
169
- createdAt: Date;
170
- updatedAt: Date;
171
- title: string;
172
- description: string | null;
173
- ownerId: string;
174
- color: string;
175
- markerColor: string | null;
176
- icon: string;
177
- folderId: string | null;
178
- fileBeingAnalyzed: boolean;
179
- analysisProgress: import("@prisma/client/runtime/library").JsonValue | null;
180
- needsAnalysis: boolean;
181
- }>;
182
- getStats(userId: string): Promise<{
183
- workspaces: number;
184
- folders: number;
185
- lastUpdated: Date | undefined;
186
- spaceUsed: number;
187
- spaceTotal: number;
188
142
  }>;
143
+ getAccountSummary(userId: string): Promise<import("../billing/usage.service.js").AccountSummary>;
144
+ getStats(userId: string): Promise<import("../billing/usage.service.js").AccountStats>;
189
145
  update(userId: string, input: {
190
146
  id: string;
191
147
  name?: string;
@@ -1,10 +1,10 @@
1
1
  import { TRPCError } from '@trpc/server';
2
2
  import { BaseService } from '../base.service.js';
3
- import { ArtifactType } from '../../lib/constants.js';
4
3
  import { supabaseClient } from '../../lib/storage.js';
5
4
  import PusherService from '../../lib/pusher.js';
6
5
  import { ai } from '../../lib/ai/index.js';
7
6
  import { workspaceKbService } from './workspace-kb.service.js';
7
+ import { getAccountSummary, invalidateUserBillingCache, } from '../billing/usage.service.js';
8
8
  import { getUserStorageLimit } from '../billing/subscription.service.js';
9
9
  import { notifyWorkspaceDeleted } from '../notifications/notification.service.js';
10
10
  export class WorkspaceService extends BaseService {
@@ -22,24 +22,41 @@ export class WorkspaceService extends BaseService {
22
22
  return { workspaces, folders };
23
23
  }
24
24
  async getTree(userId) {
25
- const allFolders = await this.db.folder.findMany({
26
- where: { ownerId: userId },
27
- orderBy: { updatedAt: 'desc' },
28
- });
29
- const allWorkspaces = await this.db.workspace.findMany({
30
- where: { ownerId: userId },
31
- include: {
32
- uploads: {
33
- select: {
34
- id: true,
35
- name: true,
36
- mimeType: true,
37
- createdAt: true,
25
+ const [allFolders, allWorkspaces] = await Promise.all([
26
+ this.db.folder.findMany({
27
+ where: { ownerId: userId },
28
+ select: {
29
+ id: true,
30
+ name: true,
31
+ parentId: true,
32
+ color: true,
33
+ markerColor: true,
34
+ updatedAt: true,
35
+ },
36
+ orderBy: { updatedAt: 'desc' },
37
+ }),
38
+ this.db.workspace.findMany({
39
+ where: { ownerId: userId },
40
+ select: {
41
+ id: true,
42
+ title: true,
43
+ folderId: true,
44
+ icon: true,
45
+ color: true,
46
+ markerColor: true,
47
+ updatedAt: true,
48
+ uploads: {
49
+ select: {
50
+ id: true,
51
+ name: true,
52
+ mimeType: true,
53
+ createdAt: true,
54
+ },
38
55
  },
39
56
  },
40
- },
41
- orderBy: { updatedAt: 'desc' },
42
- });
57
+ orderBy: { updatedAt: 'desc' },
58
+ }),
59
+ ]);
43
60
  return { folders: allFolders, workspaces: allWorkspaces };
44
61
  }
45
62
  async create(userId, input) {
@@ -50,27 +67,16 @@ export class WorkspaceService extends BaseService {
50
67
  ownerId: userId,
51
68
  folderId: input.parentId ?? null,
52
69
  ...(input.markerColor !== undefined ? { markerColor: input.markerColor } : {}),
53
- artifacts: {
54
- create: {
55
- type: ArtifactType.FLASHCARD_SET,
56
- title: 'New Flashcard Set',
57
- },
58
- createMany: {
59
- data: [
60
- { type: ArtifactType.WORKSHEET, title: 'Worksheet 1' },
61
- { type: ArtifactType.WORKSHEET, title: 'Worksheet 2' },
62
- ],
63
- },
64
- },
65
70
  },
66
71
  });
67
- await ai.backend.initSession(ws.id, userId).catch((err) => {
72
+ void ai.backend.initSession(ws.id, userId).catch((err) => {
68
73
  this.logger.error('Failed to init AI session on workspace creation:', err);
69
74
  });
70
- await workspaceKbService.ensureWorkspaceKb(ws.id, userId, input.name).catch((err) => {
75
+ void workspaceKbService.ensureWorkspaceKb(ws.id, userId, input.name).catch((err) => {
71
76
  this.logger.error('Failed to create workspace knowledge base:', err);
72
77
  });
73
- await PusherService.emitLibraryUpdate(userId);
78
+ invalidateUserBillingCache(userId);
79
+ void PusherService.emitLibraryUpdate(userId);
74
80
  return ws;
75
81
  }
76
82
  async createFolder(userId, input) {
@@ -101,43 +107,44 @@ export class WorkspaceService extends BaseService {
101
107
  async get(userId, id) {
102
108
  const ws = await this.db.workspace.findFirst({
103
109
  where: { id, ownerId: userId },
104
- include: {
105
- artifacts: true,
106
- folder: true,
107
- uploads: true,
110
+ select: {
111
+ id: true,
112
+ title: true,
113
+ description: true,
114
+ icon: true,
115
+ color: true,
116
+ markerColor: true,
117
+ ownerId: true,
118
+ folderId: true,
119
+ fileBeingAnalyzed: true,
120
+ analysisProgress: true,
121
+ needsAnalysis: true,
122
+ createdAt: true,
123
+ updatedAt: true,
124
+ folder: { select: { id: true, name: true, color: true } },
125
+ uploads: {
126
+ select: {
127
+ id: true,
128
+ name: true,
129
+ mimeType: true,
130
+ size: true,
131
+ createdAt: true,
132
+ objectKey: true,
133
+ },
134
+ orderBy: { createdAt: 'desc' },
135
+ },
108
136
  },
109
137
  });
110
138
  if (!ws)
111
139
  throw new TRPCError({ code: 'NOT_FOUND' });
112
140
  return ws;
113
141
  }
142
+ async getAccountSummary(userId) {
143
+ return getAccountSummary(userId);
144
+ }
114
145
  async getStats(userId) {
115
- const workspaces = await this.db.workspace.findMany({
116
- where: {
117
- OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
118
- },
119
- });
120
- const folders = await this.db.folder.findMany({
121
- where: { OR: [{ ownerId: userId }] },
122
- });
123
- const lastUpdated = await this.db.workspace.findFirst({
124
- where: {
125
- OR: [{ ownerId: userId }, { sharedWith: { some: { id: userId } } }],
126
- },
127
- orderBy: { updatedAt: 'desc' },
128
- });
129
- const spaceLeft = await this.db.fileAsset.aggregate({
130
- where: { workspaceId: { in: workspaces.map((ws) => ws.id) }, userId },
131
- _sum: { size: true },
132
- });
133
- const storageLimit = await getUserStorageLimit(userId);
134
- return {
135
- workspaces: workspaces.length,
136
- folders: folders.length,
137
- lastUpdated: lastUpdated?.updatedAt,
138
- spaceUsed: spaceLeft._sum?.size ?? 0,
139
- spaceTotal: storageLimit,
140
- };
146
+ const summary = await getAccountSummary(userId);
147
+ return summary.stats;
141
148
  }
142
149
  async update(userId, input) {
143
150
  const existed = await this.db.workspace.findFirst({
@@ -0,0 +1,27 @@
1
+ import type { CreateExpressContextOptions } from "@trpc/server/adapters/express";
2
+ import { prisma } from "./lib/prisma.js";
3
+ import cookie from "cookie";
4
+ export type SessionUser = {
5
+ id: string;
6
+ emailVerified: boolean;
7
+ isSystemAdmin: boolean;
8
+ };
9
+ export declare function createContext({ req, res }: CreateExpressContextOptions): Promise<{
10
+ db: import("../generated/prisma/client.js").PrismaClient;
11
+ session: null;
12
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
13
+ res: import("express").Response<any, Record<string, any>>;
14
+ cookies: cookie.Cookies;
15
+ } | {
16
+ db: import("../generated/prisma/client.js").PrismaClient;
17
+ session: {
18
+ user: SessionUser;
19
+ };
20
+ req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
21
+ res: import("express").Response<any, Record<string, any>>;
22
+ cookies: cookie.Cookies;
23
+ }>;
24
+ /** Use `typeof prisma` for `db` so TS keeps generated model delegates (not a bare PrismaClient). */
25
+ export type Context = Omit<Awaited<ReturnType<typeof createContext>>, "db"> & {
26
+ db: typeof prisma;
27
+ };
@@ -0,0 +1,33 @@
1
+ import { prisma } from "./lib/prisma.js";
2
+ import { verifyCustomAuthCookie } from "./lib/auth.js";
3
+ import cookie from "cookie";
4
+ export async function createContext({ req, res }) {
5
+ const cookies = cookie.parse(req.headers.cookie ?? "");
6
+ const custom = verifyCustomAuthCookie(cookies["auth_token"]);
7
+ if (custom) {
8
+ const user = await prisma.user.findUnique({
9
+ where: { id: custom.userId },
10
+ select: {
11
+ id: true,
12
+ emailVerified: true,
13
+ role: { select: { name: true } },
14
+ },
15
+ });
16
+ if (!user) {
17
+ return { db: prisma, session: null, req, res, cookies };
18
+ }
19
+ const sessionUser = {
20
+ id: user.id,
21
+ emailVerified: !!user.emailVerified,
22
+ isSystemAdmin: user.role?.name === "System Admin",
23
+ };
24
+ return {
25
+ db: prisma,
26
+ session: { user: sessionUser },
27
+ req,
28
+ res,
29
+ cookies,
30
+ };
31
+ }
32
+ return { db: prisma, session: null, req, res, cookies };
33
+ }
@@ -0,0 +1,3 @@
1
+ export type { AppRouter } from "./routers/_app.js";
2
+ export type { RouterInputs } from "./routers/_app.js";
3
+ export type { RouterOutputs } from "./routers/_app.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ export declare const aiConfig: {
2
+ readonly llm: {
3
+ readonly apiKey: string | undefined;
4
+ readonly baseUrl: string | undefined;
5
+ readonly model: string;
6
+ };
7
+ readonly embeddings: {
8
+ readonly apiKey: string | undefined;
9
+ readonly baseUrl: undefined;
10
+ readonly model: string;
11
+ readonly dim: number;
12
+ };
13
+ readonly inferenceBackend: {
14
+ readonly url: string | undefined;
15
+ readonly mockEnabled: boolean;
16
+ readonly mockDelayMs: 0 | 10000;
17
+ };
18
+ };
19
+ export declare function getInferenceBackendUploadUrl(): string;
20
+ export declare function tryGetInferenceBackendUploadUrl(): string | null;
@@ -0,0 +1,31 @@
1
+ export const aiConfig = {
2
+ llm: {
3
+ apiKey: process.env.INFERENCE_API_KEY,
4
+ baseUrl: process.env.INFERENCE_BASE_URL,
5
+ model: process.env.INFERENCE_MODEL ?? 'command-a-03-2025',
6
+ },
7
+ embeddings: {
8
+ apiKey: process.env.OPENAI_API_KEY,
9
+ baseUrl: undefined,
10
+ model: process.env.EMBEDDING_MODEL ?? 'text-embedding-3-small',
11
+ dim: Number(process.env.EMBEDDING_DIM ?? 1536),
12
+ },
13
+ inferenceBackend: {
14
+ url: process.env.INFERENCE_API_URL,
15
+ mockEnabled: process.env.DONT_TEST_INFERENCE === 'true',
16
+ mockDelayMs: process.env.DONT_TEST_INFERENCE === 'true' ? 10000 : 0,
17
+ },
18
+ };
19
+ export function getInferenceBackendUploadUrl() {
20
+ const base = aiConfig.inferenceBackend.url;
21
+ if (!base) {
22
+ throw new Error('INFERENCE_API_URL is not configured');
23
+ }
24
+ return `${base.replace(/\/$/, '')}/upload`;
25
+ }
26
+ export function tryGetInferenceBackendUploadUrl() {
27
+ const base = aiConfig.inferenceBackend.url;
28
+ if (!base)
29
+ return null;
30
+ return `${base.replace(/\/$/, '')}/upload`;
31
+ }
@@ -0,0 +1,8 @@
1
+ export declare const DEFAULT_EMBEDDING_MODEL: string;
2
+ export declare const DEFAULT_EMBEDDING_DIM: number;
3
+ export interface EmbedOptions {
4
+ model?: string;
5
+ }
6
+ export declare function embedTexts(texts: string[], opts?: EmbedOptions): Promise<number[][]>;
7
+ export declare function embedQuery(text: string, opts?: EmbedOptions): Promise<number[]>;
8
+ export declare function toVectorLiteral(vec: number[]): string;
@@ -0,0 +1,30 @@
1
+ import OpenAI from 'openai';
2
+ import { aiConfig } from './config.js';
3
+ const client = new OpenAI({
4
+ apiKey: aiConfig.embeddings.apiKey,
5
+ baseURL: aiConfig.embeddings.baseUrl,
6
+ });
7
+ export const DEFAULT_EMBEDDING_MODEL = aiConfig.embeddings.model;
8
+ export const DEFAULT_EMBEDDING_DIM = aiConfig.embeddings.dim;
9
+ export async function embedTexts(texts, opts = {}) {
10
+ const model = opts.model ?? DEFAULT_EMBEDDING_MODEL;
11
+ if (texts.length === 0)
12
+ return [];
13
+ const BATCH = 96;
14
+ const out = new Array(texts.length);
15
+ for (let i = 0; i < texts.length; i += BATCH) {
16
+ const batch = texts.slice(i, i + BATCH);
17
+ const res = await client.embeddings.create({ model, input: batch });
18
+ res.data.forEach((row, j) => {
19
+ out[i + j] = row.embedding;
20
+ });
21
+ }
22
+ return out;
23
+ }
24
+ export async function embedQuery(text, opts = {}) {
25
+ const [vec] = await embedTexts([text], opts);
26
+ return vec;
27
+ }
28
+ export function toVectorLiteral(vec) {
29
+ return `[${vec.map((n) => (Number.isFinite(n) ? n : 0)).join(',')}]`;
30
+ }
@@ -0,0 +1,48 @@
1
+ import { aiConfig } from './config.js';
2
+ import { complete, completeText, streamComplete } from './llm-client.js';
3
+ import { DEFAULT_EMBEDDING_DIM, DEFAULT_EMBEDDING_MODEL, embedQuery, embedTexts, toVectorLiteral } from './embedding-client.js';
4
+ import { extractJson, parseJsonField } from './json-parse.js';
5
+ import { isAiMockMode, mockDelay } from './mock.js';
6
+ import { inferenceBackend } from './inference-backend/client.js';
7
+ export declare const ai: {
8
+ config: {
9
+ readonly llm: {
10
+ readonly apiKey: string | undefined;
11
+ readonly baseUrl: string | undefined;
12
+ readonly model: string;
13
+ };
14
+ readonly embeddings: {
15
+ readonly apiKey: string | undefined;
16
+ readonly baseUrl: undefined;
17
+ readonly model: string;
18
+ readonly dim: number;
19
+ };
20
+ readonly inferenceBackend: {
21
+ readonly url: string | undefined;
22
+ readonly mockEnabled: boolean;
23
+ readonly mockDelayMs: 0 | 10000;
24
+ };
25
+ };
26
+ isMockMode: typeof isAiMockMode;
27
+ mockDelay: typeof mockDelay;
28
+ llm: {
29
+ complete: typeof complete;
30
+ completeText: typeof completeText;
31
+ streamComplete: typeof streamComplete;
32
+ };
33
+ embed: {
34
+ texts: typeof embedTexts;
35
+ query: typeof embedQuery;
36
+ toVectorLiteral: typeof toVectorLiteral;
37
+ DEFAULT_MODEL: string;
38
+ DEFAULT_DIM: number;
39
+ };
40
+ backend: import("./inference-backend/client.js").InferenceBackendClient;
41
+ parse: {
42
+ extractJson: typeof extractJson;
43
+ parseJsonField: typeof parseJsonField;
44
+ };
45
+ };
46
+ export type { ChatMessage, ChatRole, CompleteOptions } from './types.js';
47
+ export type { AISession, ProcessFileResult, PodcastSpeaker, StudyGuideSegment, WorksheetGenerationOptions, } from './inference-backend/types.js';
48
+ export { aiConfig, complete, completeText, streamComplete, DEFAULT_EMBEDDING_DIM, DEFAULT_EMBEDDING_MODEL, embedQuery, embedTexts, extractJson, inferenceBackend, isAiMockMode, mockDelay, parseJsonField, toVectorLiteral, };
@@ -0,0 +1,29 @@
1
+ import { aiConfig } from './config.js';
2
+ import { complete, completeText, streamComplete, } from './llm-client.js';
3
+ import { DEFAULT_EMBEDDING_DIM, DEFAULT_EMBEDDING_MODEL, embedQuery, embedTexts, toVectorLiteral, } from './embedding-client.js';
4
+ import { extractJson, parseJsonField } from './json-parse.js';
5
+ import { isAiMockMode, mockDelay } from './mock.js';
6
+ import { inferenceBackend } from './inference-backend/client.js';
7
+ export const ai = {
8
+ config: aiConfig,
9
+ isMockMode: isAiMockMode,
10
+ mockDelay,
11
+ llm: {
12
+ complete,
13
+ completeText,
14
+ streamComplete,
15
+ },
16
+ embed: {
17
+ texts: embedTexts,
18
+ query: embedQuery,
19
+ toVectorLiteral,
20
+ DEFAULT_MODEL: DEFAULT_EMBEDDING_MODEL,
21
+ DEFAULT_DIM: DEFAULT_EMBEDDING_DIM,
22
+ },
23
+ backend: inferenceBackend,
24
+ parse: {
25
+ extractJson,
26
+ parseJsonField,
27
+ },
28
+ };
29
+ export { aiConfig, complete, completeText, streamComplete, DEFAULT_EMBEDDING_DIM, DEFAULT_EMBEDDING_MODEL, embedQuery, embedTexts, extractJson, inferenceBackend, isAiMockMode, mockDelay, parseJsonField, toVectorLiteral, };