@m5kdev/backend 0.8.5 → 0.8.7
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.
- package/dist/src/modules/ai/ai.service.d.mts +13 -1
- package/dist/src/modules/ai/ai.service.mjs +61 -18
- package/dist/src/modules/ai/ai.service.mjs.map +1 -1
- package/dist/src/modules/auth/auth.dto.d.mts +2 -2
- package/dist/src/modules/auth/auth.trpc.d.mts +3 -3
- package/dist/src/modules/connect/connect.dto.d.mts +4 -4
- package/dist/src/modules/connect/connect.repository.d.mts +2 -2
- package/dist/src/modules/connect/connect.service.d.mts +4 -4
- package/dist/src/modules/file/file.service.mjs +2 -2
- package/dist/src/modules/recurrence/recurrence.service.d.mts +1 -1
- package/dist/src/modules/recurrence/recurrence.trpc.d.mts +2 -2
- package/dist/src/modules/video/video.service.mjs +74 -14
- package/dist/src/modules/video/video.service.mjs.map +1 -1
- package/package.json +3 -5
|
@@ -35,6 +35,8 @@ type AIServiceGenerateTextParams = Omit<GenerateTextParams, "model" | "prompt" |
|
|
|
35
35
|
model: string;
|
|
36
36
|
removeMDash?: boolean;
|
|
37
37
|
ctx?: AIServiceActorContext;
|
|
38
|
+
retryAttempts?: number;
|
|
39
|
+
retryModels?: string[];
|
|
38
40
|
};
|
|
39
41
|
type AIServiceGenerateObjectParams<T extends ZodType> = Omit<GenerateTextParams, "model" | "prompt" | "messages" | "output"> & GenerateTextInput & {
|
|
40
42
|
model: string;
|
|
@@ -42,6 +44,15 @@ type AIServiceGenerateObjectParams<T extends ZodType> = Omit<GenerateTextParams,
|
|
|
42
44
|
repairAttempts?: number;
|
|
43
45
|
repairModel?: string;
|
|
44
46
|
ctx?: AIServiceActorContext;
|
|
47
|
+
retryAttempts?: number;
|
|
48
|
+
retryModels?: string[];
|
|
49
|
+
};
|
|
50
|
+
type AIServiceOptions = {
|
|
51
|
+
retryAttempts?: number;
|
|
52
|
+
retryModels?: string[];
|
|
53
|
+
repairAttempts?: number;
|
|
54
|
+
repairModel?: string;
|
|
55
|
+
removeMDash?: boolean;
|
|
45
56
|
};
|
|
46
57
|
declare class AIService<MastraInstance extends Mastra> extends BaseService<{
|
|
47
58
|
aiUsage?: AiUsageRepository;
|
|
@@ -54,6 +65,7 @@ declare class AIService<MastraInstance extends Mastra> extends BaseService<{
|
|
|
54
65
|
mastra?: MastraInstance;
|
|
55
66
|
openrouter?: OpenRouterProvider;
|
|
56
67
|
replicate?: Replicate;
|
|
68
|
+
options?: AIServiceOptions;
|
|
57
69
|
constructor(repositories: {
|
|
58
70
|
aiUsage?: AiUsageRepository;
|
|
59
71
|
}, services: {
|
|
@@ -62,7 +74,7 @@ declare class AIService<MastraInstance extends Mastra> extends BaseService<{
|
|
|
62
74
|
mastra?: MastraInstance;
|
|
63
75
|
openrouter?: OpenRouterProvider;
|
|
64
76
|
replicate?: Replicate;
|
|
65
|
-
});
|
|
77
|
+
}, options?: AIServiceOptions);
|
|
66
78
|
getMastra(): MastraInstance;
|
|
67
79
|
prepareModel(model: string): ReturnType<OpenRouterProvider["chat"]>;
|
|
68
80
|
prepareEmbeddingModel(model: string): ReturnType<OpenRouterProvider["textEmbeddingModel"]>;
|
|
@@ -13,11 +13,13 @@ var AIService = class extends BaseService {
|
|
|
13
13
|
mastra;
|
|
14
14
|
openrouter;
|
|
15
15
|
replicate;
|
|
16
|
-
|
|
16
|
+
options;
|
|
17
|
+
constructor(repositories, services, libs, options) {
|
|
17
18
|
super(repositories, services);
|
|
18
19
|
this.mastra = libs.mastra;
|
|
19
20
|
this.openrouter = libs.openrouter;
|
|
20
21
|
this.replicate = libs.replicate;
|
|
22
|
+
this.options = options;
|
|
21
23
|
}
|
|
22
24
|
getMastra() {
|
|
23
25
|
if (!this.mastra) throw new Error("Mastra is not available");
|
|
@@ -134,8 +136,8 @@ var AIService = class extends BaseService {
|
|
|
134
136
|
}
|
|
135
137
|
async generateText(params) {
|
|
136
138
|
return this.throwableAsync(async () => {
|
|
137
|
-
const { removeMDash = true, model, prompt, messages, ctx, ...rest } = params;
|
|
138
|
-
const
|
|
139
|
+
const { removeMDash = this.options?.removeMDash ?? true, model, prompt, messages, ctx, retryAttempts = this.options?.retryAttempts ?? 0, retryModels = this.options?.retryModels ?? [], ...rest } = params;
|
|
140
|
+
const request = messages ? {
|
|
139
141
|
...rest,
|
|
140
142
|
model: this.prepareModel(model),
|
|
141
143
|
messages
|
|
@@ -143,26 +145,48 @@ var AIService = class extends BaseService {
|
|
|
143
145
|
...rest,
|
|
144
146
|
model: this.prepareModel(model),
|
|
145
147
|
prompt
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
148
|
+
};
|
|
149
|
+
try {
|
|
150
|
+
const result = await generateText(request);
|
|
151
|
+
if (this.repository.aiUsage) {
|
|
152
|
+
const createUsageResult = await this.repository.aiUsage.create({
|
|
153
|
+
userId: ctx?.actor?.userId,
|
|
154
|
+
model,
|
|
155
|
+
provider: "openrouter",
|
|
156
|
+
feature: "generateText",
|
|
157
|
+
traceId: result.providerMetadata?.openrouter?.traceId?.toString(),
|
|
158
|
+
inputTokens: result.usage.inputTokens,
|
|
159
|
+
outputTokens: result.usage.outputTokens,
|
|
160
|
+
totalTokens: result.usage.totalTokens,
|
|
161
|
+
cost: (result?.providerMetadata?.openrouter?.usage)?.cost ?? 0
|
|
162
|
+
});
|
|
163
|
+
if (createUsageResult.isErr()) return err(createUsageResult.error);
|
|
164
|
+
}
|
|
165
|
+
return ok(removeMDash ? result.text.replace(/\u2013|\u2014/g, "-") : result.text);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (retryAttempts <= 0) throw error;
|
|
168
|
+
this.logger.warn(`generateText failed, retrying (${retryAttempts} attempts left)`, {
|
|
150
169
|
model,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
error
|
|
171
|
+
});
|
|
172
|
+
const delay = Math.min(1e3 * 2 ** ((this.options?.retryAttempts ?? 3) - retryAttempts), 1e4);
|
|
173
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
174
|
+
const nextModel = retryModels?.[0] ?? model;
|
|
175
|
+
const nextRetryModels = retryModels ? [...retryModels.slice(1), model] : void 0;
|
|
176
|
+
return this.generateText({
|
|
177
|
+
...rest,
|
|
178
|
+
...messages ? { messages } : { prompt },
|
|
179
|
+
model: nextModel,
|
|
180
|
+
removeMDash,
|
|
181
|
+
ctx,
|
|
182
|
+
retryAttempts: retryAttempts - 1,
|
|
183
|
+
retryModels: nextRetryModels
|
|
158
184
|
});
|
|
159
|
-
if (createUsageResult.isErr()) return err(createUsageResult.error);
|
|
160
185
|
}
|
|
161
|
-
return ok(removeMDash ? result.text.replace(/\u2013|\u2014/g, "-") : result.text);
|
|
162
186
|
});
|
|
163
187
|
}
|
|
164
188
|
async generateObject(params) {
|
|
165
|
-
const { model, schema, prompt, messages, repairAttempts = 0, repairModel, ctx, ...rest } = params;
|
|
189
|
+
const { model, schema, prompt, messages, repairAttempts = this.options?.repairAttempts ?? 0, repairModel = this.options?.repairModel ?? model, ctx, retryAttempts = this.options?.retryAttempts ?? 0, retryModels = this.options?.retryModels ?? [], ...rest } = params;
|
|
166
190
|
const request = messages ? {
|
|
167
191
|
...rest,
|
|
168
192
|
model: this.prepareModel(model),
|
|
@@ -226,7 +250,26 @@ var AIService = class extends BaseService {
|
|
|
226
250
|
}
|
|
227
251
|
return this.error("PARSE_ERROR", "AI: Agent object failed without text", { cause: error });
|
|
228
252
|
}
|
|
229
|
-
return this.error("BAD_REQUEST", "AI:
|
|
253
|
+
if (retryAttempts <= 0) return this.error("BAD_REQUEST", "AI: Provider failed to generate object", { cause: error });
|
|
254
|
+
this.logger.warn(`generateObject failed, retrying (${retryAttempts} attempts left)`, {
|
|
255
|
+
model,
|
|
256
|
+
error
|
|
257
|
+
});
|
|
258
|
+
const delay = Math.min(1e3 * 2 ** ((this.options?.retryAttempts ?? 3) - retryAttempts), 1e4);
|
|
259
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
260
|
+
const nextModel = retryModels?.[0] ?? model;
|
|
261
|
+
const nextRetryModels = retryModels ? [...retryModels.slice(1), model] : void 0;
|
|
262
|
+
return this.generateObject({
|
|
263
|
+
...rest,
|
|
264
|
+
...messages ? { messages } : { prompt },
|
|
265
|
+
model: nextModel,
|
|
266
|
+
schema,
|
|
267
|
+
repairAttempts,
|
|
268
|
+
repairModel,
|
|
269
|
+
ctx,
|
|
270
|
+
retryAttempts: retryAttempts - 1,
|
|
271
|
+
retryModels: nextRetryModels
|
|
272
|
+
});
|
|
230
273
|
}
|
|
231
274
|
}
|
|
232
275
|
async generateReplicate(model, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.service.mjs","names":[],"sources":["../../../../src/modules/ai/ai.service.ts"],"sourcesContent":["import { OPENAI_TEXT_EMBEDDING_3_SMALL } from \"@m5kdev/commons/modules/ai/ai.constants\";\r\nimport { arrayToPseudoXML } from \"@m5kdev/commons/modules/ai/ai.utils\";\r\nimport type { Mastra } from \"@mastra/core\";\r\nimport { RequestContext } from \"@mastra/core/request-context\";\r\nimport type { FullOutput, MastraModelOutput } from \"@mastra/core/stream\";\r\nimport { MDocument } from \"@mastra/rag\";\r\nimport type { OpenRouterProvider } from \"@openrouter/ai-sdk-provider\";\r\nimport {\r\n embed,\r\n embedMany,\r\n generateText,\r\n type ModelMessage,\r\n NoObjectGeneratedError,\r\n Output,\r\n} from \"ai\";\r\nimport { jsonrepair } from \"jsonrepair\";\r\nimport { err, ok } from \"neverthrow\";\r\nimport type Replicate from \"replicate\";\r\nimport type { ZodType, z } from \"zod\";\r\nimport type { RequiredServiceActor } from \"../base/base.actor\";\r\nimport type { ServerResultAsync } from \"../base/base.dto\";\r\nimport { BaseService } from \"../base/base.service\";\r\nimport { repairJsonPrompt } from \"./ai.prompts\";\r\nimport type { AiUsageRepository, AiUsageRow } from \"./ai.repository\";\r\nimport type { IdeogramV3GenerateInput, IdeogramV3GenerateOutput } from \"./ideogram/ideogram.dto\";\r\nimport type { IdeogramService } from \"./ideogram/ideogram.service\";\r\n\r\ntype MastraAgent = ReturnType<Mastra[\"getAgent\"]>;\r\ntype MastraAgentGenerateOptions = Parameters<MastraAgent[\"generate\"]>[1];\r\ntype MessageListInput = { role: \"user\" | \"assistant\" | \"system\"; content: string }[];\r\ntype GenerateTextParams = Parameters<typeof generateText>[0];\r\ntype GenerateTextInput =\r\n | { prompt: string | ModelMessage[]; messages?: never }\r\n | { messages: ModelMessage[]; prompt?: never };\r\ntype AIServiceActorContext = { actor: RequiredServiceActor<\"user\"> };\r\ntype AIServiceGenerateTextParams = Omit<GenerateTextParams, \"model\" | \"prompt\" | \"messages\"> &\r\n GenerateTextInput & {\r\n model: string;\r\n removeMDash?: boolean;\r\n ctx?: AIServiceActorContext;\r\n };\r\ntype AIServiceGenerateObjectParams<T extends ZodType> = Omit<\r\n GenerateTextParams,\r\n \"model\" | \"prompt\" | \"messages\" | \"output\"\r\n> &\r\n GenerateTextInput & {\r\n model: string;\r\n schema: T;\r\n repairAttempts?: number;\r\n repairModel?: string;\r\n ctx?: AIServiceActorContext;\r\n };\r\n\r\nexport class AIService<MastraInstance extends Mastra> extends BaseService<\r\n { aiUsage?: AiUsageRepository },\r\n { ideogram?: IdeogramService }\r\n> {\r\n helpers = {\r\n arrayToPseudoXML,\r\n };\r\n\r\n mastra?: MastraInstance;\r\n openrouter?: OpenRouterProvider;\r\n replicate?: Replicate;\r\n\r\n constructor(\r\n repositories: { aiUsage?: AiUsageRepository },\r\n services: { ideogram?: IdeogramService },\r\n libs: { mastra?: MastraInstance; openrouter?: OpenRouterProvider; replicate?: Replicate }\r\n ) {\r\n super(repositories, services);\r\n this.mastra = libs.mastra;\r\n this.openrouter = libs.openrouter;\r\n this.replicate = libs.replicate;\r\n }\r\n\r\n getMastra(): MastraInstance {\r\n if (!this.mastra) {\r\n throw new Error(\"Mastra is not available\");\r\n }\r\n return this.mastra;\r\n }\r\n\r\n prepareModel(model: string): ReturnType<OpenRouterProvider[\"chat\"]> {\r\n if (!this.openrouter) {\r\n throw new Error(\"OpenRouter is not configured\");\r\n }\r\n return this.openrouter.chat(model, {\r\n usage: {\r\n include: true,\r\n },\r\n });\r\n }\r\n\r\n prepareEmbeddingModel(model: string): ReturnType<OpenRouterProvider[\"textEmbeddingModel\"]> {\r\n if (!this.openrouter) {\r\n throw new Error(\"OpenRouter is not configured\");\r\n }\r\n const openrouter = this.openrouter as OpenRouterProvider & {\r\n embeddingModel?: (modelId: string) => unknown;\r\n };\r\n return (openrouter.embeddingModel?.(model) ??\r\n openrouter.textEmbeddingModel(model)) as ReturnType<OpenRouterProvider[\"textEmbeddingModel\"]>;\r\n }\r\n\r\n async agentUse(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<Awaited<ReturnType<MastraModelOutput<any>[\"getFullOutput\"]>>> {\r\n return this.throwableAsync(async () => {\r\n this.logger.info(\"AGENT USE\");\r\n const { prompt, messages, ...rest } = options;\r\n const payload = messages || prompt;\r\n if (!payload) return this.error(\"BAD_REQUEST\", \"No prompt or messages provided\");\r\n const requestContext = options.requestContext ?? new RequestContext();\r\n\r\n if (ctx?.actor) {\r\n requestContext.set(\"userId\", ctx.actor.userId);\r\n }\r\n if (ctx?.model) {\r\n requestContext.set(\"model\", ctx.model);\r\n }\r\n const mAgent = this.getMastra().getAgent(agent);\r\n\r\n const result = await mAgent.generate(payload as any, {\r\n ...rest,\r\n requestContext: rest.requestContext ?? requestContext,\r\n });\r\n this.logger.info(\"AGENT USE DONE\");\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model: ctx?.model ?? \"unknown\",\r\n provider: \"openrouter\",\r\n feature: agent,\r\n traceId: result.traceId,\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n this.logger.info(\"AGENT USE CREATED USAGE\");\r\n return ok(result);\r\n });\r\n }\r\n\r\n async agentText(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<string> {\r\n const result = await this.agentUse(agent, options, ctx);\r\n if (result.isErr())\r\n return this.error(\"SERVICE_UNAVAILABLE\", \"AI: Agent text failed\", { cause: result.error });\r\n return ok(result.value.text);\r\n }\r\n\r\n async agentTextResult(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<FullOutput<any>> {\r\n const result = await this.agentUse(agent, options, ctx);\r\n if (result.isErr()) return err(result.error);\r\n return ok(result.value);\r\n }\r\n\r\n async agentObject<T extends ZodType<any>>(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & {\r\n schema: T;\r\n prompt?: string;\r\n messages?: MessageListInput;\r\n },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<z.infer<T>> {\r\n const { schema, ...rest } = options;\r\n const result = await this.agentUse(agent, { ...rest, structuredOutput: { schema } }, ctx);\r\n if (result.isErr())\r\n return this.error(\"SERVICE_UNAVAILABLE\", \"AI: Agent object failed\", { cause: result.error });\r\n return ok(result.value.object as z.infer<T>);\r\n }\r\n\r\n async agentObjectResult<T extends ZodType<any>>(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & {\r\n schema: T;\r\n prompt?: string;\r\n messages?: MessageListInput;\r\n },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<FullOutput<any> & { object: z.infer<T> }> {\r\n this.logger.info(\"AGENT OBJECT RESULT\");\r\n const { schema, ...rest } = options;\r\n const result = await this.agentUse(agent, { ...rest, structuredOutput: { schema } }, ctx);\r\n if (result.isErr()) return err(result.error);\r\n this.logger.info(\"AGENT OBJECT RESULT DONE\");\r\n return ok({ ...result.value, object: result.value.object as z.infer<T> });\r\n }\r\n\r\n async embedDocument(\r\n value: string,\r\n options?: Parameters<ReturnType<typeof MDocument.fromText>[\"chunk\"]>[0],\r\n type: \"text\" | \"markdown\" | \"html\" | \"json\" = \"text\",\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embeddings: number[][]; chunks: { text: string }[] }> {\r\n return this.throwableAsync(async () => {\r\n if (type === \"text\") {\r\n const doc = MDocument.fromText(value);\r\n const chunks = await doc.chunk(\r\n options ?? {\r\n strategy: \"recursive\",\r\n maxSize: 512,\r\n overlap: 50,\r\n separators: [\"\\n\"],\r\n }\r\n );\r\n const embeddings = await this.embedMany(chunks, model);\r\n if (embeddings.isErr()) return err(embeddings.error);\r\n return ok({ embeddings: embeddings.value.embeddings, chunks });\r\n }\r\n return this.error(\"BAD_REQUEST\", \"Unsupported document type\");\r\n });\r\n }\r\n\r\n async embed(\r\n text: string,\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embedding: number[] }> {\r\n return this.throwableAsync(async () => {\r\n const result = await embed({\r\n model: this.prepareEmbeddingModel(model),\r\n value: text,\r\n });\r\n return ok(result);\r\n });\r\n }\r\n\r\n async embedMany(\r\n chunks: { text: string }[],\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embeddings: number[][] }> {\r\n return this.throwableAsync(async () => {\r\n const result = await embedMany({\r\n model: this.prepareEmbeddingModel(model),\r\n values: chunks.map((chunk) => chunk.text),\r\n });\r\n return ok(result);\r\n });\r\n }\r\n\r\n async generateText(params: AIServiceGenerateTextParams): ServerResultAsync<string> {\r\n return this.throwableAsync(async () => {\r\n const { removeMDash = true, model, prompt, messages, ctx, ...rest } = params;\r\n const request = messages\r\n ? { ...rest, model: this.prepareModel(model), messages }\r\n : { ...rest, model: this.prepareModel(model), prompt };\r\n const result = await generateText(request);\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateText\",\r\n traceId: result.providerMetadata?.openrouter?.traceId?.toString(),\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n return ok(removeMDash ? result.text.replace(/\\u2013|\\u2014/g, \"-\") : result.text);\r\n });\r\n }\r\n\r\n async generateObject<T extends ZodType>(\r\n params: AIServiceGenerateObjectParams<T>\r\n ): ServerResultAsync<z.infer<T>> {\r\n const {\r\n model,\r\n schema,\r\n prompt,\r\n messages,\r\n repairAttempts = 0,\r\n repairModel,\r\n ctx,\r\n ...rest\r\n } = params;\r\n const request = messages\r\n ? {\r\n ...rest,\r\n model: this.prepareModel(model),\r\n messages,\r\n output: Output.object({ schema }),\r\n }\r\n : {\r\n ...rest,\r\n model: this.prepareModel(model),\r\n prompt,\r\n output: Output.object({ schema }),\r\n };\r\n try {\r\n const result = await generateText(request);\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateObject\",\r\n traceId: result.providerMetadata?.openrouter?.traceId?.toString(),\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n return ok(result.output as z.infer<T>);\r\n } catch (error) {\r\n if (NoObjectGeneratedError.isInstance(error)) {\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateObject\",\r\n traceId: null,\r\n inputTokens: error?.usage?.inputTokens,\r\n outputTokens: error?.usage?.outputTokens,\r\n totalTokens: error?.usage?.totalTokens,\r\n cost: 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n if (error.text) {\r\n const repairedText = jsonrepair(error.text);\r\n const parsed = schema.safeParse(repairedText);\r\n if (parsed.success) return ok(parsed.data);\r\n\r\n if (repairAttempts === 0)\r\n return this.error(\"PARSE_ERROR\", \"AI: Agent object failed\", { cause: error });\r\n\r\n return this.generateObject({\r\n ...rest,\r\n prompt: repairJsonPrompt.compile({\r\n text: error.text,\r\n error: JSON.stringify(error.cause ?? \"Unknown error\"),\r\n }),\r\n repairAttempts: repairAttempts - 1,\r\n model: repairModel ?? model,\r\n schema,\r\n ctx,\r\n });\r\n }\r\n return this.error(\"PARSE_ERROR\", \"AI: Agent object failed without text\", {\r\n cause: error,\r\n });\r\n }\r\n return this.error(\"BAD_REQUEST\", \"AI: Provided failed to generate object\", { cause: error });\r\n }\r\n }\r\n\r\n async generateReplicate(\r\n model: Parameters<Replicate[\"run\"]>[0],\r\n options: Parameters<Replicate[\"run\"]>[1]\r\n ): ServerResultAsync<object> {\r\n return this.throwableAsync(async () => {\r\n if (!this.replicate) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"Replicate is not configured\");\r\n }\r\n try {\r\n return ok(await this.replicate.run(model, options));\r\n } catch (error) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", undefined, { cause: error });\r\n }\r\n });\r\n }\r\n\r\n async generateTranscript(\r\n file_url: string\r\n ): ServerResultAsync<{ text: string; metadata: unknown }> {\r\n const output = await this.generateReplicate(\r\n \"thomasmol/whisper-diarization:1495a9cddc83b2203b0d8d3516e38b80fd1572ebc4bc5700ac1da56a9b3ed886\",\r\n {\r\n input: {\r\n file_url,\r\n },\r\n }\r\n );\r\n\r\n if (output.isErr()) return err(output.error);\r\n\r\n try {\r\n const { segments } = output.value as { segments: { text: string }[] };\r\n return ok({ text: segments.map((segment) => segment.text).join(\"\"), metadata: segments });\r\n } catch (error) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", undefined, { cause: error });\r\n }\r\n }\r\n\r\n async generateIdeogram(\r\n input: IdeogramV3GenerateInput\r\n ): ServerResultAsync<IdeogramV3GenerateOutput> {\r\n if (!this.service.ideogram) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"Ideogram service is not available\");\r\n }\r\n return this.service.ideogram.generate(input);\r\n }\r\n\r\n async getUsage(\r\n userId: string\r\n ): ServerResultAsync<Pick<AiUsageRow, \"inputTokens\" | \"outputTokens\" | \"totalTokens\" | \"cost\">> {\r\n if (!this.repository.aiUsage) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"AI usage repository is not available\");\r\n }\r\n return this.repository.aiUsage.getUsage(userId);\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai.service.mjs","names":[],"sources":["../../../../src/modules/ai/ai.service.ts"],"sourcesContent":["import { OPENAI_TEXT_EMBEDDING_3_SMALL } from \"@m5kdev/commons/modules/ai/ai.constants\";\r\nimport { arrayToPseudoXML } from \"@m5kdev/commons/modules/ai/ai.utils\";\r\nimport type { Mastra } from \"@mastra/core\";\r\nimport { RequestContext } from \"@mastra/core/request-context\";\r\nimport type { FullOutput, MastraModelOutput } from \"@mastra/core/stream\";\r\nimport { MDocument } from \"@mastra/rag\";\r\nimport type { OpenRouterProvider } from \"@openrouter/ai-sdk-provider\";\r\nimport {\r\n embed,\r\n embedMany,\r\n generateText,\r\n type ModelMessage,\r\n NoObjectGeneratedError,\r\n Output,\r\n} from \"ai\";\r\nimport { jsonrepair } from \"jsonrepair\";\r\nimport { err, ok } from \"neverthrow\";\r\nimport type Replicate from \"replicate\";\r\nimport type { ZodType, z } from \"zod\";\r\nimport type { RequiredServiceActor } from \"../base/base.actor\";\r\nimport type { ServerResultAsync } from \"../base/base.dto\";\r\nimport { BaseService } from \"../base/base.service\";\r\nimport { repairJsonPrompt } from \"./ai.prompts\";\r\nimport type { AiUsageRepository, AiUsageRow } from \"./ai.repository\";\r\nimport type { IdeogramV3GenerateInput, IdeogramV3GenerateOutput } from \"./ideogram/ideogram.dto\";\r\nimport type { IdeogramService } from \"./ideogram/ideogram.service\";\r\n\r\ntype MastraAgent = ReturnType<Mastra[\"getAgent\"]>;\r\ntype MastraAgentGenerateOptions = Parameters<MastraAgent[\"generate\"]>[1];\r\ntype MessageListInput = { role: \"user\" | \"assistant\" | \"system\"; content: string }[];\r\ntype GenerateTextParams = Parameters<typeof generateText>[0];\r\ntype GenerateTextInput =\r\n | { prompt: string | ModelMessage[]; messages?: never }\r\n | { messages: ModelMessage[]; prompt?: never };\r\ntype AIServiceActorContext = { actor: RequiredServiceActor<\"user\"> };\r\ntype AIServiceGenerateTextParams = Omit<GenerateTextParams, \"model\" | \"prompt\" | \"messages\"> &\r\n GenerateTextInput & {\r\n model: string;\r\n removeMDash?: boolean;\r\n ctx?: AIServiceActorContext;\r\n retryAttempts?: number;\r\n retryModels?: string[];\r\n };\r\ntype AIServiceGenerateObjectParams<T extends ZodType> = Omit<\r\n GenerateTextParams,\r\n \"model\" | \"prompt\" | \"messages\" | \"output\"\r\n> &\r\n GenerateTextInput & {\r\n model: string;\r\n schema: T;\r\n repairAttempts?: number;\r\n repairModel?: string;\r\n ctx?: AIServiceActorContext;\r\n retryAttempts?: number;\r\n retryModels?: string[];\r\n };\r\n\r\ntype AIServiceOptions = {\r\n retryAttempts?: number;\r\n retryModels?: string[];\r\n repairAttempts?: number;\r\n repairModel?: string;\r\n removeMDash?: boolean;\r\n};\r\n\r\nexport class AIService<MastraInstance extends Mastra> extends BaseService<\r\n { aiUsage?: AiUsageRepository },\r\n { ideogram?: IdeogramService }\r\n> {\r\n helpers = {\r\n arrayToPseudoXML,\r\n };\r\n\r\n mastra?: MastraInstance;\r\n openrouter?: OpenRouterProvider;\r\n replicate?: Replicate;\r\n options?: AIServiceOptions;\r\n\r\n constructor(\r\n repositories: { aiUsage?: AiUsageRepository },\r\n services: { ideogram?: IdeogramService },\r\n libs: { mastra?: MastraInstance; openrouter?: OpenRouterProvider; replicate?: Replicate },\r\n options?: AIServiceOptions\r\n ) {\r\n super(repositories, services);\r\n this.mastra = libs.mastra;\r\n this.openrouter = libs.openrouter;\r\n this.replicate = libs.replicate;\r\n this.options = options;\r\n }\r\n\r\n getMastra(): MastraInstance {\r\n if (!this.mastra) {\r\n throw new Error(\"Mastra is not available\");\r\n }\r\n return this.mastra;\r\n }\r\n\r\n prepareModel(model: string): ReturnType<OpenRouterProvider[\"chat\"]> {\r\n if (!this.openrouter) {\r\n throw new Error(\"OpenRouter is not configured\");\r\n }\r\n return this.openrouter.chat(model, {\r\n usage: {\r\n include: true,\r\n },\r\n });\r\n }\r\n\r\n prepareEmbeddingModel(model: string): ReturnType<OpenRouterProvider[\"textEmbeddingModel\"]> {\r\n if (!this.openrouter) {\r\n throw new Error(\"OpenRouter is not configured\");\r\n }\r\n const openrouter = this.openrouter as OpenRouterProvider & {\r\n embeddingModel?: (modelId: string) => unknown;\r\n };\r\n return (openrouter.embeddingModel?.(model) ??\r\n openrouter.textEmbeddingModel(model)) as ReturnType<OpenRouterProvider[\"textEmbeddingModel\"]>;\r\n }\r\n\r\n async agentUse(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<Awaited<ReturnType<MastraModelOutput<any>[\"getFullOutput\"]>>> {\r\n return this.throwableAsync(async () => {\r\n this.logger.info(\"AGENT USE\");\r\n const { prompt, messages, ...rest } = options;\r\n const payload = messages || prompt;\r\n if (!payload) return this.error(\"BAD_REQUEST\", \"No prompt or messages provided\");\r\n const requestContext = options.requestContext ?? new RequestContext();\r\n\r\n if (ctx?.actor) {\r\n requestContext.set(\"userId\", ctx.actor.userId);\r\n }\r\n if (ctx?.model) {\r\n requestContext.set(\"model\", ctx.model);\r\n }\r\n const mAgent = this.getMastra().getAgent(agent);\r\n\r\n const result = await mAgent.generate(payload as any, {\r\n ...rest,\r\n requestContext: rest.requestContext ?? requestContext,\r\n });\r\n this.logger.info(\"AGENT USE DONE\");\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model: ctx?.model ?? \"unknown\",\r\n provider: \"openrouter\",\r\n feature: agent,\r\n traceId: result.traceId,\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n this.logger.info(\"AGENT USE CREATED USAGE\");\r\n return ok(result);\r\n });\r\n }\r\n\r\n async agentText(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<string> {\r\n const result = await this.agentUse(agent, options, ctx);\r\n if (result.isErr())\r\n return this.error(\"SERVICE_UNAVAILABLE\", \"AI: Agent text failed\", { cause: result.error });\r\n return ok(result.value.text);\r\n }\r\n\r\n async agentTextResult(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & { prompt?: string; messages?: MessageListInput },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<FullOutput<any>> {\r\n const result = await this.agentUse(agent, options, ctx);\r\n if (result.isErr()) return err(result.error);\r\n return ok(result.value);\r\n }\r\n\r\n async agentObject<T extends ZodType<any>>(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & {\r\n schema: T;\r\n prompt?: string;\r\n messages?: MessageListInput;\r\n },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<z.infer<T>> {\r\n const { schema, ...rest } = options;\r\n const result = await this.agentUse(agent, { ...rest, structuredOutput: { schema } }, ctx);\r\n if (result.isErr())\r\n return this.error(\"SERVICE_UNAVAILABLE\", \"AI: Agent object failed\", { cause: result.error });\r\n return ok(result.value.object as z.infer<T>);\r\n }\r\n\r\n async agentObjectResult<T extends ZodType<any>>(\r\n agent: string,\r\n options: MastraAgentGenerateOptions & {\r\n schema: T;\r\n prompt?: string;\r\n messages?: MessageListInput;\r\n },\r\n ctx?: AIServiceActorContext & { model?: string }\r\n ): ServerResultAsync<FullOutput<any> & { object: z.infer<T> }> {\r\n this.logger.info(\"AGENT OBJECT RESULT\");\r\n const { schema, ...rest } = options;\r\n const result = await this.agentUse(agent, { ...rest, structuredOutput: { schema } }, ctx);\r\n if (result.isErr()) return err(result.error);\r\n this.logger.info(\"AGENT OBJECT RESULT DONE\");\r\n return ok({ ...result.value, object: result.value.object as z.infer<T> });\r\n }\r\n\r\n async embedDocument(\r\n value: string,\r\n options?: Parameters<ReturnType<typeof MDocument.fromText>[\"chunk\"]>[0],\r\n type: \"text\" | \"markdown\" | \"html\" | \"json\" = \"text\",\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embeddings: number[][]; chunks: { text: string }[] }> {\r\n return this.throwableAsync(async () => {\r\n if (type === \"text\") {\r\n const doc = MDocument.fromText(value);\r\n const chunks = await doc.chunk(\r\n options ?? {\r\n strategy: \"recursive\",\r\n maxSize: 512,\r\n overlap: 50,\r\n separators: [\"\\n\"],\r\n }\r\n );\r\n const embeddings = await this.embedMany(chunks, model);\r\n if (embeddings.isErr()) return err(embeddings.error);\r\n return ok({ embeddings: embeddings.value.embeddings, chunks });\r\n }\r\n return this.error(\"BAD_REQUEST\", \"Unsupported document type\");\r\n });\r\n }\r\n\r\n async embed(\r\n text: string,\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embedding: number[] }> {\r\n return this.throwableAsync(async () => {\r\n const result = await embed({\r\n model: this.prepareEmbeddingModel(model),\r\n value: text,\r\n });\r\n return ok(result);\r\n });\r\n }\r\n\r\n async embedMany(\r\n chunks: { text: string }[],\r\n model: string = OPENAI_TEXT_EMBEDDING_3_SMALL\r\n ): ServerResultAsync<{ embeddings: number[][] }> {\r\n return this.throwableAsync(async () => {\r\n const result = await embedMany({\r\n model: this.prepareEmbeddingModel(model),\r\n values: chunks.map((chunk) => chunk.text),\r\n });\r\n return ok(result);\r\n });\r\n }\r\n\r\n async generateText(params: AIServiceGenerateTextParams): ServerResultAsync<string> {\r\n return this.throwableAsync(async () => {\r\n const {\r\n removeMDash = this.options?.removeMDash ?? true,\r\n model,\r\n prompt,\r\n messages,\r\n ctx,\r\n retryAttempts = this.options?.retryAttempts ?? 0,\r\n retryModels = this.options?.retryModels ?? [],\r\n ...rest\r\n } = params;\r\n const request = messages\r\n ? { ...rest, model: this.prepareModel(model), messages }\r\n : { ...rest, model: this.prepareModel(model), prompt };\r\n try {\r\n const result = await generateText(request);\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateText\",\r\n traceId: result.providerMetadata?.openrouter?.traceId?.toString(),\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n return ok(removeMDash ? result.text.replace(/\\u2013|\\u2014/g, \"-\") : result.text);\r\n } catch (error) {\r\n if (retryAttempts <= 0) throw error;\r\n this.logger.warn(`generateText failed, retrying (${retryAttempts} attempts left)`, {\r\n model,\r\n error,\r\n });\r\n // Exponential backoff: wait before retrying\r\n const delay = Math.min(\r\n 1000 * 2 ** ((this.options?.retryAttempts ?? 3) - retryAttempts),\r\n 10000\r\n );\r\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\r\n const nextModel = retryModels?.[0] ?? model;\r\n const nextRetryModels = retryModels ? [...retryModels.slice(1), model] : undefined;\r\n return this.generateText({\r\n ...rest,\r\n ...(messages ? { messages } : { prompt: prompt! }),\r\n model: nextModel,\r\n removeMDash,\r\n ctx,\r\n retryAttempts: retryAttempts - 1,\r\n retryModels: nextRetryModels,\r\n } as AIServiceGenerateTextParams);\r\n }\r\n });\r\n }\r\n\r\n async generateObject<T extends ZodType>(\r\n params: AIServiceGenerateObjectParams<T>\r\n ): ServerResultAsync<z.infer<T>> {\r\n const {\r\n model,\r\n schema,\r\n prompt,\r\n messages,\r\n repairAttempts = this.options?.repairAttempts ?? 0,\r\n repairModel = this.options?.repairModel ?? model,\r\n ctx,\r\n retryAttempts = this.options?.retryAttempts ?? 0,\r\n retryModels = this.options?.retryModels ?? [],\r\n ...rest\r\n } = params;\r\n const request = messages\r\n ? {\r\n ...rest,\r\n model: this.prepareModel(model),\r\n messages,\r\n output: Output.object({ schema }),\r\n }\r\n : {\r\n ...rest,\r\n model: this.prepareModel(model),\r\n prompt,\r\n output: Output.object({ schema }),\r\n };\r\n try {\r\n const result = await generateText(request);\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateObject\",\r\n traceId: result.providerMetadata?.openrouter?.traceId?.toString(),\r\n inputTokens: result.usage.inputTokens,\r\n outputTokens: result.usage.outputTokens,\r\n totalTokens: result.usage.totalTokens,\r\n cost: (result?.providerMetadata?.openrouter?.usage as any)?.cost ?? 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n return ok(result.output as z.infer<T>);\r\n } catch (error) {\r\n if (NoObjectGeneratedError.isInstance(error)) {\r\n if (this.repository.aiUsage) {\r\n const createUsageResult = await this.repository.aiUsage.create({\r\n userId: ctx?.actor?.userId,\r\n model,\r\n provider: \"openrouter\",\r\n feature: \"generateObject\",\r\n traceId: null,\r\n inputTokens: error?.usage?.inputTokens,\r\n outputTokens: error?.usage?.outputTokens,\r\n totalTokens: error?.usage?.totalTokens,\r\n cost: 0,\r\n });\r\n if (createUsageResult.isErr()) return err(createUsageResult.error);\r\n }\r\n if (error.text) {\r\n const repairedText = jsonrepair(error.text);\r\n const parsed = schema.safeParse(repairedText);\r\n if (parsed.success) return ok(parsed.data);\r\n\r\n if (repairAttempts === 0)\r\n return this.error(\"PARSE_ERROR\", \"AI: Agent object failed\", { cause: error });\r\n\r\n return this.generateObject({\r\n ...rest,\r\n prompt: repairJsonPrompt.compile({\r\n text: error.text,\r\n error: JSON.stringify(error.cause ?? \"Unknown error\"),\r\n }),\r\n repairAttempts: repairAttempts - 1,\r\n model: repairModel ?? model,\r\n schema,\r\n ctx,\r\n });\r\n }\r\n return this.error(\"PARSE_ERROR\", \"AI: Agent object failed without text\", {\r\n cause: error,\r\n });\r\n }\r\n if (retryAttempts <= 0)\r\n return this.error(\"BAD_REQUEST\", \"AI: Provider failed to generate object\", {\r\n cause: error,\r\n });\r\n this.logger.warn(`generateObject failed, retrying (${retryAttempts} attempts left)`, {\r\n model,\r\n error,\r\n });\r\n // Exponential backoff: wait before retrying\r\n const delay = Math.min(\r\n 1000 * 2 ** ((this.options?.retryAttempts ?? 3) - retryAttempts),\r\n 10000\r\n );\r\n await new Promise<void>((resolve) => setTimeout(resolve, delay));\r\n const nextModel = retryModels?.[0] ?? model;\r\n const nextRetryModels = retryModels ? [...retryModels.slice(1), model] : undefined;\r\n return this.generateObject({\r\n ...rest,\r\n ...(messages ? { messages } : { prompt: prompt! }),\r\n model: nextModel,\r\n schema,\r\n repairAttempts,\r\n repairModel,\r\n ctx,\r\n retryAttempts: retryAttempts - 1,\r\n retryModels: nextRetryModels,\r\n } as AIServiceGenerateObjectParams<T>);\r\n }\r\n }\r\n\r\n async generateReplicate(\r\n model: Parameters<Replicate[\"run\"]>[0],\r\n options: Parameters<Replicate[\"run\"]>[1]\r\n ): ServerResultAsync<object> {\r\n return this.throwableAsync(async () => {\r\n if (!this.replicate) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"Replicate is not configured\");\r\n }\r\n try {\r\n return ok(await this.replicate.run(model, options));\r\n } catch (error) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", undefined, { cause: error });\r\n }\r\n });\r\n }\r\n\r\n async generateTranscript(\r\n file_url: string\r\n ): ServerResultAsync<{ text: string; metadata: unknown }> {\r\n const output = await this.generateReplicate(\r\n \"thomasmol/whisper-diarization:1495a9cddc83b2203b0d8d3516e38b80fd1572ebc4bc5700ac1da56a9b3ed886\",\r\n {\r\n input: {\r\n file_url,\r\n },\r\n }\r\n );\r\n\r\n if (output.isErr()) return err(output.error);\r\n\r\n try {\r\n const { segments } = output.value as { segments: { text: string }[] };\r\n return ok({ text: segments.map((segment) => segment.text).join(\"\"), metadata: segments });\r\n } catch (error) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", undefined, { cause: error });\r\n }\r\n }\r\n\r\n async generateIdeogram(\r\n input: IdeogramV3GenerateInput\r\n ): ServerResultAsync<IdeogramV3GenerateOutput> {\r\n if (!this.service.ideogram) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"Ideogram service is not available\");\r\n }\r\n return this.service.ideogram.generate(input);\r\n }\r\n\r\n async getUsage(\r\n userId: string\r\n ): ServerResultAsync<Pick<AiUsageRow, \"inputTokens\" | \"outputTokens\" | \"totalTokens\" | \"cost\">> {\r\n if (!this.repository.aiUsage) {\r\n return this.error(\"INTERNAL_SERVER_ERROR\", \"AI usage repository is not available\");\r\n }\r\n return this.repository.aiUsage.getUsage(userId);\r\n }\r\n}\r\n"],"mappings":"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"}
|
|
@@ -36,8 +36,8 @@ declare const accountClaimOutputSchema: z.ZodObject<{
|
|
|
36
36
|
id: z.ZodString;
|
|
37
37
|
createdAt: z.ZodDate;
|
|
38
38
|
updatedAt: z.ZodNullable<z.ZodDate>;
|
|
39
|
-
status: z.ZodString;
|
|
40
39
|
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
40
|
+
status: z.ZodString;
|
|
41
41
|
claimUserId: z.ZodNullable<z.ZodString>;
|
|
42
42
|
claimedAt: z.ZodNullable<z.ZodDate>;
|
|
43
43
|
claimedEmail: z.ZodNullable<z.ZodString>;
|
|
@@ -58,8 +58,8 @@ declare const accountClaimMagicLinkOutputSchema: z.ZodObject<{
|
|
|
58
58
|
id: z.ZodString;
|
|
59
59
|
email: z.ZodString;
|
|
60
60
|
createdAt: z.ZodDate;
|
|
61
|
-
userId: z.ZodString;
|
|
62
61
|
expiresAt: z.ZodNullable<z.ZodDate>;
|
|
62
|
+
userId: z.ZodString;
|
|
63
63
|
claimId: z.ZodString;
|
|
64
64
|
url: z.ZodString;
|
|
65
65
|
}, z.core.$strip>;
|
|
@@ -59,8 +59,8 @@ declare function createAuthTRPC({
|
|
|
59
59
|
id: string;
|
|
60
60
|
createdAt: Date;
|
|
61
61
|
updatedAt: Date | null;
|
|
62
|
-
status: string;
|
|
63
62
|
expiresAt: Date | null;
|
|
63
|
+
status: string;
|
|
64
64
|
claimUserId: string | null;
|
|
65
65
|
claimedAt: Date | null;
|
|
66
66
|
claimedEmail: string | null;
|
|
@@ -76,8 +76,8 @@ declare function createAuthTRPC({
|
|
|
76
76
|
id: string;
|
|
77
77
|
email: string;
|
|
78
78
|
createdAt: Date;
|
|
79
|
-
userId: string;
|
|
80
79
|
expiresAt: Date | null;
|
|
80
|
+
userId: string;
|
|
81
81
|
claimId: string;
|
|
82
82
|
url: string;
|
|
83
83
|
};
|
|
@@ -91,8 +91,8 @@ declare function createAuthTRPC({
|
|
|
91
91
|
id: string;
|
|
92
92
|
email: string;
|
|
93
93
|
createdAt: Date;
|
|
94
|
-
userId: string;
|
|
95
94
|
expiresAt: Date | null;
|
|
95
|
+
userId: string;
|
|
96
96
|
claimId: string;
|
|
97
97
|
url: string;
|
|
98
98
|
}[];
|
|
@@ -27,10 +27,10 @@ declare const connectSelectOutputSchema: z.ZodObject<{
|
|
|
27
27
|
id: z.ZodString;
|
|
28
28
|
createdAt: z.ZodDate;
|
|
29
29
|
updatedAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
30
|
-
userId: z.ZodString;
|
|
31
|
-
provider: z.ZodString;
|
|
32
30
|
expiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
31
|
+
userId: z.ZodString;
|
|
33
32
|
scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
33
|
+
provider: z.ZodString;
|
|
34
34
|
accountType: z.ZodString;
|
|
35
35
|
providerAccountId: z.ZodString;
|
|
36
36
|
handle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -51,10 +51,10 @@ declare const connectListOutputSchema: z.ZodArray<z.ZodObject<{
|
|
|
51
51
|
id: z.ZodString;
|
|
52
52
|
createdAt: z.ZodDate;
|
|
53
53
|
updatedAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
54
|
-
userId: z.ZodString;
|
|
55
|
-
provider: z.ZodString;
|
|
56
54
|
expiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
55
|
+
userId: z.ZodString;
|
|
57
56
|
scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
57
|
+
provider: z.ZodString;
|
|
58
58
|
accountType: z.ZodString;
|
|
59
59
|
providerAccountId: z.ZodString;
|
|
60
60
|
handle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -396,12 +396,12 @@ declare class ConnectRepository extends BaseTableRepository<Orm, Schema, Record<
|
|
|
396
396
|
id: string;
|
|
397
397
|
createdAt: Date;
|
|
398
398
|
updatedAt: Date | null;
|
|
399
|
-
userId: string;
|
|
400
|
-
provider: string;
|
|
401
399
|
expiresAt: Date | null;
|
|
400
|
+
userId: string;
|
|
402
401
|
accessToken: string;
|
|
403
402
|
refreshToken: string | null;
|
|
404
403
|
scope: string | null;
|
|
404
|
+
provider: string;
|
|
405
405
|
accountType: string;
|
|
406
406
|
providerAccountId: string;
|
|
407
407
|
handle: string | null;
|
|
@@ -22,12 +22,12 @@ declare class ConnectService extends BaseService<{
|
|
|
22
22
|
id: string;
|
|
23
23
|
createdAt: Date;
|
|
24
24
|
updatedAt: Date | null;
|
|
25
|
-
userId: string;
|
|
26
|
-
provider: string;
|
|
27
25
|
expiresAt: Date | null;
|
|
26
|
+
userId: string;
|
|
28
27
|
accessToken: string;
|
|
29
28
|
refreshToken: string | null;
|
|
30
29
|
scope: string | null;
|
|
30
|
+
provider: string;
|
|
31
31
|
accountType: string;
|
|
32
32
|
providerAccountId: string;
|
|
33
33
|
handle: string | null;
|
|
@@ -43,12 +43,12 @@ declare class ConnectService extends BaseService<{
|
|
|
43
43
|
id: string;
|
|
44
44
|
createdAt: Date;
|
|
45
45
|
updatedAt: Date | null;
|
|
46
|
-
userId: string;
|
|
47
|
-
provider: string;
|
|
48
46
|
expiresAt: Date | null;
|
|
47
|
+
userId: string;
|
|
49
48
|
accessToken: string;
|
|
50
49
|
refreshToken: string | null;
|
|
51
50
|
scope: string | null;
|
|
51
|
+
provider: string;
|
|
52
52
|
accountType: string;
|
|
53
53
|
providerAccountId: string;
|
|
54
54
|
handle: string | null;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BaseService } from "../base/base.service.mjs";
|
|
2
2
|
import { err, ok } from "neverthrow";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
|
-
import { createWriteStream } from "node:fs";
|
|
5
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
4
|
import path, { dirname } from "node:path";
|
|
7
5
|
import { fileTypes } from "@m5kdev/commons/modules/file/file.constants";
|
|
6
|
+
import { createWriteStream } from "node:fs";
|
|
7
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
8
8
|
import { tmpdir } from "node:os";
|
|
9
9
|
import { Readable } from "node:stream";
|
|
10
10
|
import { pipeline } from "node:stream/promises";
|
|
@@ -47,8 +47,8 @@ declare class RecurrenceService extends BaseService<{
|
|
|
47
47
|
kind: string;
|
|
48
48
|
enabled: boolean;
|
|
49
49
|
recurrenceRules: {
|
|
50
|
-
freq: number;
|
|
51
50
|
interval: number;
|
|
51
|
+
freq: number;
|
|
52
52
|
bysetpos?: number | number[] | null | undefined;
|
|
53
53
|
bymonth?: number | number[] | null | undefined;
|
|
54
54
|
bymonthday?: number | number[] | null | undefined;
|
|
@@ -50,8 +50,8 @@ declare function createRecurrenceTRPC({
|
|
|
50
50
|
kind: string;
|
|
51
51
|
enabled: boolean;
|
|
52
52
|
recurrenceRules: {
|
|
53
|
-
freq: number;
|
|
54
53
|
interval: number;
|
|
54
|
+
freq: number;
|
|
55
55
|
bysetpos?: number | number[] | null | undefined;
|
|
56
56
|
bymonth?: number | number[] | null | undefined;
|
|
57
57
|
bymonthday?: number | number[] | null | undefined;
|
|
@@ -150,8 +150,8 @@ declare function createRecurrenceTRPC({
|
|
|
150
150
|
updateRule: _$_trpc_server0.TRPCMutationProcedure<{
|
|
151
151
|
input: {
|
|
152
152
|
id: string;
|
|
153
|
-
freq: number;
|
|
154
153
|
interval: number;
|
|
154
|
+
freq: number;
|
|
155
155
|
bysetpos?: number | number[] | null | undefined;
|
|
156
156
|
bymonth?: number | number[] | null | undefined;
|
|
157
157
|
bymonthday?: number | number[] | null | undefined;
|
|
@@ -1,25 +1,60 @@
|
|
|
1
1
|
import { BaseService } from "../base/base.service.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { ok } from "neverthrow";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
|
-
import { closeSync, existsSync, mkdirSync, openSync } from "node:fs";
|
|
5
4
|
import path from "node:path";
|
|
5
|
+
import { closeSync, existsSync, mkdirSync, openSync } from "node:fs";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
6
7
|
import ffbin from "ffmpeg-ffprobe-static";
|
|
7
|
-
import ffmpeg from "fluent-ffmpeg";
|
|
8
8
|
//#region src/modules/video/video.service.ts
|
|
9
9
|
if (!ffbin.ffmpegPath || !ffbin.ffprobePath) throw new Error("FFmpeg or FFprobe not found");
|
|
10
|
-
ffmpeg.setFfmpegPath(ffbin.ffmpegPath);
|
|
11
|
-
ffmpeg.setFfprobePath(ffbin.ffprobePath);
|
|
12
10
|
const uploadsDir = path.join(__dirname, "..", "uploads");
|
|
13
11
|
if (!existsSync(uploadsDir)) mkdirSync(uploadsDir, { recursive: true });
|
|
12
|
+
const runFfmpeg = async (args) => {
|
|
13
|
+
await new Promise((resolve, reject) => {
|
|
14
|
+
const child = spawn(ffbin.ffmpegPath, [...args], { stdio: [
|
|
15
|
+
"ignore",
|
|
16
|
+
"ignore",
|
|
17
|
+
"pipe"
|
|
18
|
+
] });
|
|
19
|
+
let stderr = "";
|
|
20
|
+
child.stderr?.setEncoding("utf8");
|
|
21
|
+
child.stderr?.on("data", (chunk) => {
|
|
22
|
+
stderr += chunk;
|
|
23
|
+
});
|
|
24
|
+
child.on("error", (error) => reject(error));
|
|
25
|
+
child.on("close", (code) => {
|
|
26
|
+
if (code === 0) {
|
|
27
|
+
resolve();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
reject(new Error(stderr || `ffmpeg exited with code ${code ?? "unknown"}`));
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
};
|
|
14
34
|
var VideoService = class extends BaseService {
|
|
15
35
|
async cut(file, start, end) {
|
|
16
36
|
return this.throwableAsync(async () => {
|
|
17
37
|
const duration = end - start;
|
|
18
38
|
const output = path.join(uploadsDir, `${v4()}.mp4`);
|
|
19
39
|
if (!existsSync(output)) closeSync(openSync(output, "w"));
|
|
20
|
-
await
|
|
21
|
-
|
|
22
|
-
|
|
40
|
+
await runFfmpeg([
|
|
41
|
+
"-i",
|
|
42
|
+
file,
|
|
43
|
+
"-ss",
|
|
44
|
+
String(start),
|
|
45
|
+
"-t",
|
|
46
|
+
String(duration),
|
|
47
|
+
"-c:v",
|
|
48
|
+
"libx264",
|
|
49
|
+
"-c:a",
|
|
50
|
+
"copy",
|
|
51
|
+
"-movflags",
|
|
52
|
+
"+faststart",
|
|
53
|
+
"-y",
|
|
54
|
+
output
|
|
55
|
+
]).catch((error) => {
|
|
56
|
+
throw this.handleUnknownError(error);
|
|
57
|
+
});
|
|
23
58
|
return ok(output);
|
|
24
59
|
});
|
|
25
60
|
}
|
|
@@ -27,9 +62,23 @@ var VideoService = class extends BaseService {
|
|
|
27
62
|
return this.throwableAsync(async () => {
|
|
28
63
|
const output = path.join(uploadsDir, `${v4()}.wav`);
|
|
29
64
|
if (!existsSync(output)) closeSync(openSync(output, "w"));
|
|
30
|
-
await
|
|
31
|
-
|
|
32
|
-
|
|
65
|
+
await runFfmpeg([
|
|
66
|
+
"-i",
|
|
67
|
+
input,
|
|
68
|
+
"-vn",
|
|
69
|
+
"-c:a",
|
|
70
|
+
"pcm_s16le",
|
|
71
|
+
"-ar",
|
|
72
|
+
String(hz),
|
|
73
|
+
"-ac",
|
|
74
|
+
"2",
|
|
75
|
+
"-f",
|
|
76
|
+
"wav",
|
|
77
|
+
"-y",
|
|
78
|
+
output
|
|
79
|
+
]).catch((error) => {
|
|
80
|
+
throw this.handleUnknownError(error);
|
|
81
|
+
});
|
|
33
82
|
return ok(output);
|
|
34
83
|
});
|
|
35
84
|
}
|
|
@@ -37,9 +86,20 @@ var VideoService = class extends BaseService {
|
|
|
37
86
|
return this.throwableAsync(async () => {
|
|
38
87
|
const output = path.join(uploadsDir, `${v4()}.mp3`);
|
|
39
88
|
if (!existsSync(output)) closeSync(openSync(output, "w"));
|
|
40
|
-
await
|
|
41
|
-
|
|
42
|
-
|
|
89
|
+
await runFfmpeg([
|
|
90
|
+
"-i",
|
|
91
|
+
input,
|
|
92
|
+
"-map",
|
|
93
|
+
`0:a:${streamIndex}`,
|
|
94
|
+
"-c:a",
|
|
95
|
+
"libmp3lame",
|
|
96
|
+
"-b:a",
|
|
97
|
+
`${kbps}k`,
|
|
98
|
+
"-y",
|
|
99
|
+
output
|
|
100
|
+
]).catch((error) => {
|
|
101
|
+
throw this.handleUnknownError(error);
|
|
102
|
+
});
|
|
43
103
|
return ok(output);
|
|
44
104
|
});
|
|
45
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.service.mjs","names":["uuidv4"],"sources":["../../../../src/modules/video/video.service.ts"],"sourcesContent":["import { closeSync, existsSync, mkdirSync, openSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\
|
|
1
|
+
{"version":3,"file":"video.service.mjs","names":["uuidv4"],"sources":["../../../../src/modules/video/video.service.ts"],"sourcesContent":["import { closeSync, existsSync, mkdirSync, openSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { spawn } from \"node:child_process\";\r\n//\r\nimport ffbin from \"ffmpeg-ffprobe-static\";\r\nimport { err, ok } from \"neverthrow\";\r\nimport { v4 as uuidv4 } from \"uuid\";\r\nimport type { ServerResultAsync } from \"../base/base.dto\";\r\nimport { BaseService } from \"../base/base.service\";\r\n\r\nif (!ffbin.ffmpegPath || !ffbin.ffprobePath) {\r\n throw new Error(\"FFmpeg or FFprobe not found\");\r\n}\r\n\r\nconst uploadsDir = path.join(__dirname, \"..\", \"uploads\");\r\nif (!existsSync(uploadsDir)) {\r\n mkdirSync(uploadsDir, { recursive: true });\r\n}\r\n\r\nconst runFfmpeg = async (args: readonly string[]): Promise<void> => {\r\n await new Promise<void>((resolve, reject) => {\r\n const child = spawn(ffbin.ffmpegPath as string, [...args], {\r\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\r\n });\r\n\r\n let stderr = \"\";\r\n child.stderr?.setEncoding(\"utf8\");\r\n child.stderr?.on(\"data\", (chunk: string) => {\r\n stderr += chunk;\r\n });\r\n\r\n child.on(\"error\", (error) => reject(error));\r\n child.on(\"close\", (code) => {\r\n if (code === 0) {\r\n resolve();\r\n return;\r\n }\r\n reject(new Error(stderr || `ffmpeg exited with code ${code ?? \"unknown\"}`));\r\n });\r\n });\r\n};\r\n\r\nexport class VideoService extends BaseService<never, never> {\r\n async cut(file: string, start: number, end: number): ServerResultAsync<string> {\r\n return this.throwableAsync(async () => {\r\n const duration = end - start;\r\n const output = path.join(uploadsDir, `${uuidv4()}.mp4`);\r\n if (!existsSync(output)) {\r\n closeSync(openSync(output, \"w\"));\r\n }\r\n\r\n await runFfmpeg([\r\n \"-i\",\r\n file,\r\n \"-ss\",\r\n String(start),\r\n \"-t\",\r\n String(duration),\r\n \"-c:v\",\r\n \"libx264\",\r\n \"-c:a\",\r\n \"copy\",\r\n \"-movflags\",\r\n \"+faststart\",\r\n \"-y\",\r\n output,\r\n ]).catch((error) => {\r\n throw this.handleUnknownError(error);\r\n });\r\n\r\n return ok(output);\r\n });\r\n }\r\n\r\n async webmToWav(input: string, hz = 48000): ServerResultAsync<string> {\r\n return this.throwableAsync(async () => {\r\n const output = path.join(uploadsDir, `${uuidv4()}.wav`);\r\n if (!existsSync(output)) {\r\n closeSync(openSync(output, \"w\"));\r\n }\r\n\r\n await runFfmpeg([\r\n \"-i\",\r\n input,\r\n \"-vn\",\r\n \"-c:a\",\r\n \"pcm_s16le\",\r\n \"-ar\",\r\n String(hz),\r\n \"-ac\",\r\n \"2\",\r\n \"-f\",\r\n \"wav\",\r\n \"-y\",\r\n output,\r\n ]).catch((error) => {\r\n throw this.handleUnknownError(error);\r\n });\r\n return ok(output);\r\n });\r\n }\r\n\r\n async extractAudioMp3(input: string, kbps = 192, streamIndex = 0): ServerResultAsync<string> {\r\n return this.throwableAsync(async () => {\r\n const output = path.join(uploadsDir, `${uuidv4()}.mp3`);\r\n if (!existsSync(output)) {\r\n closeSync(openSync(output, \"w\"));\r\n }\r\n await runFfmpeg([\r\n \"-i\",\r\n input,\r\n \"-map\",\r\n `0:a:${streamIndex}`,\r\n \"-c:a\",\r\n \"libmp3lame\",\r\n \"-b:a\",\r\n `${kbps}k`,\r\n \"-y\",\r\n output,\r\n ]).catch((error) => {\r\n throw this.handleUnknownError(error);\r\n });\r\n\r\n return ok(output);\r\n });\r\n }\r\n}\r\n"],"mappings":";;;;;;;;AAUA,IAAI,CAAC,MAAM,cAAc,CAAC,MAAM,YAC9B,OAAM,IAAI,MAAM,8BAA8B;AAGhD,MAAM,aAAa,KAAK,KAAK,WAAW,MAAM,UAAU;AACxD,IAAI,CAAC,WAAW,WAAW,CACzB,WAAU,YAAY,EAAE,WAAW,MAAM,CAAC;AAG5C,MAAM,YAAY,OAAO,SAA2C;AAClE,OAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,MAAM,QAAQ,MAAM,MAAM,YAAsB,CAAC,GAAG,KAAK,EAAE,EACzD,OAAO;GAAC;GAAU;GAAU;GAAO,EACpC,CAAC;EAEF,IAAI,SAAS;AACb,QAAM,QAAQ,YAAY,OAAO;AACjC,QAAM,QAAQ,GAAG,SAAS,UAAkB;AAC1C,aAAU;IACV;AAEF,QAAM,GAAG,UAAU,UAAU,OAAO,MAAM,CAAC;AAC3C,QAAM,GAAG,UAAU,SAAS;AAC1B,OAAI,SAAS,GAAG;AACd,aAAS;AACT;;AAEF,UAAO,IAAI,MAAM,UAAU,2BAA2B,QAAQ,YAAY,CAAC;IAC3E;GACF;;AAGJ,IAAa,eAAb,cAAkC,YAA0B;CAC1D,MAAM,IAAI,MAAc,OAAe,KAAwC;AAC7E,SAAO,KAAK,eAAe,YAAY;GACrC,MAAM,WAAW,MAAM;GACvB,MAAM,SAAS,KAAK,KAAK,YAAY,GAAGA,IAAQ,CAAC,MAAM;AACvD,OAAI,CAAC,WAAW,OAAO,CACrB,WAAU,SAAS,QAAQ,IAAI,CAAC;AAGlC,SAAM,UAAU;IACd;IACA;IACA;IACA,OAAO,MAAM;IACb;IACA,OAAO,SAAS;IAChB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD,CAAC,CAAC,OAAO,UAAU;AAClB,UAAM,KAAK,mBAAmB,MAAM;KACpC;AAEF,UAAO,GAAG,OAAO;IACjB;;CAGJ,MAAM,UAAU,OAAe,KAAK,MAAkC;AACpE,SAAO,KAAK,eAAe,YAAY;GACrC,MAAM,SAAS,KAAK,KAAK,YAAY,GAAGA,IAAQ,CAAC,MAAM;AACvD,OAAI,CAAC,WAAW,OAAO,CACrB,WAAU,SAAS,QAAQ,IAAI,CAAC;AAGlC,SAAM,UAAU;IACd;IACA;IACA;IACA;IACA;IACA;IACA,OAAO,GAAG;IACV;IACA;IACA;IACA;IACA;IACA;IACD,CAAC,CAAC,OAAO,UAAU;AAClB,UAAM,KAAK,mBAAmB,MAAM;KACpC;AACF,UAAO,GAAG,OAAO;IACjB;;CAGJ,MAAM,gBAAgB,OAAe,OAAO,KAAK,cAAc,GAA8B;AAC3F,SAAO,KAAK,eAAe,YAAY;GACrC,MAAM,SAAS,KAAK,KAAK,YAAY,GAAGA,IAAQ,CAAC,MAAM;AACvD,OAAI,CAAC,WAAW,OAAO,CACrB,WAAU,SAAS,QAAQ,IAAI,CAAC;AAElC,SAAM,UAAU;IACd;IACA;IACA;IACA,OAAO;IACP;IACA;IACA;IACA,GAAG,KAAK;IACR;IACA;IACD,CAAC,CAAC,OAAO,UAAU;AAClB,UAAM,KAAK,mBAAmB,MAAM;KACpC;AAEF,UAAO,GAAG,OAAO;IACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m5kdev/backend",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"description": "Composable Express server stack with Drizzle ORM and tRPC.",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"drizzle-zod": "0.8.2",
|
|
38
38
|
"express": "4.21.2",
|
|
39
39
|
"ffmpeg-ffprobe-static": "6.1.2-rc.1",
|
|
40
|
-
"fluent-ffmpeg": "2.1.3",
|
|
41
40
|
"ioredis": "5.7.0",
|
|
42
41
|
"jsonrepair": "^3.13.3",
|
|
43
42
|
"luxon": "3.7.1",
|
|
@@ -59,15 +58,14 @@
|
|
|
59
58
|
"trpc-to-openapi": "2.3.0",
|
|
60
59
|
"uuid": "11.0.5",
|
|
61
60
|
"zod": "4.2.1",
|
|
62
|
-
"@m5kdev/commons": "0.8.
|
|
63
|
-
"@m5kdev/config": "0.8.
|
|
61
|
+
"@m5kdev/commons": "0.8.7",
|
|
62
|
+
"@m5kdev/config": "0.8.7"
|
|
64
63
|
},
|
|
65
64
|
"devDependencies": {
|
|
66
65
|
"@jest/globals": "30.2.0",
|
|
67
66
|
"@types/body-parser": "1.19.5",
|
|
68
67
|
"@types/cors": "2.8.17",
|
|
69
68
|
"@types/express": "4.17.21",
|
|
70
|
-
"@types/fluent-ffmpeg": "2.1.27",
|
|
71
69
|
"@types/jest": "30.0.0",
|
|
72
70
|
"@types/luxon": "3.7.1",
|
|
73
71
|
"@types/mustache": "4.2.6",
|