@goscribe/server 1.1.2 → 1.1.4

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 (36) hide show
  1. package/dist/lib/ai-session.d.ts +13 -3
  2. package/dist/lib/ai-session.js +66 -146
  3. package/dist/lib/pusher.js +1 -1
  4. package/dist/routers/_app.d.ts +114 -7
  5. package/dist/routers/chat.js +2 -23
  6. package/dist/routers/flashcards.d.ts +25 -1
  7. package/dist/routers/flashcards.js +0 -14
  8. package/dist/routers/members.d.ts +18 -0
  9. package/dist/routers/members.js +14 -1
  10. package/dist/routers/worksheets.js +5 -4
  11. package/dist/routers/workspace.d.ts +89 -6
  12. package/dist/routers/workspace.js +389 -259
  13. package/dist/services/flashcard-progress.service.d.ts +25 -1
  14. package/dist/services/flashcard-progress.service.js +70 -31
  15. package/package.json +3 -2
  16. package/prisma/schema.prisma +196 -184
  17. package/src/lib/ai-session.ts +3 -21
  18. package/src/routers/auth.ts +50 -2
  19. package/src/routers/flashcards.ts +0 -16
  20. package/src/routers/members.ts +27 -6
  21. package/src/routers/workspace.ts +468 -439
  22. package/src/server.ts +13 -0
  23. package/ANALYSIS_PROGRESS_SPEC.md +0 -463
  24. package/PROGRESS_QUICK_REFERENCE.md +0 -239
  25. package/dist/lib/podcast-prompts.d.ts +0 -43
  26. package/dist/lib/podcast-prompts.js +0 -135
  27. package/dist/routers/ai-session.d.ts +0 -0
  28. package/dist/routers/ai-session.js +0 -1
  29. package/dist/services/flashcard.service.d.ts +0 -183
  30. package/dist/services/flashcard.service.js +0 -224
  31. package/dist/services/podcast-segment-reorder.d.ts +0 -0
  32. package/dist/services/podcast-segment-reorder.js +0 -107
  33. package/dist/services/podcast.service.d.ts +0 -0
  34. package/dist/services/podcast.service.js +0 -326
  35. package/dist/services/worksheet.service.d.ts +0 -0
  36. package/dist/services/worksheet.service.js +0 -295
