@jxburros/ai-nugget 0.3.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +134 -271
  2. package/UPGRADING.md +158 -0
  3. package/dist/adapters/engines/anthropic.d.ts +7 -1
  4. package/dist/adapters/engines/anthropic.js +64 -37
  5. package/dist/adapters/engines/base.d.ts +29 -2
  6. package/dist/adapters/engines/base.js +52 -8
  7. package/dist/adapters/engines/google.d.ts +17 -1
  8. package/dist/adapters/engines/google.js +93 -29
  9. package/dist/adapters/engines/ollama.d.ts +2 -1
  10. package/dist/adapters/engines/ollama.js +51 -15
  11. package/dist/adapters/engines/openaiChat.d.ts +2 -1
  12. package/dist/adapters/engines/openaiChat.js +60 -30
  13. package/dist/adapters/profiles.d.ts +21 -1
  14. package/dist/adapters/profiles.js +12 -2
  15. package/dist/agent/loop.d.ts +43 -1
  16. package/dist/agent/loop.js +120 -13
  17. package/dist/cjs/adapters/engines/anthropic.js +308 -0
  18. package/dist/cjs/adapters/engines/base.js +147 -0
  19. package/dist/cjs/adapters/engines/google.js +284 -0
  20. package/dist/cjs/adapters/engines/ollama.js +199 -0
  21. package/dist/cjs/adapters/engines/openaiChat.js +261 -0
  22. package/dist/cjs/adapters/index.js +22 -0
  23. package/dist/cjs/adapters/profiles.js +125 -0
  24. package/dist/cjs/agent/index.js +18 -0
  25. package/dist/cjs/agent/loop.js +372 -0
  26. package/dist/cjs/agent/tools.js +51 -0
  27. package/dist/cjs/connect.js +27 -0
  28. package/dist/cjs/errors.js +110 -0
  29. package/dist/cjs/handler.js +561 -0
  30. package/dist/cjs/index.js +27 -0
  31. package/dist/cjs/json.js +121 -0
  32. package/dist/cjs/keys.js +81 -0
  33. package/dist/cjs/package.json +3 -0
  34. package/dist/cjs/policy.js +42 -0
  35. package/dist/cjs/redact.js +78 -0
  36. package/dist/cjs/tokens.js +22 -0
  37. package/dist/cjs/transport.js +172 -0
  38. package/dist/cjs/types.js +6 -0
  39. package/dist/cjs/util.js +112 -0
  40. package/dist/connect.d.ts +31 -0
  41. package/dist/connect.js +25 -0
  42. package/dist/errors.js +25 -1
  43. package/dist/handler.d.ts +61 -1
  44. package/dist/handler.js +247 -61
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.js +1 -0
  47. package/dist/keys.js +1 -4
  48. package/dist/redact.d.ts +18 -0
  49. package/dist/redact.js +29 -1
  50. package/dist/transport.d.ts +3 -1
  51. package/dist/transport.js +21 -1
  52. package/dist/types.d.ts +96 -2
  53. package/dist/util.d.ts +16 -0
  54. package/dist/util.js +50 -0
  55. package/nugget/VERSION.txt +2 -2
  56. package/nugget/dist/adapters/engines/anthropic.d.ts +14 -0
  57. package/nugget/dist/adapters/engines/anthropic.d.ts.map +1 -0
  58. package/nugget/dist/adapters/engines/anthropic.js +305 -0
  59. package/nugget/dist/adapters/engines/anthropic.js.map +1 -0
  60. package/nugget/dist/adapters/engines/base.d.ts +50 -0
  61. package/nugget/dist/adapters/engines/base.d.ts.map +1 -0
  62. package/nugget/dist/adapters/engines/base.js +137 -0
  63. package/nugget/dist/adapters/engines/base.js.map +1 -0
  64. package/nugget/dist/adapters/engines/google.d.ts +24 -0
  65. package/nugget/dist/adapters/engines/google.d.ts.map +1 -0
  66. package/nugget/dist/adapters/engines/google.js +281 -0
  67. package/nugget/dist/adapters/engines/google.js.map +1 -0
  68. package/nugget/dist/adapters/engines/ollama.d.ts +11 -0
  69. package/nugget/dist/adapters/engines/ollama.d.ts.map +1 -0
  70. package/nugget/dist/adapters/engines/ollama.js +196 -0
  71. package/nugget/dist/adapters/engines/ollama.js.map +1 -0
  72. package/nugget/dist/adapters/engines/openaiChat.d.ts +16 -0
  73. package/nugget/dist/adapters/engines/openaiChat.d.ts.map +1 -0
  74. package/nugget/dist/adapters/engines/openaiChat.js +258 -0
  75. package/nugget/dist/adapters/engines/openaiChat.js.map +1 -0
  76. package/nugget/dist/adapters/index.d.ts +5 -0
  77. package/nugget/dist/adapters/index.d.ts.map +1 -0
  78. package/nugget/dist/adapters/index.js +17 -0
  79. package/nugget/dist/adapters/index.js.map +1 -0
  80. package/nugget/dist/adapters/profiles.d.ts +62 -0
  81. package/nugget/dist/adapters/profiles.d.ts.map +1 -0
  82. package/nugget/dist/adapters/profiles.js +121 -0
  83. package/nugget/dist/adapters/profiles.js.map +1 -0
  84. package/nugget/dist/agent/index.d.ts +3 -0
  85. package/nugget/dist/agent/index.d.ts.map +1 -0
  86. package/nugget/dist/agent/index.js +3 -0
  87. package/nugget/dist/agent/index.js.map +1 -0
  88. package/nugget/dist/agent/loop.d.ts +112 -0
  89. package/nugget/dist/agent/loop.d.ts.map +1 -0
  90. package/nugget/dist/agent/loop.js +370 -0
  91. package/nugget/dist/agent/loop.js.map +1 -0
  92. package/nugget/dist/agent/tools.d.ts +29 -0
  93. package/nugget/dist/agent/tools.d.ts.map +1 -0
  94. package/nugget/dist/agent/tools.js +48 -0
  95. package/nugget/dist/agent/tools.js.map +1 -0
  96. package/nugget/dist/cjs/adapters/engines/anthropic.js +308 -0
  97. package/nugget/dist/cjs/adapters/engines/base.js +147 -0
  98. package/nugget/dist/cjs/adapters/engines/google.js +284 -0
  99. package/nugget/dist/cjs/adapters/engines/ollama.js +199 -0
  100. package/nugget/dist/cjs/adapters/engines/openaiChat.js +261 -0
  101. package/nugget/dist/cjs/adapters/index.js +22 -0
  102. package/nugget/dist/cjs/adapters/profiles.js +125 -0
  103. package/nugget/dist/cjs/agent/index.js +18 -0
  104. package/nugget/dist/cjs/agent/loop.js +372 -0
  105. package/nugget/dist/cjs/agent/tools.js +51 -0
  106. package/nugget/dist/cjs/connect.js +27 -0
  107. package/nugget/dist/cjs/errors.js +110 -0
  108. package/nugget/dist/cjs/handler.js +561 -0
  109. package/nugget/dist/cjs/index.js +27 -0
  110. package/nugget/dist/cjs/json.js +121 -0
  111. package/nugget/dist/cjs/keys.js +81 -0
  112. package/nugget/dist/cjs/package.json +3 -0
  113. package/nugget/dist/cjs/policy.js +42 -0
  114. package/nugget/dist/cjs/redact.js +78 -0
  115. package/nugget/dist/cjs/tokens.js +22 -0
  116. package/nugget/dist/cjs/transport.js +172 -0
  117. package/nugget/dist/cjs/types.js +6 -0
  118. package/nugget/dist/cjs/util.js +112 -0
  119. package/nugget/dist/connect.d.ts +31 -0
  120. package/nugget/dist/connect.d.ts.map +1 -0
  121. package/nugget/dist/connect.js +25 -0
  122. package/nugget/dist/connect.js.map +1 -0
  123. package/nugget/dist/errors.d.ts +22 -0
  124. package/nugget/dist/errors.d.ts.map +1 -0
  125. package/nugget/dist/errors.js +104 -0
  126. package/nugget/dist/errors.js.map +1 -0
  127. package/nugget/dist/handler.d.ts +108 -0
  128. package/nugget/dist/handler.d.ts.map +1 -0
  129. package/nugget/dist/handler.js +557 -0
  130. package/nugget/dist/handler.js.map +1 -0
  131. package/nugget/dist/index.d.ts +12 -0
  132. package/nugget/dist/index.d.ts.map +1 -0
  133. package/nugget/dist/index.js +12 -0
  134. package/nugget/dist/index.js.map +1 -0
  135. package/nugget/dist/json.d.ts +7 -0
  136. package/nugget/dist/json.d.ts.map +1 -0
  137. package/nugget/dist/json.js +114 -0
  138. package/nugget/dist/json.js.map +1 -0
  139. package/nugget/dist/keys.d.ts +7 -0
  140. package/nugget/dist/keys.d.ts.map +1 -0
  141. package/nugget/dist/keys.js +75 -0
  142. package/nugget/dist/keys.js.map +1 -0
  143. package/nugget/dist/policy.d.ts +6 -0
  144. package/nugget/dist/policy.d.ts.map +1 -0
  145. package/nugget/dist/policy.js +37 -0
  146. package/nugget/dist/policy.js.map +1 -0
  147. package/nugget/dist/redact.d.ts +26 -0
  148. package/nugget/dist/redact.d.ts.map +1 -0
  149. package/nugget/dist/redact.js +74 -0
  150. package/nugget/dist/redact.js.map +1 -0
  151. package/nugget/dist/tokens.d.ts +5 -0
  152. package/nugget/dist/tokens.d.ts.map +1 -0
  153. package/nugget/dist/tokens.js +18 -0
  154. package/nugget/dist/tokens.js.map +1 -0
  155. package/nugget/dist/transport.d.ts +30 -0
  156. package/nugget/dist/transport.d.ts.map +1 -0
  157. package/nugget/dist/transport.js +165 -0
  158. package/nugget/dist/transport.js.map +1 -0
  159. package/nugget/dist/types.d.ts +285 -0
  160. package/nugget/dist/types.d.ts.map +1 -0
  161. package/nugget/dist/types.js +4 -0
  162. package/nugget/dist/types.js.map +1 -0
  163. package/nugget/dist/util.d.ts +24 -0
  164. package/nugget/dist/util.d.ts.map +1 -0
  165. package/nugget/dist/util.js +101 -0
  166. package/nugget/dist/util.js.map +1 -0
  167. package/nugget/src/adapters/engines/anthropic.ts +62 -37
  168. package/nugget/src/adapters/engines/base.ts +50 -7
  169. package/nugget/src/adapters/engines/google.ts +92 -29
  170. package/nugget/src/adapters/engines/ollama.ts +51 -17
  171. package/nugget/src/adapters/engines/openaiChat.ts +61 -32
  172. package/nugget/src/adapters/profiles.ts +53 -3
  173. package/nugget/src/agent/loop.ts +158 -14
  174. package/nugget/src/connect.ts +48 -0
  175. package/nugget/src/errors.ts +25 -1
  176. package/nugget/src/handler.ts +286 -59
  177. package/nugget/src/index.ts +1 -0
  178. package/nugget/src/keys.ts +1 -5
  179. package/nugget/src/redact.ts +32 -1
  180. package/nugget/src/transport.ts +20 -1
  181. package/nugget/src/types.ts +96 -1
  182. package/nugget/src/util.ts +55 -0
  183. package/package.json +20 -6
