feat: preliminary chat api

This commit is contained in:
2026-01-30 16:42:50 +01:00
parent 5b6addac9a
commit 221aff0050
8 changed files with 988 additions and 76 deletions

View File

@@ -26,6 +26,7 @@
"author": "Izan Gil <npm@srizan.dev>",
"license": "MIT",
"devDependencies": {
"@types/node": "^25.1.0",
"@typescript-eslint/eslint-plugin": "^8.50.1",
"@typescript-eslint/parser": "^8.50.1",
"eslint": "^9.39.2",

94
packages/sdk/src/chat.ts Normal file
View File

@@ -0,0 +1,94 @@
// most code here has been written by claude opus 4.5
import type { ChatMessage, MessageHandler, SystemMessage, SystemMessageHandler } from './types';
export class ChatClient {
private botToken: string;
private ws: WebSocket | null = null;
private messageHandlers: Set<MessageHandler> = new Set();
private systemMessageHandlers: Set<SystemMessageHandler> = new Set();
private channelName: string | null = null;
constructor(botToken: string) {
this.botToken = botToken;
}
connect(channelName: string): Promise<void> {
if (this.isConnected) {
return Promise.reject(new Error('Already connected. Disconnect first.'));
}
this.channelName = channelName;
const wsUrl = `${process.env.CHAT_WS_URL || 'ws://localhost:3001'}/ws`;
this.ws = new WebSocket(wsUrl);
return new Promise((resolve, reject) => {
this.ws!.onopen = () => {
this.ws!.send(JSON.stringify({ type: 'auth', token: this.botToken, channelName }));
this.emit('system', { type: 'connected', channelName, message: `Connected to ${channelName}`, timestamp: Date.now() });
resolve();
};
this.ws!.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'message' && typeof data.message === 'string') {
this.emit('message', {
id: data.id || `${Date.now()}-${Math.random()}`,
channelName: data.channelName || channelName,
username: data.username || data.user?.username || 'Unknown',
message: data.message,
timestamp: data.timestamp || Date.now(),
type: data.messageType || 'message',
});
}
};
this.ws!.onerror = () => {
this.emit('system', { type: 'error', channelName, message: 'WebSocket error', timestamp: Date.now() });
reject(new Error('WebSocket error'));
};
this.ws!.onclose = () => {
this.emit('system', { type: 'disconnected', channelName, message: 'Disconnected', timestamp: Date.now() });
this.ws = null;
};
});
}
disconnect(): void {
this.ws?.close();
this.ws = null;
this.channelName = null;
}
sendMessage(message: string): void {
if (!this.isConnected) {
throw new Error('Not connected to a channel');
}
this.ws!.send(JSON.stringify({ type: 'message', message, channelName: this.channelName }));
}
onMessage(handler: MessageHandler): () => void {
this.messageHandlers.add(handler);
return () => this.messageHandlers.delete(handler);
}
onSystemMessage(handler: SystemMessageHandler): () => void {
this.systemMessageHandlers.add(handler);
return () => this.systemMessageHandlers.delete(handler);
}
private emit(type: 'message', data: ChatMessage): void;
private emit(type: 'system', data: SystemMessage): void;
private emit(type: 'message' | 'system', data: ChatMessage | SystemMessage): void {
const handlers = type === 'message' ? this.messageHandlers : this.systemMessageHandlers;
handlers.forEach((handler) => handler(data as any));
}
get isConnected(): boolean {
return this.ws?.readyState === WebSocket.OPEN;
}
get currentChannel(): string | null {
return this.channelName;
}
}

View File

@@ -1,21 +1,18 @@
import { ChatClient } from './chat.js';
import type { ChatMessage, MessageHandler } from './types.js';
export class HctvSdk {
private botToken: string
private botToken: string;
public chat: ChatClient;
constructor(args: ConstructorArgs) {
this.botToken = args.botToken
this.botToken = args.botToken;
this.chat = new ChatClient(args.botToken);
}
}
/*
const client = new HctvSdk({ botToken: 'hctvb_asddfasdfasdfasdfasdf' });
await client.chat.connect('channelName');
client.chat.onMessage((message) => {
// message would include data like the channelname etc
console.log('New message:', message);
});
*/
interface ConstructorArgs {
botToken: string;
}
export { ChatClient } from './chat.js';
export type { ChatMessage, MessageHandler } from './types.js';

