diff --git a/js/examples/browser/README.md b/js/examples/browser/README.md index a575c10..5a339e4 100644 --- a/js/examples/browser/README.md +++ b/js/examples/browser/README.md @@ -1,6 +1,6 @@ # IDKit Browser Example -A simple browser example demonstrating World ID verification using IDKit 4.0. +A simple browser example demonstrating World ID verification using the IDKit core package. ## Usage @@ -20,12 +20,12 @@ cd js/examples/browser pnpm dev ``` -Open http://localhost:5173 in your browser (Vite will auto-open it) +Open http://localhost:4000 in your browser (Vite will auto-open it) #### Production -The example already uses the `@worldcoin/idkit` import. In production, install the package: +The example uses `@worldcoin/idkit-core` for pure TypeScript/browser usage. In production: ```bash -npm install @worldcoin/idkit +npm install @worldcoin/idkit-core ``` diff --git a/js/examples/browser/index.html b/js/examples/browser/index.html index 2749c63..b545891 100644 --- a/js/examples/browser/index.html +++ b/js/examples/browser/index.html @@ -37,10 +37,10 @@

Error

diff --git a/js/examples/browser/package.json b/js/examples/browser/package.json index 9fa0cdb..288652f 100644 --- a/js/examples/browser/package.json +++ b/js/examples/browser/package.json @@ -7,6 +7,9 @@ "build": "vite build", "preview": "vite preview" }, + "dependencies": { + "@worldcoin/idkit-core": "workspace:*" + }, "devDependencies": { "vite": "^7.0.0" } diff --git a/js/examples/browser/vite.config.js b/js/examples/browser/vite.config.js index 1f2fbfa..3bd8e28 100644 --- a/js/examples/browser/vite.config.js +++ b/js/examples/browser/vite.config.js @@ -1,13 +1,6 @@ import { defineConfig } from 'vite'; -import { resolve } from 'path'; export default defineConfig({ - resolve: { - alias: { - // Resolve to the locally-built core package output in this monorepo. - '@worldcoin/idkit': resolve(__dirname, '../../packages/core/dist/index.js'), - }, - }, server: { port: 4000, open: true, diff --git a/js/packages/core/README.md b/js/packages/core/README.md index a0eefe4..51eb4a3 100644 --- a/js/packages/core/README.md +++ b/js/packages/core/README.md @@ -13,20 +13,18 @@ pnpm add @worldcoin/idkit ## Quick Start ```typescript -import { - useWorldBridgeStore, - VerificationLevel, -} from '@worldcoin/idkit' +import { useWorldBridgeStore } from '@worldcoin/idkit' // 1. Get store instance const store = useWorldBridgeStore() -// 2. Create client - returns immutable client object +// 2. Create client with explicit requests const client = await store.createClient({ app_id: 'app_staging_xxxxx', action: 'my-action', - verification_level: VerificationLevel.Orb, - signal: 'user-id-123', + requests: [ + { credential_type: 'orb', signal: 'user-id-123' }, + ], }) // 3. Display QR code for World App @@ -41,38 +39,60 @@ try { } ``` -## V2 API +## Multiple Credential Types -```typescript -const store = useWorldBridgeStore() +You can request verification with multiple credential types. The user can satisfy the request with any of them: -await store.createClient({ +```typescript +const client = await store.createClient({ app_id: 'app_staging_xxxxx', action: 'my-action', - verification_level: VerificationLevel.Orb, - signal: 'user-id-123', + requests: [ + { credential_type: 'orb', signal: 'user-id-123' }, + { credential_type: 'device', signal: 'user-id-123' }, + ], }) +``` -console.log('Scan this:', store.connectorURI) - -await store.pollForUpdates() +## Credential Types -if (store.result) { - console.log('Proof received:', store.result) -} -``` +- `orb` - Verified via Orb biometric scan (highest trust) +- `face` - Verified via Face ID +- `device` - Verified via device binding +- `document` - Verified via document scan +- `secure_document` - Verified via secure document scan ## API Reference +### Creating a Client + ```typescript const client = await store.createClient(config) ``` -**Properties:** +**Config:** +```typescript +interface IDKitConfig { + app_id: `app_${string}` // Your World ID app ID + action: string // Action identifier + requests: RequestConfig[] // Required: credential type requests + bridge_url?: string // Custom bridge URL (optional) + partner?: boolean // Partner mode (optional) +} + +interface RequestConfig { + credential_type: CredentialType + signal?: string | AbiEncodedValue // Optional signal for this request +} + +type CredentialType = 'orb' | 'face' | 'device' | 'document' | 'secure_document' +``` + +**Client Properties:** - `connectorURI: string` - QR code URL for World App - `requestId: string` - Unique request ID -**Methods:** +**Client Methods:** - `pollForUpdates(options?: WaitOptions): Promise` - Poll for proof (auto-polls) - `pollOnce(): Promise` - Poll once for status (manual polling) @@ -91,44 +111,24 @@ interface WaitOptions { const store = useWorldBridgeStore() ``` -**V3 Methods:** +**Methods:** - `createClient(config: IDKitConfig): Promise` - Create new client +- `reset(): void` - Clear state and start over -**V2 State (backward compat):** +**State (for reactive frameworks):** - `verificationState: VerificationState` - Current verification state - `connectorURI: string | null` - QR code URL for World App - `result: ISuccessResult | null` - Proof data when verified - `errorCode: AppErrorCodes | null` - Error code if failed -**V2 Methods (deprecated):** -- `pollForUpdates(): Promise` - Check for proof (call repeatedly) ⚠️ Use `client.pollForUpdates()` with auto-polling instead -- `reset(): void` - Clear state and start over - -### Types +### Result Types ```typescript -interface IDKitConfig { - app_id: `app_${string}` - action: string - signal?: string - verification_level?: VerificationLevel - bridge_url?: string - partner?: boolean -} - interface ISuccessResult { proof: string merkle_root: string nullifier_hash: string - verification_level: VerificationLevel -} - -enum VerificationLevel { - Orb = 'orb', - Face = 'face', - Device = 'device', - Document = 'document', - SecureDocument = 'secure_document', + verification_level: CredentialType // The credential type used } ``` @@ -142,6 +142,31 @@ hashToField(input: string): HashFunctionOutput solidityEncode(types: string[], values: unknown[]): AbiEncodedValue ``` +## React Integration + +```tsx +import { useWorldBridgeStore, IDKitWidget } from '@worldcoin/idkit' + +function MyComponent() { + const handleSuccess = (result) => { + console.log('Verified:', result) + } + + return ( + + {({ open }) => } + + ) +} +``` + ## Examples See [examples/browser](../../examples/browser) for a complete working example. diff --git a/js/packages/core/package.json b/js/packages/core/package.json index ef148b7..37f6c80 100644 --- a/js/packages/core/package.json +++ b/js/packages/core/package.json @@ -1,7 +1,7 @@ { - "name": "@worldcoin/idkit", + "name": "@worldcoin/idkit-core", "version": "4.0.1", - "description": "Core IDKit SDK for World ID - Browser and Node.js support", + "description": "Core IDKit SDK for World ID - Pure TypeScript, no dependencies", "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -11,11 +11,6 @@ "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.cjs" - }, - "./react": { - "types": "./dist/react.d.ts", - "import": "./dist/react.js", - "require": "./dist/react.cjs" } }, "files": [ @@ -46,23 +41,10 @@ "type": "git", "url": "https://github.com/worldcoin/idkit" }, - "dependencies": { - "zustand": "^4.5" - }, - "peerDependencies": { - "react": ">=17.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - }, "devDependencies": { "@types/node": "^20.0.0", - "@types/react": "^18.2.0", "@vitest/coverage-v8": "^2.0.0", "happy-dom": "^15.0.0", - "react": "^18.2.0", "tsup": "^8.0.0", "typescript": "^5.3.0", "vitest": "^2.0.0" diff --git a/js/packages/core/src/__tests__/smoke.test.ts b/js/packages/core/src/__tests__/smoke.test.ts index 0e27e6f..95fb08d 100644 --- a/js/packages/core/src/__tests__/smoke.test.ts +++ b/js/packages/core/src/__tests__/smoke.test.ts @@ -3,18 +3,16 @@ * These tests verify that the WASM integration and core APIs are functional */ -import { describe, it, expect, beforeAll } from 'vitest' +import { describe, it, expect } from 'vitest' import { initIDKit, isInitialized, - useWorldBridgeStore, + createSession, hashToField, solidityEncode, buffer_encode, buffer_decode, isNode, - isWeb, - VerificationLevel, AppErrorCodes, VerificationState, } from '../index' @@ -125,64 +123,23 @@ describe('Platform Detection', () => { }) }) -describe('Bridge Store', () => { - it('should create store instance', () => { - const store = useWorldBridgeStore.getState() - expect(store).toBeDefined() - expect(store.verificationState).toBe(VerificationState.PreparingClient) +describe('Session API', () => { + it('should export createSession function', () => { + expect(typeof createSession).toBe('function') }) - it('should have correct initial state', () => { - const store = useWorldBridgeStore.getState() - - expect(store.requestId).toBeNull() - expect(store.connectorURI).toBeNull() - expect(store.result).toBeNull() - expect(store.errorCode).toBeNull() - }) - - it('should have all required methods', () => { - const store = useWorldBridgeStore.getState() - - expect(typeof store.createClient).toBe('function') - expect(typeof store.pollForUpdates).toBe('function') - expect(typeof store.reset).toBe('function') - }) - - it('should reset state', () => { - const store = useWorldBridgeStore.getState() - store.reset() - - expect(store.verificationState).toBe(VerificationState.PreparingClient) - expect(store.requestId).toBeNull() - expect(store.connectorURI).toBeNull() - expect(store.result).toBeNull() - expect(store.errorCode).toBeNull() - }) - - it('should be callable both ways for v2 compatibility', () => { - // v3 style - const store1 = useWorldBridgeStore.getState() - expect(store1).toBeDefined() - - // v2 style also works (returns same state outside React) - const store2 = useWorldBridgeStore() as ReturnType - expect(store2).toBeDefined() - - // Should be the same store - expect(store1).toBe(store2) + it('should throw error when requests is empty', async () => { + await expect( + createSession({ + app_id: 'app_staging_test', + action: 'test-action', + requests: [], + }) + ).rejects.toThrow('At least one request is required') }) }) describe('Enums', () => { - it('should export VerificationLevel enum', () => { - expect(VerificationLevel.Orb).toBe('orb') - expect(VerificationLevel.Face).toBe('face') - expect(VerificationLevel.Device).toBe('device') - expect(VerificationLevel.SecureDocument).toBe('secure_document') - expect(VerificationLevel.Document).toBe('document') - }) - it('should export AppErrorCodes enum', () => { expect(AppErrorCodes.ConnectionFailed).toBe('connection_failed') expect(AppErrorCodes.VerificationRejected).toBe('verification_rejected') diff --git a/js/packages/core/src/bridge.ts b/js/packages/core/src/bridge.ts deleted file mode 100644 index 12b5291..0000000 --- a/js/packages/core/src/bridge.ts +++ /dev/null @@ -1,194 +0,0 @@ -/** - * IDKit Bridge Client - * Handles communication with the World ID bridge using WASM for cryptography - */ - -import { create, type StateCreator } from 'zustand' -import type { IDKitConfig, VerificationLevel } from './types/config' -import type { ISuccessResult } from './types/result' -import { VerificationState, AppErrorCodes, ResponseStatus } from './types/bridge' -import { validate_bridge_url } from './lib/validation' -import { encodeAction, generateSignal } from './lib/hashing' -import { - DEFAULT_VERIFICATION_LEVEL, - credential_type_to_verification_level, - verification_level_to_credential_types, -} from './lib/utils' -import { WasmModule, initIDKit } from './lib/wasm' -import { WorldBridgeClient } from './client' - -const DEFAULT_BRIDGE_URL = 'https://bridge.worldcoin.org' - -type BridgeResponse = - | { - status: ResponseStatus.Retrieved | ResponseStatus.Initialized - response: null - } - | { - status: ResponseStatus.Completed - response: { iv: string; payload: string } - } - -type BridgeResult = - | ISuccessResult - | (Omit & { credential_type: VerificationLevel }) - | { error_code: AppErrorCodes } - -export type WorldBridgeStore = { - bridge_url: string - encryption: typeof WasmModule.BridgeEncryption.prototype | null - requestId: string | null - connectorURI: string | null - result: ISuccessResult | null - errorCode: AppErrorCodes | null - verificationState: VerificationState - - createClient: (config: IDKitConfig) => Promise - - /** @deprecated V2 API - requires manual polling. Use client.pollForUpdates() for automatic polling instead */ - pollForUpdates: () => Promise - - reset: () => void -} - -const createStoreImplementation: StateCreator = (set, get) => ({ - encryption: null, - result: null, - errorCode: null, - requestId: null, - connectorURI: null, - bridge_url: DEFAULT_BRIDGE_URL, - verificationState: VerificationState.PreparingClient, - - createClient: async ({ bridge_url, app_id, verification_level, action, signal, requests, constraints, action_description }) => { - // Ensure WASM is initialized - await initIDKit() - - // Validate bridge URL - if (bridge_url) { - const validation = validate_bridge_url(bridge_url, app_id.includes('staging')) - if (!validation.valid) { - console.error(validation.errors.join('\n')) - set({ verificationState: VerificationState.Failed }) - throw new Error('Invalid bridge_url. Please check the console for more details.') - } - } - - let session: WasmModule.Session - - if (requests && requests.length > 0) { - if (verification_level) { - console.warn('`verification_level` is ignored when `requests` are provided. Use one or the other.') - } - const reqs = (requests as any[]).map((req) => ({ - credential_type: req.credential_type ?? req.credentialType ?? req.credential, - signal: typeof req.signal === 'string' ? req.signal : undefined, - signal_bytes: req.signal_bytes ?? req.signalBytes, - face_auth: req.face_auth ?? req.faceAuth, - })) - - const constraintsPayload = constraints ? constraints : undefined - - session = (await WasmModule.Session.createWithRequests( - app_id, - encodeAction(action), - reqs, - constraintsPayload ?? undefined, - action_description ?? null, - bridge_url ?? null - )) as unknown as WasmModule.Session - } else { - // Create WASM Session from verification level - session = (await new WasmModule.Session( - app_id, - encodeAction(action), - verification_level ?? DEFAULT_VERIFICATION_LEVEL, - signal ? generateSignal(signal).digest : null - )) as WasmModule.Session - } - - const client = new WorldBridgeClient(session) - - // Update store state for v2 compat - set({ - requestId: client.requestId, - connectorURI: client.connectorURI, - bridge_url: bridge_url ?? DEFAULT_BRIDGE_URL, - verificationState: VerificationState.WaitingForConnection, - encryption: null, - result: null, - errorCode: null, - }) - - // Store client reference for pollForUpdates - ;(get() as any)._activeClient = client - - return client - }, - - pollForUpdates: async () => { - // Use client if available - const client = (get() as any)._activeClient as WorldBridgeClient | undefined - - if (!client) { - throw new Error('No active client. Please call createClient() first.') - } - - const status = await client.pollOnce() - - if (status.type === 'awaiting_confirmation') { - set({ verificationState: VerificationState.WaitingForApp }) - } else if (status.type === 'confirmed' && status.proof) { - set({ - result: status.proof, - verificationState: VerificationState.Confirmed, - requestId: null, - connectorURI: null, - }) - ;(get() as any)._activeClient = undefined - } else if (status.type === 'failed') { - set({ - errorCode: status.error ?? AppErrorCodes.UnexpectedResponse, - verificationState: VerificationState.Failed, - }) - ;(get() as any)._activeClient = undefined - } - }, - - reset: () => { - set({ - encryption: null, - result: null, - errorCode: null, - requestId: null, - connectorURI: null, - verificationState: VerificationState.PreparingClient, - }) - ;(get() as any)._activeClient = undefined - }, -}) - -/** - * Single instance of the store (vanilla) - */ -const store = create(createStoreImplementation) - -/** - * Hook-compatible export that also works as direct function call for v2 compatibility - * - * Usage: - * - React: const state = useWorldBridgeStore() or useWorldBridgeStore(selector) - * - Vanilla: const store = useWorldBridgeStore.getState() - * - v2: const store = useWorldBridgeStore() (works outside React) - */ -export const useWorldBridgeStore = Object.assign( - // Make it callable directly for v2 compatibility (returns state when called outside React) - (...args: unknown[]) => (args.length === 0 ? store.getState() : store(...(args as [any]))), - // Also expose all store methods - store -) - -/** - * Factory function to create a new instance of the store - */ -export const createWorldBridgeStore = () => create(createStoreImplementation) diff --git a/js/packages/core/src/client.ts b/js/packages/core/src/client.ts deleted file mode 100644 index a638a91..0000000 --- a/js/packages/core/src/client.ts +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Immutable World ID verification client - * - * Provides a clean, promise-based API for World ID verification flows. - * Each client represents a single verification session. - * - * @example - * ```typescript - * const store = useWorldBridgeStore() - * const client = await store.createClient({ - * app_id: 'app_staging_xxxxx', - * action: 'my-action', - * verification_level: VerificationLevel.Orb, - * signal: 'user-id-123', - * }) - * - * // Display QR code - * console.log('Scan this:', client.connectorURI) - * - * // Wait for proof - * try { - * const proof = await client.waitForProof() - * console.log('Success:', proof) - * } catch (error) { - * console.error('Failed:', error) - * } - * ``` - */ - -import type { WasmModule } from './lib/wasm' -import type { ISuccessResult } from './types/result' -import { AppErrorCodes } from './types/bridge' - -/** Options for pollForUpdates() */ -export interface WaitOptions { - /** Milliseconds between polls (default: 1000) */ - pollInterval?: number - /** Total timeout in milliseconds (default: 300000 = 5 minutes) */ - timeout?: number - /** AbortSignal for cancellation */ - signal?: AbortSignal -} - -/** Status returned from pollOnce() */ -export interface Status { - type: 'waiting_for_connection' | 'awaiting_confirmation' | 'confirmed' | 'failed' - proof?: ISuccessResult - error?: AppErrorCodes -} - -/** - * Immutable client for World ID verification - * - * This class wraps the WASM Session and provides a clean TypeScript API. - * Clients are immutable - all properties are read-only. - */ -export class WorldBridgeClient { - private session: InstanceType - private _connectorURI: string - private _requestId: string - - /** - * @internal - * Creates a new client (called by store.createClient()) - */ - constructor(session: InstanceType) { - this.session = session - this._connectorURI = session.connectUrl() - this._requestId = session.requestId() - } - - /** - * QR code URL for World App - * - * Display this URL as a QR code for users to scan with World App. - * - * @example - * ```typescript - * console.log('Scan this QR code:', client.connectorURI) - * // or with QR code library: - * QRCode.toCanvas(canvas, client.connectorURI) - * ``` - */ - get connectorURI(): string { - return this._connectorURI - } - - /** - * Unique request ID for this verification - */ - get requestId(): string { - return this._requestId - } - - /** - * Poll for proof from World App (handles polling automatically) - * - * This method polls the bridge until the user completes the verification - * or an error occurs. It handles all the polling logic internally. - * - * @param options - Optional configuration for polling and timeout - * @returns Promise that resolves with the proof when verification succeeds - * @throws {Error} On timeout, cancellation, or verification failure - * - * @example - * ```typescript - * // Basic usage - * const proof = await client.pollForUpdates() - * - * // With custom options - * const proof = await client.pollForUpdates({ - * pollInterval: 500, // Poll every 500ms - * timeout: 120000, // 2 minute timeout - * }) - * - * // With cancellation - * const controller = new AbortController() - * setTimeout(() => controller.abort(), 10000) // Cancel after 10s - * - * try { - * const proof = await client.pollForUpdates({ - * signal: controller.signal - * }) - * } catch (error) { - * if (error.message.includes('cancelled')) { - * console.log('User cancelled') - * } - * } - * ``` - */ - async pollForUpdates(options?: WaitOptions): Promise { - const pollInterval = options?.pollInterval ?? 1000 - const timeout = options?.timeout ?? 300000 // 5 minutes default - const startTime = Date.now() - - while (true) { - // Check for cancellation - if (options?.signal?.aborted) { - throw new Error('Verification cancelled') - } - - // Check timeout - if (Date.now() - startTime > timeout) { - throw new Error(`Timeout waiting for proof after ${timeout}ms`) - } - - // Poll status - const status = await this.pollOnce() - - if (status.type === 'confirmed' && status.proof) { - return status.proof - } - - if (status.type === 'failed') { - const errorCode = status.error ?? AppErrorCodes.GenericError - throw new Error(`Verification failed: ${errorCode}`) - } - - // Wait before next poll - await new Promise(resolve => setTimeout(resolve, pollInterval)) - } - } - - /** - * Poll once for current status (for manual polling) - * - * Use this if you want to implement your own polling logic instead of - * using pollForUpdates(). - * - * @returns Current status of the verification - * - * @example - * ```typescript - * // Manual polling loop - * while (true) { - * const status = await client.pollOnce() - * - * if (status.type === 'awaiting_confirmation') { - * console.log('Waiting for user...') - * } else if (status.type === 'confirmed') { - * console.log('Success!', status.proof) - * break - * } else if (status.type === 'failed') { - * console.error('Failed:', status.error) - * break - * } - * - * await new Promise(resolve => setTimeout(resolve, 1000)) - * } - * ``` - */ - async pollOnce(): Promise { - return (await this.session.pollForStatus()) as Status - } -} diff --git a/js/packages/core/src/index.ts b/js/packages/core/src/index.ts index 40d7085..fb44c4c 100644 --- a/js/packages/core/src/index.ts +++ b/js/packages/core/src/index.ts @@ -1,26 +1,24 @@ /** - * @worldcoin/idkit + * @worldcoin/idkit-core * Core bridge logic for IDKit powered by Rust/WASM + * Pure TypeScript - no dependencies */ -export { WorldBridgeClient, type WaitOptions, type Status } from './client' -export { useWorldBridgeStore, createWorldBridgeStore, type WorldBridgeStore } from './bridge' +// Session API (main entry point) +export { createSession, type Session, type SessionOptions, type Status, type WaitOptions } from './session' // Types -export type { IDKitConfig, AbiEncodedValue } from './types/config' +export type { IDKitConfig, AbiEncodedValue, RequestConfig, CredentialType } from './types/config' export type { ISuccessResult, IErrorState } from './types/result' -export { VerificationLevel } from './types/config' -export type { CredentialType } from './types/config' export { AppErrorCodes, VerificationState, ResponseStatus } from './types/bridge' // Backend verification export { verifyCloudProof, type IVerifyResponse } from './lib/backend' // Utilities -export { DEFAULT_VERIFICATION_LEVEL, buffer_encode, buffer_decode } from './lib/utils' +export { buffer_encode, buffer_decode } from './lib/utils' export { solidityEncode, hashToField, generateSignal, encodeAction } from './lib/hashing' -export { initIDKit, isInitialized } from './lib/wasm' export { isReactNative, isWeb, isNode } from './lib/platform' // WASM exports -export { WasmModule } from './lib/wasm' +export { initIDKit, isInitialized, WasmModule } from './lib/wasm' diff --git a/js/packages/core/src/lib/hashing.ts b/js/packages/core/src/lib/hashing.ts index 2c7b391..a857d1c 100644 --- a/js/packages/core/src/lib/hashing.ts +++ b/js/packages/core/src/lib/hashing.ts @@ -242,17 +242,17 @@ export const solidityEncode = (types: string[], values: unknown[]): AbiEncodedVa } /** - * Generates a signal hash from IDKitConfig signal + * Generates a signal hash from a signal value * Handles both string signals and ABI-encoded signals - * @param signal Signal from IDKitConfig + * @param signal Signal string or ABI-encoded value * @returns Hash output */ -export const generateSignal = (signal: IDKitConfig['signal']): HashFunctionOutput => { +export const generateSignal = (signal: AbiEncodedValue | string | undefined): HashFunctionOutput => { if (!signal || typeof signal === 'string') { return hashToField(signal ?? '') } - return packAndEncode(signal.types.map((type, index) => [type, signal.values[index]])) + return packAndEncode(signal.types.map((type: string, index: number) => [type, signal.values[index]])) } /** diff --git a/js/packages/core/src/lib/utils.ts b/js/packages/core/src/lib/utils.ts index 7bf74a0..6f61e94 100644 --- a/js/packages/core/src/lib/utils.ts +++ b/js/packages/core/src/lib/utils.ts @@ -1,44 +1,5 @@ -import { VerificationLevel } from '../types/config' import { WasmModule } from './wasm' -export const DEFAULT_VERIFICATION_LEVEL = VerificationLevel.Orb - -/** - * Converts verification level to accepted credential types for proof request - * @param verification_level - * @returns Array of credential types - */ -export const verification_level_to_credential_types = (verification_level: VerificationLevel): string[] => { - switch (verification_level) { - case VerificationLevel.Device: - // Intentionally exclude document and secure document for backwards compatibility with older app versions - return [VerificationLevel.Orb, VerificationLevel.Device] - case VerificationLevel.Document: - return [VerificationLevel.Document, VerificationLevel.SecureDocument, VerificationLevel.Orb] - case VerificationLevel.SecureDocument: - return [VerificationLevel.SecureDocument, VerificationLevel.Orb] - case VerificationLevel.Orb: - return [VerificationLevel.Orb] - case VerificationLevel.Face: - return [VerificationLevel.Face, VerificationLevel.Orb] - default: - throw new Error(`Unknown verification level: ${verification_level}`) - } -} - -/** - * Converts credential type string to verification level upon proof response - * @param credential_type - * @returns VerificationLevel - */ -export const credential_type_to_verification_level = (credential_type: VerificationLevel | string): VerificationLevel => { - if (!Object.values(VerificationLevel).includes(credential_type as VerificationLevel)) { - throw new Error(`Unknown credential_type: ${credential_type}`) - } - - return credential_type as VerificationLevel -} - /** * Encodes an ArrayBuffer to base64 string * @param buffer - ArrayBuffer to encode diff --git a/js/packages/core/src/react/IDKitWidget.tsx b/js/packages/core/src/react/IDKitWidget.tsx deleted file mode 100644 index ff856ff..0000000 --- a/js/packages/core/src/react/IDKitWidget.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react' -import { useWorldBridgeStore, type WorldBridgeStore, VerificationState, AppErrorCodes } from '../' -import type { WidgetProps, WidgetStatus } from './types' - -const STATUS_MAP: Record = { - [VerificationState.PreparingClient]: 'preparing', - [VerificationState.WaitingForConnection]: 'waiting', - [VerificationState.WaitingForApp]: 'waiting_for_app', - [VerificationState.Confirmed]: 'success', - [VerificationState.Failed]: 'error', -} - -const PollInterval = 2500 - -export const IDKitWidget: React.FC = ({ - children, - show_modal = true, - onSuccess, - handleVerify, - onError, - autoClose = true, - ...config -}) => { - const { connectorURI, verificationState, createClient, pollForUpdates, result, errorCode, reset } = useWorldBridgeStore() as WorldBridgeStore - const [open, setOpen] = useState(false) - const [localError, setLocalError] = useState(null) - - const status: WidgetStatus = useMemo(() => STATUS_MAP[verificationState] ?? 'idle', [verificationState]) - - // Start session when opened - useEffect(() => { - if (!open) return - let cancelled = false - ;(async () => { - try { - await createClient(config) - } catch (err) { - if (cancelled) return - setLocalError(AppErrorCodes.UnexpectedResponse) - } - })() - return () => { - cancelled = true - } - }, [open, createClient, config]) - - // Poll while waiting - useEffect(() => { - if (!open) return - if (verificationState === VerificationState.PreparingClient) return - if (verificationState === VerificationState.Confirmed || verificationState === VerificationState.Failed) return - - const id = setInterval(() => { - void pollForUpdates() - }, PollInterval) - return () => clearInterval(id) - }, [open, verificationState, pollForUpdates]) - - // Handle result - useEffect(() => { - if (!result) return - let cancelled = false - ;(async () => { - try { - if (handleVerify) await handleVerify(result) - await onSuccess(result) - if (autoClose && !cancelled) { - setOpen(false) - reset() - } - } catch (err) { - if (cancelled) return - const message = (err as Error)?.message - onError?.({ code: AppErrorCodes.FailedByHostApp, message }) - setLocalError(AppErrorCodes.FailedByHostApp) - } - })() - return () => { - cancelled = true - } - }, [result, handleVerify, onSuccess, autoClose, reset, onError]) - - // Handle errors from bridge - useEffect(() => { - if (!errorCode) return - onError?.({ code: errorCode }) - setLocalError(errorCode) - }, [errorCode, onError]) - - const trigger = children?.({ - open: () => { - reset() - setOpen(true) - }, - status, - }) - - const body = ( -
{ - setOpen(false) - reset() - }} - > -
e.stopPropagation()} - > -

Verify with World ID

- {status === 'preparing' &&

Preparing session…

} - {status === 'waiting' && ( -
-

Scan the QR code with World App to continue.

- {connectorURI ? ( - World ID QR - ) : ( -

Generating connection link…

- )} - {connectorURI && ( -

- {connectorURI} -

- )} -
- )} - {status === 'waiting_for_app' &&

Waiting for confirmation in World App…

} - {status === 'success' &&

Success! You can close this window.

} - {status === 'error' && ( -

Something went wrong {localError ? `(${localError})` : ''}

- )} - -
-
- ) - - return ( - <> - {trigger ?? ( - - )} - {show_modal && open && body} - - ) -} diff --git a/js/packages/core/src/react/index.ts b/js/packages/core/src/react/index.ts deleted file mode 100644 index c8b5393..0000000 --- a/js/packages/core/src/react/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @worldcoin/idkit/react - * React components and hooks for IDKit - */ - -export { IDKitWidget } from './IDKitWidget' -export type { WidgetProps, WidgetConfig, WidgetStatus } from './types' - -// Re-export commonly used types from core for convenience -export { VerificationLevel } from '../types/config' -export type { ISuccessResult, IErrorState } from '../types/result' -export type { CredentialType } from '../types/config' diff --git a/js/packages/core/src/react/types.ts b/js/packages/core/src/react/types.ts deleted file mode 100644 index 5214be6..0000000 --- a/js/packages/core/src/react/types.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IDKitConfig, ISuccessResult, IErrorState } from '../' - -export type WidgetConfig = Pick & { - /** Called when a proof is received and optionally validated by handleVerify */ - onSuccess: (result: ISuccessResult) => void | Promise - /** Called after proof is received but before success is shown; throw to surface an error to the user */ - handleVerify?: (result: ISuccessResult) => void | Promise - /** Called when the session errors or handleVerify rejects */ - onError?: (error: IErrorState) => void - /** Auto-close overlay on success (default true) */ - autoClose?: boolean -} - -export type WidgetProps = WidgetConfig & { - children?: (helpers: { open: () => void; status: WidgetStatus }) => JSX.Element - show_modal?: boolean -} - -export type WidgetStatus = 'idle' | 'preparing' | 'waiting' | 'waiting_for_app' | 'success' | 'error' diff --git a/js/packages/core/src/session.ts b/js/packages/core/src/session.ts new file mode 100644 index 0000000..287b4ec --- /dev/null +++ b/js/packages/core/src/session.ts @@ -0,0 +1,183 @@ +/** + * IDKit Session + * Pure functional API for World ID verification - no dependencies + */ + +import type { IDKitConfig } from './types/config' +import type { ISuccessResult } from './types/result' +import { AppErrorCodes } from './types/bridge' +import { validate_bridge_url } from './lib/validation' +import { encodeAction } from './lib/hashing' +import { WasmModule, initIDKit } from './lib/wasm' + +/** Options for pollForUpdates() */ +export interface WaitOptions { + /** Milliseconds between polls (default: 1000) */ + pollInterval?: number + /** Total timeout in milliseconds (default: 300000 = 5 minutes) */ + timeout?: number + /** AbortSignal for cancellation */ + signal?: AbortSignal +} + +/** Status returned from pollOnce() */ +export interface Status { + type: 'waiting_for_connection' | 'awaiting_confirmation' | 'confirmed' | 'failed' + proof?: ISuccessResult + error?: AppErrorCodes +} + +/** Session configuration - same as IDKitConfig */ +export type SessionOptions = IDKitConfig + +/** + * A World ID verification session + * + * Provides a clean, promise-based API for World ID verification flows. + * Each session represents a single verification attempt. + */ +export interface Session { + /** QR code URL for World App - display this as a QR code for users to scan */ + readonly connectorURI: string + /** Unique request ID for this verification */ + readonly requestId: string + /** Poll once for current status (for manual polling) */ + pollOnce(): Promise + /** Poll continuously until completion or timeout */ + pollForUpdates(options?: WaitOptions): Promise +} + +/** + * Internal session implementation + */ +class SessionImpl implements Session { + private wasmSession: WasmModule.Session + private _connectorURI: string + private _requestId: string + + constructor(wasmSession: WasmModule.Session) { + this.wasmSession = wasmSession + this._connectorURI = wasmSession.connectUrl() + this._requestId = wasmSession.requestId() + } + + get connectorURI(): string { + return this._connectorURI + } + + get requestId(): string { + return this._requestId + } + + async pollOnce(): Promise { + return (await this.wasmSession.pollForStatus()) as Status + } + + async pollForUpdates(options?: WaitOptions): Promise { + const pollInterval = options?.pollInterval ?? 1000 + const timeout = options?.timeout ?? 300000 // 5 minutes default + const startTime = Date.now() + + while (true) { + // Check for cancellation + if (options?.signal?.aborted) { + throw new Error('Verification cancelled') + } + + // Check timeout + if (Date.now() - startTime > timeout) { + throw new Error(`Timeout waiting for proof after ${timeout}ms`) + } + + // Poll status + const status = await this.pollOnce() + + if (status.type === 'confirmed' && status.proof) { + return status.proof + } + + if (status.type === 'failed') { + const errorCode = status.error ?? AppErrorCodes.GenericError + throw new Error(`Verification failed: ${errorCode}`) + } + + // Wait before next poll + await new Promise((resolve) => setTimeout(resolve, pollInterval)) + } + } +} + +/** + * Creates a new World ID verification session + * + * This is a pure function with no global state. Each call creates an independent session. + * + * @param config - Session configuration + * @returns A new Session instance + * + * @example + * ```typescript + * import { createSession, initIDKit } from '@worldcoin/idkit-core' + * + * // Initialize WASM (only needed once) + * await initIDKit() + * + * // Create a verification session + * const session = await createSession({ + * app_id: 'app_staging_xxxxx', + * action: 'my-action', + * requests: [ + * { credential_type: 'orb', signal: 'user-id-123' }, + * ], + * }) + * + * // Display QR code + * console.log('Scan this:', session.connectorURI) + * + * // Wait for proof + * try { + * const proof = await session.pollForUpdates() + * console.log('Success:', proof) + * } catch (error) { + * console.error('Failed:', error) + * } + * ``` + */ +export async function createSession(config: SessionOptions): Promise { + // Ensure WASM is initialized + await initIDKit() + + // Validate requests + if (!config.requests || config.requests.length === 0) { + throw new Error('At least one request is required') + } + + // Validate bridge URL if provided + if (config.bridge_url) { + const validation = validate_bridge_url(config.bridge_url, config.app_id.includes('staging')) + if (!validation.valid) { + console.error(validation.errors.join('\n')) + throw new Error('Invalid bridge_url. Please check the console for more details.') + } + } + + // Map requests to WASM format + const reqs = config.requests.map((req) => ({ + credential_type: req.credential_type, + signal: typeof req.signal === 'string' ? req.signal : undefined, + signal_bytes: req.signal_bytes, + face_auth: req.face_auth, + })) + + // Create WASM session + const wasmSession = (await WasmModule.Session.createWithRequests( + config.app_id, + encodeAction(config.action), + reqs, + config.constraints ?? undefined, + config.action_description ?? null, + config.bridge_url ?? null + )) as unknown as WasmModule.Session + + return new SessionImpl(wasmSession) +} diff --git a/js/packages/core/src/types/config.ts b/js/packages/core/src/types/config.ts index 89b9141..2b737c5 100644 --- a/js/packages/core/src/types/config.ts +++ b/js/packages/core/src/types/config.ts @@ -5,12 +5,18 @@ export type AbiEncodedValue = Brand<{ types: string[]; values: unknown[] }, 'Abi export type CredentialType = 'orb' | 'face' | 'secure_document' | 'document' | 'device' -export enum VerificationLevel { - Orb = 'orb', - Face = 'face', - SecureDocument = 'secure_document', - Document = 'document', - Device = 'device', +/** + * A single credential request + */ +export type RequestConfig = { + /** The type of credential being requested */ + credential_type: CredentialType + /** Optional signal string for cryptographic binding */ + signal?: AbiEncodedValue | string + /** Optional ABI-encoded signal bytes (for on-chain use cases) */ + signal_bytes?: Uint8Array + /** Whether face authentication is required (only valid for orb and face credentials) */ + face_auth?: boolean } export type IDKitConfig = { @@ -20,21 +26,10 @@ export type IDKitConfig = { action: AbiEncodedValue | string /** The description of the specific action (shown to users in World App). Only recommended for actions created on-the-fly. */ action_description?: string - /** Encodes data into a proof that must match when validating. Read more on the [On-chain section](https://docs.world.org/advanced/on-chain). */ - signal?: AbiEncodedValue | string /** URL to a third-party bridge to use when connecting to the World App. Optional. */ bridge_url?: string - /** The minimum required level of verification. Defaults to "orb". */ - verification_level?: VerificationLevel - /** Optional explicit requests (takes precedence over verification_level) */ - requests?: Array<{ - credential_type: CredentialType - signal?: AbiEncodedValue | string - signal_bytes?: Uint8Array - face_auth?: boolean - }> + /** Credential requests - at least one required */ + requests: RequestConfig[] /** Optional constraints JSON (matches Rust Constraints any/all structure) */ constraints?: unknown - /** Whether the app is a partner app and should allow deferred verification. Defaults to false. */ - partner?: boolean } diff --git a/js/packages/core/src/types/result.ts b/js/packages/core/src/types/result.ts index 7bf9d6f..864e418 100644 --- a/js/packages/core/src/types/result.ts +++ b/js/packages/core/src/types/result.ts @@ -1,11 +1,12 @@ import type { AppErrorCodes } from './bridge' -import type { VerificationLevel } from './config' +import type { CredentialType } from './config' export interface ISuccessResult { proof: string merkle_root: string nullifier_hash: string - verification_level: VerificationLevel + /** The credential type used to generate the proof */ + verification_level: CredentialType } export interface IErrorState { diff --git a/js/packages/core/tsup.config.ts b/js/packages/core/tsup.config.ts index 23154c4..3ee9b2a 100644 --- a/js/packages/core/tsup.config.ts +++ b/js/packages/core/tsup.config.ts @@ -1,30 +1,26 @@ -import { defineConfig } from 'tsup'; -import { copyFileSync, existsSync } from 'fs'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; +import { defineConfig } from 'tsup' +import { copyFileSync, existsSync } from 'fs' +import { resolve, dirname } from 'path' +import { fileURLToPath } from 'url' -const __dirname = dirname(fileURLToPath(import.meta.url)); +const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ - entry: { - index: 'src/index.ts', - react: 'src/react/index.ts', - }, - format: ['esm', 'cjs'], - dts: true, - splitting: false, - sourcemap: true, - clean: true, - treeshake: true, - external: ['react'], - outDir: 'dist', - onSuccess: async () => { - // Copy WASM file to dist folder so it can be resolved via import.meta.url - const wasmSrc = resolve(__dirname, 'wasm/idkit_wasm_bg.wasm'); - const wasmDst = resolve(__dirname, 'dist/idkit_wasm_bg.wasm'); - if (existsSync(wasmSrc)) { - copyFileSync(wasmSrc, wasmDst); - console.log('Copied idkit_wasm_bg.wasm to dist/'); - } - }, -}); + entry: ['src/index.ts'], + format: ['esm', 'cjs'], + dts: true, + splitting: false, + sourcemap: true, + clean: true, + treeshake: true, + outDir: 'dist', + onSuccess: async () => { + // Copy WASM file to dist folder so it can be resolved via import.meta.url + const wasmSrc = resolve(__dirname, 'wasm/idkit_wasm_bg.wasm') + const wasmDst = resolve(__dirname, 'dist/idkit_wasm_bg.wasm') + if (existsSync(wasmSrc)) { + copyFileSync(wasmSrc, wasmDst) + console.log('Copied idkit_wasm_bg.wasm to dist/') + } + }, +}) diff --git a/kotlin/README.md b/kotlin/README.md index eba45e2..7be0dcc 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -26,4 +26,3 @@ Set `SKIP_ANDROID=1` to skip Android builds (useful on local Macs without Docker - `IdKit.request(...)` / `requestAbi(...)` – build requests with optional faceAuth - `IdKit.anyOf(...)` / `allOf(...)` – quick constraints - `IdKit.session(...)` – create sessions with optional description/constraints/bridge URL -- `IdKit.sessionFromVerificationLevel(...)` – verification-level shortcut diff --git a/kotlin/bindings/src/main/kotlin/com/worldcoin/idkit/IdKit.kt b/kotlin/bindings/src/main/kotlin/com/worldcoin/idkit/IdKit.kt index 96227e9..2be7df8 100644 --- a/kotlin/bindings/src/main/kotlin/com/worldcoin/idkit/IdKit.kt +++ b/kotlin/bindings/src/main/kotlin/com/worldcoin/idkit/IdKit.kt @@ -6,11 +6,10 @@ import uniffi.idkit.Request import uniffi.idkit.Session import uniffi.idkit.Signal import uniffi.idkit_core.CredentialType -import uniffi.idkit_core.VerificationLevel /** * Lightweight Kotlin conveniences mirroring the Swift helpers and adding - * simple factories for common flows (multiple requests, verification level). + * simple factories for common flows. * * These wrap the UniFFI-generated types but keep everything in Kotlin land. */ @@ -69,15 +68,4 @@ object IdKit { ) else -> Session.create(appId, action, requests) } - - /** - * Convenience to map a verification level into the appropriate requests/constraints. - * Equivalent to the Swift `fromVerificationLevel` convenience. - */ - fun sessionFromVerificationLevel( - appId: String, - action: String, - verificationLevel: VerificationLevel, - signal: String = "", - ): Session = Session.fromVerificationLevel(appId, action, verificationLevel, signal) } diff --git a/package.json b/package.json index f9ae780..fc8aa93 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "private": true, "description": "IDKit - World ID SDK with Rust Core", "scripts": { - "build": "pnpm --filter @worldcoin/idkit build", - "test": "pnpm --filter @worldcoin/idkit test", - "type-check": "pnpm --filter @worldcoin/idkit type-check", + "build": "pnpm -r build", + "test": "pnpm -r test", + "type-check": "pnpm -r type-check", "lint:rust": "cargo fmt --all -- --check && cargo clippy --all-targets --all-features -- -D warnings" }, "keywords": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5e1b33..e36c2bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,41 +9,35 @@ importers: .: {} js/examples/browser: + dependencies: + '@worldcoin/idkit-core': + specifier: workspace:* + version: link:../../packages/core devDependencies: vite: specifier: ^7.0.0 - version: 7.3.1(@types/node@20.19.24) + version: 7.3.1(@types/node@20.19.30) js/packages/core: - dependencies: - zustand: - specifier: ^4.5 - version: 4.5.7(@types/react@18.3.27)(react@18.3.1) devDependencies: '@types/node': specifier: ^20.0.0 - version: 20.19.24 - '@types/react': - specifier: ^18.2.0 - version: 18.3.27 + version: 20.19.30 '@vitest/coverage-v8': specifier: ^2.0.0 - version: 2.1.9(vitest@2.1.9(@types/node@20.19.24)(happy-dom@15.11.7)) + version: 2.1.9(vitest@2.1.9(@types/node@20.19.30)(happy-dom@15.11.7)) happy-dom: specifier: ^15.0.0 version: 15.11.7 - react: - specifier: ^18.2.0 - version: 18.3.1 tsup: specifier: ^8.0.0 - version: 8.5.0(postcss@8.5.6)(typescript@5.9.3) + version: 8.5.1(postcss@8.5.6)(typescript@5.9.3) typescript: specifier: ^5.3.0 version: 5.9.3 vitest: specifier: ^2.0.0 - version: 2.1.9(@types/node@20.19.24)(happy-dom@15.11.7) + version: 2.1.9(@types/node@20.19.30)(happy-dom@15.11.7) packages: @@ -59,13 +53,13 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -77,12 +71,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} @@ -95,12 +83,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.2': resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} @@ -113,12 +95,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.2': resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} @@ -131,12 +107,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.2': resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} @@ -149,12 +119,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.2': resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} @@ -167,12 +131,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.2': resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} @@ -185,12 +143,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.2': resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} @@ -203,12 +155,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} @@ -221,12 +167,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.2': resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} @@ -239,12 +179,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.2': resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} @@ -257,12 +191,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.2': resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} @@ -275,12 +203,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.2': resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} @@ -293,12 +215,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.2': resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} @@ -311,12 +227,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.2': resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} @@ -329,12 +239,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.2': resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} @@ -347,12 +251,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.2': resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} @@ -365,24 +263,12 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.2': resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.2': resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} @@ -395,24 +281,12 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.2': resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} @@ -425,24 +299,12 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.2': resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} @@ -455,12 +317,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.2': resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} @@ -473,12 +329,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.2': resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} @@ -491,12 +341,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.2': resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} @@ -509,12 +353,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.2': resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} @@ -546,127 +384,136 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.52.5': - resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.5': - resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.5': - resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.5': - resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.5': - resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.5': - resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': - resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.5': - resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.5': - resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.5': - resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.5': - resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.5': - resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.5': - resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.5': - resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.5': - resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.5': - resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.5': - resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.5': - resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.5': - resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.5': - resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.5': - resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.5': - resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} cpu: [x64] os: [win32] '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/node@20.19.24': - resolution: {integrity: sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/react@18.3.27': - resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + '@types/node@20.19.30': + resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} '@vitest/coverage-v8@2.1.9': resolution: {integrity: sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==} @@ -754,8 +601,8 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} chokidar@4.0.3: @@ -784,9 +631,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -821,11 +665,6 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -834,8 +673,8 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} fdir@6.5.0: @@ -859,8 +698,8 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true happy-dom@15.11.7: @@ -904,9 +743,6 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -918,13 +754,6 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -1024,14 +853,6 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -1040,8 +861,8 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - rollup@4.52.5: - resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1069,10 +890,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1096,8 +916,8 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true @@ -1138,9 +958,6 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -1148,8 +965,8 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tsup@8.5.0: - resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -1172,17 +989,12 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1284,9 +1096,6 @@ packages: jsdom: optional: true - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -1295,9 +1104,6 @@ packages: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1316,21 +1122,6 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - zustand@4.5.7: - resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} - engines: {node: '>=12.7.0'} - peerDependencies: - '@types/react': '>=16.8' - immer: '>=9.0.6' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - snapshots: '@ampproject/remapping@2.3.0': @@ -1342,11 +1133,11 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.5': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.6 - '@babel/types@7.28.5': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -1356,225 +1147,147 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/aix-ppc64@0.27.2': optional: true '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm64@0.27.2': optional: true '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - '@esbuild/android-arm@0.27.2': optional: true '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.25.12': - optional: true - '@esbuild/android-x64@0.27.2': optional: true '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.25.12': - optional: true - '@esbuild/darwin-arm64@0.27.2': optional: true '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.25.12': - optional: true - '@esbuild/darwin-x64@0.27.2': optional: true '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.25.12': - optional: true - '@esbuild/freebsd-arm64@0.27.2': optional: true '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.25.12': - optional: true - '@esbuild/freebsd-x64@0.27.2': optional: true '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.25.12': - optional: true - '@esbuild/linux-arm64@0.27.2': optional: true '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.25.12': - optional: true - '@esbuild/linux-arm@0.27.2': optional: true '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.25.12': - optional: true - '@esbuild/linux-ia32@0.27.2': optional: true '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.25.12': - optional: true - '@esbuild/linux-loong64@0.27.2': optional: true '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.25.12': - optional: true - '@esbuild/linux-mips64el@0.27.2': optional: true '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.25.12': - optional: true - '@esbuild/linux-ppc64@0.27.2': optional: true '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.25.12': - optional: true - '@esbuild/linux-riscv64@0.27.2': optional: true '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.25.12': - optional: true - '@esbuild/linux-s390x@0.27.2': optional: true '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.25.12': - optional: true - '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.12': - optional: true - '@esbuild/netbsd-arm64@0.27.2': optional: true '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.25.12': - optional: true - '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.12': - optional: true - '@esbuild/openbsd-arm64@0.27.2': optional: true '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.25.12': - optional: true - '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.2': optional: true '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/sunos-x64@0.27.2': optional: true '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.27.2': optional: true '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-ia32@0.27.2': optional: true '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@esbuild/win32-x64@0.27.2': optional: true @@ -1606,86 +1319,88 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.52.5': + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true - '@rollup/rollup-android-arm64@4.52.5': + '@rollup/rollup-android-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-arm64@4.52.5': + '@rollup/rollup-darwin-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-x64@4.52.5': + '@rollup/rollup-darwin-x64@4.55.1': optional: true - '@rollup/rollup-freebsd-arm64@4.52.5': + '@rollup/rollup-freebsd-arm64@4.55.1': optional: true - '@rollup/rollup-freebsd-x64@4.52.5': + '@rollup/rollup-freebsd-x64@4.55.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.5': + '@rollup/rollup-linux-arm-musleabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.5': + '@rollup/rollup-linux-arm64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.5': + '@rollup/rollup-linux-arm64-musl@4.55.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.5': + '@rollup/rollup-linux-loong64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.5': + '@rollup/rollup-linux-loong64-musl@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.5': + '@rollup/rollup-linux-ppc64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.5': + '@rollup/rollup-linux-ppc64-musl@4.55.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.5': + '@rollup/rollup-linux-riscv64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.5': + '@rollup/rollup-linux-riscv64-musl@4.55.1': optional: true - '@rollup/rollup-linux-x64-musl@4.52.5': + '@rollup/rollup-linux-s390x-gnu@4.55.1': optional: true - '@rollup/rollup-openharmony-arm64@4.52.5': + '@rollup/rollup-linux-x64-gnu@4.55.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.5': + '@rollup/rollup-linux-x64-musl@4.55.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.5': + '@rollup/rollup-openbsd-x64@4.55.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.5': + '@rollup/rollup-openharmony-arm64@4.55.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.5': + '@rollup/rollup-win32-arm64-msvc@4.55.1': optional: true - '@types/estree@1.0.8': {} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true - '@types/node@20.19.24': - dependencies: - undici-types: 6.21.0 + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true - '@types/prop-types@15.7.15': {} + '@rollup/rollup-win32-x64-msvc@4.55.1': + optional: true + + '@types/estree@1.0.8': {} - '@types/react@18.3.27': + '@types/node@20.19.30': dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.2.3 + undici-types: 6.21.0 - '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.19.24)(happy-dom@15.11.7))': + '@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.19.30)(happy-dom@15.11.7))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -1699,7 +1414,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.9(@types/node@20.19.24)(happy-dom@15.11.7) + vitest: 2.1.9(@types/node@20.19.30)(happy-dom@15.11.7) transitivePeerDependencies: - supports-color @@ -1710,13 +1425,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.19.24))': + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.19.30))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 5.4.21(@types/node@20.19.24) + vite: 5.4.21(@types/node@20.19.30) '@vitest/pretty-format@2.1.9': dependencies: @@ -1765,9 +1480,9 @@ snapshots: dependencies: balanced-match: 1.0.2 - bundle-require@5.1.0(esbuild@0.25.12): + bundle-require@5.1.0(esbuild@0.27.2): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.2 load-tsconfig: 0.2.5 cac@6.7.14: {} @@ -1775,12 +1490,12 @@ snapshots: chai@5.3.3: dependencies: assertion-error: 2.0.1 - check-error: 2.1.1 + check-error: 2.1.3 deep-eql: 5.0.2 loupe: 3.2.1 pathval: 2.0.1 - check-error@2.1.1: {} + check-error@2.1.3: {} chokidar@4.0.3: dependencies: @@ -1804,8 +1519,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - csstype@3.2.3: {} - debug@4.4.3: dependencies: ms: 2.1.3 @@ -1848,35 +1561,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -1910,7 +1594,7 @@ snapshots: dependencies: '@types/estree': 1.0.8 - expect-type@1.2.2: {} + expect-type@1.3.0: {} fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -1920,7 +1604,7 @@ snapshots: dependencies: magic-string: 0.30.21 mlly: 1.8.0 - rollup: 4.52.5 + rollup: 4.55.1 foreground-child@3.3.1: dependencies: @@ -1930,7 +1614,7 @@ snapshots: fsevents@2.3.3: optional: true - glob@10.4.5: + glob@10.5.0: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 @@ -1982,20 +1666,12 @@ snapshots: joycon@3.1.1: {} - js-tokens@4.0.0: {} - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} load-tsconfig@0.2.5: {} - lodash.sortby@4.7.0: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - loupe@3.2.1: {} lru-cache@10.4.3: {} @@ -2006,8 +1682,8 @@ snapshots: magicast@0.3.5: dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 source-map-js: 1.2.1 make-dir@4.0.0: @@ -2025,7 +1701,7 @@ snapshots: acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 + ufo: 1.6.3 ms@2.1.3: {} @@ -2078,42 +1754,39 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - punycode@2.3.1: {} - - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - readdirp@4.1.2: {} resolve-from@5.0.0: {} - rollup@4.52.5: + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.5 - '@rollup/rollup-android-arm64': 4.52.5 - '@rollup/rollup-darwin-arm64': 4.52.5 - '@rollup/rollup-darwin-x64': 4.52.5 - '@rollup/rollup-freebsd-arm64': 4.52.5 - '@rollup/rollup-freebsd-x64': 4.52.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 - '@rollup/rollup-linux-arm-musleabihf': 4.52.5 - '@rollup/rollup-linux-arm64-gnu': 4.52.5 - '@rollup/rollup-linux-arm64-musl': 4.52.5 - '@rollup/rollup-linux-loong64-gnu': 4.52.5 - '@rollup/rollup-linux-ppc64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-gnu': 4.52.5 - '@rollup/rollup-linux-riscv64-musl': 4.52.5 - '@rollup/rollup-linux-s390x-gnu': 4.52.5 - '@rollup/rollup-linux-x64-gnu': 4.52.5 - '@rollup/rollup-linux-x64-musl': 4.52.5 - '@rollup/rollup-openharmony-arm64': 4.52.5 - '@rollup/rollup-win32-arm64-msvc': 4.52.5 - '@rollup/rollup-win32-ia32-msvc': 4.52.5 - '@rollup/rollup-win32-x64-gnu': 4.52.5 - '@rollup/rollup-win32-x64-msvc': 4.52.5 + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 semver@7.7.3: {} @@ -2130,9 +1803,7 @@ snapshots: source-map-js@1.2.1: {} - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 + source-map@0.7.6: {} stackback@0.0.2: {} @@ -2158,14 +1829,14 @@ snapshots: dependencies: ansi-regex: 6.2.2 - sucrase@3.35.0: + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 - glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 + tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 supports-color@7.2.0: @@ -2175,7 +1846,7 @@ snapshots: test-exclude@7.0.1: dependencies: '@istanbuljs/schema': 0.1.3 - glob: 10.4.5 + glob: 10.5.0 minimatch: 9.0.5 thenify-all@1.6.0: @@ -2201,30 +1872,26 @@ snapshots: tinyspy@3.0.2: {} - tr46@1.0.1: - dependencies: - punycode: 2.3.1 - tree-kill@1.2.2: {} ts-interface-checker@0.1.13: {} - tsup@8.5.0(postcss@8.5.6)(typescript@5.9.3): + tsup@8.5.1(postcss@8.5.6)(typescript@5.9.3): dependencies: - bundle-require: 5.1.0(esbuild@0.25.12) + bundle-require: 5.1.0(esbuild@0.27.2) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.3 - esbuild: 0.25.12 + esbuild: 0.27.2 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 postcss-load-config: 6.0.1(postcss@8.5.6) resolve-from: 5.0.0 - rollup: 4.52.5 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 + rollup: 4.55.1 + source-map: 0.7.6 + sucrase: 3.35.1 tinyexec: 0.3.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 @@ -2239,21 +1906,17 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.1: {} + ufo@1.6.3: {} undici-types@6.21.0: {} - use-sync-external-store@1.6.0(react@18.3.1): - dependencies: - react: 18.3.1 - - vite-node@2.1.9(@types/node@20.19.24): + vite-node@2.1.9(@types/node@20.19.30): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 1.1.2 - vite: 5.4.21(@types/node@20.19.24) + vite: 5.4.21(@types/node@20.19.30) transitivePeerDependencies: - '@types/node' - less @@ -2265,31 +1928,31 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@20.19.24): + vite@5.4.21(@types/node@20.19.30): dependencies: esbuild: 0.21.5 postcss: 8.5.6 - rollup: 4.52.5 + rollup: 4.55.1 optionalDependencies: - '@types/node': 20.19.24 + '@types/node': 20.19.30 fsevents: 2.3.3 - vite@7.3.1(@types/node@20.19.24): + vite@7.3.1(@types/node@20.19.30): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.5 + rollup: 4.55.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 20.19.24 + '@types/node': 20.19.30 fsevents: 2.3.3 - vitest@2.1.9(@types/node@20.19.24)(happy-dom@15.11.7): + vitest@2.1.9(@types/node@20.19.30)(happy-dom@15.11.7): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.19.24)) + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.19.30)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -2297,7 +1960,7 @@ snapshots: '@vitest/utils': 2.1.9 chai: 5.3.3 debug: 4.4.3 - expect-type: 1.2.2 + expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 std-env: 3.10.0 @@ -2305,11 +1968,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@20.19.24) - vite-node: 2.1.9(@types/node@20.19.24) + vite: 5.4.21(@types/node@20.19.30) + vite-node: 2.1.9(@types/node@20.19.30) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.19.24 + '@types/node': 20.19.30 happy-dom: 15.11.7 transitivePeerDependencies: - less @@ -2322,18 +1985,10 @@ snapshots: - supports-color - terser - webidl-conversions@4.0.2: {} - webidl-conversions@7.0.0: {} whatwg-mimetype@3.0.0: {} - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - which@2.0.2: dependencies: isexe: 2.0.0 @@ -2354,10 +2009,3 @@ snapshots: ansi-styles: 6.2.3 string-width: 5.1.2 strip-ansi: 7.1.2 - - zustand@4.5.7(@types/react@18.3.27)(react@18.3.1): - dependencies: - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.27 - react: 18.3.1 diff --git a/rust/core/src/bridge.rs b/rust/core/src/bridge.rs index 2d4d45c..27d4e56 100644 --- a/rust/core/src/bridge.rs +++ b/rust/core/src/bridge.rs @@ -4,7 +4,7 @@ use crate::{ crypto::{base64_decode, base64_encode, decrypt, encrypt}, error::{AppError, Error, Result}, types::{AppId, BridgeUrl, Proof, Request, Signal, VerificationLevel}, - ConstraintNode, Constraints, + Constraints, }; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -28,12 +28,45 @@ struct BridgeRequestPayload { #[serde(skip_serializing_if = "Option::is_none")] action_description: Option, - /// Set of requests + /// Set of requests (World App 4.0+ format - signals are unhashed) requests: Vec, - /// Optional constraints + /// Optional constraints (World App 4.0+ format) #[serde(skip_serializing_if = "Option::is_none")] constraints: Option, + + /// Hashed signal for legacy compatibility (World App 3.0) + /// Derived from the request with the max verification level credential type + signal: String, + + /// Max verification level derived from requests (World App 3.0 compatibility) + verification_level: VerificationLevel, +} + +/// Derives legacy bridge fields (`verification_level`, hashed signal) from requests. +/// +/// This enables backwards compatibility with World App 3.0 which expects: +/// - `verification_level`: The maximum (least restrictive) level from all credential types +/// - `signal`: The hashed signal from the request with the max credential type +/// +/// Priority (most to least restrictive): orb > `secure_document` > document > face > device +//TODO: This is not 100% accurate, will refine this in a followup PR, but for now it "works". +fn derive_legacy_fields(requests: &[Request]) -> (VerificationLevel, String) { + let cred_types: Vec<_> = requests.iter().map(|r| r.credential_type).collect(); + let verification_level = VerificationLevel::from_credential_types(&cred_types); + + let target_cred = verification_level.primary_credential(); + + let signal = requests + .iter() + .find(|r| r.credential_type == target_cred) + .and_then(|r| r.signal.as_ref()) + .map_or_else( + || crate::crypto::encode_signal(&Signal::from_string("")), + crate::crypto::encode_signal, + ); + + (verification_level, signal) } /// Encrypted payload sent to/from the bridge @@ -166,6 +199,9 @@ impl Session { #[cfg(not(feature = "native-crypto"))] let (key_bytes, nonce_bytes) = crate::crypto::generate_key()?; + // Derive legacy fields for World App 3.0 compatibility + let (verification_level, signal) = derive_legacy_fields(&requests); + // Prepare the payload let payload = BridgeRequestPayload { app_id: app_id.as_str().to_string(), @@ -173,6 +209,8 @@ impl Session { action_description, requests: requests.clone(), constraints, + signal, + verification_level, }; let payload_json = serde_json::to_vec(&payload)?; @@ -226,38 +264,6 @@ impl Session { }) } - /// Creates a session from a verification level - /// - /// This is a convenience method that maps a verification level (like "device" or "orb") - /// to the appropriate set of credential requests and constraints. - /// - /// # Errors - /// - /// Returns an error if the session cannot be created or the request fails - pub async fn from_verification_level( - app_id: AppId, - action: impl Into, - verification_level: VerificationLevel, - signal: impl Into, - ) -> Result { - let signal_str = signal.into(); - let credentials = verification_level.to_credentials(); - - let requests = credentials - .iter() - .map(|cred| Request::new(*cred, Some(Signal::from_string(signal_str.clone())))) - .collect(); - - let constraints = Constraints::new(ConstraintNode::any( - credentials - .into_iter() - .map(ConstraintNode::credential) - .collect(), - )); - - Self::create_with_options(app_id, action, requests, None, Some(constraints), None).await - } - /// Returns the connect URL for World App #[must_use] pub fn connect_url(&self) -> String { @@ -436,37 +442,6 @@ impl SessionWrapper { Ok(Self { runtime, inner }) } - /// Creates a session from a verification level - /// - /// # Errors - /// - /// Returns an error if the session cannot be created or the request fails - #[uniffi::constructor] - pub fn from_verification_level( - app_id: String, - action: String, - verification_level: VerificationLevel, - signal: String, - ) -> std::result::Result { - let runtime = - tokio::runtime::Runtime::new().map_err(|e| crate::error::IdkitError::BridgeError { - details: format!("Failed to create runtime: {e}"), - })?; - - let app_id_parsed = AppId::new(&app_id)?; - - let inner = runtime - .block_on(Session::from_verification_level( - app_id_parsed, - action, - verification_level, - signal, - )) - .map_err(crate::error::IdkitError::from)?; - - Ok(Self { runtime, inner }) - } - /// Returns the connect URL for World App #[must_use] pub fn connect_url(&self) -> String { @@ -531,17 +506,24 @@ mod tests { #[test] fn test_bridge_request_payload_serialization() { let request = Request::new(CredentialType::Orb, Some(Signal::from_string("test"))); + let requests = vec![request]; + let (verification_level, signal) = derive_legacy_fields(&requests); + let payload = BridgeRequestPayload { app_id: "app_test".to_string(), action: "test_action".to_string(), action_description: Some("Test description".to_string()), - requests: vec![request], + requests, constraints: None, + signal, + verification_level, }; let json = serde_json::to_string(&payload).unwrap(); assert!(json.contains("app_test")); assert!(json.contains("test_action")); + assert!(json.contains("verification_level")); + assert!(json.contains("\"signal\":\"0x")); } #[test] diff --git a/rust/core/src/types.rs b/rust/core/src/types.rs index 0bdc04c..139c3a1 100644 --- a/rust/core/src/types.rs +++ b/rust/core/src/types.rs @@ -470,6 +470,39 @@ impl VerificationLevel { ], } } + + /// Derives the maximum (least restrictive) verification level from credential types. + /// + /// Priority (most to least restrictive): orb > `secure_document` > document > face > device + #[must_use] + pub fn from_credential_types(types: &[CredentialType]) -> Self { + // Check in reverse priority order (least restrictive first) + if types.contains(&CredentialType::Device) { + Self::Device + } else if types.contains(&CredentialType::Face) { + Self::Face + } else if types.contains(&CredentialType::Document) { + Self::Document + } else if types.contains(&CredentialType::SecureDocument) { + Self::SecureDocument + } else { + Self::Orb + } + } + + /// Returns the primary credential type for this verification level. + /// + /// This is the credential type that determines the level (the least restrictive one). + #[must_use] + pub const fn primary_credential(&self) -> CredentialType { + match self { + Self::Orb => CredentialType::Orb, + Self::Face => CredentialType::Face, + Self::Device => CredentialType::Device, + Self::SecureDocument => CredentialType::SecureDocument, + Self::Document => CredentialType::Document, + } + } } // UniFFI helper function for CredentialType @@ -620,4 +653,74 @@ mod tests { ] ); } + + #[test] + fn test_verification_level_from_credential_types() { + // Priority (most → least restrictive): orb > secure_document > document > face > device + + // Single credentials + assert_eq!( + VerificationLevel::from_credential_types(&[CredentialType::Orb]), + VerificationLevel::Orb + ); + assert_eq!( + VerificationLevel::from_credential_types(&[CredentialType::Device]), + VerificationLevel::Device + ); + assert_eq!( + VerificationLevel::from_credential_types(&[CredentialType::Face]), + VerificationLevel::Face + ); + + // Multiple credentials - should return least restrictive + assert_eq!( + VerificationLevel::from_credential_types(&[ + CredentialType::Orb, + CredentialType::Device + ]), + VerificationLevel::Device + ); + assert_eq!( + VerificationLevel::from_credential_types(&[CredentialType::Orb, CredentialType::Face]), + VerificationLevel::Face + ); + assert_eq!( + VerificationLevel::from_credential_types(&[ + CredentialType::Orb, + CredentialType::SecureDocument, + CredentialType::Document + ]), + VerificationLevel::Document + ); + + // Empty defaults to Orb + assert_eq!( + VerificationLevel::from_credential_types(&[]), + VerificationLevel::Orb + ); + } + + #[test] + fn test_verification_level_primary_credential() { + assert_eq!( + VerificationLevel::Orb.primary_credential(), + CredentialType::Orb + ); + assert_eq!( + VerificationLevel::Device.primary_credential(), + CredentialType::Device + ); + assert_eq!( + VerificationLevel::Face.primary_credential(), + CredentialType::Face + ); + assert_eq!( + VerificationLevel::SecureDocument.primary_credential(), + CredentialType::SecureDocument + ); + assert_eq!( + VerificationLevel::Document.primary_credential(), + CredentialType::Document + ); + } } diff --git a/rust/core/src/wasm_bindings.rs b/rust/core/src/wasm_bindings.rs index d204e36..a769662 100644 --- a/rust/core/src/wasm_bindings.rs +++ b/rust/core/src/wasm_bindings.rs @@ -7,7 +7,7 @@ #![allow(clippy::missing_panics_doc)] #![allow(clippy::future_not_send)] -use crate::{CredentialType, Signal, VerificationLevel}; +use crate::{CredentialType, Signal}; use serde::Serialize; use std::cell::RefCell; use std::rc::Rc; @@ -251,54 +251,6 @@ pub struct Session { #[wasm_bindgen] impl Session { - /// Creates a new session from a verification level - /// - /// This is a convenience method that maps a verification level (like `"device"` or `"orb"`) - /// to the appropriate set of credential requests and constraints. - /// - /// # Errors - /// - /// Returns an error if the session cannot be created or the request fails - /// - /// # Arguments - /// - /// * `app_id` - Application ID from the Developer Portal (e.g., `"app_staging_xxxxx"`) - /// * `action` - Action identifier - /// * `verification_level` - Verification level as string (`"orb"`, `"device"`, etc.) - /// * `signal` - Optional signal string for cryptographic binding - #[wasm_bindgen(constructor)] - #[allow(clippy::new_ret_no_self)] // WASM async constructors return Promise - pub fn new( - app_id: String, - action: String, - verification_level: JsValue, - signal: Option, - ) -> js_sys::Promise { - future_to_promise(async move { - // Parse app_id - let app_id = crate::AppId::new(app_id) - .map_err(|e| JsValue::from_str(&format!("Invalid app_id: {e}")))?; - - // Parse verification level - let vl: VerificationLevel = serde_wasm_bindgen::from_value(verification_level) - .map_err(|e| JsValue::from_str(&format!("Invalid verification_level: {e}")))?; - - // Create session - let session = crate::Session::from_verification_level( - app_id, - action, - vl, - signal.unwrap_or_default(), - ) - .await - .map_err(|e| JsValue::from_str(&format!("Failed to create session: {e}")))?; - - Ok(JsValue::from(Self { - inner: Rc::new(RefCell::new(Some(session))), - })) - }) - } - /// Creates a new session from explicit requests and optional constraints /// /// # Arguments diff --git a/swift/Examples/BasicVerification.swift b/swift/Examples/BasicVerification.swift index 17a1167..570a4ed 100644 --- a/swift/Examples/BasicVerification.swift +++ b/swift/Examples/BasicVerification.swift @@ -73,14 +73,17 @@ func verificationWithStatusUpdates() async throws { } } -/// Example: Using verification level (Rust convenience method) +/// Example: Simple Orb verification (convenience pattern) @available(macOS 12.0, iOS 15.0, *) -func verificationWithLevel() async throws { - let session = try Session.fromVerificationLevel( +func verificationSimple() async throws { + // Simple helper: create Orb request with signal + let signal = Signal.fromString(s: "session_token_abc123") + let request = Request(credentialType: .orb, signal: signal) + + let session = try Session.create( appId: "app_staging_1234567890abcdef", action: "login", - verificationLevel: .orb, - signal: "session_token_abc123" + requests: [request] ) print("📱 QR Code: \(session.connectUrl())\n") @@ -221,7 +224,7 @@ struct ExamplesRunner { // try await basicVerification() // try await verificationWithStatusUpdates() - // try await verificationWithLevel() + // try await verificationSimple() // try await verificationWithConstraints() // try await verificationWithFaceAuth() // try await verificationWithAbiSignal() diff --git a/swift/README.md b/swift/README.md index 363d681..057c33c 100644 --- a/swift/README.md +++ b/swift/README.md @@ -88,17 +88,6 @@ for try await status in session.status() { } ``` -### Using Verification Level - -```swift -let session = try Session.fromVerificationLevel( - appId: "app_staging_123abc", - action: "login", - verificationLevel: .orb, - signal: "session_token" -) -``` - ### Multiple Requests with Constraints ```swift @@ -153,9 +142,8 @@ All core types are generated by UniFFI from the Rust implementation. This ensure **Static Methods:** - `create(appId:action:requests:)` - Create session - `createWithOptions(appId:action:requests:actionDescription:constraints:bridgeUrl:)` - Full options -- `fromVerificationLevel(appId:action:verificationLevel:signal:)` - Convenience method -- **Instance Methods:** +**Instance Methods:** - `pollForStatus() -> Status` - Poll for status (blocking) - `connectUrl() -> String` - Get connection URL - `requestId() -> String` - Get request ID diff --git a/swift/Tests/IDKitTests/IDKitTests.swift b/swift/Tests/IDKitTests/IDKitTests.swift index 81cedfc..dcd5e81 100644 --- a/swift/Tests/IDKitTests/IDKitTests.swift +++ b/swift/Tests/IDKitTests/IDKitTests.swift @@ -157,13 +157,6 @@ func sessionCreationAPIShape() { bridgeUrl: nil ) - _ = try? Session.fromVerificationLevel( - appId: "app_test_invalid", - action: "test", - verificationLevel: .orb, - signal: "test" - ) - // If we reach here without crashing, the APIs exist #expect(Bool(true)) }