@@ -1,3 +1,7 @@
1
+ import type { KnownProvider } from './adapters/profiles.js';
2
+
3
+ export type { KnownProvider };
4
+
1
5
  export type Role = 'system' | 'user' | 'assistant' | 'tool';
2
6
 
3
7
  export interface ContentPart {
@@ -41,15 +45,40 @@ export interface ChatRequest {
41
45
  stopSequences?: string[];
42
46
  signal?: AbortSignal;
43
47
  metadata?: Record<string, unknown>;
48
+ /**
49
+ * Provider-native request fields the nugget does not model as first-class
50
+ * options — an escape hatch so a caller can reach a capability without waiting
51
+ * for a library release. Merged into the outgoing provider request body:
52
+ * shallow at the top level, and one level deep into the provider's own nested
53
+ * option container (Ollama `options`, Google `generationConfig`). Examples:
54
+ * `{ options: { num_ctx: 8192 }, keep_alive: '30m' }` (Ollama),
55
+ * `{ reasoning_effort: 'high' }` (OpenAI), `{ thinking: { type: 'enabled' } }`
56
+ * (Anthropic), `{ safetySettings: [...] }` (Google). Values here win over the
57
+ * nugget's own fields on a key collision, so use with care.
58
+ */
59
+ providerOptions?: Record<string, unknown>;
44
60
  }
45
61
 
46
62
  export interface Connection {
47
63
  id: string;
48
- provider: string;
64
+ /**
65
+ * A provider with a profile in the table, or any other string — an unknown
66
+ * key with a `baseUrl` resolves through the `openai-compat` escape hatch.
67
+ * The union is there for autocomplete and typo-catching; the `string & {}`
68
+ * arm keeps the escape hatch open.
69
+ */
70
+ provider: KnownProvider | (string & {});
49
71
  baseUrl?: string;
50
72
  keyRef?: KeyRef;
51
73
  timeoutMs?: number;
52
74
  headers?: Record<string, string>;
75
+ /**
76
+ * Idle timeout for streaming calls: aborts the stream only if no bytes arrive
77
+ * for this many milliseconds, resetting on every chunk. Distinct from
78
+ * `timeoutMs`, which bounds the total call lifetime. Set this (and a generous
79
+ * `timeoutMs`) for long local generations that stream slowly but healthily.
80
+ */
81
+ idleTimeoutMs?: number;
53
82
  }
54
83
 
55
84
  export type KeyRef =
@@ -95,6 +124,25 @@ export interface ModelSource {
95
124
  baseUrl?: string;
96
125
  }
97
126
 
127
+ export interface EmbedRequest {
128
+ model: string;
129
+ /** One string, or a batch of strings embedded in a single call. */
130
+ input: string | string[];
131
+ signal?: AbortSignal;
132
+ metadata?: Record<string, unknown>;
133
+ /** Provider-native passthrough, same contract as {@link ChatRequest.providerOptions}. */
134
+ providerOptions?: Record<string, unknown>;
135
+ }
136
+
137
+ export interface EmbedResult {
138
+ /** One vector per input, in input order. */
139
+ embeddings: number[][];
140
+ model: string;
141
+ usage: Usage;
142
+ source: ModelSource;
143
+ raw?: unknown;
144
+ }
145
+
98
146
  export function modelRef(source: ModelSource, model: string): string {
99
147
  return `${source.provider}/${model}`;
100
148
  }
@@ -107,6 +155,8 @@ export type AIErrorKind =
107
155
  | 'server'
108
156
  | 'invalid_request'
109
157
  | 'invalid_response'
158
+ /** 404/410 — endpoint, deployment, or model not found (wrong baseUrl/model, or a misrouted edge). */
159
+ | 'not_found'
110
160
  | 'context_length'
111
161
  | 'canceled'
112
162
  | 'policy_blocked'
@@ -117,6 +167,11 @@ export type AIErrorKind =
117
167
  export type StreamEvent =
118
168
  | { type: 'start'; callId: string; provider: string; model: string }
119
169
  | { type: 'delta'; text: string }
170
+ // Reasoning/thinking tokens surfaced as their own channel so callers can show
171
+ // or discard them without them polluting `delta` (the user-facing answer).
172
+ // Emitted from Anthropic `thinking_delta` and OpenAI-compat `reasoning`/
173
+ // `reasoning_content` deltas; providers that don't stream reasoning never emit it.
174
+ | { type: 'reasoning'; text: string }
120
175
  | { type: 'tool_call'; call: ToolCall }
121
176
  | { type: 'context'; kind: string; data: unknown }
122
177
  | { type: 'retry'; attempt: number; reason: AIErrorKind; delayMs: number }
@@ -129,6 +184,7 @@ export interface ProviderAdapter {
129
184
  stream(conn: ResolvedConnection, req: ChatRequest): AsyncIterable<StreamEvent>;
130
185
  listModels?(conn: ResolvedConnection): Promise<ModelInfo[]>;
131
186
  health?(conn: ResolvedConnection): Promise<{ ok: boolean; detail?: string }>;
187
+ embed?(conn: ResolvedConnection, req: EmbedRequest): Promise<EmbedResult>;
132
188
  }
133
189
 
134
190
  export interface ModelInfo {
@@ -156,6 +212,15 @@ export interface CallInfo {
156
212
  provider: string;
157
213
  model: string;
158
214
  metadata?: Record<string, unknown>;
215
+ /**
216
+ * The fully resolved connection for this call — base URL defaulted from the
217
+ * provider profile and auth headers applied. Present whenever `beforeCall`
218
+ * runs after resolution (chat/stream and probes), letting a hook validate the
219
+ * *effective* endpoint (e.g. a request-time SSRF/DNS-rebinding re-check on the
220
+ * resolved `baseUrl`) without duplicating profile logic. The resolved
221
+ * `apiKey` is intentionally not exposed here.
222
+ */
223
+ resolved?: Omit<ResolvedConnection, 'apiKey'>;
159
224
  }
160
225
 
161
226
  export interface CallRecord {
@@ -172,4 +237,34 @@ export interface CallRecord {
172
237
  metadata?: Record<string, unknown>;
173
238
  promptChars: number;
174
239
  responseChars: number;
240
+ /**
241
+ * Estimated cost of this call in USD, computed by the optional `pricing` hook
242
+ * passed to the handler. Undefined when no pricing hook is configured or the
243
+ * hook returns nothing for this provider/model.
244
+ */
245
+ costUsd?: number;
246
+ }
247
+
248
+ /**
249
+ * Minimal [Standard Schema](https://standardschema.dev) validator surface. Any
250
+ * Zod / Valibot / ArkType schema (v1+) satisfies this via its `~standard`
251
+ * property, so `chatParsed` can validate model output against a schema the app
252
+ * already owns — with zero dependency added to this library.
253
+ */
254
+ export interface StandardSchemaV1<Output = unknown> {
255
+ readonly '~standard': {
256
+ readonly version: 1;
257
+ readonly vendor: string;
258
+ readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
259
+ };
260
+ }
261
+
262
+ export type StandardSchemaResult<Output> =
263
+ | { readonly value: Output; readonly issues?: undefined }
264
+ | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }> }> };
265
+
266
+ /** Output of {@link AIHandler.chatParsed}: the validated value plus the raw chat result. */
267
+ export interface ParsedResult<T> {
268
+ data: T;
269
+ result: ChatResult;
175
270
  }
