librechat-data-provider 0.7.86 → 0.7.87
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/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react-query/index.es.js +1 -1
- package/dist/react-query/index.es.js.map +1 -1
- package/package.json +1 -1
- package/specs/actions.spec.ts +7 -9
- package/src/actions.ts +17 -8
- package/src/api-endpoints.ts +10 -0
- package/src/config.ts +58 -16
- package/src/createPayload.ts +3 -2
- package/src/data-service.ts +46 -1
- package/src/feedback.ts +141 -0
- package/src/file-config.ts +0 -1
- package/src/index.ts +4 -0
- package/src/keys.ts +3 -0
- package/src/mcp.ts +7 -0
- package/src/memory.ts +62 -0
- package/src/parsers.ts +3 -1
- package/src/permissions.ts +16 -0
- package/src/react-query/react-query-service.ts +16 -0
- package/src/roles.ts +16 -0
- package/src/schemas.ts +11 -0
- package/src/types/assistants.ts +1 -0
- package/src/types/mutations.ts +8 -1
- package/src/types/queries.ts +15 -0
- package/src/types.ts +96 -20
- package/src/web.ts +17 -11
- package/src/zod.spec.ts +59 -67
package/src/permissions.ts
CHANGED
|
@@ -16,6 +16,10 @@ export enum PermissionTypes {
|
|
|
16
16
|
* Type for Agent Permissions
|
|
17
17
|
*/
|
|
18
18
|
AGENTS = 'AGENTS',
|
|
19
|
+
/**
|
|
20
|
+
* Type for Memory Permissions
|
|
21
|
+
*/
|
|
22
|
+
MEMORIES = 'MEMORIES',
|
|
19
23
|
/**
|
|
20
24
|
* Type for Multi-Conversation Permissions
|
|
21
25
|
*/
|
|
@@ -45,6 +49,8 @@ export enum Permissions {
|
|
|
45
49
|
READ = 'READ',
|
|
46
50
|
READ_AUTHOR = 'READ_AUTHOR',
|
|
47
51
|
SHARE = 'SHARE',
|
|
52
|
+
/** Can disable if desired */
|
|
53
|
+
OPT_OUT = 'OPT_OUT',
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export const promptPermissionsSchema = z.object({
|
|
@@ -60,6 +66,15 @@ export const bookmarkPermissionsSchema = z.object({
|
|
|
60
66
|
});
|
|
61
67
|
export type TBookmarkPermissions = z.infer<typeof bookmarkPermissionsSchema>;
|
|
62
68
|
|
|
69
|
+
export const memoryPermissionsSchema = z.object({
|
|
70
|
+
[Permissions.USE]: z.boolean().default(true),
|
|
71
|
+
[Permissions.CREATE]: z.boolean().default(true),
|
|
72
|
+
[Permissions.UPDATE]: z.boolean().default(true),
|
|
73
|
+
[Permissions.READ]: z.boolean().default(true),
|
|
74
|
+
[Permissions.OPT_OUT]: z.boolean().default(true),
|
|
75
|
+
});
|
|
76
|
+
export type TMemoryPermissions = z.infer<typeof memoryPermissionsSchema>;
|
|
77
|
+
|
|
63
78
|
export const agentPermissionsSchema = z.object({
|
|
64
79
|
[Permissions.SHARED_GLOBAL]: z.boolean().default(false),
|
|
65
80
|
[Permissions.USE]: z.boolean().default(true),
|
|
@@ -92,6 +107,7 @@ export type TWebSearchPermissions = z.infer<typeof webSearchPermissionsSchema>;
|
|
|
92
107
|
export const permissionsSchema = z.object({
|
|
93
108
|
[PermissionTypes.PROMPTS]: promptPermissionsSchema,
|
|
94
109
|
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema,
|
|
110
|
+
[PermissionTypes.MEMORIES]: memoryPermissionsSchema,
|
|
95
111
|
[PermissionTypes.AGENTS]: agentPermissionsSchema,
|
|
96
112
|
[PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema,
|
|
97
113
|
[PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema,
|
|
@@ -347,3 +347,19 @@ export const useGetCustomConfigSpeechQuery = (
|
|
|
347
347
|
},
|
|
348
348
|
);
|
|
349
349
|
};
|
|
350
|
+
|
|
351
|
+
export const useUpdateFeedbackMutation = (
|
|
352
|
+
conversationId: string,
|
|
353
|
+
messageId: string,
|
|
354
|
+
): UseMutationResult<t.TUpdateFeedbackResponse, Error, t.TUpdateFeedbackRequest> => {
|
|
355
|
+
const queryClient = useQueryClient();
|
|
356
|
+
return useMutation(
|
|
357
|
+
(payload: t.TUpdateFeedbackRequest) =>
|
|
358
|
+
dataService.updateFeedback(conversationId, messageId, payload),
|
|
359
|
+
{
|
|
360
|
+
onSuccess: () => {
|
|
361
|
+
queryClient.invalidateQueries([QueryKeys.messages, messageId]);
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
);
|
|
365
|
+
};
|
package/src/roles.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
permissionsSchema,
|
|
6
6
|
agentPermissionsSchema,
|
|
7
7
|
promptPermissionsSchema,
|
|
8
|
+
memoryPermissionsSchema,
|
|
8
9
|
runCodePermissionsSchema,
|
|
9
10
|
webSearchPermissionsSchema,
|
|
10
11
|
bookmarkPermissionsSchema,
|
|
@@ -48,6 +49,13 @@ const defaultRolesSchema = z.object({
|
|
|
48
49
|
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema.extend({
|
|
49
50
|
[Permissions.USE]: z.boolean().default(true),
|
|
50
51
|
}),
|
|
52
|
+
[PermissionTypes.MEMORIES]: memoryPermissionsSchema.extend({
|
|
53
|
+
[Permissions.USE]: z.boolean().default(true),
|
|
54
|
+
[Permissions.CREATE]: z.boolean().default(true),
|
|
55
|
+
[Permissions.UPDATE]: z.boolean().default(true),
|
|
56
|
+
[Permissions.READ]: z.boolean().default(true),
|
|
57
|
+
[Permissions.OPT_OUT]: z.boolean().default(true),
|
|
58
|
+
}),
|
|
51
59
|
[PermissionTypes.AGENTS]: agentPermissionsSchema.extend({
|
|
52
60
|
[Permissions.SHARED_GLOBAL]: z.boolean().default(true),
|
|
53
61
|
[Permissions.USE]: z.boolean().default(true),
|
|
@@ -86,6 +94,13 @@ export const roleDefaults = defaultRolesSchema.parse({
|
|
|
86
94
|
[PermissionTypes.BOOKMARKS]: {
|
|
87
95
|
[Permissions.USE]: true,
|
|
88
96
|
},
|
|
97
|
+
[PermissionTypes.MEMORIES]: {
|
|
98
|
+
[Permissions.USE]: true,
|
|
99
|
+
[Permissions.CREATE]: true,
|
|
100
|
+
[Permissions.UPDATE]: true,
|
|
101
|
+
[Permissions.READ]: true,
|
|
102
|
+
[Permissions.OPT_OUT]: true,
|
|
103
|
+
},
|
|
89
104
|
[PermissionTypes.AGENTS]: {
|
|
90
105
|
[Permissions.SHARED_GLOBAL]: true,
|
|
91
106
|
[Permissions.USE]: true,
|
|
@@ -110,6 +125,7 @@ export const roleDefaults = defaultRolesSchema.parse({
|
|
|
110
125
|
permissions: {
|
|
111
126
|
[PermissionTypes.PROMPTS]: {},
|
|
112
127
|
[PermissionTypes.BOOKMARKS]: {},
|
|
128
|
+
[PermissionTypes.MEMORIES]: {},
|
|
113
129
|
[PermissionTypes.AGENTS]: {},
|
|
114
130
|
[PermissionTypes.MULTI_CONVO]: {},
|
|
115
131
|
[PermissionTypes.TEMPORARY_CHAT]: {},
|
package/src/schemas.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Tools } from './types/assistants';
|
|
3
3
|
import type { TMessageContentParts, FunctionTool, FunctionToolCall } from './types/assistants';
|
|
4
|
+
import { TFeedback, feedbackSchema } from './feedback';
|
|
4
5
|
import type { SearchResultData } from './types/web';
|
|
5
6
|
import type { TEphemeralAgent } from './types';
|
|
6
7
|
import type { TFile } from './types/files';
|
|
@@ -518,13 +519,22 @@ export const tMessageSchema = z.object({
|
|
|
518
519
|
thread_id: z.string().optional(),
|
|
519
520
|
/* frontend components */
|
|
520
521
|
iconURL: z.string().nullable().optional(),
|
|
522
|
+
feedback: feedbackSchema.optional(),
|
|
521
523
|
});
|
|
522
524
|
|
|
525
|
+
export type MemoryArtifact = {
|
|
526
|
+
key: string;
|
|
527
|
+
value?: string;
|
|
528
|
+
tokenCount?: number;
|
|
529
|
+
type: 'update' | 'delete';
|
|
530
|
+
};
|
|
531
|
+
|
|
523
532
|
export type TAttachmentMetadata = {
|
|
524
533
|
type?: Tools;
|
|
525
534
|
messageId: string;
|
|
526
535
|
toolCallId: string;
|
|
527
536
|
[Tools.web_search]?: SearchResultData;
|
|
537
|
+
[Tools.memory]?: MemoryArtifact;
|
|
528
538
|
};
|
|
529
539
|
|
|
530
540
|
export type TAttachment =
|
|
@@ -543,6 +553,7 @@ export type TMessage = z.input<typeof tMessageSchema> & {
|
|
|
543
553
|
siblingIndex?: number;
|
|
544
554
|
attachments?: TAttachment[];
|
|
545
555
|
clientTimestamp?: string;
|
|
556
|
+
feedback?: TFeedback;
|
|
546
557
|
};
|
|
547
558
|
|
|
548
559
|
export const coerceNumber = z.union([z.number(), z.string()]).transform((val) => {
|
package/src/types/assistants.ts
CHANGED
package/src/types/mutations.ts
CHANGED
|
@@ -278,7 +278,7 @@ export type UpdatePermVars<T> = {
|
|
|
278
278
|
};
|
|
279
279
|
|
|
280
280
|
export type UpdatePromptPermVars = UpdatePermVars<p.TPromptPermissions>;
|
|
281
|
-
|
|
281
|
+
export type UpdateMemoryPermVars = UpdatePermVars<p.TMemoryPermissions>;
|
|
282
282
|
export type UpdateAgentPermVars = UpdatePermVars<p.TAgentPermissions>;
|
|
283
283
|
|
|
284
284
|
export type UpdatePermResponse = r.TRole;
|
|
@@ -290,6 +290,13 @@ export type UpdatePromptPermOptions = MutationOptions<
|
|
|
290
290
|
types.TError | null | undefined
|
|
291
291
|
>;
|
|
292
292
|
|
|
293
|
+
export type UpdateMemoryPermOptions = MutationOptions<
|
|
294
|
+
UpdatePermResponse,
|
|
295
|
+
UpdateMemoryPermVars,
|
|
296
|
+
unknown,
|
|
297
|
+
types.TError | null | undefined
|
|
298
|
+
>;
|
|
299
|
+
|
|
293
300
|
export type UpdateAgentPermOptions = MutationOptions<
|
|
294
301
|
UpdatePermResponse,
|
|
295
302
|
UpdateAgentPermVars,
|
package/src/types/queries.ts
CHANGED
|
@@ -109,3 +109,18 @@ export type VerifyToolAuthResponse = {
|
|
|
109
109
|
|
|
110
110
|
export type GetToolCallParams = { conversationId: string };
|
|
111
111
|
export type ToolCallResults = a.ToolCallResult[];
|
|
112
|
+
|
|
113
|
+
/* Memories */
|
|
114
|
+
export type TUserMemory = {
|
|
115
|
+
key: string;
|
|
116
|
+
value: string;
|
|
117
|
+
updated_at: string;
|
|
118
|
+
tokenCount?: number;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export type MemoriesResponse = {
|
|
122
|
+
memories: TUserMemory[];
|
|
123
|
+
totalTokens: number;
|
|
124
|
+
tokenLimit: number | null;
|
|
125
|
+
usagePercentage: number | null;
|
|
126
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type OpenAI from 'openai';
|
|
2
2
|
import type { InfiniteData } from '@tanstack/react-query';
|
|
3
3
|
import type {
|
|
4
|
+
TBanner,
|
|
4
5
|
TMessage,
|
|
5
6
|
TResPlugin,
|
|
6
|
-
ImageDetail,
|
|
7
7
|
TSharedLink,
|
|
8
8
|
TConversation,
|
|
9
9
|
EModelEndpoint,
|
|
10
10
|
TConversationTag,
|
|
11
|
-
|
|
11
|
+
TAttachment,
|
|
12
12
|
} from './schemas';
|
|
13
|
-
import { SettingDefinition } from './generate';
|
|
13
|
+
import type { SettingDefinition } from './generate';
|
|
14
|
+
import type { TMinimalFeedback } from './feedback';
|
|
15
|
+
import type { Agent } from './types/assistants';
|
|
16
|
+
|
|
14
17
|
export type TOpenAIMessage = OpenAI.Chat.ChatCompletionMessageParam;
|
|
15
18
|
|
|
16
19
|
export * from './schemas';
|
|
@@ -18,28 +21,78 @@ export * from './schemas';
|
|
|
18
21
|
export type TMessages = TMessage[];
|
|
19
22
|
|
|
20
23
|
/* TODO: Cleanup EndpointOption types */
|
|
21
|
-
export type TEndpointOption =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
endpoint
|
|
25
|
-
endpointType
|
|
24
|
+
export type TEndpointOption = Pick<
|
|
25
|
+
TConversation,
|
|
26
|
+
// Core conversation fields
|
|
27
|
+
| 'endpoint'
|
|
28
|
+
| 'endpointType'
|
|
29
|
+
| 'model'
|
|
30
|
+
| 'modelLabel'
|
|
31
|
+
| 'chatGptLabel'
|
|
32
|
+
| 'promptPrefix'
|
|
33
|
+
| 'temperature'
|
|
34
|
+
| 'topP'
|
|
35
|
+
| 'topK'
|
|
36
|
+
| 'top_p'
|
|
37
|
+
| 'frequency_penalty'
|
|
38
|
+
| 'presence_penalty'
|
|
39
|
+
| 'maxOutputTokens'
|
|
40
|
+
| 'maxContextTokens'
|
|
41
|
+
| 'max_tokens'
|
|
42
|
+
| 'maxTokens'
|
|
43
|
+
| 'resendFiles'
|
|
44
|
+
| 'imageDetail'
|
|
45
|
+
| 'reasoning_effort'
|
|
46
|
+
| 'instructions'
|
|
47
|
+
| 'additional_instructions'
|
|
48
|
+
| 'append_current_datetime'
|
|
49
|
+
| 'tools'
|
|
50
|
+
| 'stop'
|
|
51
|
+
| 'region'
|
|
52
|
+
| 'additionalModelRequestFields'
|
|
53
|
+
// Anthropic-specific
|
|
54
|
+
| 'promptCache'
|
|
55
|
+
| 'thinking'
|
|
56
|
+
| 'thinkingBudget'
|
|
57
|
+
// Assistant/Agent fields
|
|
58
|
+
| 'assistant_id'
|
|
59
|
+
| 'agent_id'
|
|
60
|
+
// UI/Display fields
|
|
61
|
+
| 'iconURL'
|
|
62
|
+
| 'greeting'
|
|
63
|
+
| 'spec'
|
|
64
|
+
// Artifacts
|
|
65
|
+
| 'artifacts'
|
|
66
|
+
// Files
|
|
67
|
+
| 'file_ids'
|
|
68
|
+
// System field
|
|
69
|
+
| 'system'
|
|
70
|
+
// Google examples
|
|
71
|
+
| 'examples'
|
|
72
|
+
// Context
|
|
73
|
+
| 'context'
|
|
74
|
+
> & {
|
|
75
|
+
// Fields specific to endpoint options that don't exist on TConversation
|
|
26
76
|
modelDisplayLabel?: string;
|
|
27
|
-
resendFiles?: boolean;
|
|
28
|
-
promptCache?: boolean;
|
|
29
|
-
maxContextTokens?: number;
|
|
30
|
-
imageDetail?: ImageDetail;
|
|
31
|
-
model?: string | null;
|
|
32
|
-
promptPrefix?: string;
|
|
33
|
-
temperature?: number;
|
|
34
|
-
chatGptLabel?: string | null;
|
|
35
|
-
modelLabel?: string | null;
|
|
36
|
-
jailbreak?: boolean;
|
|
37
77
|
key?: string | null;
|
|
38
|
-
|
|
78
|
+
/** @deprecated Assistants API */
|
|
39
79
|
thread_id?: string;
|
|
40
|
-
|
|
80
|
+
// Conversation identifiers for multi-response streams
|
|
41
81
|
overrideConvoId?: string;
|
|
42
82
|
overrideUserMessageId?: string;
|
|
83
|
+
// Model parameters (used by different endpoints)
|
|
84
|
+
modelOptions?: Record<string, unknown>;
|
|
85
|
+
model_parameters?: Record<string, unknown>;
|
|
86
|
+
// Configuration data (added by middleware)
|
|
87
|
+
modelsConfig?: TModelsConfig;
|
|
88
|
+
// File attachments (processed by middleware)
|
|
89
|
+
attachments?: TAttachment[];
|
|
90
|
+
// Generated prompts
|
|
91
|
+
artifactsPrompt?: string;
|
|
92
|
+
// Agent-specific fields
|
|
93
|
+
agent?: Promise<Agent>;
|
|
94
|
+
// Client-specific options
|
|
95
|
+
clientOptions?: Record<string, unknown>;
|
|
43
96
|
};
|
|
44
97
|
|
|
45
98
|
export type TEphemeralAgent = {
|
|
@@ -128,6 +181,9 @@ export type TUser = {
|
|
|
128
181
|
plugins?: string[];
|
|
129
182
|
twoFactorEnabled?: boolean;
|
|
130
183
|
backupCodes?: TBackupCode[];
|
|
184
|
+
personalization?: {
|
|
185
|
+
memories?: boolean;
|
|
186
|
+
};
|
|
131
187
|
createdAt: string;
|
|
132
188
|
updatedAt: string;
|
|
133
189
|
};
|
|
@@ -546,3 +602,23 @@ export type TAcceptTermsResponse = {
|
|
|
546
602
|
};
|
|
547
603
|
|
|
548
604
|
export type TBannerResponse = TBanner | null;
|
|
605
|
+
|
|
606
|
+
export type TUpdateFeedbackRequest = {
|
|
607
|
+
feedback?: TMinimalFeedback;
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
export type TUpdateFeedbackResponse = {
|
|
611
|
+
messageId: string;
|
|
612
|
+
conversationId: string;
|
|
613
|
+
feedback?: TMinimalFeedback;
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
export type TBalanceResponse = {
|
|
617
|
+
tokenCredits: number;
|
|
618
|
+
// Automatic refill settings
|
|
619
|
+
autoRefillEnabled: boolean;
|
|
620
|
+
refillIntervalValue?: number;
|
|
621
|
+
refillIntervalUnit?: 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months';
|
|
622
|
+
lastRefill?: Date;
|
|
623
|
+
refillAmount?: number;
|
|
624
|
+
};
|
package/src/web.ts
CHANGED
|
@@ -5,8 +5,8 @@ import type {
|
|
|
5
5
|
SearchProviders,
|
|
6
6
|
TWebSearchConfig,
|
|
7
7
|
} from './config';
|
|
8
|
-
import { extractVariableName } from './utils';
|
|
9
8
|
import { SearchCategories, SafeSearchTypes } from './config';
|
|
9
|
+
import { extractVariableName } from './utils';
|
|
10
10
|
import { AuthType } from './schemas';
|
|
11
11
|
|
|
12
12
|
export function loadWebSearchConfig(
|
|
@@ -64,23 +64,29 @@ export const webSearchAuth = {
|
|
|
64
64
|
/**
|
|
65
65
|
* Extracts all API keys from the webSearchAuth configuration object
|
|
66
66
|
*/
|
|
67
|
-
export
|
|
67
|
+
export function getWebSearchKeys(): TWebSearchKeys[] {
|
|
68
|
+
const keys: TWebSearchKeys[] = [];
|
|
68
69
|
|
|
69
|
-
// Iterate through each category (providers, scrapers, rerankers)
|
|
70
|
-
for (const category of Object.keys(webSearchAuth)) {
|
|
71
|
-
|
|
70
|
+
// Iterate through each category (providers, scrapers, rerankers)
|
|
71
|
+
for (const category of Object.keys(webSearchAuth)) {
|
|
72
|
+
const categoryObj = webSearchAuth[category as TWebSearchCategories];
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// Iterate through each service within the category
|
|
75
|
+
for (const service of Object.keys(categoryObj)) {
|
|
76
|
+
const serviceObj = categoryObj[service as keyof typeof categoryObj];
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
// Extract the API keys from the service
|
|
79
|
+
for (const key of Object.keys(serviceObj)) {
|
|
80
|
+
keys.push(key as TWebSearchKeys);
|
|
81
|
+
}
|
|
80
82
|
}
|
|
81
83
|
}
|
|
84
|
+
|
|
85
|
+
return keys;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
export const webSearchKeys: TWebSearchKeys[] = getWebSearchKeys();
|
|
89
|
+
|
|
84
90
|
export function extractWebSearchEnvVars({
|
|
85
91
|
keys,
|
|
86
92
|
config,
|
package/src/zod.spec.ts
CHANGED
|
@@ -264,19 +264,19 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
264
264
|
properties: {
|
|
265
265
|
name: {
|
|
266
266
|
type: 'string',
|
|
267
|
-
description:
|
|
267
|
+
description: "The user's name",
|
|
268
268
|
},
|
|
269
269
|
age: {
|
|
270
270
|
type: 'number',
|
|
271
|
-
description:
|
|
271
|
+
description: "The user's age",
|
|
272
272
|
},
|
|
273
273
|
},
|
|
274
274
|
};
|
|
275
275
|
const zodSchema = convertJsonSchemaToZod(schema);
|
|
276
276
|
|
|
277
277
|
const shape = (zodSchema as z.ZodObject<any>).shape;
|
|
278
|
-
expect(shape.name.description).toBe(
|
|
279
|
-
expect(shape.age.description).toBe(
|
|
278
|
+
expect(shape.name.description).toBe("The user's name");
|
|
279
|
+
expect(shape.age.description).toBe("The user's age");
|
|
280
280
|
});
|
|
281
281
|
|
|
282
282
|
it('should preserve descriptions in nested objects', () => {
|
|
@@ -290,7 +290,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
290
290
|
properties: {
|
|
291
291
|
name: {
|
|
292
292
|
type: 'string',
|
|
293
|
-
description:
|
|
293
|
+
description: "The user's name",
|
|
294
294
|
},
|
|
295
295
|
settings: {
|
|
296
296
|
type: 'object',
|
|
@@ -318,7 +318,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
318
318
|
|
|
319
319
|
const userShape = shape.user instanceof z.ZodObject ? shape.user.shape : {};
|
|
320
320
|
if ('name' in userShape && 'settings' in userShape) {
|
|
321
|
-
expect(userShape.name.description).toBe(
|
|
321
|
+
expect(userShape.name.description).toBe("The user's name");
|
|
322
322
|
expect(userShape.settings.description).toBe('User preferences');
|
|
323
323
|
|
|
324
324
|
const settingsShape =
|
|
@@ -682,10 +682,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
682
682
|
name: { type: 'string' },
|
|
683
683
|
age: { type: 'number' },
|
|
684
684
|
},
|
|
685
|
-
anyOf: [
|
|
686
|
-
{ required: ['name'] },
|
|
687
|
-
{ required: ['age'] },
|
|
688
|
-
],
|
|
685
|
+
anyOf: [{ required: ['name'] }, { required: ['age'] }],
|
|
689
686
|
oneOf: [
|
|
690
687
|
{ properties: { role: { type: 'string', enum: ['admin'] } } },
|
|
691
688
|
{ properties: { role: { type: 'string', enum: ['user'] } } },
|
|
@@ -708,7 +705,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
708
705
|
it('should drop fields from nested schemas', () => {
|
|
709
706
|
// Create a schema with nested fields that should be dropped
|
|
710
707
|
const schema: JsonSchemaType & {
|
|
711
|
-
properties?: Record<string, JsonSchemaType & { anyOf?: any; oneOf?: any }
|
|
708
|
+
properties?: Record<string, JsonSchemaType & { anyOf?: any; oneOf?: any }>;
|
|
712
709
|
} = {
|
|
713
710
|
type: 'object',
|
|
714
711
|
properties: {
|
|
@@ -718,10 +715,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
718
715
|
name: { type: 'string' },
|
|
719
716
|
role: { type: 'string' },
|
|
720
717
|
},
|
|
721
|
-
anyOf: [
|
|
722
|
-
{ required: ['name'] },
|
|
723
|
-
{ required: ['role'] },
|
|
724
|
-
],
|
|
718
|
+
anyOf: [{ required: ['name'] }, { required: ['role'] }],
|
|
725
719
|
},
|
|
726
720
|
settings: {
|
|
727
721
|
type: 'object',
|
|
@@ -742,20 +736,24 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
742
736
|
});
|
|
743
737
|
|
|
744
738
|
// The schema should still validate normal properties
|
|
745
|
-
expect(
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
739
|
+
expect(
|
|
740
|
+
zodSchema?.parse({
|
|
741
|
+
user: { name: 'John', role: 'admin' },
|
|
742
|
+
settings: { theme: 'custom' }, // This would fail if oneOf was still present
|
|
743
|
+
}),
|
|
744
|
+
).toEqual({
|
|
749
745
|
user: { name: 'John', role: 'admin' },
|
|
750
746
|
settings: { theme: 'custom' },
|
|
751
747
|
});
|
|
752
748
|
|
|
753
749
|
// But the anyOf constraint should be gone from user
|
|
754
750
|
// (If it was present, this would fail because neither name nor role is required)
|
|
755
|
-
expect(
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
751
|
+
expect(
|
|
752
|
+
zodSchema?.parse({
|
|
753
|
+
user: {},
|
|
754
|
+
settings: { theme: 'light' },
|
|
755
|
+
}),
|
|
756
|
+
).toEqual({
|
|
759
757
|
user: {},
|
|
760
758
|
settings: { theme: 'light' },
|
|
761
759
|
});
|
|
@@ -803,10 +801,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
803
801
|
anyOf: [{ minItems: 1 }],
|
|
804
802
|
},
|
|
805
803
|
},
|
|
806
|
-
oneOf: [
|
|
807
|
-
{ required: ['name', 'permissions'] },
|
|
808
|
-
{ required: ['name'] },
|
|
809
|
-
],
|
|
804
|
+
oneOf: [{ required: ['name', 'permissions'] }, { required: ['name'] }],
|
|
810
805
|
},
|
|
811
806
|
},
|
|
812
807
|
},
|
|
@@ -871,10 +866,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
871
866
|
const schema = {
|
|
872
867
|
type: 'object', // Add a type to satisfy JsonSchemaType
|
|
873
868
|
properties: {}, // Empty properties
|
|
874
|
-
oneOf: [
|
|
875
|
-
{ type: 'string' },
|
|
876
|
-
{ type: 'number' },
|
|
877
|
-
],
|
|
869
|
+
oneOf: [{ type: 'string' }, { type: 'number' }],
|
|
878
870
|
} as JsonSchemaType & { oneOf?: any };
|
|
879
871
|
|
|
880
872
|
// Convert with transformOneOfAnyOf option
|
|
@@ -893,10 +885,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
893
885
|
const schema = {
|
|
894
886
|
type: 'object', // Add a type to satisfy JsonSchemaType
|
|
895
887
|
properties: {}, // Empty properties
|
|
896
|
-
anyOf: [
|
|
897
|
-
{ type: 'string' },
|
|
898
|
-
{ type: 'number' },
|
|
899
|
-
],
|
|
888
|
+
anyOf: [{ type: 'string' }, { type: 'number' }],
|
|
900
889
|
} as JsonSchemaType & { anyOf?: any };
|
|
901
890
|
|
|
902
891
|
// Convert with transformOneOfAnyOf option
|
|
@@ -956,10 +945,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
956
945
|
properties: {
|
|
957
946
|
value: { type: 'string' },
|
|
958
947
|
},
|
|
959
|
-
oneOf: [
|
|
960
|
-
{ required: ['value'] },
|
|
961
|
-
{ properties: { optional: { type: 'boolean' } } },
|
|
962
|
-
],
|
|
948
|
+
oneOf: [{ required: ['value'] }, { properties: { optional: { type: 'boolean' } } }],
|
|
963
949
|
} as JsonSchemaType & { oneOf?: any };
|
|
964
950
|
|
|
965
951
|
// Convert with transformOneOfAnyOf option
|
|
@@ -1013,9 +999,12 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
1013
999
|
},
|
|
1014
1000
|
},
|
|
1015
1001
|
} as JsonSchemaType & {
|
|
1016
|
-
properties?: Record<
|
|
1017
|
-
|
|
1018
|
-
|
|
1002
|
+
properties?: Record<
|
|
1003
|
+
string,
|
|
1004
|
+
JsonSchemaType & {
|
|
1005
|
+
properties?: Record<string, JsonSchemaType & { oneOf?: any }>;
|
|
1006
|
+
}
|
|
1007
|
+
>;
|
|
1019
1008
|
};
|
|
1020
1009
|
|
|
1021
1010
|
// Convert with transformOneOfAnyOf option
|
|
@@ -1024,14 +1013,16 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
1024
1013
|
});
|
|
1025
1014
|
|
|
1026
1015
|
// The schema should validate nested unions
|
|
1027
|
-
expect(
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1016
|
+
expect(
|
|
1017
|
+
zodSchema?.parse({
|
|
1018
|
+
user: {
|
|
1019
|
+
contact: {
|
|
1020
|
+
type: 'email',
|
|
1021
|
+
email: 'test@example.com',
|
|
1022
|
+
},
|
|
1032
1023
|
},
|
|
1033
|
-
},
|
|
1034
|
-
|
|
1024
|
+
}),
|
|
1025
|
+
).toEqual({
|
|
1035
1026
|
user: {
|
|
1036
1027
|
contact: {
|
|
1037
1028
|
type: 'email',
|
|
@@ -1040,14 +1031,16 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
1040
1031
|
},
|
|
1041
1032
|
});
|
|
1042
1033
|
|
|
1043
|
-
expect(
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1034
|
+
expect(
|
|
1035
|
+
zodSchema?.parse({
|
|
1036
|
+
user: {
|
|
1037
|
+
contact: {
|
|
1038
|
+
type: 'phone',
|
|
1039
|
+
phone: '123-456-7890',
|
|
1040
|
+
},
|
|
1048
1041
|
},
|
|
1049
|
-
},
|
|
1050
|
-
|
|
1042
|
+
}),
|
|
1043
|
+
).toEqual({
|
|
1051
1044
|
user: {
|
|
1052
1045
|
contact: {
|
|
1053
1046
|
type: 'phone',
|
|
@@ -1057,14 +1050,16 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
1057
1050
|
});
|
|
1058
1051
|
|
|
1059
1052
|
// Should reject invalid contact types
|
|
1060
|
-
expect(() =>
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1053
|
+
expect(() =>
|
|
1054
|
+
zodSchema?.parse({
|
|
1055
|
+
user: {
|
|
1056
|
+
contact: {
|
|
1057
|
+
type: 'email',
|
|
1058
|
+
phone: '123-456-7890', // Missing email, has phone instead
|
|
1059
|
+
},
|
|
1065
1060
|
},
|
|
1066
|
-
},
|
|
1067
|
-
|
|
1061
|
+
}),
|
|
1062
|
+
).toThrow();
|
|
1068
1063
|
});
|
|
1069
1064
|
|
|
1070
1065
|
it('should work with dropFields option', () => {
|
|
@@ -1072,10 +1067,7 @@ describe('convertJsonSchemaToZod', () => {
|
|
|
1072
1067
|
const schema = {
|
|
1073
1068
|
type: 'object', // Add a type to satisfy JsonSchemaType
|
|
1074
1069
|
properties: {}, // Empty properties
|
|
1075
|
-
oneOf: [
|
|
1076
|
-
{ type: 'string' },
|
|
1077
|
-
{ type: 'number' },
|
|
1078
|
-
],
|
|
1070
|
+
oneOf: [{ type: 'string' }, { type: 'number' }],
|
|
1079
1071
|
deprecated: true, // Field to drop
|
|
1080
1072
|
} as JsonSchemaType & { oneOf?: any; deprecated?: boolean };
|
|
1081
1073
|
|