@purpleschool/multisite 0.0.34 → 0.0.41
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/api/controller/http/auth.ts +1 -0
- package/api/controller/http/catalog.ts +6 -0
- package/api/controller/http/file.ts +1 -0
- package/api/controller/http/index.ts +2 -0
- package/api/controller/http/text-chat.ts +18 -0
- package/api/routes.ts +1 -0
- package/build/api/controller/http/auth.d.ts +1 -0
- package/build/api/controller/http/auth.d.ts.map +1 -1
- package/build/api/controller/http/auth.js +1 -0
- package/build/api/controller/http/catalog.d.ts +7 -0
- package/build/api/controller/http/catalog.d.ts.map +1 -0
- package/build/api/controller/http/catalog.js +9 -0
- package/build/api/controller/http/file.d.ts +1 -0
- package/build/api/controller/http/file.d.ts.map +1 -1
- package/build/api/controller/http/file.js +1 -0
- package/build/api/controller/http/index.d.ts +2 -0
- package/build/api/controller/http/index.d.ts.map +1 -1
- package/build/api/controller/http/index.js +2 -0
- package/build/api/controller/http/text-chat.d.ts +18 -0
- package/build/api/controller/http/text-chat.d.ts.map +1 -0
- package/build/api/controller/http/text-chat.js +20 -0
- package/build/api/routes.d.ts +1 -0
- package/build/api/routes.d.ts.map +1 -1
- package/build/api/routes.js +1 -0
- package/build/commands/auth/change-password.command.d.ts +5 -0
- package/build/commands/auth/change-password.command.d.ts.map +1 -1
- package/build/commands/auth/change-password.command.js +1 -0
- package/build/commands/auth/index.d.ts +1 -0
- package/build/commands/auth/index.d.ts.map +1 -1
- package/build/commands/auth/index.js +1 -0
- package/build/commands/auth/login.command.d.ts +5 -0
- package/build/commands/auth/login.command.d.ts.map +1 -1
- package/build/commands/auth/login.command.js +1 -0
- package/build/commands/auth/refresh.command.d.ts +30 -0
- package/build/commands/auth/refresh.command.d.ts.map +1 -0
- package/build/commands/auth/refresh.command.js +15 -0
- package/build/commands/auth/register.command.d.ts +5 -0
- package/build/commands/auth/register.command.d.ts.map +1 -1
- package/build/commands/auth/register.command.js +1 -0
- package/build/commands/auth/reset-password.command.d.ts +5 -0
- package/build/commands/auth/reset-password.command.d.ts.map +1 -1
- package/build/commands/auth/reset-password.command.js +1 -0
- package/build/commands/auth/verify-email.command.d.ts.map +1 -1
- package/build/commands/auth/verify-email.command.js +2 -1
- package/build/commands/auth/vk-login.command.d.ts +5 -0
- package/build/commands/auth/vk-login.command.d.ts.map +1 -1
- package/build/commands/auth/vk-login.command.js +1 -0
- package/build/commands/auth/yandex-login.command.d.ts +5 -0
- package/build/commands/auth/yandex-login.command.d.ts.map +1 -1
- package/build/commands/auth/yandex-login.command.js +1 -0
- package/build/commands/catalog/index.d.ts +156 -0
- package/build/commands/catalog/index.d.ts.map +1 -0
- package/build/commands/catalog/index.js +23 -0
- package/build/commands/index.d.ts +2 -0
- package/build/commands/index.d.ts.map +1 -1
- package/build/commands/index.js +2 -0
- package/build/commands/page/create-page.command.d.ts +8 -0
- package/build/commands/page/create-page.command.d.ts.map +1 -1
- package/build/commands/page/find-page-by-alias.command.d.ts +16 -0
- package/build/commands/page/find-page-by-alias.command.d.ts.map +1 -1
- package/build/commands/page/find-page-by-criteria.command.d.ts +5 -0
- package/build/commands/page/find-page-by-criteria.command.d.ts.map +1 -1
- package/build/commands/page/find-page.command.d.ts +11 -0
- package/build/commands/page/find-page.command.d.ts.map +1 -1
- package/build/commands/page/update-page.command.d.ts +8 -0
- package/build/commands/page/update-page.command.d.ts.map +1 -1
- package/build/commands/product/fast-buy-product.command.d.ts.map +1 -1
- package/build/commands/product/fast-buy-product.command.js +2 -1
- package/build/commands/subscription/fast-buy-subscription.command.d.ts.map +1 -1
- package/build/commands/subscription/fast-buy-subscription.command.js +2 -1
- package/build/commands/text-chat/category.d.ts +321 -0
- package/build/commands/text-chat/category.d.ts.map +1 -0
- package/build/commands/text-chat/category.js +29 -0
- package/build/commands/text-chat/index.d.ts +292 -0
- package/build/commands/text-chat/index.d.ts.map +1 -0
- package/build/commands/text-chat/index.js +73 -0
- package/build/constants/catalog.d.ts +5 -0
- package/build/constants/catalog.d.ts.map +1 -0
- package/build/constants/catalog.js +8 -0
- package/build/constants/errors/errors.d.ts +77 -0
- package/build/constants/errors/errors.d.ts.map +1 -1
- package/build/constants/errors/errors.js +77 -0
- package/build/constants/files/enums/file-type.enum.d.ts +3 -1
- package/build/constants/files/enums/file-type.enum.d.ts.map +1 -1
- package/build/constants/files/enums/file-type.enum.js +2 -0
- package/build/constants/index.d.ts +3 -0
- package/build/constants/index.d.ts.map +1 -1
- package/build/constants/index.js +3 -0
- package/build/constants/text-chat/attachments.d.ts +12 -0
- package/build/constants/text-chat/attachments.d.ts.map +1 -0
- package/build/constants/text-chat/attachments.js +52 -0
- package/build/constants/text-chat/index.d.ts +38 -0
- package/build/constants/text-chat/index.d.ts.map +1 -0
- package/build/constants/text-chat/index.js +59 -0
- package/build/constants/text-provider/index.d.ts +37 -0
- package/build/constants/text-provider/index.d.ts.map +1 -0
- package/build/constants/text-provider/index.js +46 -0
- package/build/constants/tools/enums/tool-type.enum.d.ts +1 -0
- package/build/constants/tools/enums/tool-type.enum.d.ts.map +1 -1
- package/build/constants/tools/enums/tool-type.enum.js +1 -0
- package/build/helpers/index.d.ts +1 -0
- package/build/helpers/index.d.ts.map +1 -1
- package/build/helpers/index.js +1 -0
- package/build/helpers/text-chat/index.d.ts +23 -0
- package/build/helpers/text-chat/index.d.ts.map +1 -0
- package/build/helpers/text-chat/index.js +91 -0
- package/build/models/catalog/index.d.ts +181 -0
- package/build/models/catalog/index.d.ts.map +1 -0
- package/build/models/catalog/index.js +36 -0
- package/build/models/index.d.ts +2 -0
- package/build/models/index.d.ts.map +1 -1
- package/build/models/index.js +2 -0
- package/build/models/page.schema.d.ts +6 -0
- package/build/models/page.schema.d.ts.map +1 -1
- package/build/models/page.schema.js +1 -0
- package/build/models/text-chat/category.schema.d.ts +79 -0
- package/build/models/text-chat/category.schema.d.ts.map +1 -0
- package/build/models/text-chat/category.schema.js +38 -0
- package/build/models/text-chat/index.d.ts +319 -0
- package/build/models/text-chat/index.d.ts.map +1 -0
- package/build/models/text-chat/index.js +79 -0
- package/build/models/text-chat/provider-config.schema.d.ts +92 -0
- package/build/models/text-chat/provider-config.schema.d.ts.map +1 -0
- package/build/models/text-chat/provider-config.schema.js +42 -0
- package/build/models/text-chat/stream.schema.d.ts +83 -0
- package/build/models/text-chat/stream.schema.d.ts.map +1 -0
- package/build/models/text-chat/stream.schema.js +24 -0
- package/build/models/user.schema.d.ts +1 -0
- package/build/models/user.schema.d.ts.map +1 -1
- package/build/models/user.schema.js +3 -2
- package/build/queries/catalog/index.d.ts +259 -0
- package/build/queries/catalog/index.d.ts.map +1 -0
- package/build/queries/catalog/index.js +31 -0
- package/build/queries/index.d.ts +2 -0
- package/build/queries/index.d.ts.map +1 -1
- package/build/queries/index.js +2 -0
- package/build/queries/subscription/get-subscriptions-summary.command.d.ts +5 -0
- package/build/queries/subscription/get-subscriptions-summary.command.d.ts.map +1 -1
- package/build/queries/subscription/get-subscriptions-summary.command.js +1 -0
- package/build/queries/text-chat/category.d.ts +297 -0
- package/build/queries/text-chat/category.d.ts.map +1 -0
- package/build/queries/text-chat/category.js +45 -0
- package/build/queries/text-chat/index.d.ts +472 -0
- package/build/queries/text-chat/index.d.ts.map +1 -0
- package/build/queries/text-chat/index.js +61 -0
- package/commands/auth/change-password.command.ts +1 -0
- package/commands/auth/index.ts +1 -0
- package/commands/auth/login.command.ts +1 -0
- package/commands/auth/refresh.command.ts +15 -0
- package/commands/auth/register.command.ts +1 -0
- package/commands/auth/reset-password.command.ts +1 -0
- package/commands/auth/verify-email.command.ts +2 -1
- package/commands/auth/vk-login.command.ts +1 -0
- package/commands/auth/yandex-login.command.ts +1 -0
- package/commands/catalog/index.ts +26 -0
- package/commands/index.ts +2 -0
- package/commands/product/fast-buy-product.command.ts +2 -1
- package/commands/subscription/fast-buy-subscription.command.ts +2 -1
- package/commands/text-chat/category.ts +42 -0
- package/commands/text-chat/index.ts +71 -0
- package/constants/catalog.ts +4 -0
- package/constants/errors/errors.ts +78 -0
- package/constants/files/enums/file-type.enum.ts +2 -0
- package/constants/index.ts +3 -0
- package/constants/text-chat/attachments.ts +55 -0
- package/constants/text-chat/index.ts +43 -0
- package/constants/text-provider/index.ts +42 -0
- package/constants/tools/enums/tool-type.enum.ts +1 -0
- package/helpers/index.ts +1 -0
- package/helpers/text-chat/index.ts +91 -0
- package/models/catalog/index.ts +35 -0
- package/models/index.ts +2 -0
- package/models/page.schema.ts +1 -0
- package/models/text-chat/category.schema.ts +40 -0
- package/models/text-chat/index.ts +82 -0
- package/models/text-chat/provider-config.schema.ts +47 -0
- package/models/text-chat/stream.schema.ts +43 -0
- package/models/user.schema.ts +3 -1
- package/package.json +1 -1
- package/queries/catalog/index.ts +29 -0
- package/queries/index.ts +2 -0
- package/queries/subscription/get-subscriptions-summary.command.ts +1 -0
- package/queries/text-chat/category.ts +51 -0
- package/queries/text-chat/index.ts +56 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { CatalogGroupAdminSchema, CatalogGroupFieldsSchema } from '../../models/catalog';
|
|
3
|
+
|
|
4
|
+
export namespace CreateCatalogGroupCommand {
|
|
5
|
+
export const RequestSchema = CatalogGroupFieldsSchema.strict();
|
|
6
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
7
|
+
export const ResponseSchema = z.object({ data: CatalogGroupAdminSchema });
|
|
8
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
9
|
+
}
|
|
10
|
+
export namespace UpdateCatalogGroupCommand {
|
|
11
|
+
export const RequestParamsSchema = z.object({ uuid: z.string().uuid() }).strict();
|
|
12
|
+
export const RequestSchema = CatalogGroupFieldsSchema.partial()
|
|
13
|
+
.strict()
|
|
14
|
+
.refine(
|
|
15
|
+
(input) => Object.values(input).some((value) => value !== undefined),
|
|
16
|
+
'At least one field is required',
|
|
17
|
+
);
|
|
18
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
19
|
+
export const ResponseSchema = CreateCatalogGroupCommand.ResponseSchema;
|
|
20
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
21
|
+
}
|
|
22
|
+
export namespace DeleteCatalogGroupCommand {
|
|
23
|
+
export const RequestParamsSchema = UpdateCatalogGroupCommand.RequestParamsSchema;
|
|
24
|
+
export const ResponseSchema = z.object({ data: z.object({ deleted: z.literal(true) }) });
|
|
25
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
26
|
+
}
|
package/commands/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { CloudPaymentsWidgetSchema } from '../../models';
|
|
3
|
+
import { EmailInputSchema } from '../../models/user.schema';
|
|
3
4
|
|
|
4
5
|
export namespace FastBuyProductCommand {
|
|
5
6
|
export const RequestParamSchema = z.object({
|
|
@@ -8,7 +9,7 @@ export namespace FastBuyProductCommand {
|
|
|
8
9
|
export type RequestParam = z.infer<typeof RequestParamSchema>;
|
|
9
10
|
|
|
10
11
|
export const RequestSchema = z.object({
|
|
11
|
-
email:
|
|
12
|
+
email: EmailInputSchema,
|
|
12
13
|
partnerId: z.string().uuid().optional(),
|
|
13
14
|
marketingConsent: z.boolean().optional().default(false),
|
|
14
15
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { CloudPaymentsWidgetSchema } from '../../models';
|
|
3
|
+
import { EmailInputSchema } from '../../models/user.schema';
|
|
3
4
|
|
|
4
5
|
export namespace FastBuySubscriptionCommand {
|
|
5
6
|
export const RequestParamSchema = z.object({
|
|
@@ -8,7 +9,7 @@ export namespace FastBuySubscriptionCommand {
|
|
|
8
9
|
export type RequestParam = z.infer<typeof RequestParamSchema>;
|
|
9
10
|
|
|
10
11
|
export const RequestSchema = z.object({
|
|
11
|
-
email:
|
|
12
|
+
email: EmailInputSchema,
|
|
12
13
|
partnerId: z.string().uuid().optional(),
|
|
13
14
|
marketingConsent: z.boolean().optional().default(false),
|
|
14
15
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
TextChatCategoryAdminSchema,
|
|
4
|
+
TextChatCategoryFieldsSchema,
|
|
5
|
+
} from '../../models/text-chat/category.schema';
|
|
6
|
+
|
|
7
|
+
export namespace CreateTextChatCategoryCommand {
|
|
8
|
+
export const RequestSchema = TextChatCategoryFieldsSchema.strict();
|
|
9
|
+
export type Request = z.input<typeof RequestSchema>;
|
|
10
|
+
export const ResponseSchema = z.object({ data: TextChatCategoryAdminSchema });
|
|
11
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export namespace UpdateTextChatCategoryCommand {
|
|
15
|
+
export const RequestParamsSchema = z.object({ uuid: z.string().uuid() }).strict();
|
|
16
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
17
|
+
export const RequestSchema = TextChatCategoryFieldsSchema.partial()
|
|
18
|
+
.strict()
|
|
19
|
+
.refine(
|
|
20
|
+
(input) => Object.values(input).some((value) => value !== undefined),
|
|
21
|
+
'At least one field is required',
|
|
22
|
+
);
|
|
23
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
24
|
+
export const ResponseSchema = CreateTextChatCategoryCommand.ResponseSchema;
|
|
25
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export namespace ArchiveTextChatCategoryCommand {
|
|
29
|
+
export const RequestParamsSchema = UpdateTextChatCategoryCommand.RequestParamsSchema;
|
|
30
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
31
|
+
export const RequestSchema = z.object({}).strict();
|
|
32
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
33
|
+
export const ResponseSchema = CreateTextChatCategoryCommand.ResponseSchema;
|
|
34
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export namespace DeleteTextChatCategoryCommand {
|
|
38
|
+
export const RequestParamsSchema = UpdateTextChatCategoryCommand.RequestParamsSchema;
|
|
39
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
40
|
+
export const ResponseSchema = z.object({ data: z.object({ deleted: z.literal(true) }) });
|
|
41
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TextChatSchema, TextChatPriceSchema, TextChatFileSchema } from '../../models/text-chat';
|
|
3
|
+
export * from './category';
|
|
4
|
+
|
|
5
|
+
export namespace UploadTextChatFileCommand {
|
|
6
|
+
// Multipart field `file`. No owner, site, content or extraction metadata from the client.
|
|
7
|
+
export const ResponseSchema = z.object({ data: TextChatFileSchema });
|
|
8
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export namespace CreateTextChatCommand {
|
|
12
|
+
export const RequestSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
// Page.toolOptionId, supplied only when starting a specialized chat.
|
|
15
|
+
categoryId: z.string().uuid().nullable().optional(),
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
18
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
19
|
+
export const ResponseSchema = z.object({ data: TextChatSchema });
|
|
20
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export namespace RenameTextChatCommand {
|
|
24
|
+
export const RequestParamsSchema = z.object({ uuid: z.string().uuid() });
|
|
25
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
26
|
+
export const RequestSchema = z.object({ title: z.string().trim().min(1).max(200) }).strict();
|
|
27
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
28
|
+
export const ResponseSchema = z.object({ data: TextChatSchema });
|
|
29
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export namespace DeleteTextChatCommand {
|
|
33
|
+
export const RequestParamsSchema = z.object({ uuid: z.string().uuid() });
|
|
34
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
35
|
+
export const ResponseSchema = z.object({ data: z.object({ deleted: z.literal(true) }) });
|
|
36
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export namespace SendTextChatMessageCommand {
|
|
40
|
+
export const RequestParamsSchema = z.object({ uuid: z.string().uuid() });
|
|
41
|
+
export type RequestParams = z.infer<typeof RequestParamsSchema>;
|
|
42
|
+
export const RequestSchema = z
|
|
43
|
+
.object({
|
|
44
|
+
modelId: z.string().uuid(),
|
|
45
|
+
text: z.string().refine((text) => text.trim().length > 0, 'Message must not be blank'),
|
|
46
|
+
fileIds: z.array(z.string().uuid()).default([]),
|
|
47
|
+
})
|
|
48
|
+
.strict();
|
|
49
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
50
|
+
// Response is a TextChatStreamFrame sequence, not a JSON response envelope.
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export namespace CalculateTextChatPriceCommand {
|
|
54
|
+
export const RequestSchema = z
|
|
55
|
+
.object({
|
|
56
|
+
chatId: z.string().uuid().optional(),
|
|
57
|
+
// Only new chats accept a category; existing chats use their saved category.
|
|
58
|
+
categoryId: z.string().uuid().nullable().optional(),
|
|
59
|
+
modelId: z.string().uuid(),
|
|
60
|
+
inputLength: z.number().int().safe().nonnegative(),
|
|
61
|
+
fileIds: z.array(z.string().uuid()).default([]),
|
|
62
|
+
})
|
|
63
|
+
.strict()
|
|
64
|
+
.refine(
|
|
65
|
+
(request) => !request.chatId || request.categoryId === undefined,
|
|
66
|
+
'Existing chats use their saved category',
|
|
67
|
+
);
|
|
68
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
69
|
+
export const ResponseSchema = z.object({ data: TextChatPriceSchema });
|
|
70
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
71
|
+
}
|
|
@@ -1,4 +1,77 @@
|
|
|
1
|
+
import { TEXT_CHAT_ERROR_CODE } from '../text-chat';
|
|
2
|
+
import { CATALOG_ERROR_CODE } from '../catalog';
|
|
3
|
+
|
|
1
4
|
export const ERRORS = {
|
|
5
|
+
TEXT_CHAT_GENERATION_FAILED: {
|
|
6
|
+
message: 'Не удалось получить ответ нейросети. Попробуйте позже.',
|
|
7
|
+
code: TEXT_CHAT_ERROR_CODE.GENERATION_FAILED,
|
|
8
|
+
httpCode: 502,
|
|
9
|
+
},
|
|
10
|
+
TEXT_CHAT_STREAM_INTERRUPTED: {
|
|
11
|
+
message: 'Соединение прервано. Часть ответа могла сохраниться в истории.',
|
|
12
|
+
code: TEXT_CHAT_ERROR_CODE.STREAM_INTERRUPTED,
|
|
13
|
+
httpCode: 502,
|
|
14
|
+
},
|
|
15
|
+
TEXT_CHAT_SETTLEMENT_FAILED: {
|
|
16
|
+
message: 'Не удалось завершить обработку ответа. Проверьте сохранённую историю.',
|
|
17
|
+
code: TEXT_CHAT_ERROR_CODE.SETTLEMENT_FAILED,
|
|
18
|
+
httpCode: 500,
|
|
19
|
+
},
|
|
20
|
+
CATALOG_GROUP_NOT_FOUND: {
|
|
21
|
+
message: 'Группа каталога не найдена',
|
|
22
|
+
code: CATALOG_ERROR_CODE.GROUP_NOT_FOUND,
|
|
23
|
+
httpCode: 404,
|
|
24
|
+
},
|
|
25
|
+
CATALOG_GROUP_IN_USE: {
|
|
26
|
+
message: 'Перенесите или отвяжите категории перед удалением группы',
|
|
27
|
+
code: CATALOG_ERROR_CODE.GROUP_IN_USE,
|
|
28
|
+
httpCode: 409,
|
|
29
|
+
},
|
|
30
|
+
TEXT_CHAT_CONTEXT_LIMIT: {
|
|
31
|
+
message: 'Превышен допустимый размер запроса или контекста',
|
|
32
|
+
code: TEXT_CHAT_ERROR_CODE.CONTEXT_LIMIT,
|
|
33
|
+
httpCode: 400,
|
|
34
|
+
},
|
|
35
|
+
TEXT_CHAT_INVALID_ATTACHMENT: {
|
|
36
|
+
message: 'Недопустимое вложение текстового чата',
|
|
37
|
+
code: TEXT_CHAT_ERROR_CODE.INVALID_ATTACHMENT,
|
|
38
|
+
httpCode: 400,
|
|
39
|
+
},
|
|
40
|
+
TEXT_CHAT_NOT_FOUND: {
|
|
41
|
+
message: 'Текстовый чат не найден',
|
|
42
|
+
code: TEXT_CHAT_ERROR_CODE.NOT_FOUND,
|
|
43
|
+
httpCode: 404,
|
|
44
|
+
},
|
|
45
|
+
TEXT_CHAT_BUSY: {
|
|
46
|
+
message: 'Дождитесь завершения ответа в этом чате',
|
|
47
|
+
code: TEXT_CHAT_ERROR_CODE.BUSY,
|
|
48
|
+
httpCode: 409,
|
|
49
|
+
},
|
|
50
|
+
TEXT_CHAT_CATEGORY_TOOL_MISMATCH: {
|
|
51
|
+
message: 'Инструмент категории не соответствует инструменту страницы',
|
|
52
|
+
code: TEXT_CHAT_ERROR_CODE.CATEGORY_TOOL_MISMATCH,
|
|
53
|
+
httpCode: 409,
|
|
54
|
+
},
|
|
55
|
+
TEXT_CHAT_CATEGORY_NOT_FOUND: {
|
|
56
|
+
message: 'Категория текстового чата не найдена',
|
|
57
|
+
code: TEXT_CHAT_ERROR_CODE.CATEGORY_NOT_FOUND,
|
|
58
|
+
httpCode: 404,
|
|
59
|
+
},
|
|
60
|
+
TEXT_CHAT_CATEGORY_UNAVAILABLE: {
|
|
61
|
+
message: 'Категория недоступна для нового чата',
|
|
62
|
+
code: TEXT_CHAT_ERROR_CODE.CATEGORY_UNAVAILABLE,
|
|
63
|
+
httpCode: 409,
|
|
64
|
+
},
|
|
65
|
+
TEXT_CHAT_CATEGORY_IN_USE: {
|
|
66
|
+
message: 'Категория используется чатами или SEO-страницами; её можно архивировать',
|
|
67
|
+
code: TEXT_CHAT_ERROR_CODE.CATEGORY_IN_USE,
|
|
68
|
+
httpCode: 409,
|
|
69
|
+
},
|
|
70
|
+
TEXT_CHAT_MODEL_UNAVAILABLE: {
|
|
71
|
+
message: 'Текстовая модель недоступна',
|
|
72
|
+
code: TEXT_CHAT_ERROR_CODE.MODEL_UNAVAILABLE,
|
|
73
|
+
httpCode: 403,
|
|
74
|
+
},
|
|
2
75
|
UNKNOWN_ERROR: {
|
|
3
76
|
message: 'Неизвестная ошибка',
|
|
4
77
|
code: 'UNKNOWN_001',
|
|
@@ -103,6 +176,11 @@ export const ERRORS = {
|
|
|
103
176
|
code: 'AUTH_011',
|
|
104
177
|
httpCode: 403,
|
|
105
178
|
},
|
|
179
|
+
AUTH_REFRESH_TOKEN_INVALID: {
|
|
180
|
+
message: 'Сессия истекла, требуется повторный вход',
|
|
181
|
+
code: 'AUTH_014',
|
|
182
|
+
httpCode: 401,
|
|
183
|
+
},
|
|
106
184
|
|
|
107
185
|
// USER
|
|
108
186
|
USER_NOT_FOUND: {
|
package/constants/index.ts
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FILE_TYPE } from '../files/enums/file-type.enum';
|
|
2
|
+
|
|
3
|
+
export const TEXT_CHAT_UPLOAD_LIMITS = {
|
|
4
|
+
[FILE_TYPE.IMAGE]: 5 * 1024 ** 2,
|
|
5
|
+
[FILE_TYPE.DOCUMENT]: 20 * 1024 ** 2,
|
|
6
|
+
[FILE_TYPE.TEXT]: 10 * 1024 ** 2,
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export const TEXT_CHAT_FILE_FORMATS: ReadonlyArray<{
|
|
10
|
+
extensions: readonly string[];
|
|
11
|
+
mimeType: string;
|
|
12
|
+
type: FILE_TYPE.IMAGE | FILE_TYPE.DOCUMENT | FILE_TYPE.TEXT;
|
|
13
|
+
}> = [
|
|
14
|
+
{ extensions: ['jpg', 'jpeg'], mimeType: 'image/jpeg', type: FILE_TYPE.IMAGE },
|
|
15
|
+
{ extensions: ['png'], mimeType: 'image/png', type: FILE_TYPE.IMAGE },
|
|
16
|
+
{ extensions: ['webp'], mimeType: 'image/webp', type: FILE_TYPE.IMAGE },
|
|
17
|
+
{ extensions: ['pdf'], mimeType: 'application/pdf', type: FILE_TYPE.DOCUMENT },
|
|
18
|
+
{
|
|
19
|
+
extensions: ['docx'],
|
|
20
|
+
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
21
|
+
type: FILE_TYPE.DOCUMENT,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
extensions: ['xlsx'],
|
|
25
|
+
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
26
|
+
type: FILE_TYPE.DOCUMENT,
|
|
27
|
+
},
|
|
28
|
+
{ extensions: ['txt'], mimeType: 'text/plain', type: FILE_TYPE.TEXT },
|
|
29
|
+
{ extensions: ['md', 'markdown'], mimeType: 'text/markdown', type: FILE_TYPE.TEXT },
|
|
30
|
+
{ extensions: ['csv'], mimeType: 'text/csv', type: FILE_TYPE.TEXT },
|
|
31
|
+
{ extensions: ['tsv'], mimeType: 'text/tab-separated-values', type: FILE_TYPE.TEXT },
|
|
32
|
+
{ extensions: ['json'], mimeType: 'application/json', type: FILE_TYPE.TEXT },
|
|
33
|
+
{ extensions: ['xml'], mimeType: 'application/xml', type: FILE_TYPE.TEXT },
|
|
34
|
+
{ extensions: ['yaml', 'yml'], mimeType: 'application/x-yaml', type: FILE_TYPE.TEXT },
|
|
35
|
+
{ extensions: ['html', 'htm'], mimeType: 'text/html', type: FILE_TYPE.TEXT },
|
|
36
|
+
{ extensions: ['css'], mimeType: 'text/css', type: FILE_TYPE.TEXT },
|
|
37
|
+
{ extensions: ['scss'], mimeType: 'text/x-scss', type: FILE_TYPE.TEXT },
|
|
38
|
+
{ extensions: ['js', 'mjs', 'cjs'], mimeType: 'application/javascript', type: FILE_TYPE.TEXT },
|
|
39
|
+
{ extensions: ['ts', 'tsx'], mimeType: 'application/typescript', type: FILE_TYPE.TEXT },
|
|
40
|
+
{ extensions: ['sh'], mimeType: 'application/x-sh', type: FILE_TYPE.TEXT },
|
|
41
|
+
{ extensions: ['py'], mimeType: 'text/x-python', type: FILE_TYPE.TEXT },
|
|
42
|
+
{ extensions: ['c', 'h'], mimeType: 'text/x-c', type: FILE_TYPE.TEXT },
|
|
43
|
+
{
|
|
44
|
+
extensions: ['cpp', 'hpp', 'cc', 'cxx', 'hh', 'hxx'],
|
|
45
|
+
mimeType: 'text/x-c++',
|
|
46
|
+
type: FILE_TYPE.TEXT,
|
|
47
|
+
},
|
|
48
|
+
{ extensions: ['java'], mimeType: 'text/x-java-source', type: FILE_TYPE.TEXT },
|
|
49
|
+
{ extensions: ['php'], mimeType: 'text/x-php', type: FILE_TYPE.TEXT },
|
|
50
|
+
{ extensions: ['rb'], mimeType: 'text/x-ruby', type: FILE_TYPE.TEXT },
|
|
51
|
+
{ extensions: ['go'], mimeType: 'text/x-go', type: FILE_TYPE.TEXT },
|
|
52
|
+
{ extensions: ['ini'], mimeType: 'text/x-ini', type: FILE_TYPE.TEXT },
|
|
53
|
+
{ extensions: ['properties'], mimeType: 'text/x-properties', type: FILE_TYPE.TEXT },
|
|
54
|
+
{ extensions: ['conf', 'config', 'env'], mimeType: 'text/x-config', type: FILE_TYPE.TEXT },
|
|
55
|
+
];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export * from './attachments';
|
|
2
|
+
|
|
3
|
+
export enum TEXT_CHAT_MESSAGE_ROLE {
|
|
4
|
+
USER = 'user',
|
|
5
|
+
ASSISTANT = 'assistant',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export enum TEXT_CHAT_MESSAGE_STATUS {
|
|
9
|
+
PENDING = 'pending',
|
|
10
|
+
SUCCESS = 'success',
|
|
11
|
+
FAILED = 'failed',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export enum TEXT_CHAT_ERROR_CODE {
|
|
15
|
+
CATEGORY_TOOL_MISMATCH = 'CATEGORY_TOOL_MISMATCH',
|
|
16
|
+
NOT_FOUND = 'text_chat_not_found',
|
|
17
|
+
MODEL_UNAVAILABLE = 'text_chat_model_unavailable',
|
|
18
|
+
INSUFFICIENT_BALANCE = 'text_chat_insufficient_balance',
|
|
19
|
+
INVALID_ATTACHMENT = 'text_chat_invalid_attachment',
|
|
20
|
+
CONTEXT_LIMIT = 'text_chat_context_limit',
|
|
21
|
+
BUSY = 'text_chat_busy',
|
|
22
|
+
GENERATION_FAILED = 'text_chat_generation_failed',
|
|
23
|
+
STREAM_INTERRUPTED = 'text_chat_stream_interrupted',
|
|
24
|
+
SETTLEMENT_FAILED = 'text_chat_settlement_failed',
|
|
25
|
+
CATEGORY_NOT_FOUND = 'text_chat_category_not_found',
|
|
26
|
+
CATEGORY_UNAVAILABLE = 'text_chat_category_unavailable',
|
|
27
|
+
CATEGORY_IN_USE = 'text_chat_category_in_use',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export enum TEXT_CHAT_CATEGORY_SCOPE {
|
|
31
|
+
ACTIVE = 'active',
|
|
32
|
+
ARCHIVED = 'archived',
|
|
33
|
+
ALL = 'all',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export enum TEXT_CHAT_STREAM_EVENT {
|
|
37
|
+
START = 'start',
|
|
38
|
+
DELTA = 'delta',
|
|
39
|
+
FINISH = 'finish',
|
|
40
|
+
ERROR = 'error',
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const TEXT_CHAT_STREAM_CONTENT_TYPE = 'application/x-ndjson' as const;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export enum TEXT_PROVIDER_CODE {
|
|
2
|
+
WELLFLOW = 'wellflow',
|
|
3
|
+
API_ROUTE = 'api_route',
|
|
4
|
+
DEROUTER = 'derouter',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum TEXT_PROVIDER_MESSAGE_ROLE {
|
|
8
|
+
SYSTEM = 'system',
|
|
9
|
+
USER = 'user',
|
|
10
|
+
ASSISTANT = 'assistant',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum TEXT_PROVIDER_TRANSPORT {
|
|
14
|
+
AI_PROXY = 'ai_proxy',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export enum TEXT_PROVIDER_ATTEMPT_EVENT {
|
|
18
|
+
START = 'start',
|
|
19
|
+
FIRST_DELTA = 'first_delta',
|
|
20
|
+
SUCCESS = 'success',
|
|
21
|
+
FAILED = 'failed',
|
|
22
|
+
CANCELLED = 'cancelled',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export enum TEXT_PROVIDER_FAILURE_KIND {
|
|
26
|
+
TIMEOUT = 'timeout',
|
|
27
|
+
REQUEST = 'request',
|
|
28
|
+
PROVIDER = 'provider',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export enum TEXT_PROVIDER_FALLBACK_REASON {
|
|
32
|
+
NO_CANDIDATES = 'no_candidates',
|
|
33
|
+
QUERY_FAILED = 'query_failed',
|
|
34
|
+
EXHAUSTED = 'exhausted',
|
|
35
|
+
BUDGET = 'budget',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum TEXT_PROVIDER_SKIP_REASON {
|
|
39
|
+
INVALID = 'invalid',
|
|
40
|
+
TRAFFIC = 'traffic',
|
|
41
|
+
COOLDOWN = 'cooldown',
|
|
42
|
+
}
|
package/helpers/index.ts
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { TEXT_CHAT_STREAM_EVENT } from '../../constants/text-chat';
|
|
2
|
+
import {
|
|
3
|
+
TextChatStreamFrame,
|
|
4
|
+
TextChatStreamFrameSchema,
|
|
5
|
+
} from '../../models/text-chat/stream.schema';
|
|
6
|
+
|
|
7
|
+
/** UTF-8 NDJSON, one validated JSON frame followed by LF. Not SSE. */
|
|
8
|
+
export function encodeTextChatStreamFrame(frame: TextChatStreamFrame): string {
|
|
9
|
+
return `${JSON.stringify(TextChatStreamFrameSchema.parse(frame))}\n`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** One parser per HTTP response. EOF without a terminal frame is never success. */
|
|
13
|
+
export class TextChatStreamParser {
|
|
14
|
+
private readonly decoder = new TextDecoder('utf-8', { fatal: true });
|
|
15
|
+
private pending = '';
|
|
16
|
+
private sequence = -1;
|
|
17
|
+
private correlation: { chatId: string; messageId: string } | undefined;
|
|
18
|
+
private terminal = false;
|
|
19
|
+
private closed = false;
|
|
20
|
+
private failed = false;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
private readonly expected: { chatId?: string; messageId?: string } = {},
|
|
24
|
+
private readonly maxFrameLength = 1024 * 1024,
|
|
25
|
+
) {
|
|
26
|
+
if (!Number.isSafeInteger(maxFrameLength) || maxFrameLength < 1) {
|
|
27
|
+
throw new Error('Invalid stream frame limit');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
push(chunk: Uint8Array): TextChatStreamFrame[] {
|
|
32
|
+
if (this.closed || this.failed) throw new Error('Stream parser is closed');
|
|
33
|
+
try {
|
|
34
|
+
this.pending += this.decoder.decode(chunk, { stream: true });
|
|
35
|
+
const frames: TextChatStreamFrame[] = [];
|
|
36
|
+
let newline: number;
|
|
37
|
+
while ((newline = this.pending.indexOf('\n')) !== -1) {
|
|
38
|
+
if (newline > this.maxFrameLength) throw new Error('Stream frame is too large');
|
|
39
|
+
const line = this.pending.slice(0, newline);
|
|
40
|
+
this.pending = this.pending.slice(newline + 1);
|
|
41
|
+
if (!line.trim()) continue;
|
|
42
|
+
const frame = TextChatStreamFrameSchema.parse(JSON.parse(line));
|
|
43
|
+
this.accept(frame);
|
|
44
|
+
frames.push(frame);
|
|
45
|
+
}
|
|
46
|
+
if (this.pending.length > this.maxFrameLength)
|
|
47
|
+
throw new Error('Stream frame is too large');
|
|
48
|
+
return frames;
|
|
49
|
+
} catch (error: unknown) {
|
|
50
|
+
this.failed = true;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
finish(): void {
|
|
56
|
+
if (this.closed || this.failed) throw new Error('Stream parser is closed');
|
|
57
|
+
this.closed = true;
|
|
58
|
+
this.pending += this.decoder.decode();
|
|
59
|
+
if (this.pending.length) throw new Error('Incomplete stream frame');
|
|
60
|
+
if (!this.terminal) throw new Error('Stream ended without a terminal frame');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private accept(frame: TextChatStreamFrame): void {
|
|
64
|
+
if (this.terminal) throw new Error('Frame received after stream completion');
|
|
65
|
+
if (frame.sequence !== this.sequence + 1) throw new Error('Invalid stream sequence');
|
|
66
|
+
if (!this.correlation) {
|
|
67
|
+
if (frame.type !== TEXT_CHAT_STREAM_EVENT.START)
|
|
68
|
+
throw new Error('Missing stream start');
|
|
69
|
+
if (
|
|
70
|
+
(this.expected.chatId && frame.chatId !== this.expected.chatId) ||
|
|
71
|
+
(this.expected.messageId && frame.messageId !== this.expected.messageId)
|
|
72
|
+
) {
|
|
73
|
+
throw new Error('Unexpected stream correlation');
|
|
74
|
+
}
|
|
75
|
+
this.correlation = { chatId: frame.chatId, messageId: frame.messageId };
|
|
76
|
+
} else {
|
|
77
|
+
if (frame.type === TEXT_CHAT_STREAM_EVENT.START)
|
|
78
|
+
throw new Error('Duplicate stream start');
|
|
79
|
+
if (
|
|
80
|
+
frame.chatId !== this.correlation.chatId ||
|
|
81
|
+
frame.messageId !== this.correlation.messageId
|
|
82
|
+
) {
|
|
83
|
+
throw new Error('Stream correlation changed');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
this.sequence = frame.sequence;
|
|
87
|
+
this.terminal =
|
|
88
|
+
frame.type === TEXT_CHAT_STREAM_EVENT.FINISH ||
|
|
89
|
+
frame.type === TEXT_CHAT_STREAM_EVENT.ERROR;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TOOL_TYPE } from '../../constants';
|
|
3
|
+
|
|
4
|
+
export const CatalogOrderSchema = z.number().int().min(0).max(2147483647);
|
|
5
|
+
export const CatalogGroupFieldsSchema = z.object({
|
|
6
|
+
title: z.string().trim().min(1).max(200),
|
|
7
|
+
order: CatalogOrderSchema.optional(),
|
|
8
|
+
});
|
|
9
|
+
export const CatalogGroupSchema = z.object({
|
|
10
|
+
uuid: z.string().uuid(),
|
|
11
|
+
title: z.string(),
|
|
12
|
+
order: CatalogOrderSchema,
|
|
13
|
+
});
|
|
14
|
+
const TimestampSchema = z.string().datetime().or(z.date());
|
|
15
|
+
export const CatalogGroupAdminSchema = CatalogGroupSchema.extend({
|
|
16
|
+
siteId: z.string().uuid(),
|
|
17
|
+
createdAt: TimestampSchema,
|
|
18
|
+
updatedAt: TimestampSchema,
|
|
19
|
+
});
|
|
20
|
+
export const CatalogItemSchema = z.object({
|
|
21
|
+
categoryId: z.string().uuid(),
|
|
22
|
+
title: z.string(),
|
|
23
|
+
order: CatalogOrderSchema,
|
|
24
|
+
page: z.object({
|
|
25
|
+
uuid: z.string().uuid(),
|
|
26
|
+
alias: z.string(),
|
|
27
|
+
title: z.string(),
|
|
28
|
+
toolType: z.nativeEnum(TOOL_TYPE).nullable(),
|
|
29
|
+
toolOptionId: z.string().nullable(),
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
export const PublicCatalogGroupSchema = CatalogGroupSchema.extend({
|
|
33
|
+
items: z.array(CatalogItemSchema),
|
|
34
|
+
});
|
|
35
|
+
export type PublicCatalogGroup = z.infer<typeof PublicCatalogGroupSchema>;
|
package/models/index.ts
CHANGED
package/models/page.schema.ts
CHANGED
|
@@ -12,6 +12,7 @@ export const PageSchema = z.object({
|
|
|
12
12
|
alias: z.string().min(3).max(16384),
|
|
13
13
|
toolType: z.nativeEnum(TOOL_TYPE).nullable().optional(),
|
|
14
14
|
toolOptionId: z.string().uuid().nullable().optional(),
|
|
15
|
+
categoryId: z.string().uuid().nullable().optional(),
|
|
15
16
|
createdAt: z.date(),
|
|
16
17
|
updatedAt: z.date(),
|
|
17
18
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TOOL_TYPE } from '../../constants/tools';
|
|
3
|
+
import { CatalogOrderSchema } from '../catalog';
|
|
4
|
+
|
|
5
|
+
export const TextChatCategoryFieldsSchema = z.object({
|
|
6
|
+
title: z.string().trim().min(1).max(200),
|
|
7
|
+
toolType: z
|
|
8
|
+
.enum([TOOL_TYPE.TEXT, TOOL_TYPE.IMAGE_GENERATION, TOOL_TYPE.IMAGE_EDITOR])
|
|
9
|
+
.default(TOOL_TYPE.TEXT),
|
|
10
|
+
placeholder: z.string().trim().max(1000).default(''),
|
|
11
|
+
groupId: z.string().uuid().nullable().optional(),
|
|
12
|
+
order: CatalogOrderSchema.optional(),
|
|
13
|
+
prompt: z
|
|
14
|
+
.string()
|
|
15
|
+
.max(100_000)
|
|
16
|
+
.nullable()
|
|
17
|
+
.optional()
|
|
18
|
+
.transform((value) => (typeof value === 'string' && !value.trim() ? null : value)),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/** Explicit allowlist. Never extend the administrative schema for public responses. */
|
|
22
|
+
export const TextChatCategoryPublicSchema = z.object({
|
|
23
|
+
uuid: z.string().uuid(),
|
|
24
|
+
title: z.string(),
|
|
25
|
+
placeholder: z.string(),
|
|
26
|
+
});
|
|
27
|
+
export type TextChatCategoryPublic = z.infer<typeof TextChatCategoryPublicSchema>;
|
|
28
|
+
|
|
29
|
+
const TimestampSchema = z.string().datetime().or(z.date());
|
|
30
|
+
export const TextChatCategoryAdminSchema = TextChatCategoryPublicSchema.extend({
|
|
31
|
+
siteId: z.string().uuid(),
|
|
32
|
+
toolType: TextChatCategoryFieldsSchema.shape.toolType,
|
|
33
|
+
groupId: z.string().uuid().nullable().default(null),
|
|
34
|
+
order: CatalogOrderSchema.default(0),
|
|
35
|
+
prompt: z.string().nullable(),
|
|
36
|
+
archivedAt: TimestampSchema.nullable(),
|
|
37
|
+
createdAt: TimestampSchema,
|
|
38
|
+
updatedAt: TimestampSchema,
|
|
39
|
+
});
|
|
40
|
+
export type TextChatCategoryAdmin = z.infer<typeof TextChatCategoryAdminSchema>;
|