18
packages/sdk/src/types.ts Normal file
View File

@@ -0,0 +1,18 @@
export interface ChatMessage {
id: string;
channelName: string;
username: string;
message: string;
timestamp: number;
type: 'message' | 'systemMsg';
}
export interface SystemMessage {
type: 'connected' | 'disconnected' | 'error';
channelName: string;
message: string;
timestamp: number;
}
export type MessageHandler = (message: ChatMessage) => void;
export type SystemMessageHandler = (message: SystemMessage) => void;

View File

@@ -0,0 +1,793 @@
// testing completely controlled by claude opus 4.5 because i'm lazy as heck
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { HctvSdk, ChatClient } from '../src/index.js';
import type { ChatMessage, SystemMessage } from '../src/types.js';
class MockWebSocket {
static CONNECTING = 0;
static OPEN = 1;
static CLOSING = 2;
static CLOSED = 3;
readyState = MockWebSocket.CONNECTING;
onopen: (() => void) | null = null;
onmessage: ((event: { data: string }) => void) | null = null;
onerror: ((error: any) => void) | null = null;
onclose: (() => void) | null = null;
sentMessages: string[] = [];
url: string;
constructor(url: string) {
this.url = url;
setTimeout(() => {
this.readyState = MockWebSocket.OPEN;
this.onopen?.();
}, 10);
}
send(data: string) {
this.sentMessages.push(data);
}
close() {
this.readyState = MockWebSocket.CLOSED;
this.onclose?.();
}
simulateMessage(data: any) {
this.onmessage?.({ data: JSON.stringify(data) });
}
simulateError(error: any) {
this.onerror?.(error);
}
}
let mockWebSocketInstance: MockWebSocket | null = null;
vi.stubGlobal('WebSocket', class extends MockWebSocket {
constructor(url: string) {
super(url);
mockWebSocketInstance = this;
}
});
describe('HctvSdk', () => {
beforeEach(() => {
mockWebSocketInstance = null;
});
afterEach(() => {
vi.clearAllMocks();
});
describe('constructor', () => {
it('should initialize with bot token', () => {
const sdk = new HctvSdk({ botToken: 'test-token' });
expect(sdk).toBeDefined();
expect(sdk.chat).toBeInstanceOf(ChatClient);
});
});
});
describe('ChatClient', () => {
let client: ChatClient;
beforeEach(() => {
mockWebSocketInstance = null;
client = new ChatClient('test-bot-token');
});
afterEach(() => {
client.disconnect();
vi.clearAllMocks();
});
describe('constructor', () => {
it('should initialize with bot token', () => {
expect(client).toBeDefined();
expect(client.isConnected).toBe(false);
expect(client.currentChannel).toBeNull();
});
});
describe('connect', () => {
it('should connect to a channel', async () => {
const connectPromise = client.connect('testchannel');
await connectPromise;
expect(client.isConnected).toBe(true);
expect(mockWebSocketInstance).not.toBeNull();
expect(mockWebSocketInstance?.url).toContain('/ws');
});
it('should send auth message on connect', async () => {
await client.connect('testchannel');
expect(mockWebSocketInstance?.sentMessages.length).toBeGreaterThan(0);
const authMsg = JSON.parse(mockWebSocketInstance!.sentMessages[0]);
expect(authMsg.type).toBe('auth');
expect(authMsg.token).toBe('test-bot-token');
expect(authMsg.channelName).toBe('testchannel');
});
it('should throw error when already connected', async () => {
await client.connect('testchannel');
await expect(client.connect('anotherchannel')).rejects.toThrow(
'Already connected to a channel'
);
});
it('should emit connected system message', async () => {
const systemHandler = vi.fn();
client.onSystemMessage(systemHandler);
await client.connect('testchannel');
expect(systemHandler).toHaveBeenCalledWith(
expect.objectContaining({
type: 'connected',
channelName: 'testchannel',
})
);
});
});
describe('disconnect', () => {
it('should disconnect from channel', async () => {
await client.connect('testchannel');
expect(client.isConnected).toBe(true);
client.disconnect();
expect(client.isConnected).toBe(false);
expect(client.currentChannel).toBeNull();
});
it('should emit disconnected system message', async () => {
const systemHandler = vi.fn();
client.onSystemMessage(systemHandler);
await client.connect('testchannel');
client.disconnect();
expect(systemHandler).toHaveBeenCalledWith(
expect.objectContaining({
type: 'disconnected',
})
);
});
});
describe('sendMessage', () => {
it('should send a message when connected', async () => {
await client.connect('testchannel');
client.sendMessage('Hello, world!');
const messages = mockWebSocketInstance!.sentMessages;
const lastMsg = JSON.parse(messages[messages.length - 1]);
expect(lastMsg.type).toBe('message');
expect(lastMsg.message).toBe('Hello, world!');
});
it('should throw error when not connected', () => {
expect(() => client.sendMessage('test')).toThrow('Not connected to a channel');
});
});
describe('onMessage', () => {
it('should call handler when message received', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Hello from server',
user: {
id: 'user-123',
username: 'testuser',
pfpUrl: 'https://example.com/pfp.jpg',
},
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
message: 'Hello from server',
username: 'testuser',
})
);
});
it('should return unsubscribe function', async () => {
const messageHandler = vi.fn();
const unsubscribe = client.onMessage(messageHandler);
await client.connect('testchannel');
unsubscribe();
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Should not receive',
user: { username: 'testuser' },
});
expect(messageHandler).not.toHaveBeenCalled();
});
it('should handle multiple message handlers', async () => {
const handler1 = vi.fn();
const handler2 = vi.fn();
client.onMessage(handler1);
client.onMessage(handler2);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'test message',
user: { username: 'testuser' },
});
expect(handler1).toHaveBeenCalled();
expect(handler2).toHaveBeenCalled();
});
});
describe('onSystemMessage', () => {
it('should call handler for system events', async () => {
const systemHandler = vi.fn();
client.onSystemMessage(systemHandler);
await client.connect('testchannel');
expect(systemHandler).toHaveBeenCalledWith(
expect.objectContaining({
type: 'connected',
})
);
});
it('should return unsubscribe function', async () => {
const systemHandler = vi.fn();
const unsubscribe = client.onSystemMessage(systemHandler);
unsubscribe();
await client.connect('testchannel');
expect(systemHandler).not.toHaveBeenCalled();
});
});
describe('message parsing', () => {
it('should handle message with full user object', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Hello',
user: {
id: 'user-123',
username: 'johndoe',
pfpUrl: 'https://example.com/pfp.jpg',
displayName: 'John Doe',
isBot: false,
},
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
username: 'johndoe',
message: 'Hello',
})
);
});
it('should handle message with username directly', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Direct username',
username: 'directuser',
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
username: 'directuser',
message: 'Direct username',
})
);
});
it('should ignore invalid messages', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
});
expect(messageHandler).not.toHaveBeenCalled();
});
it('should ignore non-message types', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'pong',
});
mockWebSocketInstance?.simulateMessage({
type: 'history',
messages: [],
});
expect(messageHandler).not.toHaveBeenCalled();
});
});
describe('currentChannel', () => {
it('should return null when not connected', () => {
expect(client.currentChannel).toBeNull();
});
it('should return channel name when connected', async () => {
await client.connect('mychannel');
expect(client.currentChannel).toBe('mychannel');
});
it('should return null after disconnect', async () => {
await client.connect('mychannel');
client.disconnect();
expect(client.currentChannel).toBeNull();
});
});
describe('isConnected', () => {
it('should return false initially', () => {
expect(client.isConnected).toBe(false);
});
it('should return true when connected', async () => {
await client.connect('testchannel');
expect(client.isConnected).toBe(true);
});
it('should return false after disconnect', async () => {
await client.connect('testchannel');
client.disconnect();
expect(client.isConnected).toBe(false);
});
});
describe('error handling', () => {
it('should emit error system message on WebSocket error', async () => {
const systemHandler = vi.fn();
client.onSystemMessage(systemHandler);
const connectPromise = client.connect('testchannel');
await new Promise(resolve => setTimeout(resolve, 5));
mockWebSocketInstance?.simulateError(new Error('Connection failed'));
await expect(connectPromise).rejects.toBeDefined();
expect(systemHandler).toHaveBeenCalledWith(
expect.objectContaining({
type: 'error',
})
);
});
it('should handle malformed message data gracefully', async () => {
const messageHandler = vi.fn();
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.onmessage?.({ data: 'not valid json{' });
expect(messageHandler).not.toHaveBeenCalled();
consoleSpy.mockRestore();
});
});
});
describe('ChatMessage type', () => {
it('should have correct structure', () => {
const message: ChatMessage = {
id: 'msg-123',
channelName: 'testchannel',
username: 'testuser',
message: 'Hello, world!',
timestamp: Date.now(),
type: 'message',
};
expect(message.id).toBe('msg-123');
expect(message.channelName).toBe('testchannel');
expect(message.username).toBe('testuser');
expect(message.message).toBe('Hello, world!');
expect(typeof message.timestamp).toBe('number');
expect(message.type).toBe('message');
});
it('should support systemMsg type', () => {
const message: ChatMessage = {
id: 'sys-123',
channelName: 'testchannel',
username: 'system',
message: 'User joined',
timestamp: Date.now(),
type: 'systemMsg',
};
expect(message.type).toBe('systemMsg');
});
});
describe('SystemMessage type', () => {
it('should support connected type', () => {
const message: SystemMessage = {
type: 'connected',
channelName: 'testchannel',
message: 'Connected to testchannel',
timestamp: Date.now(),
};
expect(message.type).toBe('connected');
});
it('should support disconnected type', () => {
const message: SystemMessage = {
type: 'disconnected',
channelName: 'testchannel',
message: 'Disconnected from testchannel',
timestamp: Date.now(),
};
expect(message.type).toBe('disconnected');
});
it('should support error type', () => {
const message: SystemMessage = {
type: 'error',
channelName: 'testchannel',
message: 'An error occurred',
timestamp: Date.now(),
};
expect(message.type).toBe('error');
});
});
describe('Integration with Chat Server Protocol', () => {
let client: ChatClient;
beforeEach(() => {
mockWebSocketInstance = null;
client = new ChatClient('test-bot-token');
});
afterEach(() => {
client.disconnect();
vi.clearAllMocks();
});
describe('history messages', () => {
it('should handle history message from server', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'history',
messages: [
{
user: { id: 'u1', username: 'user1', pfpUrl: '' },
message: 'First message',
type: 'message',
},
{
user: { id: 'u2', username: 'user2', pfpUrl: '' },
message: 'Second message',
type: 'message',
},
],
});
expect(messageHandler).not.toHaveBeenCalled();
});
});
describe('ping/pong', () => {
it('should handle pong response from server', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'pong',
});
expect(messageHandler).not.toHaveBeenCalled();
});
});
describe('emoji responses', () => {
it('should handle emojiMsgResponse from server', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'emojiMsgResponse',
emojis: {
smile: 'https://example.com/emoji/smile.png',
laugh: 'https://example.com/emoji/laugh.png',
},
});
expect(messageHandler).not.toHaveBeenCalled();
});
it('should handle emojiSearchResponse from server', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'emojiSearchResponse',
results: ['smile', 'smirk', 'smiley'],
});
expect(messageHandler).not.toHaveBeenCalled();
});
});
describe('bot user messages', () => {
it('should handle messages from bot users', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Hello from bot!',
user: {
id: 'bot-123',
username: 'mybot',
pfpUrl: 'https://example.com/bot-avatar.png',
displayName: 'My Bot',
isBot: true,
},
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
username: 'mybot',
message: 'Hello from bot!',
})
);
});
});
describe('message structure from server', () => {
it('should handle message structure matching chat server format', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
user: {
id: 'user-abc',
username: 'streamuser',
pfpUrl: 'https://example.com/pfp.jpg',
displayName: 'Stream User',
isBot: false,
},
message: 'Great stream!',
});
expect(messageHandler).not.toHaveBeenCalled();
});
it('should handle message with explicit type', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
user: {
id: 'user-abc',
username: 'streamuser',
pfpUrl: 'https://example.com/pfp.jpg',
},
message: 'Great stream!',
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
username: 'streamuser',
message: 'Great stream!',
})
);
});
});
});
describe('Edge cases', () => {
let client: ChatClient;
beforeEach(() => {
mockWebSocketInstance = null;
client = new ChatClient('test-bot-token');
});
afterEach(() => {
client.disconnect();
vi.clearAllMocks();
});
it('should handle empty message', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: '',
user: { username: 'testuser' },
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
message: '',
})
);
});
it('should handle message with special characters', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
const specialMessage = '🎉 Hello <script>alert("xss")</script> & "quotes" \'apostrophe\'';
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: specialMessage,
user: { username: 'testuser' },
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
message: specialMessage,
})
);
});
it('should handle very long messages', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
const longMessage = 'a'.repeat(10000);
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: longMessage,
user: { username: 'testuser' },
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
message: longMessage,
})
);
});
it('should handle unicode usernames', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Hello',
user: { username: '日本語ユーザー' },
});
expect(messageHandler).toHaveBeenCalledWith(
expect.objectContaining({
username: '日本語ユーザー',
})
);
});
it('should handle rapid successive messages', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
for (let i = 0; i < 100; i++) {
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: `Message ${i}`,
user: { username: 'testuser' },
});
}
expect(messageHandler).toHaveBeenCalledTimes(100);
});
it('should handle errors in message handlers gracefully', async () => {
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const errorHandler = vi.fn(() => {
throw new Error('Handler error');
});
const goodHandler = vi.fn();
client.onMessage(errorHandler);
client.onMessage(goodHandler);
await client.connect('testchannel');
mockWebSocketInstance?.simulateMessage({
type: 'message',
message: 'Test',
user: { username: 'testuser' },
});
expect(goodHandler).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalled();
consoleSpy.mockRestore();
});
it('should handle disconnect while message is being processed', async () => {
const messageHandler = vi.fn();
client.onMessage(messageHandler);
await client.connect('testchannel');
client.disconnect();
expect(() => client.sendMessage('test')).toThrow('Not connected');
});
});

