@gammatech/aijsx 0.14.0-dev.2024-07-15 → 0.15.0-dev.2024-07-30
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.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -11
- package/dist/index.mjs +61 -11
- package/dist/{jsx-dev-runtime-S--1HQKU.d.mts → jsx-dev-runtime-lYsmphqH.d.mts} +2 -1
- package/dist/{jsx-dev-runtime-S--1HQKU.d.ts → jsx-dev-runtime-lYsmphqH.d.ts} +2 -1
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L as LogChatCompletionRequest, A as AINode, C as ChatMessage, R as RenderContext, a as LogImplementation, S as SpanProcessor, b as ContextValues, c as Context, T as Tracer, d as ReadableSpan, e as SpanAttributes, f as SpanExporter, g as AIComponent, P as Prompt, h as ChatCompletionRequestPayloads, D as DebugMessage, E as EvaluatorResult, i as EvaluatorFn, j as PromptParsed, J as JSX } from './jsx-dev-runtime-
|
|
2
|
-
export { y as AIElement, l as AIFragment, B as BoundLogger, n as ChatRole, u as CombinedLogger, s as ConsoleLogger, I as ImagePart, o as ImagePartProps, v as Literal, p as LogChatCompletionResponse, q as LogLevel, r as Logger, N as NoopLogImplementation, V as OutputParser, F as PropsOfAIComponent, w as RenderResult, z as Renderable, K as Span, G as SpanContext, M as SpanEvent, H as SpanStatus, Q as TracingContext, O as TracingContextKey, U as TracingContextManager, x as attachedContextSymbol, k as createAIElement, m as createContext, t as toDebugMessage } from './jsx-dev-runtime-
|
|
1
|
+
import { L as LogChatCompletionRequest, A as AINode, C as ChatMessage, R as RenderContext, a as LogImplementation, S as SpanProcessor, b as ContextValues, c as Context, T as Tracer, d as ReadableSpan, e as SpanAttributes, f as SpanExporter, g as AIComponent, P as Prompt, h as ChatCompletionRequestPayloads, D as DebugMessage, E as EvaluatorResult, i as EvaluatorFn, j as PromptParsed, J as JSX } from './jsx-dev-runtime-lYsmphqH.mjs';
|
|
2
|
+
export { y as AIElement, l as AIFragment, B as BoundLogger, n as ChatRole, u as CombinedLogger, s as ConsoleLogger, I as ImagePart, o as ImagePartProps, v as Literal, p as LogChatCompletionResponse, q as LogLevel, r as Logger, N as NoopLogImplementation, V as OutputParser, F as PropsOfAIComponent, w as RenderResult, z as Renderable, K as Span, G as SpanContext, M as SpanEvent, H as SpanStatus, Q as TracingContext, O as TracingContextKey, U as TracingContextManager, x as attachedContextSymbol, k as createAIElement, m as createContext, t as toDebugMessage } from './jsx-dev-runtime-lYsmphqH.mjs';
|
|
3
3
|
import { ZodObject, ZodRawShape, ZodTypeAny, ZodString, z } from 'zod';
|
|
4
4
|
import { OpenAI } from 'openai';
|
|
5
5
|
export { OpenAI as OpenAIClient } from 'openai';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L as LogChatCompletionRequest, A as AINode, C as ChatMessage, R as RenderContext, a as LogImplementation, S as SpanProcessor, b as ContextValues, c as Context, T as Tracer, d as ReadableSpan, e as SpanAttributes, f as SpanExporter, g as AIComponent, P as Prompt, h as ChatCompletionRequestPayloads, D as DebugMessage, E as EvaluatorResult, i as EvaluatorFn, j as PromptParsed, J as JSX } from './jsx-dev-runtime-
|
|
2
|
-
export { y as AIElement, l as AIFragment, B as BoundLogger, n as ChatRole, u as CombinedLogger, s as ConsoleLogger, I as ImagePart, o as ImagePartProps, v as Literal, p as LogChatCompletionResponse, q as LogLevel, r as Logger, N as NoopLogImplementation, V as OutputParser, F as PropsOfAIComponent, w as RenderResult, z as Renderable, K as Span, G as SpanContext, M as SpanEvent, H as SpanStatus, Q as TracingContext, O as TracingContextKey, U as TracingContextManager, x as attachedContextSymbol, k as createAIElement, m as createContext, t as toDebugMessage } from './jsx-dev-runtime-
|
|
1
|
+
import { L as LogChatCompletionRequest, A as AINode, C as ChatMessage, R as RenderContext, a as LogImplementation, S as SpanProcessor, b as ContextValues, c as Context, T as Tracer, d as ReadableSpan, e as SpanAttributes, f as SpanExporter, g as AIComponent, P as Prompt, h as ChatCompletionRequestPayloads, D as DebugMessage, E as EvaluatorResult, i as EvaluatorFn, j as PromptParsed, J as JSX } from './jsx-dev-runtime-lYsmphqH.js';
|
|
2
|
+
export { y as AIElement, l as AIFragment, B as BoundLogger, n as ChatRole, u as CombinedLogger, s as ConsoleLogger, I as ImagePart, o as ImagePartProps, v as Literal, p as LogChatCompletionResponse, q as LogLevel, r as Logger, N as NoopLogImplementation, V as OutputParser, F as PropsOfAIComponent, w as RenderResult, z as Renderable, K as Span, G as SpanContext, M as SpanEvent, H as SpanStatus, Q as TracingContext, O as TracingContextKey, U as TracingContextManager, x as attachedContextSymbol, k as createAIElement, m as createContext, t as toDebugMessage } from './jsx-dev-runtime-lYsmphqH.js';
|
|
3
3
|
import { ZodObject, ZodRawShape, ZodTypeAny, ZodString, z } from 'zod';
|
|
4
4
|
import { OpenAI } from 'openai';
|
|
5
5
|
export { OpenAI as OpenAIClient } from 'openai';
|
package/dist/index.js
CHANGED
|
@@ -89,6 +89,12 @@ var ChatCompletionError = class extends Error {
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
// src/chat/image.ts
|
|
92
|
+
var SUPPORTED_TYPES = [
|
|
93
|
+
"image/jpeg",
|
|
94
|
+
"image/png",
|
|
95
|
+
"image/gif",
|
|
96
|
+
"image/webp"
|
|
97
|
+
];
|
|
92
98
|
var IMAGE_RENDERED_PROPS = {
|
|
93
99
|
ImagePart: {
|
|
94
100
|
url: true,
|
|
@@ -104,8 +110,7 @@ var ImagePart = (_props) => {
|
|
|
104
110
|
async function fetchImageAndConvertToBase64(url) {
|
|
105
111
|
const response = await fetch(url);
|
|
106
112
|
const contentType = response.headers.get("content-type");
|
|
107
|
-
|
|
108
|
-
if (!contentType || !allowedTypes.includes(contentType)) {
|
|
113
|
+
if (!contentType || !RE_ALLOWED_MEDIA_TYPES.test(contentType)) {
|
|
109
114
|
throw new Error(`Unsupported media type: ${contentType}`);
|
|
110
115
|
}
|
|
111
116
|
const blob = await response.blob();
|
|
@@ -116,10 +121,40 @@ async function fetchImageAndConvertToBase64(url) {
|
|
|
116
121
|
mediaType: contentType
|
|
117
122
|
};
|
|
118
123
|
}
|
|
119
|
-
|
|
124
|
+
var RE_ALLOWED_MEDIA_TYPES = new RegExp(
|
|
125
|
+
`^(${SUPPORTED_TYPES.join("|")})$`,
|
|
126
|
+
"i"
|
|
127
|
+
);
|
|
128
|
+
var RE_DATA_IMAGE = new RegExp(
|
|
129
|
+
`^data:(${SUPPORTED_TYPES.join("|")});base64,(.+)$`,
|
|
130
|
+
"i"
|
|
131
|
+
);
|
|
132
|
+
var parseDataUrl = (dataUrl) => {
|
|
133
|
+
const matches = dataUrl.match(RE_DATA_IMAGE);
|
|
134
|
+
if (!matches) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const [, mediaType, base64] = matches;
|
|
138
|
+
return {
|
|
139
|
+
mediaType,
|
|
140
|
+
base64
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
async function processImageMessageProps(props, opts) {
|
|
120
144
|
const { dimensions, detail, ...rest } = props;
|
|
121
|
-
if ("url" in rest) {
|
|
122
|
-
|
|
145
|
+
if ("url" in rest && rest.url) {
|
|
146
|
+
const parsed = parseDataUrl(rest.url);
|
|
147
|
+
if (parsed) {
|
|
148
|
+
const { mediaType, base64 } = parsed;
|
|
149
|
+
return {
|
|
150
|
+
url: null,
|
|
151
|
+
data: base64,
|
|
152
|
+
mediaType,
|
|
153
|
+
dimensions,
|
|
154
|
+
detail
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (opts.downloadUrl) {
|
|
123
158
|
const { base64, mediaType } = await fetchImageAndConvertToBase64(rest.url);
|
|
124
159
|
return {
|
|
125
160
|
url: rest.url,
|
|
@@ -138,6 +173,16 @@ async function processImageMessageProps(props, downloadUrl) {
|
|
|
138
173
|
};
|
|
139
174
|
}
|
|
140
175
|
if ("data" in rest) {
|
|
176
|
+
const parsed = parseDataUrl(rest.data);
|
|
177
|
+
if (parsed) {
|
|
178
|
+
return {
|
|
179
|
+
url: null,
|
|
180
|
+
mediaType: parsed.mediaType,
|
|
181
|
+
data: parsed.base64,
|
|
182
|
+
dimensions,
|
|
183
|
+
detail
|
|
184
|
+
};
|
|
185
|
+
}
|
|
141
186
|
return {
|
|
142
187
|
url: null,
|
|
143
188
|
mediaType: rest.mediaType,
|
|
@@ -159,6 +204,9 @@ var cleanProps = (props) => {
|
|
|
159
204
|
}
|
|
160
205
|
return res;
|
|
161
206
|
};
|
|
207
|
+
var buildDataUri = (mediaType, base64) => {
|
|
208
|
+
return `data:${mediaType};base64,${base64}`;
|
|
209
|
+
};
|
|
162
210
|
|
|
163
211
|
// src/chat/ChatMessage.ts
|
|
164
212
|
var toDebugMessage = (message) => {
|
|
@@ -185,8 +233,8 @@ var toDebugMessage = (message) => {
|
|
|
185
233
|
};
|
|
186
234
|
};
|
|
187
235
|
var UserChatMessageBuilder = class {
|
|
188
|
-
constructor(
|
|
189
|
-
this.
|
|
236
|
+
constructor(opts) {
|
|
237
|
+
this.opts = opts;
|
|
190
238
|
}
|
|
191
239
|
content = [];
|
|
192
240
|
text(text) {
|
|
@@ -206,7 +254,9 @@ var UserChatMessageBuilder = class {
|
|
|
206
254
|
text: part
|
|
207
255
|
};
|
|
208
256
|
} else {
|
|
209
|
-
const image = await processImageMessageProps(part,
|
|
257
|
+
const image = await processImageMessageProps(part, {
|
|
258
|
+
downloadUrl: this.opts.useBase64Images
|
|
259
|
+
});
|
|
210
260
|
return {
|
|
211
261
|
type: "image",
|
|
212
262
|
image
|
|
@@ -221,7 +271,7 @@ var UserChatMessageBuilder = class {
|
|
|
221
271
|
}
|
|
222
272
|
};
|
|
223
273
|
var userChatMessageBuilder = (opts) => {
|
|
224
|
-
return new UserChatMessageBuilder(opts
|
|
274
|
+
return new UserChatMessageBuilder(opts);
|
|
225
275
|
};
|
|
226
276
|
|
|
227
277
|
// src/chat/components.ts
|
|
@@ -2073,7 +2123,7 @@ async function buildChatMessages(ctx, children, opts) {
|
|
|
2073
2123
|
const nodes = await toXml(ctx, children);
|
|
2074
2124
|
const handleUserMessage = async (node) => {
|
|
2075
2125
|
const childNodes = node.childNodes;
|
|
2076
|
-
const builder = userChatMessageBuilder(
|
|
2126
|
+
const builder = userChatMessageBuilder(opts);
|
|
2077
2127
|
for (const n of childNodes) {
|
|
2078
2128
|
if (n.nodeName === "#text") {
|
|
2079
2129
|
builder.text(n.value);
|
|
@@ -2142,7 +2192,7 @@ function buildOpenAIMessages(chatMessages) {
|
|
|
2142
2192
|
};
|
|
2143
2193
|
}
|
|
2144
2194
|
if (part.type === "image") {
|
|
2145
|
-
const url = part.image.url
|
|
2195
|
+
const url = part.image.url ?? buildDataUri(part.image.mediaType, part.image.data);
|
|
2146
2196
|
return {
|
|
2147
2197
|
type: "image_url",
|
|
2148
2198
|
image_url: {
|
package/dist/index.mjs
CHANGED
|
@@ -19,6 +19,12 @@ var ChatCompletionError = class extends Error {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// src/chat/image.ts
|
|
22
|
+
var SUPPORTED_TYPES = [
|
|
23
|
+
"image/jpeg",
|
|
24
|
+
"image/png",
|
|
25
|
+
"image/gif",
|
|
26
|
+
"image/webp"
|
|
27
|
+
];
|
|
22
28
|
var IMAGE_RENDERED_PROPS = {
|
|
23
29
|
ImagePart: {
|
|
24
30
|
url: true,
|
|
@@ -34,8 +40,7 @@ var ImagePart = (_props) => {
|
|
|
34
40
|
async function fetchImageAndConvertToBase64(url) {
|
|
35
41
|
const response = await fetch(url);
|
|
36
42
|
const contentType = response.headers.get("content-type");
|
|
37
|
-
|
|
38
|
-
if (!contentType || !allowedTypes.includes(contentType)) {
|
|
43
|
+
if (!contentType || !RE_ALLOWED_MEDIA_TYPES.test(contentType)) {
|
|
39
44
|
throw new Error(`Unsupported media type: ${contentType}`);
|
|
40
45
|
}
|
|
41
46
|
const blob = await response.blob();
|
|
@@ -46,10 +51,40 @@ async function fetchImageAndConvertToBase64(url) {
|
|
|
46
51
|
mediaType: contentType
|
|
47
52
|
};
|
|
48
53
|
}
|
|
49
|
-
|
|
54
|
+
var RE_ALLOWED_MEDIA_TYPES = new RegExp(
|
|
55
|
+
`^(${SUPPORTED_TYPES.join("|")})$`,
|
|
56
|
+
"i"
|
|
57
|
+
);
|
|
58
|
+
var RE_DATA_IMAGE = new RegExp(
|
|
59
|
+
`^data:(${SUPPORTED_TYPES.join("|")});base64,(.+)$`,
|
|
60
|
+
"i"
|
|
61
|
+
);
|
|
62
|
+
var parseDataUrl = (dataUrl) => {
|
|
63
|
+
const matches = dataUrl.match(RE_DATA_IMAGE);
|
|
64
|
+
if (!matches) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const [, mediaType, base64] = matches;
|
|
68
|
+
return {
|
|
69
|
+
mediaType,
|
|
70
|
+
base64
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
async function processImageMessageProps(props, opts) {
|
|
50
74
|
const { dimensions, detail, ...rest } = props;
|
|
51
|
-
if ("url" in rest) {
|
|
52
|
-
|
|
75
|
+
if ("url" in rest && rest.url) {
|
|
76
|
+
const parsed = parseDataUrl(rest.url);
|
|
77
|
+
if (parsed) {
|
|
78
|
+
const { mediaType, base64 } = parsed;
|
|
79
|
+
return {
|
|
80
|
+
url: null,
|
|
81
|
+
data: base64,
|
|
82
|
+
mediaType,
|
|
83
|
+
dimensions,
|
|
84
|
+
detail
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (opts.downloadUrl) {
|
|
53
88
|
const { base64, mediaType } = await fetchImageAndConvertToBase64(rest.url);
|
|
54
89
|
return {
|
|
55
90
|
url: rest.url,
|
|
@@ -68,6 +103,16 @@ async function processImageMessageProps(props, downloadUrl) {
|
|
|
68
103
|
};
|
|
69
104
|
}
|
|
70
105
|
if ("data" in rest) {
|
|
106
|
+
const parsed = parseDataUrl(rest.data);
|
|
107
|
+
if (parsed) {
|
|
108
|
+
return {
|
|
109
|
+
url: null,
|
|
110
|
+
mediaType: parsed.mediaType,
|
|
111
|
+
data: parsed.base64,
|
|
112
|
+
dimensions,
|
|
113
|
+
detail
|
|
114
|
+
};
|
|
115
|
+
}
|
|
71
116
|
return {
|
|
72
117
|
url: null,
|
|
73
118
|
mediaType: rest.mediaType,
|
|
@@ -89,6 +134,9 @@ var cleanProps = (props) => {
|
|
|
89
134
|
}
|
|
90
135
|
return res;
|
|
91
136
|
};
|
|
137
|
+
var buildDataUri = (mediaType, base64) => {
|
|
138
|
+
return `data:${mediaType};base64,${base64}`;
|
|
139
|
+
};
|
|
92
140
|
|
|
93
141
|
// src/chat/ChatMessage.ts
|
|
94
142
|
var toDebugMessage = (message) => {
|
|
@@ -115,8 +163,8 @@ var toDebugMessage = (message) => {
|
|
|
115
163
|
};
|
|
116
164
|
};
|
|
117
165
|
var UserChatMessageBuilder = class {
|
|
118
|
-
constructor(
|
|
119
|
-
this.
|
|
166
|
+
constructor(opts) {
|
|
167
|
+
this.opts = opts;
|
|
120
168
|
}
|
|
121
169
|
content = [];
|
|
122
170
|
text(text) {
|
|
@@ -136,7 +184,9 @@ var UserChatMessageBuilder = class {
|
|
|
136
184
|
text: part
|
|
137
185
|
};
|
|
138
186
|
} else {
|
|
139
|
-
const image = await processImageMessageProps(part,
|
|
187
|
+
const image = await processImageMessageProps(part, {
|
|
188
|
+
downloadUrl: this.opts.useBase64Images
|
|
189
|
+
});
|
|
140
190
|
return {
|
|
141
191
|
type: "image",
|
|
142
192
|
image
|
|
@@ -151,7 +201,7 @@ var UserChatMessageBuilder = class {
|
|
|
151
201
|
}
|
|
152
202
|
};
|
|
153
203
|
var userChatMessageBuilder = (opts) => {
|
|
154
|
-
return new UserChatMessageBuilder(opts
|
|
204
|
+
return new UserChatMessageBuilder(opts);
|
|
155
205
|
};
|
|
156
206
|
|
|
157
207
|
// src/chat/components.ts
|
|
@@ -1970,7 +2020,7 @@ async function buildChatMessages(ctx, children, opts) {
|
|
|
1970
2020
|
const nodes = await toXml(ctx, children);
|
|
1971
2021
|
const handleUserMessage = async (node) => {
|
|
1972
2022
|
const childNodes = node.childNodes;
|
|
1973
|
-
const builder = userChatMessageBuilder(
|
|
2023
|
+
const builder = userChatMessageBuilder(opts);
|
|
1974
2024
|
for (const n of childNodes) {
|
|
1975
2025
|
if (n.nodeName === "#text") {
|
|
1976
2026
|
builder.text(n.value);
|
|
@@ -2039,7 +2089,7 @@ function buildOpenAIMessages(chatMessages) {
|
|
|
2039
2089
|
};
|
|
2040
2090
|
}
|
|
2041
2091
|
if (part.type === "image") {
|
|
2042
|
-
const url = part.image.url
|
|
2092
|
+
const url = part.image.url ?? buildDataUri(part.image.mediaType, part.image.data);
|
|
2043
2093
|
return {
|
|
2044
2094
|
type: "image_url",
|
|
2045
2095
|
image_url: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ZodTypeAny, ZodObject, ZodRawShape } from 'zod';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
declare const SUPPORTED_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
4
|
+
type ImageMediaType = (typeof SUPPORTED_TYPES)[number];
|
|
4
5
|
type ImageMessageExtraProps = {
|
|
5
6
|
dimensions?: {
|
|
6
7
|
width: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ZodTypeAny, ZodObject, ZodRawShape } from 'zod';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
declare const SUPPORTED_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
4
|
+
type ImageMediaType = (typeof SUPPORTED_TYPES)[number];
|
|
4
5
|
type ImageMessageExtraProps = {
|
|
5
6
|
dimensions?: {
|
|
6
7
|
width: number;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-
|
|
1
|
+
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-lYsmphqH.mjs';
|
|
2
2
|
import 'zod';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-
|
|
1
|
+
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-lYsmphqH.js';
|
|
2
2
|
import 'zod';
|
package/dist/jsx-runtime.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-
|
|
1
|
+
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-lYsmphqH.mjs';
|
|
2
2
|
import 'zod';
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-
|
|
1
|
+
export { Z as Fragment, J as JSX, W as jsx, X as jsxDEV, Y as jsxs } from './jsx-dev-runtime-lYsmphqH.js';
|
|
2
2
|
import 'zod';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gammatech/aijsx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-dev.2024-07-30",
|
|
4
4
|
"description": "Rewrite of aijsx",
|
|
5
5
|
"author": "Jordan Garcia",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"eslint-plugin-prettier": "^4.2.1",
|
|
59
59
|
"eslint-plugin-react": "^7.24.0",
|
|
60
60
|
"eslint-plugin-react-hooks": "^4.2.0",
|
|
61
|
+
"fetch-mock-jest": "^1.5.1",
|
|
61
62
|
"jest": "^29.7.0",
|
|
62
63
|
"prettier": "^2.2.1",
|
|
63
64
|
"tinybench": "^2.5.1",
|