@@ -26,6 +26,61 @@ export function textFromMessages(messages: ChatMessage[]): string {
26
26
  }).join('\n');
27
27
  }
28
28
 
29
+ export function globalEnv(): Record<string, string | undefined> {
30
+ const maybeProcess = globalThis as typeof globalThis & { process?: { env?: Record<string, string | undefined> } };
31
+ return maybeProcess.process?.env ?? {};
32
+ }
33
+
34
+ /**
35
+ * Merges app-supplied {@link ChatRequest.providerOptions} into a provider
36
+ * request body: shallow at the top level, and one level deep for each key in
37
+ * `nestedKeys` where both sides are plain objects (Ollama `options`, Google
38
+ * `generationConfig`). Values in `providerOptions` win on collision.
39
+ */
40
+ export function applyProviderOptions(
41
+ body: Record<string, unknown>,
42
+ providerOptions: Record<string, unknown> | undefined,
43
+ nestedKeys: readonly string[] = [],
44
+ ): Record<string, unknown> {
45
+ if (!providerOptions) return body;
46
+ const merged: Record<string, unknown> = { ...body };
47
+ for (const [key, value] of Object.entries(providerOptions)) {
48
+ const base = asRecord(merged[key]);
49
+ if (nestedKeys.includes(key) && base && asRecord(value)) {
50
+ merged[key] = { ...base, ...(value as Record<string, unknown>) };
51
+ } else {
52
+ merged[key] = value;
53
+ }
54
+ }
55
+ return merged;
56
+ }
57
+
58
+ /** Joins a base URL and path without producing a double slash, even if `base` ends with `/`. */
59
+ export function joinUrl(base: string, path: string): string {
60
+ return `${base.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`;
61
+ }
62
+
63
+ /**
64
+ * Runs `fn` over `items` with at most `limit` in flight at once, preserving
65
+ * input order in the returned array. Used to probe many local models
66
+ * concurrently without opening an unbounded number of sockets.
67
+ */
68
+ export async function mapWithConcurrency<T, R>(items: readonly T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]> {
69
+ const results = new Array<R>(items.length);
70
+ let next = 0;
71
+ const workerCount = Math.max(1, Math.min(limit, items.length));
72
+ const worker = async (): Promise<void> => {
73
+ for (;;) {
74
+ const index = next;
75
+ next += 1;
76
+ if (index >= items.length) return;
77
+ results[index] = await fn(items[index]!, index);
78
+ }
79
+ };
80
+ await Promise.all(Array.from({ length: workerCount }, worker));
81
+ return results;
82
+ }
83
+
29
84
  export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