View File

@@ -1,7 +0,0 @@
import { describe, it, expect } from 'vitest'
describe('index', () => {
it('should pass', () => {
expect(1 + 1).toBe(2)
})
})

View File

@@ -49,13 +49,12 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declarationMap": true, /* Create sourcemaps for d.ts files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
"outDir": "./dist", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
@@ -105,5 +104,12 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}

110
pnpm-lock.yaml generated
View File

@@ -56,16 +56,16 @@ importers:
dependencies:
'@astrojs/starlight':
specifier: ^0.35.2
version: 0.35.3(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
version: 0.35.3(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
'@catppuccin/starlight':
specifier: ^1.0.2
version: 1.0.2(@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)))(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
version: 1.0.2(@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)))(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
astro:
specifier: ^5.6.1
version: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
version: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro-mermaid:
specifier: ^1.0.4
version: 1.2.0(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))(mermaid@11.12.2)
version: 1.2.0(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))(mermaid@11.12.2)
mermaid:
specifier: ^11.10.1
version: 11.12.2
@@ -364,6 +364,9 @@ importers:
packages/sdk:
devDependencies:
'@types/node':
specifier: ^25.1.0
version: 25.1.0
'@typescript-eslint/eslint-plugin':
specifier: ^8.50.1
version: 8.51.0(@typescript-eslint/parser@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
@@ -381,7 +384,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^4.0.16
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(jiti@2.6.1)(msw@2.12.7(@types/node@24.10.4)(typescript@5.9.3))(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@25.1.0)(jiti@2.6.1)(msw@2.12.7(@types/node@25.1.0)(typescript@5.9.3))(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
packages:
@@ -3174,6 +3177,9 @@ packages:
'@types/node@24.10.4':
resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==}
'@types/node@25.1.0':
resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==}
'@types/pg-pool@2.0.6':
resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==}
@@ -8125,12 +8131,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@astrojs/mdx@4.3.13(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
'@astrojs/mdx@4.3.13(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
dependencies:
'@astrojs/markdown-remark': 6.3.10
'@mdx-js/mdx': 3.1.1
acorn: 8.15.0
astro: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
es-module-lexer: 1.7.0
estree-util-visit: 2.0.0
hast-util-to-html: 9.0.5
@@ -8154,17 +8160,17 @@ snapshots:
stream-replace-string: 2.0.0
zod: 3.25.76
'@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
'@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
dependencies:
'@astrojs/markdown-remark': 6.3.10
'@astrojs/mdx': 4.3.13(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
'@astrojs/mdx': 4.3.13(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
'@astrojs/sitemap': 3.6.0
'@pagefind/default-ui': 1.4.0
'@types/hast': 3.0.4
'@types/js-yaml': 4.0.9
'@types/mdast': 4.0.4
astro: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro-expressive-code: 0.41.5(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
astro: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro-expressive-code: 0.41.5(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
bcp-47: 2.1.0
hast-util-from-html: 2.0.3
hast-util-select: 6.0.4
@@ -8369,10 +8375,10 @@ snapshots:
dependencies:
fontkit: 2.0.4
'@catppuccin/starlight@1.0.2(@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)))(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
'@catppuccin/starlight@1.0.2(@astrojs/starlight@0.35.3(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)))(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))':
dependencies:
'@astrojs/starlight': 0.35.3(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
astro: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
'@astrojs/starlight': 0.35.3(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))
astro: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
'@chevrotain/cst-dts-gen@11.0.3':
dependencies:
@@ -9026,12 +9032,12 @@ snapshots:
optionalDependencies:
'@types/node': 20.19.27
'@inquirer/confirm@5.1.21(@types/node@24.10.4)':
'@inquirer/confirm@5.1.21(@types/node@25.1.0)':
dependencies:
'@inquirer/core': 10.3.2(@types/node@24.10.4)
'@inquirer/type': 3.0.10(@types/node@24.10.4)
'@inquirer/core': 10.3.2(@types/node@25.1.0)
'@inquirer/type': 3.0.10(@types/node@25.1.0)
optionalDependencies:
'@types/node': 24.10.4
'@types/node': 25.1.0
optional: true
'@inquirer/core@10.3.2(@types/node@20.19.27)':
@@ -9047,18 +9053,18 @@ snapshots:
optionalDependencies:
'@types/node': 20.19.27
'@inquirer/core@10.3.2(@types/node@24.10.4)':
'@inquirer/core@10.3.2(@types/node@25.1.0)':
dependencies:
'@inquirer/ansi': 1.0.2
'@inquirer/figures': 1.0.15
'@inquirer/type': 3.0.10(@types/node@24.10.4)
'@inquirer/type': 3.0.10(@types/node@25.1.0)
cli-width: 4.1.0
mute-stream: 2.0.0
signal-exit: 4.1.0
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
optionalDependencies:
'@types/node': 24.10.4
'@types/node': 25.1.0
optional: true
'@inquirer/figures@1.0.15': {}
@@ -9067,9 +9073,9 @@ snapshots:
optionalDependencies:
'@types/node': 20.19.27
'@inquirer/type@3.0.10(@types/node@24.10.4)':
'@inquirer/type@3.0.10(@types/node@25.1.0)':
optionalDependencies:
'@types/node': 24.10.4
'@types/node': 25.1.0
optional: true
'@internationalized/date@3.10.1':
@@ -11273,6 +11279,10 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@types/node@25.1.0':
dependencies:
undici-types: 7.16.0
'@types/pg-pool@2.0.6':
dependencies:
'@types/pg': 8.15.6
@@ -11578,14 +11588,14 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.16(msw@2.12.7(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))':
'@vitest/mocker@4.0.16(msw@2.12.7(@types/node@25.1.0)(typescript@5.9.3))(vite@7.3.0(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))':
dependencies:
'@vitest/spy': 4.0.16
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
msw: 2.12.7(@types/node@24.10.4)(typescript@5.9.3)
vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
msw: 2.12.7(@types/node@25.1.0)(typescript@5.9.3)
vite: 7.3.0(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
'@vitest/pretty-format@4.0.16':
dependencies:
@@ -11961,21 +11971,21 @@ snapshots:
astring@1.9.0: {}
astro-expressive-code@0.41.5(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)):
astro-expressive-code@0.41.5(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)):
dependencies:
astro: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
rehype-expressive-code: 0.41.5
astro-mermaid@1.2.0(astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))(mermaid@11.12.2):
astro-mermaid@1.2.0(astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0))(mermaid@11.12.2):
dependencies:
'@anthropic-ai/claude-code': 1.0.128
astro: 5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
astro: 5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0)
import-meta-resolve: 4.2.0
mdast-util-to-string: 4.0.0
mermaid: 11.12.2
unist-util-visit: 5.0.0
astro@5.16.6(@types/node@24.10.4)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0):
astro@5.16.6(@types/node@25.1.0)(ioredis@5.8.2)(jiti@2.6.1)(rollup@4.54.0)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))(yaml@2.8.0):
dependencies:
'@astrojs/compiler': 2.13.0
'@astrojs/internal-helpers': 0.7.5
@@ -12032,8 +12042,8 @@ snapshots:
unist-util-visit: 5.0.0
unstorage: 1.17.3(ioredis@5.8.2)(uploadthing@7.7.4(express@5.2.1)(h3@1.15.4)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.0)))
vfile: 6.0.3
vite: 6.4.1(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
vitefu: 1.1.1(vite@6.4.1(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))
vite: 6.4.1(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
vitefu: 1.1.1(vite@6.4.1(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))
xxhash-wasm: 1.1.0
yargs-parser: 21.1.1
yocto-spinner: 0.2.3
@@ -13074,7 +13084,7 @@ snapshots:
'@typescript-eslint/parser': 8.51.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1)
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
@@ -13094,7 +13104,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1):
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.3
@@ -13109,14 +13119,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.51.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1)
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
@@ -13131,7 +13141,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.51.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -15060,9 +15070,9 @@ snapshots:
transitivePeerDependencies:
- '@types/node'
msw@2.12.7(@types/node@24.10.4)(typescript@5.9.3):
msw@2.12.7(@types/node@25.1.0)(typescript@5.9.3):
dependencies:
'@inquirer/confirm': 5.1.21(@types/node@24.10.4)
'@inquirer/confirm': 5.1.21(@types/node@25.1.0)
'@mswjs/interceptors': 0.40.0
'@open-draft/deferred-promise': 2.2.0
'@types/statuses': 2.0.6
@@ -16973,7 +16983,7 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
vite@6.4.1(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
vite@6.4.1(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
@@ -16982,14 +16992,14 @@ snapshots:
rollup: 4.54.0
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.4
'@types/node': 25.1.0
fsevents: 2.3.3
jiti: 2.6.1
terser: 5.44.1
tsx: 4.21.0
yaml: 2.8.0
vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
vite@7.3.0(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
dependencies:
esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -16998,21 +17008,21 @@ snapshots:
rollup: 4.54.0
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.4
'@types/node': 25.1.0
fsevents: 2.3.3
jiti: 2.6.1
terser: 5.44.1
tsx: 4.21.0
yaml: 2.8.0
vitefu@1.1.1(vite@6.4.1(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)):
vitefu@1.1.1(vite@6.4.1(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)):
optionalDependencies:
vite: 6.4.1(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
vite: 6.4.1(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(jiti@2.6.1)(msw@2.12.7(@types/node@24.10.4)(typescript@5.9.3))(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@25.1.0)(jiti@2.6.1)(msw@2.12.7(@types/node@25.1.0)(typescript@5.9.3))(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0):
dependencies:
'@vitest/expect': 4.0.16
'@vitest/mocker': 4.0.16(msw@2.12.7(@types/node@24.10.4)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))
'@vitest/mocker': 4.0.16(msw@2.12.7(@types/node@25.1.0)(typescript@5.9.3))(vite@7.3.0(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0))
'@vitest/pretty-format': 4.0.16
'@vitest/runner': 4.0.16
'@vitest/snapshot': 4.0.16
@@ -17029,11 +17039,11 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
vite: 7.3.0(@types/node@25.1.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@types/node': 24.10.4
'@types/node': 25.1.0
transitivePeerDependencies:
- jiti
- less