@@ -1,43 +0,0 @@
1
- /**
2
- * Podcast generation prompts
3
- */
4
- export interface StructurePromptParams {
5
- title: string;
6
- description?: string;
7
- userPrompt: string;
8
- studyGuideContent: string;
9
- generateIntro: boolean;
10
- generateOutro: boolean;
11
- }
12
- export interface RegenerateSegmentPromptParams {
13
- oldContent: string;
14
- userPrompt: string;
15
- segmentTitle: string;
16
- context: {
17
- episodeTitle: string;
18
- allSegmentTitles: string[];
19
- segmentIndex: number;
20
- };
21
- }
22
- /**
23
- * Generate prompt for structuring podcast content
24
- */
25
- export declare function createStructurePrompt(params: StructurePromptParams): string;
26
- /**
27
- * Generate prompt for episode summary
28
- */
29
- export declare function createSummaryPrompt(episodeTitle: string, segments: Array<{
30
- title: string;
31
- keyPoints: string[];
32
- }>): string;
33
- /**
34
- * Generate improved prompt for segment regeneration
35
- */
36
- export declare function createRegenerateSegmentPrompt(params: RegenerateSegmentPromptParams): string;
37
- /**
38
- * Validate environment for podcast generation
39
- */
40
- export declare function validatePodcastEnvironment(): {
41
- valid: boolean;
42
- errors: string[];
43
- };
@@ -1,135 +0,0 @@
1
- /**
2
- * Podcast generation prompts
3
- */
4
- /**
5
- * Generate prompt for structuring podcast content
6
- */
7
- export function createStructurePrompt(params) {
8
- const { title, description, userPrompt, studyGuideContent, generateIntro, generateOutro } = params;
9
- return `You are an expert podcast content creator and scriptwriter. Your task is to create an engaging, educational podcast episode with professional structure and natural conversational language.
10
-
11
- OBJECTIVE:
12
- Create a complete podcast episode that is informative, engaging, and flows naturally. The content should be suitable for audio delivery with a conversational tone.
13
-
14
- USER REQUEST:
15
- Title: ${title}
16
- Description: ${description || 'No description provided'}
17
- Prompt: ${userPrompt}
18
-
19
- REQUIREMENTS:
20
- 1. Create segments that are 2-5 minutes each when spoken at a normal pace
21
- 2. Use natural, conversational language (avoid reading lists, use storytelling)
22
- 3. Include smooth transitions between segments
23
- 4. Each segment should have a clear focus and takeaways
24
- 5. Make content accessible but informative
25
- ${generateIntro ? '6. Start with an engaging hook that captures attention immediately' : ''}
26
- ${generateOutro ? '7. End with a strong conclusion that summarizes and motivates action' : ''}
27
-
28
- CONTEXT (if available):
29
- ${studyGuideContent ? `Study Guide Content (use as reference, don't copy verbatim):\n${studyGuideContent.substring(0, 2000)}` : 'No study guide available'}
30
-
31
- OUTPUT FORMAT (strict JSON):
32
- {
33
- "episodeTitle": "Enhanced, engaging title for the podcast",
34
- "totalEstimatedDuration": "XX minutes",
35
- "segments": [
36
- {
37
- "title": "Segment title (concise and descriptive)",
38
- "content": "Natural conversational script. Use 'I', 'we', 'you'. Tell stories. Ask rhetorical questions. Use analogies. Make it sound like a real conversation, not a lecture.",
39
- "keyPoints": ["Main point 1", "Main point 2", "Main point 3"],
40
- "estimatedDuration": "X minutes",
41
- "order": 1
42
- }
43
- ]
44
- }
45
-
46
- IMPORTANT:
47
- - Write like you're having a conversation with a friend
48
- - Use contractions (I'm, you're, let's)
49
- - Include verbal cues ("Now, here's the interesting part...", "You know what's fascinating?")
50
- - Vary sentence length for natural rhythm
51
- - Each segment should be self-contained but connected to the narrative
52
-
53
- Return ONLY the JSON, no additional text.`;
54
- }
55
- /**
56
- * Generate prompt for episode summary
57
- */
58
- export function createSummaryPrompt(episodeTitle, segments) {
59
- return `Create a comprehensive analysis and summary for this podcast episode.
60
-
61
- EPISODE: "${episodeTitle}"
62
-
63
- SEGMENTS:
64
- ${JSON.stringify(segments, null, 2)}
65
-
66
- Generate a detailed summary with the following structure (return as JSON):
67
-
68
- {
69
- "executiveSummary": "2-3 sentence overview of what listeners will learn",
70
- "learningObjectives": ["Specific, actionable objectives (3-5 items)"],
71
- "keyConcepts": ["Main concepts covered (5-7 items)"],
72
- "followUpActions": ["Concrete next steps listeners can take (3-5 items)"],
73
- "targetAudience": "Detailed description of who will benefit most",
74
- "prerequisites": ["Knowledge or background helpful but not required (2-3 items, or empty array)"],
75
- "tags": ["Relevant searchable tags (5-8 items)"]
76
- }
77
-
78
- Make it specific, actionable, and useful for potential listeners trying to decide if this episode is for them.
79
-
80
- Return ONLY the JSON, no additional text.`;
81
- }
82
- /**
83
- * Generate improved prompt for segment regeneration
84
- */
85
- export function createRegenerateSegmentPrompt(params) {
86
- const { oldContent, userPrompt, segmentTitle, context } = params;
87
- return `You are revising a specific segment of a podcast episode.
88
-
89
- EPISODE CONTEXT:
90
- - Episode Title: "${context.episodeTitle}"
91
- - All Segments: ${context.allSegmentTitles.map((t, i) => `${i + 1}. ${t}`).join(', ')}
92
- - Current Segment: #${context.segmentIndex + 1} - "${segmentTitle}"
93
-
94
- CURRENT CONTENT:
95
- """
96
- ${oldContent}
97
- """
98
-
99
- USER REQUEST FOR REVISION:
100
- """
101
- ${userPrompt}
102
- """
103
-
104
- TASK:
105
- Rewrite this segment following the user's request while maintaining:
106
- 1. Natural, conversational tone
107
- 2. Connection to the overall episode narrative
108
- 3. Appropriate length (2-5 minutes spoken)
109
- 4. Engaging and informative content
110
-
111
- GUIDELINES:
112
- - If user asks to make it "longer", expand on concepts with examples and stories
113
- - If user asks to make it "shorter", focus on key points and remove tangents
114
- - If user asks to "add more detail", include specific examples, data, or anecdotes
115
- - If user asks to "simplify", use clearer language and better analogies
116
- - If user asks to "make it more engaging", add hooks, questions, and storytelling
117
-
118
- Return ONLY the revised content as plain text, no JSON or formatting. Write as if you're speaking to listeners.`;
119
- }
120
- /**
121
- * Validate environment for podcast generation
122
- */
123
- export function validatePodcastEnvironment() {
124
- const errors = [];
125
- if (!process.env.MURF_TTS_KEY) {
126
- errors.push('MURF_TTS_KEY environment variable is not set');
127
- }
128
- if (!process.env.INFERENCE_API_URL && !process.env.OPENAI_API_KEY) {
129
- errors.push('No AI inference API configured (need INFERENCE_API_URL or OPENAI_API_KEY)');
130
- }
131
- return {
132
- valid: errors.length === 0,
133
- errors,
134
- };
135
- }
File without changes
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,183 +0,0 @@
1
- import type { PrismaClient } from '@prisma/client';
2
- import type { CreateFlashcardInput } from '../types/index.js';
3
- export declare class FlashcardService {
4
- private db;
5
- constructor(db: PrismaClient);
6
- jsonToFlashcards(json: string): Promise<any>;
7
- /**
8
- * List all flashcard sets for a workspace
9
- */
10
- listFlashcardSets(workspaceId: string, userId: string): Promise<({
11
- flashcards: {
12
- id: string;
13
- createdAt: Date;
14
- artifactId: string;
15
- order: number;
16
- front: string;
17
- back: string;
18
- tags: string[];
19
- }[];
20
- } & {
21
- id: string;
22
- createdAt: Date;
23
- updatedAt: Date;
24
- title: string;
25
- description: string | null;
26
- workspaceId: string;
27
- type: import("@prisma/client").$Enums.ArtifactType;
28
- isArchived: boolean;
29
- generating: boolean;
30
- generatingMetadata: import("@prisma/client/runtime/library").JsonValue | null;
31
- difficulty: import("@prisma/client").$Enums.Difficulty | null;
32
- estimatedTime: string | null;
33
- imageObjectKey: string | null;
34
- createdById: string | null;
35
- })[]>;
36
- /**
37
- * Get a single flashcard set
38
- */
39
- getFlashcardSet(setId: string, userId: string): Promise<{
40
- flashcards: {
41
- id: string;
42
- createdAt: Date;
43
- artifactId: string;
44
- order: number;
45
- front: string;
46
- back: string;
47
- tags: string[];
48
- }[];
49
- } & {
50
- id: string;
51
- createdAt: Date;
52
- updatedAt: Date;
53
- title: string;
54
- description: string | null;
55
- workspaceId: string;
56
- type: import("@prisma/client").$Enums.ArtifactType;
57
- isArchived: boolean;
58
- generating: boolean;
59
- generatingMetadata: import("@prisma/client/runtime/library").JsonValue | null;
60
- difficulty: import("@prisma/client").$Enums.Difficulty | null;
61
- estimatedTime: string | null;
62
- imageObjectKey: string | null;
63
- createdById: string | null;
64
- }>;
65
- /**
66
- * Create a new flashcard set
67
- */
68
- createFlashcardSet(data: {
69
- workspaceId: string;
70
- title: string;
71
- userId: string;
72
- flashcards?: CreateFlashcardInput[];
73
- }): Promise<{
74
- flashcards: {
75
- id: string;
76
- createdAt: Date;
77
- artifactId: string;
78
- order: number;
79
- front: string;
80
- back: string;
81
- tags: string[];
82
- }[];
83
- } & {
84
- id: string;
85
- createdAt: Date;
86
- updatedAt: Date;
87
- title: string;
88
- description: string | null;
89
- workspaceId: string;
90
- type: import("@prisma/client").$Enums.ArtifactType;
91
- isArchived: boolean;
92
- generating: boolean;
93
- generatingMetadata: import("@prisma/client/runtime/library").JsonValue | null;
94
- difficulty: import("@prisma/client").$Enums.Difficulty | null;
95
- estimatedTime: string | null;
96
- imageObjectKey: string | null;
97
- createdById: string | null;
98
- }>;
99
- /**
100
- * Update a flashcard set
101
- */
102
- updateFlashcardSet(data: {
103
- id: string;
104
- title?: string;
105
- userId: string;
106
- flashcards?: (CreateFlashcardInput & {
107
- id?: string;
108
- })[];
109
- }): Promise<{
110
- flashcards: {
111
- id: string;
112
- createdAt: Date;
113
- artifactId: string;
114
- order: number;
115
- front: string;
116
- back: string;
117
- tags: string[];
118
- }[];
119
- } & {
120
- id: string;
121
- createdAt: Date;
122
- updatedAt: Date;
123
- title: string;
124
- description: string | null;
125
- workspaceId: string;
126
- type: import("@prisma/client").$Enums.ArtifactType;
127
- isArchived: boolean;
128
- generating: boolean;
129
- generatingMetadata: import("@prisma/client/runtime/library").JsonValue | null;
130
- difficulty: import("@prisma/client").$Enums.Difficulty | null;
131
- estimatedTime: string | null;
132
- imageObjectKey: string | null;
133
- createdById: string | null;
134
- }>;
135
- /**
136
- * Delete a flashcard set
137
- */
138
- deleteFlashcardSet(setId: string, userId: string): Promise<{
139
- success: boolean;
140
- }>;
141
- /**
142
- * Add a flashcard to a set
143
- */
144
- addFlashcard(data: {
145
- setId: string;
146
- userId: string;
147
- flashcard: CreateFlashcardInput;
148
- }): Promise<{
149
- id: string;
150
- createdAt: Date;
151
- artifactId: string;
152
- order: number;
153
- front: string;
154
- back: string;
155
- tags: string[];
156
- }>;
157
- /**
158
- * Update a flashcard
159
- */
160
- updateFlashcard(data: {
161
- flashcardId: string;
162
- userId: string;
163
- updates: Partial<CreateFlashcardInput>;
164
- }): Promise<{
165
- id: string;
166
- createdAt: Date;
167
- artifactId: string;
168
- order: number;
169
- front: string;
170
- back: string;
171
- tags: string[];
172
- }>;
173
- /**
174
- * Delete a flashcard
175
- */
176
- deleteFlashcard(flashcardId: string, userId: string): Promise<{
177
- success: boolean;
178
- }>;
179
- }
180
- /**
181
- * Factory function to create flashcard service
182
- */
183
- export declare function createFlashcardService(db: PrismaClient): FlashcardService;
@@ -1,224 +0,0 @@
1
- import { NotFoundError } from '../lib/errors.js';
2
- export class FlashcardService {
3
- constructor(db) {
4
- this.db = db;
5
- }
6
- async jsonToFlashcards(json) {
7
- const flashcards = JSON.parse(json);
8
- return flashcards.map((card) => ({
9
- front: card.front,
10
- back: card.back,
11
- }));
12
- }
13
- /**
14
- * List all flashcard sets for a workspace
15
- */
16
- async listFlashcardSets(workspaceId, userId) {
17
- return this.db.artifact.findMany({
18
- where: {
19
- workspaceId,
20
- type: 'FLASHCARD_SET',
21
- workspace: { ownerId: userId },
22
- },
23
- include: {
24
- flashcards: {
25
- orderBy: { order: 'asc' },
26
- },
27
- },
28
- orderBy: { updatedAt: 'desc' },
29
- });
30
- }
31
- /**
32
- * Get a single flashcard set
33
- */
34
- async getFlashcardSet(setId, userId) {
35
- const flashcardSet = await this.db.artifact.findFirst({
36
- where: {
37
- id: setId,
38
- type: 'FLASHCARD_SET',
39
- workspace: { ownerId: userId },
40
- },
41
- include: {
42
- flashcards: {
43
- orderBy: { order: 'asc' },
44
- },
45
- },
46
- });
47
- if (!flashcardSet) {
48
- throw new NotFoundError('Flashcard set');
49
- }
50
- return flashcardSet;
51
- }
52
- /**
53
- * Create a new flashcard set
54
- */
55
- async createFlashcardSet(data) {
56
- // Verify workspace ownership
57
- const workspace = await this.db.workspace.findFirst({
58
- where: {
59
- id: data.workspaceId,
60
- ownerId: data.userId,
61
- },
62
- });
63
- if (!workspace) {
64
- throw new NotFoundError('Workspace');
65
- }
66
- const { flashcards, ...setData } = data;
67
- return this.db.artifact.create({
68
- data: {
69
- workspaceId: data.workspaceId,
70
- type: 'FLASHCARD_SET',
71
- title: data.title,
72
- createdById: data.userId,
73
- flashcards: flashcards
74
- ? {
75
- create: flashcards.map((card, index) => ({
76
- ...card,
77
- order: card.order ?? index,
78
- })),
79
- }
80
- : undefined,
81
- },
82
- include: {
83
- flashcards: {
84
- orderBy: { order: 'asc' },
85
- },
86
- },
87
- });
88
- }
89
- /**
90
- * Update a flashcard set
91
- */
92
- async updateFlashcardSet(data) {
93
- const { id, flashcards, userId, ...updateData } = data;
94
- // Verify ownership
95
- const existingSet = await this.db.artifact.findFirst({
96
- where: {
97
- id,
98
- type: 'FLASHCARD_SET',
99
- workspace: { ownerId: userId },
100
- },
101
- });
102
- if (!existingSet) {
103
- throw new NotFoundError('Flashcard set');
104
- }
105
- // Handle flashcards update if provided
106
- if (flashcards) {
107
- // Delete existing flashcards
108
- await this.db.flashcard.deleteMany({
109
- where: { artifactId: id },
110
- });
111
- // Create new flashcards
112
- await this.db.flashcard.createMany({
113
- data: flashcards.map((card, index) => ({
114
- artifactId: id,
115
- front: card.front,
116
- back: card.back,
117
- tags: card.tags || [],
118
- order: card.order ?? index,
119
- })),
120
- });
121
- }
122
- return this.db.artifact.update({
123
- where: { id },
124
- data: updateData,
125
- include: {
126
- flashcards: {
127
- orderBy: { order: 'asc' },
128
- },
129
- },
130
- });
131
- }
132
- /**
133
- * Delete a flashcard set
134
- */
135
- async deleteFlashcardSet(setId, userId) {
136
- const deleted = await this.db.artifact.deleteMany({
137
- where: {
138
- id: setId,
139
- type: 'FLASHCARD_SET',
140
- workspace: { ownerId: userId },
141
- },
142
- });
143
- if (deleted.count === 0) {
144
- throw new NotFoundError('Flashcard set');
145
- }
146
- return { success: true };
147
- }
148
- /**
149
- * Add a flashcard to a set
150
- */
151
- async addFlashcard(data) {
152
- // Verify ownership
153
- const set = await this.db.artifact.findFirst({
154
- where: {
155
- id: data.setId,
156
- type: 'FLASHCARD_SET',
157
- workspace: { ownerId: data.userId },
158
- },
159
- });
160
- if (!set) {
161
- throw new NotFoundError('Flashcard set');
162
- }
163
- // Get the next order number
164
- const maxOrder = await this.db.flashcard.aggregate({
165
- where: { artifactId: data.setId },
166
- _max: { order: true },
167
- });
168
- return this.db.flashcard.create({
169
- data: {
170
- artifactId: data.setId,
171
- front: data.flashcard.front,
172
- back: data.flashcard.back,
173
- tags: data.flashcard.tags || [],
174
- order: data.flashcard.order ?? (maxOrder._max.order ?? 0) + 1,
175
- },
176
- });
177
- }
178
- /**
179
- * Update a flashcard
180
- */
181
- async updateFlashcard(data) {
182
- // Verify ownership
183
- const flashcard = await this.db.flashcard.findFirst({
184
- where: {
185
- id: data.flashcardId,
186
- artifact: {
187
- type: 'FLASHCARD_SET',
188
- workspace: { ownerId: data.userId },
189
- },
190
- },
191
- });
192
- if (!flashcard) {
193
- throw new NotFoundError('Flashcard');
194
- }
195
- return this.db.flashcard.update({
196
- where: { id: data.flashcardId },
197
- data: data.updates,
198
- });
199
- }
200
- /**
201
- * Delete a flashcard
202
- */
203
- async deleteFlashcard(flashcardId, userId) {
204
- const flashcard = await this.db.flashcard.findFirst({
205
- where: {
206
- id: flashcardId,
207
- artifact: { workspace: { ownerId: userId } },
208
- },
209
- });
210
- if (!flashcard) {
211
- throw new NotFoundError('Flashcard');
212
- }
213
- await this.db.flashcard.delete({
214
- where: { id: flashcardId },
215
- });
216
- return { success: true };
217
- }
218
- }
219
- /**
220
- * Factory function to create flashcard service
221
- */
222
- export function createFlashcardService(db) {
223
- return new FlashcardService(db);
224
- }
File without changes
@@ -1,107 +0,0 @@
1
- "use strict";
2
- // import type { PrismaClient } from '@prisma/client';
3
- // import { NotFoundError } from '../lib/errors.js';
4
- // export interface ReorderSegmentData {
5
- // id: string;
6
- // newOrder: number;
7
- // }
8
- // export class PodcastSegmentReorderService {
9
- // constructor(private db: PrismaClient) {}
10
- // /**
11
- // * Reorder podcast segments and recalculate start times
12
- // */
13
- // async reorderSegments(data: {
14
- // episodeId: string;
15
- // userId: string;
16
- // newOrder: ReorderSegmentData[];
17
- // }) {
18
- // const { episodeId, userId, newOrder } = data;
19
- // // Verify ownership
20
- // const episode = await this.db.artifact.findFirst({
21
- // where: {
22
- // id: episodeId,
23
- // type: 'PODCAST_EPISODE',
24
- // workspace: { ownerId: userId },
25
- // },
26
- // include: {
27
- // podcastSegments: {
28
- // orderBy: { order: 'asc' },
29
- // },
30
- // },
31
- // });
32
- // if (!episode) {
33
- // throw new NotFoundError('Podcast episode');
34
- // }
35
- // // Validate all segment IDs exist
36
- // const segmentIds = episode.podcastSegments.map((s) => s.id);
37
- // const invalidIds = newOrder.filter((item) => !segmentIds.includes(item.id));
38
- // if (invalidIds.length > 0) {
39
- // throw new Error(`Invalid segment IDs: ${invalidIds.map((i) => i.id).join(', ')}`);
40
- // }
41
- // // Validate order values are sequential
42
- // const orderValues = newOrder.map((item) => item.newOrder).sort((a, b) => a - b);
43
- // const expectedOrder = Array.from({ length: newOrder.length }, (_, i) => i + 1);
44
- // if (JSON.stringify(orderValues) !== JSON.stringify(expectedOrder)) {
45
- // throw new Error('Order values must be sequential starting from 1');
46
- // }
47
- // return this.db.$transaction(async (tx) => {
48
- // // Update each segment's order
49
- // for (const item of newOrder) {
50
- // await tx.podcastSegment.update({
51
- // where: { id: item.id },
52
- // data: { order: item.newOrder },
53
- // });
54
- // }
55
- // // Get all segments in new order
56
- // const reorderedSegments = await tx.podcastSegment.findMany({
57
- // where: { artifactId: episodeId },
58
- // orderBy: { order: 'asc' },
59
- // });
60
- // // Recalculate start times
61
- // let currentTime = 0;
62
- // for (const segment of reorderedSegments) {
63
- // await tx.podcastSegment.update({
64
- // where: { id: segment.id },
65
- // data: { startTime: currentTime },
66
- // });
67
- // currentTime += segment.duration;
68
- // }
69
- // // Update total duration in latest version
70
- // const latestVersion = await tx.artifactVersion.findFirst({
71
- // where: { artifactId: episodeId },
72
- // orderBy: { version: 'desc' },
73
- // });
74
- // if (latestVersion) {
75
- // const metadata = latestVersion.data as any;
76
- // if (metadata) {
77
- // metadata.totalDuration = currentTime;
78
- // // Create new version with updated metadata
79
- // await tx.artifactVersion.create({
80
- // data: {
81
- // artifactId: episodeId,
82
- // version: latestVersion.version + 1,
83
- // content: latestVersion.content,
84
- // data: metadata,
85
- // createdById: userId,
86
- // },
87
- // });
88
- // }
89
- // }
90
- // // Update artifact timestamp
91
- // await tx.artifact.update({
92
- // where: { id: episodeId },
93
- // data: { updatedAt: new Date() },
94
- // });
95
- // return {
96
- // totalDuration: currentTime,
97
- // segmentsReordered: reorderedSegments.length,
98
- // };
99
- // });
100
- // }
101
- // }
102
- // /**
103
- // * Factory function
104
- // */
105
- // export function createPodcastSegmentReorderService(db: PrismaClient) {
106
- // return new PodcastSegmentReorderService(db);
107
- // }
File without changes