30
85
  if (ms <= 0) return Promise.resolve();
31
86
  return new Promise((resolve, reject) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxburros/ai-nugget",
3
- "version": "0.3.1",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Small isomorphic AI model nugget for provider calls, policy, redaction, telemetry, and agent loops.",
@@ -17,7 +17,7 @@
17
17
  "telemetry"
18
18
  ],
19
19
  "engines": {
20
- "node": ">=20"
20
+ "node": "^20.19.0 || >=22.12.0"
21
21
  },
22
22
  "main": "./dist/index.js",
23
23
  "types": "./dist/index.d.ts",
@@ -34,36 +34,50 @@
34
34
  ".": {
35
35
  "types": "./dist/index.d.ts",
36
36
  "import": "./dist/index.js",
37
+ "require": "./dist/cjs/index.js",
37
38
  "default": "./dist/index.js"
38
39
  },
39
40
  "./agent": {
40
41
  "types": "./dist/agent/index.d.ts",
41
42
  "import": "./dist/agent/index.js",
43
+ "require": "./dist/cjs/agent/index.js",
42
44
  "default": "./dist/agent/index.js"
43
45
  }
44
46
  },
45
47
  "files": [
46
48
  "dist/**/*.js",
47
49
  "dist/**/*.d.ts",
50
+ "dist/cjs/package.json",
48
51
  "nugget",
49
52
  "README.md",
53
+ "UPGRADING.md",
50
54
  "LICENSE"
51
55
  ],
52
56
  "scripts": {
53
- "build": "tsc -p tsconfig.json",
57
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node scripts/finalize-cjs.mjs",
54
58
  "test": "vitest run",
55
59
  "test:browser": "vitest run --config vitest.browser.config.ts",
56
60
  "test:live": "vitest run tests/live-smoke.test.ts",
61
+ "test:coverage": "vitest run --coverage",
57
62
  "typecheck": "tsc -p tsconfig.json --noEmit",
63
+ "lint": "eslint .",
58
64
  "build:nugget": "node scripts/build-nugget.mjs",
65
+ "demo:steel-chat": "npm run build && node examples/steel-chat/server.mjs",
59
66
  "prepublishOnly": "npm run build && npm run build:nugget"
60
67
  },
61
68
  "devDependencies": {
62
69
  "@types/node": "^22.15.21",
63
- "@vitest/browser": "^4.1.9",
64
- "@vitest/browser-playwright": "^4.1.9",
70
+ "@vitest/browser": "^4.1.10",
71
+ "@vitest/browser-playwright": "^4.1.10",
72
+ "@vitest/coverage-v8": "^4.1.10",
73
+ "eslint": "^9.18.0",
65
74
  "playwright": "^1.61.1",
66
75
  "typescript": "^5.8.3",
67
- "vitest": "^4.1.5"
76
+ "typescript-eslint": "^8.21.0",
77
+ "vitest": "^4.1.10"
78
+ },
79
+ "overrides": {
80
+ "nanoid": "^3.3.17",
81
+ "postcss": "^8.5.23"
68
82
  }
69
83
  }